@nelsonlongxiang/dsh-open-a2a-net 0.6.43 → 0.7.0

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 (73) hide show
  1. package/assets/nexusDist/assets/index-CA_YZTWG.js +9 -0
  2. package/assets/nexusDist/index.html +1 -1
  3. package/cli/a2a.mjs +19 -3
  4. package/lib/a2a-client.js +10 -2
  5. package/lib/admitted-bookkeeping.js +7 -0
  6. package/lib/canvas-discovery.js +11 -1
  7. package/lib/canvas-member.js +43 -0
  8. package/lib/canvas-store.js +70 -4
  9. package/lib/direct-forward.js +9 -7
  10. package/lib/faces/admin.js +50 -7
  11. package/lib/faces/files.js +2 -1
  12. package/lib/faces/wire.js +566 -468
  13. package/lib/followup-delivery.js +89 -0
  14. package/lib/idempotency-store.js +8 -0
  15. package/lib/inbound-verification.js +23 -0
  16. package/lib/index.js +478 -156
  17. package/lib/nudge-observability.js +34 -0
  18. package/lib/origin-claim.js +36 -9
  19. package/lib/outbound-scope.js +4 -2
  20. package/lib/peer-directory.js +15 -5
  21. package/lib/peer-store.js +31 -17
  22. package/lib/queue-guard.js +4 -3
  23. package/lib/receipt-ladder.js +1 -1
  24. package/lib/receipt-retry.js +58 -0
  25. package/lib/reconciliation-reminders.js +148 -0
  26. package/lib/reconciliation-state.js +27 -0
  27. package/lib/session-transcript.js +46 -18
  28. package/lib/skill/SKILL.md +5 -0
  29. package/lib/skill/references/cli.md +4 -1
  30. package/lib/skill/references/routing.md +31 -1
  31. package/lib/task-auth.js +3 -3
  32. package/lib/task-delivery.js +23 -0
  33. package/lib/task-ledger-persistence.js +51 -0
  34. package/lib/task-ledger-rows.js +5 -0
  35. package/lib/task-ledger.js +219 -20
  36. package/lib/tools/info.js +37 -7
  37. package/lib/types/a2a-client.d.ts +1 -1
  38. package/lib/types/admitted-bookkeeping.d.ts +5 -0
  39. package/lib/types/canvas-member.d.ts +10 -0
  40. package/lib/types/canvas-store.d.ts +8 -0
  41. package/lib/types/faces/admin.d.ts +19 -0
  42. package/lib/types/faces/files.d.ts +1 -1
  43. package/lib/types/faces/wire.d.ts +21 -14
  44. package/lib/types/followup-delivery.d.ts +25 -0
  45. package/lib/types/idempotency-store.d.ts +2 -0
  46. package/lib/types/inbound-verification.d.ts +14 -0
  47. package/lib/types/index.d.ts +5 -0
  48. package/lib/types/nudge-observability.d.ts +17 -0
  49. package/lib/types/origin-claim.d.ts +7 -1
  50. package/lib/types/outbound-scope.d.ts +1 -0
  51. package/lib/types/peer-store.d.ts +4 -0
  52. package/lib/types/queue-guard.d.ts +9 -2
  53. package/lib/types/receipt-ladder.d.ts +2 -0
  54. package/lib/types/receipt-retry.d.ts +22 -0
  55. package/lib/types/reconciliation-reminders.d.ts +41 -0
  56. package/lib/types/reconciliation-state.d.ts +32 -0
  57. package/lib/types/session-transcript.d.ts +6 -1
  58. package/lib/types/task-auth.d.ts +7 -0
  59. package/lib/types/task-delivery.d.ts +17 -0
  60. package/lib/types/task-ledger-persistence.d.ts +3 -0
  61. package/lib/types/task-ledger-rows.d.ts +19 -2
  62. package/lib/types/task-ledger.d.ts +48 -1
  63. package/lib/types/tools/info.d.ts +3 -0
  64. package/lib/types/types.d.ts +3 -0
  65. package/nexus-stage/src/federation.ts +1 -0
  66. package/nexus-stage/src/main.ts +10 -2
  67. package/nexus-stage/src/member-provenance-picker.ts +13 -0
  68. package/nexus-stage/src/planning-member-handles.ts +4 -1
  69. package/nexus-stage/src/planning-view.ts +3 -3
  70. package/nexus-stage/src/workbench.ts +28 -6
  71. package/nexus-stage/src/world.ts +1 -0
  72. package/package.json +3 -2
  73. package/assets/nexusDist/assets/index-CaA76j0F.js +0 -9
@@ -0,0 +1,9 @@
1
+ var To=Object.defineProperty;var _o=(e,t,o)=>t in e?To(e,t,{enumerable:!0,configurable:!0,writable:!0,value:o}):e[t]=o;var Lt=(e,t,o)=>_o(e,typeof t!="symbol"?t+"":t,o);(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const n of document.querySelectorAll('link[rel="modulepreload"]'))s(n);new MutationObserver(n=>{for(const i of n)if(i.type==="childList")for(const r of i.addedNodes)r.tagName==="LINK"&&r.rel==="modulepreload"&&s(r)}).observe(document,{childList:!0,subtree:!0});function o(n){const i={};return n.integrity&&(i.integrity=n.integrity),n.referrerPolicy&&(i.referrerPolicy=n.referrerPolicy),n.crossOrigin==="use-credentials"?i.credentials="include":n.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function s(n){if(n.ep)return;n.ep=!0;const i=o(n);fetch(n.href,i)}})();const un=6e4;function Oo(e,t,o=Date.now){let s=-un;return{fault(n){const i=o();i-s>=un&&(t(`[nexus] ${n}`),s=i),e.show(n)},clear(){e.hide(),s=-un}}}function bt(e){return e.name??e.team??e.label??""}function lo(e,t){var i,r;const o=(c,l)=>c!==void 0&&c.trim()!==""?{name:c,remote:l}:void 0,s=(e.sessions??[]).find(c=>c.team===t);if(s!==void 0)return o(bt(s),!1);const n=(e.remote??[]).find(c=>c.team===t);return n!==void 0?o(bt(n),!0):o((r=(((i=e.canvas)==null?void 0:i.teams)??[]).find(c=>c.team===t))==null?void 0:r.name,!1)}function Fo(e,t){const o=lo(e,t);return o===void 0?t:o.remote?`${o.name}(远端)`:o.name}function Qt(e,t,o,s=""){const n=lo(t,o);if(e.textContent=`${s}${(n==null?void 0:n.name)??o}`,e.title=o,(n==null?void 0:n.remote)===!0){const i=e.appendChild(document.createElement("span"));i.className="wb-row-remote",i.textContent="远端",i.title="名字由对端自行发布"}}const Po=60*6e4;function Tt(e){var t;return e.direction==="inbound"||e.direction===void 0&&((t=e.peer)==null?void 0:t.startsWith("local:"))===!0}function On(e){var t;return((t=e.peer)==null?void 0:t.startsWith("local:"))===!0?e.peer.slice(6):void 0}function Bt(e,t){return e.settleable!==void 0?e.settleable===!1:t-e.startedAt>=Po}function vn(e,t){const o=(e.tasks??[]).filter(r=>r.receiptExpected!==!1),s=o.filter(r=>!Tt(r)&&Bt(r,t)),n=o.filter(r=>Tt(r)&&Bt(r,t)),i=e.tasksDead??[];return{stale:s,owedOverdue:n,deadLetters:i.filter(r=>r.reason!=="fire-forget"),expired:i.filter(r=>r.reason==="fire-forget")}}function $e(e,t){const o=document.createElement(e);return t!==void 0&&(o.className=t),o}function Fn(e,t){const o=Math.max(0,Math.round((t-e)/1e3));if(o<90)return`${o}s`;const s=Math.round(o/60);if(s<90)return`${s}m`;const n=Math.round(s/60);return n<48?`${n}h`:`${Math.round(n/24)}d`}function Kt(e,t,o,s,n){const i=$e("div",`wb-led-tile${n!==void 0?` is-${n}`:""}`);i.title=s,i.appendChild($e("span","wb-led-tile-v")).textContent=String(o),i.appendChild($e("span","wb-led-tile-k")).textContent=t,e.appendChild(i)}const yn=[{key:"completed",label:"完成",tone:"completed"},{key:"sync_completed",label:"同步完成",tone:"completed"},{key:"rejected",label:"拒绝",tone:"rejected"},{key:"failed",label:"失败",tone:"failed"},{key:"expired",label:"过期",tone:"abandoned"},{key:"abandoned",label:"放弃",tone:"abandoned"},{key:"unknown",label:"结论不明",tone:"unclassified"},{key:"unclassified",label:"未分类",tone:"unclassified"}];function Ro(e,t,o){const s=$e("div","wb-led-split"),n=$e("div","wb-led-split-bar");n.setAttribute("role","img");const i=$e("div","wb-led-split-legend"),r=new Set(yn.map(u=>u.key)),c=yn.map(u=>[u.tone,u.label,t[u.key]??0]);for(const[u,h]of Object.entries(t))r.has(u)||c.push(["other",u,h]);const l=[];for(const[u,h,m]of c){if(m<=0)continue;const C=$e("span",`wb-led-seg is-${u}`);C.style.width=`${Math.max(2,m/o*100)}%`,n.appendChild(C);const N=$e("span","wb-led-split-item");N.appendChild($e("i",`wb-led-swatch is-${u}`)),N.appendChild(document.createTextNode(`${h} ${m}`)),i.appendChild(N),l.push(`${h} ${m}`)}n.setAttribute("aria-label",`归档结局:${l.join(",")}`),s.append(n,i),e.appendChild(s)}function Do(e,t){var Se;e.replaceChildren();const{state:o,now:s}=t,n=o.tasks??[],i=o.tasksDead??[],r=o.archivedCount??0,c=vn(o,s),l=n.filter(R=>R.receiptExpected===!1),u=n.filter(R=>R.receiptExpected!==!1),h=u.filter(R=>Tt(R)),m=u.filter(R=>!Tt(R)),C=c.stale,N=m.filter(R=>!Bt(R,s)),J=c.stale.length,ne=$e("div","wb-led-tiles");Kt(ne,"待回执",u.length,`要回执、仍未结算的任务(含陈旧与本机欠对方的入站行)${l.length>0?`;另有免回执 ${l.length} 条不计`:""}`),Kt(ne,"陈旧",J,"我方派发、要回执、已等待 ≥1h 仍未回执(可催办);本机欠对方的入站行在「待本机回执」组另计,免回执行不算陈旧",J>0?"warn":void 0),Kt(ne,"死信",c.deadLetters.length,"超过 24h TTL 仍未结算(unconsumed);需清账(abandon)才能移出。免回执到期另列,不算死信",c.deadLetters.length>0?"danger":void 0),Kt(ne,"已归档",r,"已离开台账并留档的任务(结算、拒绝或放弃),用于审计"),e.appendChild(ne),r>0&&o.archivedSplit!==void 0&&Ro(e,o.archivedSplit,r);const G=(R,q)=>{const le=$e("div",`wb-led-card is-${q.tone}`),Ke=$e("div","wb-led-card-head");Ke.appendChild($e("span",`wb-led-dir${q.inbound?" is-in":""}`)).textContent=q.inbound?"↙":"↗";const Me=$e("span","wb-led-brief");Me.textContent=q.brief!==void 0&&q.brief!==""?q.brief:"(无摘要——派发未带 brief)",(q.brief===void 0||q.brief==="")&&Me.classList.add("is-missing"),Ke.appendChild(Me),le.appendChild(Ke);const de=$e("div","wb-led-meta"),Ue=de.appendChild($e("span","wb-led-team"));q.inbound?q.sender!==void 0?Qt(Ue,o,q.sender,"来自 "):Ue.textContent="来自 对端":Qt(Ue,o,q.team,"发往 "),q.inbound&&Qt(de.appendChild($e("span","wb-led-to")),o,q.team,"至 "),de.appendChild($e("span")).textContent=q.atText,de.appendChild($e("span","wb-led-task")).textContent=q.taskId;for(const ue of q.chips)de.appendChild($e("span","wb-led-chip")).textContent=ue;if(le.appendChild(de),le.title=`${q.taskId}
2
+ ${q.team}`,q.dead!==void 0){const ue=q.dead,V=ue.reason==="fire-forget",ce=$e("button",`wb-btn wb-led-abandon${V?" is-quiet":""}`);ce.type="button",ce.textContent=V?"移出":"清账",ce.title=V?"可选:把这条已过期的免回执记录移出台账(不是失败,不处理也无妨)":"从台账移出这条死信(abandon)",ce.addEventListener("click",ie=>{ie.stopPropagation(),ce.disabled=!0,t.abandon(ue.taskId,"workbench dead-letter cleanup").then(ee=>{ce.disabled=!1,ce.textContent=ee?"已清":"失败"})}),le.appendChild(ce)}if(t.canOpenTeam(q.team)){le.classList.add("is-link"),le.setAttribute("role","button"),le.tabIndex=0,le.setAttribute("aria-label",`${Me.textContent},打开 ${q.team} 的对话`);const ue=()=>{t.openTeam(q.team)};le.addEventListener("click",ue),le.addEventListener("keydown",V=>{(V.key==="Enter"||V.key===" ")&&(V.preventDefault(),ue())})}R.appendChild(le)},$=(R,q,le,Ke)=>{if(q===0)return null;const Me=$e("div",`wb-led-group is-${le}`);Me.dataset.group=R;const de=$e("div","wb-led-group-head");return de.appendChild($e("span")).textContent=`${R} · ${q}`,de.appendChild($e("span","wb-led-group-hint")).textContent=Ke,Me.appendChild(de),e.appendChild(Me),Me},E=(R,q)=>{const le=Tt(R);return{brief:R.brief,team:R.team,sender:On(R),taskId:R.taskId,atText:`${Fn(R.startedAt,s)} 前${le?"收到":"派发"}`,inbound:le,tone:q,chips:[...R.settleable===!0?["可结算"]:[],...R.receiptExpected===!1?["无回执债"]:[],...le?["入站"]:[],...R.status!=="pending"?[R.status]:[]]}},S=(R,q,le)=>({brief:R.brief,team:R.team,sender:On(R),taskId:R.taskId,atText:`${Fn(R.deadAt,s)} 前${le}`,inbound:Tt(R),tone:q,dead:R,chips:R.reason!==void 0&&R.reason!==""&&R.reason!=="unspecified"&&R.reason!=="fire-forget"?[R.reason]:[]}),w=$("死信",c.deadLetters.length,"danger","需清账");if(w!==null)for(const R of[...c.deadLetters].sort((q,le)=>le.deadAt-q.deadAt))G(w,S(R,"danger","死信"));const oe=$("陈旧",C.length,"warn","我方派发 ≥1 小时仍无回执,可催办");if(oe!==null)for(const R of[...C].sort((q,le)=>q.startedAt-le.startedAt))G(oe,E(R,"warn"));const y=c.owedOverdue.length,b=$("待本机回执",h.length,y>0?"warn":"quiet",y>0?`对方在等本机回执 · ${y} 条超过 1 小时`:"对方在等本机回执");if(b!==null)for(const R of[...h].sort((q,le)=>q.startedAt-le.startedAt))G(b,E(R,Bt(R,s)?"warn":"quiet"));const M=$("等待回执",N.length,"quiet","1 小时内");if(M!==null)for(const R of[...N].sort((q,le)=>le.startedAt-q.startedAt))G(M,E(R,"quiet"));const f=$("免回执",l.length,"muted","不等回执,24h 后自动归档");if(f!==null)for(const R of l)G(f,E(R,"muted"));const D=$("已过期(免回执)",c.expired.length,"muted","正常记账,不是失败");if(D!==null)for(const R of[...c.expired].sort((q,le)=>le.deadAt-q.deadAt))G(D,S(R,"muted","过期"));n.length+i.length===0&&(e.appendChild($e("div","wb-led-empty")).textContent="台账为空——没有待回执的任务");const K=o.idempotency,X=(Se=o.reconcile)==null?void 0:Se.state;if(K!==void 0||X!==void 0){const R=$e("details","wb-led-forensics wb-forensics");R.appendChild($e("summary")).textContent="取证";const q=$e("div","wb-led-forensics-body");K!==void 0&&(q.appendChild($e("div")).textContent=`幂等 claims ${K.claimsFresh??0} · replays ${K.replays??0} · conflicts ${K.conflicts??0}`),X!==void 0&&(q.appendChild($e("div")).textContent=`reconcile ${X}`),R.appendChild(q),e.appendChild(R)}const ye=u.length+c.deadLetters.length;return{badge:ye>0?String(ye):"",tone:c.deadLetters.length>0?"danger":J>0||y>0?"warn":void 0}}const Pt=4e3,Ho=32;function xe(e,t){const o=document.createElement(e);return t!==void 0&&(o.className=t),o}function Xt(e,t,o=""){const s=xe("button",`wb-icon-btn wb-chat-act ${o}`.trim());return s.type="button",s.setAttribute("aria-label",e),s.title=e,s.textContent=t,s}function fn(e,t){const o=Math.max(0,Math.round((t-e)/1e3));if(o<60)return"刚刚";const s=Math.round(o/60);if(s<60)return`${s} 分钟前`;const n=Math.round(s/60);return n<48?`${n} 小时前`:`${Math.round(n/24)} 天前`}function jo(e){return e>=1e6?`${(e/1e6).toFixed(1)} MB`:e>=1e3?`${Math.round(e/1e3)} KB`:`${e} B`}function pn(e){const t=e.kind==="session"||e.kind==="remote"?e.team:void 0;return t!==void 0&&t!==""?t:void 0}function Pn(e){return e.kind==="remote"?`remote:${e.team}`:`${e.kind}:${e.id}`}function Bo(e){let t=null,o=null,s=!1,n=!1;const i=new Map,r=new Map,c=new Map,l=new Map,u=new Set,h=new Map,m=new Map,C=xe("aside","wb-chat");C.setAttribute("aria-label","对话");const N=xe("div","wb-chat-head"),J=Xt("返回会话列表","‹","wb-chat-back"),ne=xe("span","wb-chat-dot"),G=xe("div","wb-chat-titles"),$=xe("span","wb-chat-title"),E=xe("span","wb-chat-sub");G.append($,E);const S=Xt("刷新对话","↻","wb-chat-refresh"),w=Xt("会话详情","ⓘ","wb-chat-info-btn");w.setAttribute("aria-expanded","false");const oe=Xt("关闭对话","✕","wb-chat-close");N.append(J,ne,G,S,w,oe);const y=xe("div","wb-chat-info");y.hidden=!0;const b=xe("div","wb-chat-thread");b.setAttribute("role","log"),b.setAttribute("aria-live","polite"),b.tabIndex=0;const M=xe("div","wb-chat-notice"),f=xe("div","wb-chat-log"),D=xe("div","wb-chat-sent");b.append(M,f,D);const K=xe("div","wb-chat-foot");C.append(N,y,b,K),J.addEventListener("click",()=>{(t==null?void 0:t.kind)==="peer"&&(t.picked=void 0,Ye())}),S.addEventListener("click",()=>{if(t===null)return;const d=X(t);d!==void 0&&i.delete(d),t.kind==="peer"&&t.picked===void 0&&t.url!==void 0&&c.delete(`peer:${t.url}`),ce(!0)}),w.addEventListener("click",()=>{n=!n,y.hidden=!n,w.setAttribute("aria-expanded",String(n))}),oe.addEventListener("click",()=>ft()),b.addEventListener("scroll",()=>{const d=t!==null?X(t):void 0;d!==void 0&&r.set(d,b.scrollTop)}),document.addEventListener("keydown",d=>{if(d.key!=="Escape"||!C.classList.contains("is-open"))return;const _=d.target;if(_ instanceof HTMLElement){if(!C.contains(_)){const I=_ instanceof HTMLTextAreaElement||_ instanceof HTMLInputElement||_.isContentEditable,Z=_.closest(".wb-stage-board")!==null;if(I||Z)return}ft()}});function X(d){if(d.kind==="session"||d.kind==="log")return e.sessionLog!==void 0?`local:${d.id}`:void 0;if(d.kind==="remote")return e.remoteSessionLog!==void 0?`remote:${d.team}`:void 0;if(d.picked!==void 0&&d.url!==void 0&&e.remoteSessionLog!==void 0)return`peer:${d.url}:${d.picked}`}function ye(d){var _,I,Z;return d.kind==="session"||d.kind==="log"?((_=e.sessionLog)==null?void 0:_.call(e,d.id))??Promise.resolve({ok:!1,error:"sessionLog unavailable"}):d.kind==="remote"?((I=e.remoteSessionLog)==null?void 0:I.call(e,{team:d.team}))??Promise.resolve({ok:!1,error:"remoteSessionLog unavailable"}):((Z=e.remoteSessionLog)==null?void 0:Z.call(e,{peer:d.url,id:d.picked}))??Promise.resolve({ok:!1,error:"remoteSessionLog unavailable"})}function Se(){const d=t;if(d===null)return;const _=d.kind==="log"||d.kind==="remote"||d.kind==="session"&&d.live===!1;ne.className=`wb-chat-dot ${d.kind==="peer"?"is-peer":_?"is-cold":"is-live"}`,ne.title=d.kind==="peer"?"对端主机":d.kind==="log"?"只读日志":d.kind==="remote"?"远端会话":d.live===!1?"冷会话":"在线",$.textContent=d.kind==="peer"&&d.picked!==void 0?`…${d.picked.slice(-12)}`:d.title,E.textContent=d.kind==="peer"&&d.picked!==void 0?d.title:d.sub,J.hidden=!(d.kind==="peer"&&d.picked!==void 0)}function R(d,_){const I=xe("div","wb-kv");I.appendChild(xe("span","wb-kv-k")).textContent=d,I.appendChild(xe("span","wb-kv-v")).textContent=_,y.appendChild(I)}function q(){var _,I,Z;y.replaceChildren();const d=t;d!==null&&(d.kind==="session"?(R("会话",d.id),d.team!==void 0&&R("路由",d.team),R("来源","本机会话日志")):d.kind==="log"?(R("会话",d.id),R("来源","本机会话日志(不在网络目录)")):d.kind==="remote"?(R("路由",d.team),((_=d.row)==null?void 0:_.origin)!==void 0&&R("来源",d.row.origin),((I=d.row)==null?void 0:I.via)!==void 0&&R("经",d.row.via),((Z=d.row)==null?void 0:Z.workspace)!==void 0&&R("工作区",d.row.workspace)):(R("对端",d.url??d.sub),d.picked!==void 0&&R("会话",d.picked),R("来源","经本机代理读取对端 /a2a/log")))}function le(d){return d.kind==="log"?"只读日志 —— 此会话当前不在网络目录(可能已归档或未入网)。":d.kind==="remote"?e.remoteSessionLog!==void 0?"远端会话 —— 经本机代理从对端 /a2a/log 读取最近对话。":"远端节点的对话记录在对端机器上;本页的代理读取面未启用。":d.kind==="peer"?d.url===void 0||e.remoteSessionLog===void 0?`对端主机节点(${d.sub})—— 会话记录存放在对端机器上,本页只读本机会话日志。`:d.picked===void 0?"对端主机 —— 选择一个会话阅读(经本机代理读取对端 /a2a/log)。":"":e.sessionLog===void 0?"本页未接入会话日志读取,只显示从这里发出的消息。":""}function Ke(){return b.scrollHeight-b.scrollTop-b.clientHeight<=Ho}function Me(d){const _=()=>{b.scrollTop=b.scrollHeight};_(),requestAnimationFrame(_)}function de(d,_){const I=xe("div",`wb-chat-empty${_==="error"?" is-error":""}`);return I.textContent=d,I}function Ue(d,_){const I=d==="user",Z=xe("div",`wb-msg ${I?"wb-msg-user":"wb-msg-assistant"}`),Y=xe("span","wb-msg-who");Y.textContent=I?"问":"答";const he=xe("div","wb-msg-text");return he.textContent=_,Z.append(Y,he),Z}function ue(d){if(f.replaceChildren(),d===void 0){f.appendChild(de("读取中…"));return}if(d.ok!==!0||d.messages===void 0){f.appendChild(de(`无法读取(${d.error??"未知错误"})`,"error"));return}if(d.messages.length===0){f.appendChild(de("暂无对话记录"));return}for(const _ of d.messages)f.appendChild(Ue(_.role,_.text))}function V(d,_){if(f.replaceChildren(),_===void 0){f.appendChild(de("读取中…"));return}if(_.ok!==!0||_.sessions===void 0){f.appendChild(de(`无法读取(${_.error??"未知错误"})`,"error"));return}if(_.sessions.length===0){f.appendChild(de("对端没有可读会话"));return}const I=xe("div","wb-chat-sessions"),Z=e.now();for(const Y of _.sessions){const he=xe("button","wb-chat-session");he.type="button",he.appendChild(xe("span","wb-chat-session-id")).textContent=`…${Y.id.slice(-12)}`;const pe=[Y.mtimeMs!==void 0?fn(Y.mtimeMs,Z):"",jo(Y.sizeBytes)].filter(Boolean).join(" · ");he.appendChild(xe("span","wb-chat-session-meta")).textContent=pe,he.title=Y.id,he.addEventListener("click",()=>{(t==null?void 0:t.kind)!=="peer"||t.url!==d||(t.picked=Y.id,Ye())}),I.appendChild(he)}f.appendChild(I)}function ce(d=!1){const _=t;if(_===null)return;if(M.textContent=le(_),M.hidden=M.textContent==="",_.kind==="peer"&&_.picked===void 0){if(_.url===void 0||e.remoteSessionLog===void 0){f.replaceChildren();return}const Y=_.url,he=`peer:${Y}`;if(!d&&c.has(he)){V(Y,c.get(he));return}c.set(he,void 0),V(Y,void 0),e.remoteSessionLog({peer:Y}).then(pe=>{c.set(he,pe),(t==null?void 0:t.kind)==="peer"&&t.url===Y&&t.picked===void 0&&V(Y,pe)},pe=>{const we={ok:!1,error:pe instanceof Error?pe.message:String(pe)};c.set(he,we),(t==null?void 0:t.kind)==="peer"&&t.url===Y&&t.picked===void 0&&V(Y,we)});return}const I=X(_);if(I===void 0){f.replaceChildren(),Ze(!0);return}const Z=()=>{const Y=r.get(I);Y===void 0||d?Me():(b.scrollTop=Y,requestAnimationFrame(()=>{t!==null&&X(t)===I&&(b.scrollTop=Y)}))};if(!d&&i.has(I)&&i.get(I)!==void 0){ue(i.get(I)),Ze(!0),Z();return}d&&r.delete(I),i.set(I,void 0),ue(void 0),Ze(!0),ye(_).then(Y=>{var he;i.set(I,Y),(Y==null?void 0:Y.ok)===!0&&Y.messages!==void 0&&((he=e.onTranscript)==null||he.call(e,_,Y.messages)),!(t===null||X(t)!==I)&&(ue(Y),Ze(),Z())},Y=>{const he={ok:!1,error:Y instanceof Error?Y.message:String(Y)};i.set(I,he),t!==null&&X(t)===I&&ue(he)})}function ie(d){return((o==null?void 0:o.tasks)??[]).filter(_=>_.team===d)}function ee(d){return((o==null?void 0:o.tasksDead)??[]).filter(_=>_.team===d)}let ke="";function et(d){return d.reason==="fire-forget"?{text:"已过期(免回执)",tone:"muted",hint:"免回执消息到 24h TTL 归档,属正常记账"}:{text:"死信",tone:"danger",hint:d.reason!==void 0&&d.reason!=="unspecified"?`${d.reason}:超过 24h TTL 仍未结算,需在台账清账`:"超过 24h TTL 仍未结算,需在台账清账"}}function Oe(d,_){const I=d.direction==="inbound";if(d.receiptExpected===!1)return{text:I?"来信 · 无需回执":"已送达 · 无回执",tone:"muted",hint:"免回执消息:不等回执,24h 后自动归档"};const Z=Bt(d,_),Y=I?Z?"待本机回执 · 超 1 小时":"待本机回执":Z?"陈旧":"待回执",he=d.status!=="pending"?` · ${d.status}`:"";return{text:`${Y}${he}`,tone:Z?"warn":"wait",hint:`${I?"对方等待本机回执;":""}${I?"收到":"派发"}于 ${fn(d.startedAt,_)}`}}function tt(d,_){const I=`结算于 ${fn(d.resolvedAt,_)}`;if(d.receiptExpected===!1&&d.endedBy==="abandoned")return d.late===!0?{text:"已移出(免回执) · 回执迟到",tone:"warn",hint:`${I};免回执消息本机移出后对方回执才到,结局不改写`}:{text:"已移出(免回执)",tone:"muted",hint:`${I};免回执消息,本机移出台账,不是失败`};if(d.endedBy==="abandoned"||d.endedBy==="cancelled"){const pe=d.endedBy==="cancelled"?"撤回":"放弃";return d.late===!0?{text:`已${pe} · 回执迟到`,tone:"warn",hint:`${I};本机${pe}之后对方回执才到,结局不改写`}:{text:`已${pe}`,tone:"muted",hint:`${I};本机${pe},未等到回执`}}if(d.endedBy==="echo")return{text:"已结算 · 内容回显",tone:"ok",hint:`${I};对方回了内容但未带正式回执,按内容回显结算`};if(d.endedBy===void 0&&d.outcome==="abandoned")return{text:"已放弃(本机或对方)",tone:"muted",hint:`${I};本机放弃或撤回,或对方回执报告放弃`};const Z=d.summary!==void 0&&d.summary!==""?` · ${d.summary}`:"";if(d.outcome==="abandoned")return{text:"已回执 · 对方放弃",tone:"warn",hint:`${I};对方回执报告放弃${Z}`};const Y=yn.find(pe=>pe.key===d.outcome),he=(Y==null?void 0:Y.tone)==="completed"?"ok":(Y==null?void 0:Y.tone)==="failed"?"danger":(Y==null?void 0:Y.tone)==="rejected"?"warn":"muted";return d.outcome==="unclassified"?{text:"已回执",tone:"ok",hint:`${I};回执未带结论${Z}`}:{text:`已回执 · ${(Y==null?void 0:Y.label)??d.outcome}`,tone:he,hint:`${I}${Z}`}}function st(d,_,I){const Z=ee(_).find(pe=>pe.taskId===d);if(Z!==void 0)return et(Z);const Y=ie(_).find(pe=>pe.taskId===d);if(Y!==void 0)return Oe(Y,I);const he=((o==null?void 0:o.archived)??[]).find(pe=>pe.taskId===d&&pe.team===_);return he!==void 0?tt(he,I):u.has(d)?{text:"已离开台账",tone:"muted",hint:"已结算、放弃或撤回之一;主机未给出这条的结局(旧主机,或已超出最近 64 条归档)"}:{text:"已派发",tone:"muted",hint:"异步送达;回执到达后进台账"}}function St(d){const _=e.now(),I=l.get(d)??[],Z=new Set(I.map(me=>me.taskId).filter(me=>me!==void 0)),Y=me=>me!==void 0&&me!==""?me:"(无摘要)",he=ie(d).filter(me=>!Z.has(me.taskId)).map(me=>({at:me.startedAt,side:me.direction==="inbound"?"theirs":"mine",text:Y(me.brief),status:Oe(me,_),taskId:me.taskId})),pe=ee(d).filter(me=>!Z.has(me.taskId)).map(me=>{var Pe;const Fe=me.direction??h.get(me.taskId)??(((Pe=me.peer)==null?void 0:Pe.startsWith("local:"))===!0?"inbound":void 0);return{at:me.startedAt,side:Fe==="inbound"?"theirs":Fe==="outbound"?"mine":"system",text:Y(me.brief),status:et(me),taskId:me.taskId}}),we=I.map(me=>({at:me.at,side:"mine",text:me.text,status:me.state==="sending"?{text:"发送中…",tone:"muted"}:me.state==="failed"?{text:`失败:${me.error??"未知原因"}`,tone:"danger"}:me.taskId!==void 0?st(me.taskId,d,_):{text:"已派发",tone:"muted"},taskId:me.taskId}));return[...he,...pe,...we].sort((me,Fe)=>me.at-Fe.at)}function Ze(d=!1){const _=t,I=_!==null?pn(_):void 0,Z=I!==void 0?St(I):[],Y=JSON.stringify([I??"",...Z.map(we=>[we.taskId??"",we.side,we.text,we.status.text])]);if(!d&&Y===ke)return;ke=Y;const he=Ke();if(D.replaceChildren(),Z.length===0)return;const pe=xe("div","wb-chat-divider");pe.textContent="台账往来 · 异步送达,回执进台账",D.appendChild(pe);for(const we of Z){const me=we.side==="mine"?"wb-msg wb-msg-user wb-msg-out":we.side==="theirs"?"wb-msg wb-msg-assistant wb-msg-in":"wb-msg wb-msg-ledger",Fe=xe("div",me);Fe.appendChild(xe("span","wb-msg-who")).textContent=we.side==="mine"?"我":we.side==="theirs"?"对方":"台账记录",Fe.appendChild(xe("div","wb-msg-text")).textContent=we.text;const Pe=xe("div","wb-msg-meta");we.taskId!==void 0&&(Pe.appendChild(xe("span","wb-msg-task")).textContent=we.taskId);const Je=xe("span",`wb-msg-status is-${we.status.tone}`);Je.textContent=we.status.text,we.status.hint!==void 0&&(Je.title=we.status.hint),Pe.appendChild(Je),Fe.appendChild(Pe),D.appendChild(Fe)}he&&Me()}function Ve(d){const _=d.text.value.length;d.note.classList.remove("is-error"),d.note.textContent=_>Pt*.9?`${_}/${Pt}`:"Enter 发送 · Shift+Enter 换行",_>Pt&&d.note.classList.add("is-error"),d.submit.disabled=d.text.value.trim()===""||_>Pt}function Nt(d){d.style.height="auto",d.style.height=`${Math.min(d.scrollHeight,160)}px`}function Ot(d){const _=xe("form","wb-dispatch-form wb-chat-composer"),I=document.createElement("textarea");I.className="wb-dispatch-text",I.rows=1,I.placeholder="发一句话任务给这个节点…",I.setAttribute("aria-label","发送消息");const Z=xe("button","wb-dispatch-submit");Z.type="submit",Z.textContent="发送",Z.setAttribute("aria-label","发送");const Y=xe("div","wb-dispatch-note");Y.setAttribute("aria-live","polite");const he=xe("div","wb-chat-composer-row");he.append(I,Z),_.append(he,Y);const pe={team:d,form:_,text:I,note:Y,submit:Z};return I.addEventListener("input",()=>{Nt(I),Ve(pe)}),I.addEventListener("keydown",we=>{we.key!=="Enter"||we.shiftKey||we.ctrlKey||we.altKey||we.metaKey||we.isComposing||(we.preventDefault(),_.requestSubmit())}),_.addEventListener("submit",we=>{we.preventDefault();const me=I.value.trim();if(me===""||me.length>Pt||e.dispatchQuick===void 0)return;const Fe={text:me,at:e.now(),state:"sending"},Pe=l.get(d)??[];Pe.push(Fe),l.set(d,Pe),I.value="",Nt(I),Ve(pe),I.focus({preventScroll:!0}),Ze(),Me(),e.dispatchQuick(d,me).then(Je=>Je,Je=>({ok:!1,error:Je instanceof Error?Je.message:String(Je)})).then(Je=>{Je.ok===!0?(Fe.state="sent",Fe.taskId=Je.task_id,Y.classList.remove("is-error"),Y.textContent=`已派发${Je.task_id!==void 0?` · ${Je.task_id}`:""} · 回执将入台账`):(Fe.state="failed",Fe.error=Je.error??"未知原因",I.value===""&&(I.value=me,Nt(I)),Y.classList.add("is-error"),Y.textContent=`失败:${Fe.error}`,Z.disabled=I.value.trim()===""),t!==null&&pn(t)===d&&Ze()})}),Ve(pe),pe}function Re(){const d=t;if(K.replaceChildren(),d===null)return;const _=pn(d);if(_!==void 0&&e.dispatchQuick!==void 0){let Z=m.get(_);Z===void 0&&(Z=Ot(_),m.set(_,Z)),K.appendChild(Z.form),s&&(s=!1,Z.text.focus({preventScroll:!0}));return}s=!1;const I=xe("div","wb-chat-readonly");I.textContent=d.kind==="log"?"只读日志:此会话不在网络目录,不能从这里派发。":d.kind==="peer"?"对端主机:选择会话阅读;要派发请打开它的远端会话节点。":"此节点没有可派发的路由。",K.appendChild(I)}function Ye(){Se(),q(),ce(),Re()}function Ge(d){const _=t!==null&&Pn(t)===Pn(d);t=d,_||(s=!0),Ye(),C.classList.add("is-open")}function ft(){t=null,C.classList.remove("is-open")}function wt(d){o=d;for(const I of(d==null?void 0:d.tasks)??[])u.add(I.taskId),h.set(I.taskId,I.direction==="inbound"?"inbound":"outbound");const _=t;if(_!==null){if(_.kind==="session"&&d!==null){const I=(d.sessions??[]).find(Z=>Z.id===_.id);I!==void 0&&(_.title=bt(I),_.live=I.live)}Se(),Ze()}}return{root:C,open:Ge,close:ft,isOpen:()=>t!==null,update:wt}}function Yo(e,t,o){const s=document.createElement("section"),n=document.createElement("h4");n.textContent="会话席位名(仅人工设定)",s.appendChild(n);const i=document.createElement("p");i.className="wb-hint",i.textContent="稳定展示名,不改变会话标题、路由句柄或准入。留空并保存可清除。",s.appendChild(i);const r=document.createElement("select");r.setAttribute("aria-label","选择命名的本机会话");for(const N of new Set([...e.map(J=>J.id),...Object.keys(t)])){const J=e.find(G=>G.id===N),ne=document.createElement("option");ne.value=N,ne.textContent=(t[N]??(J==null?void 0:J.name)??(J==null?void 0:J.label)??N)+" · "+N,r.appendChild(ne)}const c=document.createElement("input");c.type="text",c.maxLength=64,c.setAttribute("aria-label","人工席位名"),c.placeholder="例如:开发席";const l=document.createElement("button");l.type="submit",l.textContent="保存席位名",l.className="wb-member-submit";const u=document.createElement("form");u.className="wb-member-add",u.append(r,c,l);const h=document.createElement("p");h.className="wb-hint",h.setAttribute("role","status"),h.setAttribute("aria-live","polite");let m=!1;const C=()=>{c.value=t[r.value]??"",l.disabled=m||r.value===""};return r.addEventListener("change",C),C(),u.addEventListener("submit",async N=>{if(N.preventDefault(),m||r.value==="")return;const J=r.value,ne=c.value.trim(),G={...t};ne===""?delete G[J]:G[J]=ne,m=!0,l.disabled=!0,r.disabled=!0,c.disabled=!0;try{const $=await o(G);$.ok?(delete t[J],ne!==""&&(t[J]=ne),h.textContent="席位名已保存;目录将随状态刷新。"):h.textContent=$.error??"保存失败"}catch($){h.textContent="保存失败:"+String($)}finally{m=!1,r.disabled=!1,c.disabled=!1,C()}}),s.append(u,h),s}function Wo(e,t){const o=document.createElement("form");o.className="wb-cli-home";const s=document.createElement("button");s.type="button",s.textContent="指定 home",s.className="wb-member-submit";const n=document.createElement("select");n.className="wb-member-pick",n.setAttribute("aria-label","选择 CLI home 主机"),n.hidden=!0;const i=document.createElement("button");i.type="submit",i.textContent="确认 home",i.className="wb-member-submit",i.hidden=!0,i.disabled=!0;const r=document.createElement("div");r.className="wb-hint",r.setAttribute("role","status"),r.setAttribute("aria-live","polite"),r.textContent="home 未确定;点击指定 home 现读已链接主机名片。";let c=!1;return s.addEventListener("click",async()=>{var l;if(!c){c=!0,s.disabled=!0,i.disabled=!0,r.textContent="正在现读主机名片…";try{const u=await e();if(!u.ok)throw Error(u.error??"候选读取失败");if(u.held){s.hidden=!0,n.hidden=!0,i.hidden=!0,n.replaceChildren(),r.textContent="本机持有,无需指定";return}n.replaceChildren(new Option("请选择 home 主机…","",!0,!0));for(const m of u.homes??[])n.appendChild(new Option(m,m));n.hidden=!1,i.hidden=!1,s.textContent="刷新候选";const h=((l=u.homes)==null?void 0:l.length)??0;r.textContent=(u.unreadable?"有 "+u.unreadable+" 台对端名片读不到;":"")+(h>1?"多台已链接主机列出该句柄,请显式选择。":h===1?"找到 1 台已链接主机;仍需你显式确认。":"当前没有已链接且列出该句柄的可选主机。")}catch(u){r.textContent="读取失败:"+String(u),n.hidden=!0,i.hidden=!0}finally{c=!1,s.disabled=!1}}}),n.addEventListener("change",()=>{i.disabled=c||n.value===""}),o.addEventListener("submit",async l=>{if(l.preventDefault(),!(c||n.value==="")){c=!0,s.disabled=!0,n.disabled=!0,i.disabled=!0;try{r.textContent=await t(n.value)?"home 已指定:"+n.value:"指定失败:主机可能已离线或不再列出该句柄,请刷新后重选。"}catch(u){r.textContent="指定失败:"+String(u)}finally{c=!1,s.disabled=!1,n.disabled=!1,i.disabled=n.value===""}}}),o.append(s,n,i,r),o}function Ko(e,t){const o=document.createElement("form");o.className="wb-member-provenance";const s=document.createElement("select");s.setAttribute("aria-label","确认成员来源"),s.appendChild(new Option("明确选择来源…","")),e.forEach((r,c)=>s.appendChild(new Option(r.label,String(c))));const n=document.createElement("button");n.type="submit",n.textContent="确认来源";const i=document.createElement("span");return i.textContent="确认不等于恢复;已暂停槽位仍保持暂停",o.append(s,n,i),o.addEventListener("submit",async r=>{if(r.preventDefault(),s.value==="")return;const c=e[Number(s.value)];if(!c)return;n.disabled=!0;const l=await t(c);l.ok?i.textContent="来源已确认;等待状态刷新(暂停状态不变)":(n.disabled=!1,i.textContent=l.error??"来源无法验证,原槽位保留")}),o}const mo="dsh-a2a.rail.tab";function Xo(){try{return window.localStorage.getItem(mo)}catch{return null}}function Uo(e){try{window.localStorage.setItem(mo,e)}catch{}}function Jo(e,t={}){var G;const o=document.createElement("aside");o.className="wb-rail";const s=document.createElement("div");s.className="wb-tabs",s.setAttribute("role","tablist"),s.setAttribute("aria-label","工作台侧栏");const n=document.createElement("div");n.className="wb-tabpanels",o.append(s,n);const i=new Map,r=new Map,c=new Map,l=new Set;for(const $ of e){const E=document.createElement("button");E.type="button",E.className="wb-tab",E.id=`wb-tab-${$.key}`,E.dataset.sec=$.key,E.setAttribute("role","tab"),E.setAttribute("aria-controls",`wb-panel-${$.key}`);const S=document.createElement("span");S.className="wb-tab-label",S.textContent=$.label;const w=document.createElement("span");w.className="wb-tab-badge",E.append(S,w),E.addEventListener("click",()=>N($.key)),s.appendChild(E);const oe=document.createElement("section");oe.className="wb-tabpanel",oe.id=`wb-panel-${$.key}`,oe.dataset.sec=$.key,oe.setAttribute("role","tabpanel"),oe.setAttribute("aria-labelledby",E.id),oe.tabIndex=-1,n.appendChild(oe),i.set($.key,E),r.set($.key,oe),c.set($.key,w)}const u=()=>e.map($=>$.key).filter($=>!l.has($)),h=Xo();let m=((G=e.find($=>$.key===h))==null?void 0:G.key)??e[0].key;s.addEventListener("keydown",$=>{const E=u(),S=E.indexOf(m);let w;$.key==="ArrowRight"?w=E[(S+1)%E.length]:$.key==="ArrowLeft"?w=E[(S-1+E.length)%E.length]:$.key==="Home"?w=E[0]:$.key==="End"&&(w=E[E.length-1]),w!==void 0&&($.preventDefault(),N(w,{focus:!0}))});function C(){for(const $ of e){const E=$.key===m,S=i.get($.key);S.setAttribute("aria-selected",String(E)),S.tabIndex=E?0:-1,S.classList.toggle("is-active",E),S.hidden=l.has($.key),r.get($.key).hidden=!E}}function N($,E={}){var w;if(l.has($))return;const S=$!==m;m=$,Uo($),C(),E.focus===!0&&i.get($).focus(),S&&((w=t.onChange)==null||w.call(t,$))}function J($,E,S){const w=c.get($);w.textContent=E,w.className=`wb-tab-badge${S!==void 0?` is-${S}`:""}`}function ne($,E){E?l.add($):l.delete($),l.has(m)&&(m=u()[0]??e[0].key),C()}return C(),{root:o,panel:$=>r.get($),select:N,selected:()=>m,setBadge:J,setHidden:ne}}const wn="application/x-dsh-session";function qo(e,t){e.draggable=!0,e.classList.add("is-draggable"),e.title=`${e.title===""?t:e.title} · 可拖入画布队`,e.addEventListener("dragstart",o=>{o.dataTransfer!==null&&(o.dataTransfer.setData(wn,t),o.dataTransfer.effectAllowed="copy")})}function zo(e,t){const o=n=>n.dataTransfer!==null&&[...n.dataTransfer.types].includes(wn),s=n=>{for(const[i,r]of t.frames())r.classList.toggle("drop-target",i===n)};e.addEventListener("dragover",n=>{if(!o(n))return;const i=t.frameAt(n.clientX,n.clientY);s(i),i!==void 0&&(n.preventDefault(),n.dataTransfer.dropEffect="copy")},t.signal),e.addEventListener("dragleave",n=>{o(n)&&(n.relatedTarget===null||!e.contains(n.relatedTarget))&&s(void 0)},t.signal),e.ownerDocument.addEventListener("dragend",()=>s(void 0),t.signal),e.addEventListener("drop",n=>{if(!o(n))return;s(void 0);const i=t.frameAt(n.clientX,n.clientY),r=n.dataTransfer.getData(wn);i===void 0||r===""||(n.preventDefault(),t.drop(i,r))},t.signal)}const Vo=[{key:"all",label:"全部",hint:"不过滤:目录全部条目"},{key:"local",label:"本机",hint:"本机会话节点(现场 + 冷启动)"},{key:"canvas",label:"队",hint:"画布队(人类手工分配的组队)"},{key:"remote",label:"远端",hint:"远端会话队(来自对端卡片)"},{key:"logs",label:"日志",hint:"本机日志:不在网络目录里的会话档案"}];function rt(e,t){const o=document.createElement(e);return t!==void 0&&(o.className=t),o}function Ut(...e){const t=[];for(const o of e)o!==void 0&&(typeof o=="string"?t.push(o):t.push(...o));return t.join(" ").toLowerCase()}function Go(e,t){const o=Math.max(0,Math.round((t-e)/1e3));if(o<60)return"刚刚";const s=Math.round(o/60);if(s<60)return`${s} 分钟前`;const n=Math.round(s/60);return n<48?`${n} 小时前`:`${Math.round(n/24)} 天前`}function Rn(e){return e>=1e6?`${(e/1e6).toFixed(1)} MB`:e>=1e3?`${Math.round(e/1e3)} KB`:`${e} B`}function Qo(e,t){const o=new Date(t);o.setHours(0,0,0,0);const s=o.getTime();return e>=s?"今天":e>=s-864e5?"昨天":"更早"}function Zo(e,t){var S,w,oe;e.replaceChildren();const{state:o,search:s,filter:n}=t,i=s!==""||n!=="all",r=(y,b)=>(n==="all"||n===y)&&(s===""||b.includes(s)),c=(y,b,M)=>{const f=rt("div","wb-dir-group"),D=rt("div","wb-dir-head");return D.appendChild(rt("span","wb-dir-head-label")).textContent=`${y} · ${b}`,M!==void 0&&(D.appendChild(rt("span","wb-dir-head-note")).textContent=M),f.appendChild(D),e.appendChild(f),f},l=(y,b,M,f,D,K,X)=>{const ye=rt("button","wb-item");ye.type="button",ye.appendChild(rt("span",`wb-dot ${b}`)).textContent=M;const Se=rt("span","wb-item-text");return Se.appendChild(rt("span","wb-item-label")).textContent=f,D!==""&&(Se.appendChild(rt("span","wb-item-sub")).textContent=D),ye.appendChild(Se),X!==void 0&&(ye.title=X),ye.addEventListener("click",K),y.appendChild(ye),ye},u=(y,b)=>{if(b===void 0||b.length===0)return;const M=rt("span","wb-item-badge"),f=b.map(D=>D.slice(D.lastIndexOf("/")+1));M.textContent=`▤ ${f.slice(0,2).join(" ")}${f.length>2?` +${f.length-2}`:""}`,M.title=`画布队:${b.join(" · ")}`,y.appendChild(M)},h=(o.sessions??[]).filter(y=>r("local",Ut(bt(y),y.team,y.label,y.id,y.canvasTeams))),m=h.filter(y=>y.live===!0),C=h.filter(y=>y.live!==!0);if(h.length>0){const y=c("本机会话",h.length,C.length>0?`${m.length} 在线 · ${C.length} 冷`:void 0);for(const b of[...m,...C]){const M=b.live===!0,f=b.nodePromptMissing===!0,D=l(y,M?"wb-dot-live":"wb-dot-cold",M?"●":"○",bt(b),M?b.team:`冷 · ${b.team}`,()=>t.openChat({kind:"session",id:b.id,title:bt(b),sub:b.team,team:b.team,live:b.live}),b.id);if(f){D.classList.add("is-node-prompt-missing");const K=rt("span","wb-node-warning");K.textContent="本会话的组装不含节点段",(S=D.querySelector(".wb-item-text"))==null||S.appendChild(K)}u(D,b.canvasTeams),qo(D,b.id)}}const N=(((w=o.canvas)==null?void 0:w.teams)??[]).filter(y=>r("canvas",Ut(y.name,y.team,y.members.map(b=>b.team??b.id))));if(N.length>0){const y=c("画布队",N.length);for(const b of N){const M=b.members.filter(f=>f.remote===!0).length;l(y,"wb-dot-canvas","▤",b.name,`${b.members.length} 成员${M>0?` · ${M} 远端`:""}`,()=>t.selectCanvas(b),b.team)}}const J=(o.remote??[]).filter(y=>r("remote",Ut(bt(y),y.team,y.origin,y.workspace,y.canvasTeams)));if(J.length>0){const y=c("远端节点",J.length);for(const b of J){const M=l(y,"wb-dot-remote","◇",bt(b),b.origin!==void 0&&b.origin!==""?b.origin:b.team,()=>t.openChat({kind:"remote",team:b.team,title:bt(b),sub:b.team,row:b}),b.team);if(b.unreachable===!0){M.classList.add("is-unreachable");const f=rt("span","wb-unreachable-note");f.textContent="对端未应答(显示的是最后已知状态)",(oe=M.querySelector(".wb-item-text"))==null||oe.appendChild(f)}u(M,b.canvasTeams)}}const ne=new Set((o.sessions??[]).map(y=>y.id)),G=t.logs.filter(y=>!ne.has(y.id)&&r("logs",Ut(y.id,t.titles.get(y.id))));if(G.length>0){const y=t.logTotal!==void 0&&t.logTotal>t.logs.length,b=c("本机日志",G.length,y?`显示 ${t.logs.length} / 共 ${t.logTotal}`:void 0);let M="";for(const f of[...G].sort((D,K)=>K.mtimeMs-D.mtimeMs)){const D=Qo(f.mtimeMs,t.now);D!==M&&(M=D,b.appendChild(rt("div","wb-dir-day")).textContent=D);const K=t.titles.get(f.id),X=l(b,"wb-dot-log","❐",K??`会话 …${f.id.slice(-12)}`,`${Go(f.mtimeMs,t.now)} · ${Rn(f.sizeBytes)}`,()=>t.openChat({kind:"log",id:f.id,title:K??`…${f.id.slice(-12)}`,sub:"本机日志"}),`${f.id}
3
+ ${new Date(f.mtimeMs).toLocaleString()} · ${Rn(f.sizeBytes)}`);K===void 0&&X.classList.add("is-untitled")}}h.length+N.length+J.length+G.length===0&&(e.appendChild(rt("div","wb-dir-empty")).textContent=i?"无匹配条目":"目录为空");const $=o.sessions??[];return`${$.filter(y=>y.live===!0).length}/${$.length}`}const uo="dsh-a2a.logtitles",es=300,Dn=60;function ts(){try{const e=window.localStorage.getItem(uo),t=e===null?null:JSON.parse(e);if(t!==null&&typeof t=="object")return new Map(Object.entries(t).filter(o=>typeof o[1]=="string"))}catch{}return new Map}function ns(e,t,o){const s=o.find(r=>r.role==="user"&&r.text.trim()!=="")??o.find(r=>r.text.trim()!=="");if(s===void 0)return!1;const n=s.text.trim().split(`
4
+ `)[0].trim(),i=n.length>Dn?`${n.slice(0,Dn-1)}…`:n;if(e.get(t)===i)return!1;for(e.delete(t),e.set(t,i);e.size>es;)e.delete(e.keys().next().value);try{window.localStorage.setItem(uo,JSON.stringify(Object.fromEntries(e)))}catch{}return!0}function mt(e){return e.name??e.team??e.label??""}function Rt(e,t){const o=Math.max(0,Math.round((t-e)/1e3));if(o<90)return`${o}s`;const s=Math.round(o/60);if(s<90)return`${s}m`;const n=Math.round(s/60);return n<48?`${n}h`:`${Math.round(n/24)}d`}function L(e,t){const o=document.createElement(e);return t!==void 0&&(o.className=t),o}function Hn(e,t,o){const s=L("div","wb-kv");s.appendChild(L("span","wb-kv-k")).textContent=t,s.appendChild(L("span","wb-kv-v")).textContent=o,e.appendChild(s)}function os(e){try{return new URL(e).host}catch{return e}}const ss=[{key:"directory",label:"目录"},{key:"hosts",label:"主机"},{key:"ledger",label:"台账"},{key:"activity",label:"活动"},{key:"plan",label:"规划"}];function is(e){const t=e.board;let o="data",s,n=null,i="",r="all",c=null;const l=new Map,u=new Map;let h=null,m=[],C;const N=ts();let J=!1;const ne=L("div","wb");ne.setAttribute("data-testid","wb-root");const G=L("header","wb-header"),$=L("button","wb-icon-btn wb-menu");$.type="button",$.dataset.testid="wb-menu",$.setAttribute("aria-label","打开目录抽屉"),$.textContent="☰",$.addEventListener("click",()=>ne.classList.toggle("is-rail-open")),G.appendChild($);const E=L("div","wb-title");E.appendChild(L("span","wb-title-main")).textContent="A2A 工作台";const S=L("span","wb-badge");E.appendChild(S),G.appendChild(E);const w=L("button","wb-icon-btn wb-owner-btn");w.type="button",w.dataset.testid="wb-owner-btn",w.setAttribute("aria-label","主人设置"),w.title="主人设置:席位名 / 入网白名单 / 可见性 / 发布",w.textContent="⚙",w.addEventListener("click",()=>{I=!I,Y()}),G.appendChild(w);const oe=L("div","wb-header-stats");G.appendChild(oe);const y=L("button","wb-icon-btn wb-rail-toggle");y.type="button",y.dataset.testid="wb-rail-toggle",y.setAttribute("aria-label","折叠/展开侧栏"),y.textContent="◧",y.addEventListener("click",()=>{ne.classList.toggle("is-rail-collapsed"),o==="canvas"&&t!==void 0&&t.activate()}),G.appendChild(y);const b=L("div","wb-body"),M=Jo(ss),f=M.root,D=L("div","wb-directory"),K=L("div","wb-dir-tools"),X=document.createElement("input");X.className="wb-search",X.type="search",X.placeholder="搜索:名称 / 队 / 会话 / 节点",X.setAttribute("aria-label","统一搜索目录"),X.addEventListener("input",()=>{i=X.value.trim().toLowerCase(),st()}),K.appendChild(X);const ye=L("div","wb-filters");for(const k of Vo){const x=L("button","wb-filter");x.type="button",x.textContent=k.label,x.dataset.filter=k.key,x.title=k.hint,x.addEventListener("click",()=>{r=k.key,st()}),ye.appendChild(x)}K.appendChild(ye),M.panel("directory").appendChild(K),M.panel("directory").appendChild(D);const Se=L("section","wb-pane"),R=L("section","wb-pane"),q=L("section","wb-pane"),le=L("section","wb-pane"),Ke=[["ledger",Se],["activity",R],["plan",q],["hosts",le]],Me=L("main","wb-stage"),de=L("section","wb-stage-board");t!==void 0&&(de.appendChild(t.root),Me.appendChild(de));const Ue=L("div","wb-data"),ue=L("aside","wb-inspector"),V=L("div","wb-inspector-head");V.appendChild(L("span","wb-inspector-title")).textContent="详情";const ce=L("button","wb-icon-btn");ce.type="button",ce.setAttribute("aria-label","关闭详情"),ce.textContent="✕",ce.addEventListener("click",()=>tt(void 0)),V.appendChild(ce),ue.appendChild(V);const ie=L("div","wb-inspector-body");ue.appendChild(ie);const ee=Bo({now:e.now,sessionLog:e.sessionLog,remoteSessionLog:e.remoteSessionLog,dispatchQuick:e.dispatchQuick,onTranscript:(k,x)=>{k.kind!=="log"&&k.kind!=="session"||ns(N,k.id,x)&&st()}});Me.appendChild(Ue),b.appendChild(f),b.appendChild(Me),b.appendChild(ue),b.appendChild(ee.root),ne.appendChild(G),ne.appendChild(b);function ke(k){for(const[x,F]of Ke){const A=k==="canvas"?M.panel(x):Ue;M.setHidden(x,k!=="canvas"),F.parentElement!==A&&A.appendChild(F)}}function et(){const x=t!==void 0&&t.available()?"canvas":"data";ne.dataset.mode=x,de.classList.toggle("is-hidden",x!=="canvas"),Ue.classList.toggle("is-hidden",x==="canvas"),ke(x),x!==o&&(t!==void 0&&(x==="canvas"?t.activate():t.deactivate()),o=x)}function Oe(k){for(;k.firstChild!==null;)k.removeChild(k.firstChild);return k}function tt(k){s=k,((k==null?void 0:k.kind)!=="canvas"||(c==null?void 0:c.name)!==k.row.name)&&(c=null),(k==null?void 0:k.kind)!=="canvas"&&(h=null),pe(),ne.classList.remove("is-rail-open")}function st(){for(let x=0;x<ye.children.length;x++){const F=ye.children[x];F.classList.toggle("is-active",F.dataset.filter===r)}if(n===null){D.replaceChildren(L("div","wb-muted")),D.firstElementChild.textContent="载入中…",M.setBadge("directory","");return}const k=Zo(D,{state:n,logs:m,logTotal:C,titles:N,search:i,filter:r,now:e.now(),openChat:Fe,selectCanvas:x=>tt({kind:"canvas",row:x})});M.setBadge("directory",k)}function St(){const k=Oe(le);if(n===null){M.setBadge("hosts","");return}const x=e.now(),F=[...n.peers??[]].sort((A,T)=>{const j=Q=>Q.link==="linked"?0:1;return j(A)-j(T)||(T.score??0)-(A.score??0)});if(M.setBadge("hosts",F.length>0?`${F.filter(A=>A.link==="linked").length}/${F.length}`:""),F.length===0){k.appendChild(L("div","wb-nodelist-empty")).textContent="暂无 tracked peer——配 peers 种子或等 referral 到达";return}for(const A of F){const T=os(A.url),j=L("div","wb-host-row"),Q=L("span","wb-host-lamp"),se=A.lastContactAt,U=se===void 0?void 0:x-se,ge=A.lastContactOk;U===void 0?Q.classList.add("is-unknown"):ge===!1&&U<=5*6e4?Q.classList.add("is-fail"):U<=6e4?Q.classList.add("is-live"):U<=5*6e4?Q.classList.add("is-warm"):Q.classList.add("is-cold"),Q.title=se===void 0?"尚无接触记录":`最近接触 ${Rt(se,x)}${ge===!1?"(失败)":ge===!0?"(成功)":""}`,j.appendChild(Q),j.appendChild(L("span","wb-host-name")).textContent=A.name!==void 0&&A.name!==""?A.name:T;const De=L("span",`wb-host-badge ${A.link==="linked"?"is-linked":"is-stranger"}`);De.textContent=`${A.link==="linked"?"linked":"stranger"} ${A.verified===!0?"✓":"✗"}`,De.title=A.link==="linked"?`已建立运营者链接(互种或 canvas 引用);${A.verified===!0?"验签有效":"尚未持有验签通过的卡片"}`:"无运营者关系(验签 ≠ 关系)",j.appendChild(De),A.version!==void 0&&A.version!==""&&(j.appendChild(L("span","wb-host-ver")).textContent=A.version),j.appendChild(L("span","wb-host-url mono")).textContent=T,j.setAttribute("role","button"),j.tabIndex=0,j.title=`${A.url} · score ${String(A.score??0)}`;const Ie=()=>{Fe({kind:"peer",id:`peer-${T}`,title:A.name!==void 0&&A.name!==""?A.name:T,sub:T,url:A.url})};j.addEventListener("click",Ie),j.addEventListener("keydown",ot=>{(ot.key==="Enter"||ot.key===" ")&&(ot.preventDefault(),Ie())}),k.appendChild(j)}}function Ze(){if(n===null){Se.replaceChildren(),M.setBadge("ledger","");return}const k=n,x=A=>{const T=(k.sessions??[]).find(Q=>Q.team===A);if(T!==void 0)return{kind:"session",id:T.id,title:mt(T),sub:T.team,team:T.team,live:T.live};const j=(k.remote??[]).find(Q=>Q.team===A);if(j!==void 0)return{kind:"remote",team:j.team,title:mt(j),sub:j.team,row:j}},F=Do(Se,{state:k,now:e.now(),abandon:(A,T)=>e.abandon(A,T),canOpenTeam:A=>x(A)!==void 0,openTeam:A=>{const T=x(A);return T===void 0?!1:(Fe(T),!0)}});M.setBadge("ledger",F.badge,F.tone)}function Ve(k,x,F){Qt(k.appendChild(L("span","wb-row-team")),x,F)}function Nt(){var Q;const k=Oe(R);if(n===null)return;const x=e.now(),F=n.inFlight??[];M.setBadge("activity",F.length>0?String(F.length):"",F.length>0?"accent":void 0);const A=L("div","wb-pane-head");if(A.textContent=`在途 ${F.length} · 活动 ${((Q=n.activity)==null?void 0:Q.length)??0}`,k.appendChild(A),F.length>0){const se=L("div","wb-pane-subhead");se.textContent="在途路由",k.appendChild(se);for(const U of F){const ge=L("div","wb-row");ge.appendChild(L("span","wb-row-dir")).textContent="→",Ve(ge,n,U.team),ge.appendChild(L("span","wb-row-meta")).textContent=`${U.peer} · ${Rt(U.startedAt,x)}`,k.appendChild(ge)}}const T=L("div","wb-pane-subhead");T.textContent="活动环(最新在前)",k.appendChild(T);const j=n.activity??[];if(j.length===0){k.appendChild(L("div","wb-muted")).textContent="暂无活动";return}for(const se of j){const U=L("div","wb-row"),ge=L("span","wb-row-dir");ge.textContent=se.dir==="fwd"?"⇢":se.dir==="out"?"→":"←",se.ok!==!0&&ge.classList.add("is-fail"),U.appendChild(ge),Ve(U,n,se.team),U.appendChild(L("span","wb-row-meta")).textContent=`${se.peer} · ${Rt(se.ts,x)}`,U.appendChild(L("span","wb-row-badges")).textContent=se.ok===!0?"":"失败",k.appendChild(U)}}function Ot(k){var Q,se;const x=e.now(),F=[],A=vn(k,x);A.deadLetters.length>0&&F.push({severity:"high",text:`清账 ${A.deadLetters.length} 条死信(目标早已离开或死信化,无回执可期)`});for(const U of A.stale){const ge=U.brief===void 0||U.brief===""?"":`「${U.brief}」`;F.push({severity:"normal",text:`催办 ${U.taskId} → ${Fo(k,U.team)}(等待 ${Rt(U.startedAt,x)} 无回执)${ge}`,brief:`a2a_route 催收回执:task ${U.taskId}(team ${U.team})${ge===""?"":`原任务「${U.brief}」`}已派发 ${Rt(U.startedAt,x)},请回报结果或回执。`})}const T=(k.sessions??[]).filter(U=>U.live!==!0).map(U=>mt(U));if(T.length>0){const U=T.slice(0,3).join("、")+(T.length>3?` 等 ${T.length} 个`:"");F.push({severity:"normal",text:`冷会话 ${T.length} 个(${U}):在 GUI 打开即可唤醒加入面`})}for(const U of((Q=k.reconcile)==null?void 0:Q.rows)??[])if(U.needsRepair===!0){const ge=(k.sessions??[]).find(Ie=>Ie.id===U.id),De=ge!==void 0?`${mt(ge)}(${U.id})`:U.id;F.push({severity:"high",text:`reconcile 需修复:${De} ${U.error}`})}const j=((se=k.idempotency)==null?void 0:se.conflicts)??0;return j>0&&F.push({severity:"high",text:`幂等冲突 ${j} 例:人工核查 UNIQUE-ization 流量`}),F}function Re(){const k=Oe(q);if(n===null)return;const x=Ot(n);M.setBadge("plan",x.length>0?String(x.length):"",x.some(T=>T.severity==="high")?"danger":void 0);const F=L("div","wb-pane-head");F.textContent=x.length===0?"网络健康——无待办行动":`待办行动 ${x.length}`,k.appendChild(F);for(const T of x){const j=L("div",`wb-action${T.severity==="high"?" wb-action-high":""}`);if(j.appendChild(L("span","wb-action-text")).textContent=T.text,T.brief!==void 0){const Q=L("button","wb-btn");Q.type="button",Q.textContent="复制催办",Q.addEventListener("click",()=>e.copy(T.brief??"")),j.appendChild(Q)}k.appendChild(j)}const A=L("div","wb-pane-subhead");A.textContent="派单起草(复制后在任一会话粘贴执行)",k.appendChild(A),k.appendChild(Ye)}const Ye=L("div","wb-draft"),Ge=document.createElement("select");Ge.className="wb-select";const ft=document.createElement("textarea");ft.className="wb-textarea",ft.rows=3,ft.placeholder="任务正文:目标、验收、期限…";const wt=L("button","wb-btn wb-btn-primary");wt.type="button",wt.textContent="复制任务书",wt.addEventListener("click",()=>{const k=Ge.value,x=ft.value.trim();k===""||x===""||e.copy(`a2a_route 派单 → ${k}:
5
+ ${x}`)}),Ye.appendChild(Ge),Ye.appendChild(ft),Ye.appendChild(wt);function d(){var T;const k=Ge.value;Oe(Ge);const x=document.createElement("option");if(x.value="",x.textContent="选择目标队…",Ge.appendChild(x),n===null)return;const F=n,A=new Map;for(const j of F.sessions??[])j.team!==void 0&&j.team!==""&&A.set(j.team,`${mt(j)}(会话队)`);for(const j of((T=F.canvas)==null?void 0:T.teams)??[])A.set(j.team,`${j.name}(canvas 队)`);for(const j of F.remote??[])A.set(j.team,`${mt(j)}(远端)`);for(const[j,Q]of A){const se=document.createElement("option");se.value=j,se.textContent=`${Q} · ${j}`,Ge.appendChild(se)}k!==""&&A.has(k)&&(Ge.value=k)}let _,I=!1,Z=null;function Y(){var k;pe(),I&&((k=e.ownerSettingsRead)==null||k.call(e).then(x=>{if(I){if(x.ok!==!0){Z=null,pe();return}_=void 0,Z={seatNames:x.seatNames??{},teamJoinAllowlist:x.teamJoinAllowlist??[],teamScopeInfo:x.teamScopeInfo!==!1,announce:x.announce===!0,announceRestartPending:x.announceRestartPending===!0},pe()}}))}function he(k){const x=L("div","wb-card"),F=L("div","wb-inspector-head");F.appendChild(L("span","wb-inspector-title")).textContent="主人设置";const A=L("button","wb-icon-btn");if(A.type="button",A.setAttribute("aria-label","关闭主人设置"),A.textContent="✕",A.addEventListener("click",()=>{I=!1,pe()}),F.appendChild(A),x.appendChild(F),e.ownerSettingsRead===void 0){const re=L("div","wb-hint");re.textContent="此宿主未提供主人设置面(旧版本)——升级后可用。",x.appendChild(re),k.appendChild(x);return}if(Z===null){const re=L("div","wb-hint");re.textContent="读取中…",x.appendChild(re),k.appendChild(x);return}const T=Z;_??(_=Yo((n==null?void 0:n.sessions)??[],T.seatNames,async re=>{var Ne;const Ce=await((Ne=e.ownerSettingsWrite)==null?void 0:Ne.call(e,{seatNames:re}));return Ce!=null&&Ce.ok?(T.seatNames=re,{ok:!0}):{ok:!1,error:(Ce==null?void 0:Ce.error)??"保存失败"}})),x.appendChild(_);const j=L("div","wb-side-head");j.textContent="入网白名单(精确团队名)",x.appendChild(j);for(const re of T.teamJoinAllowlist){const Ce=L("div","wb-member-row");Ce.appendChild(L("span","wb-member-label")).textContent=re;const Ne=L("button","wb-member-remove");Ne.type="button",Ne.textContent="移除",Ne.addEventListener("click",()=>{var it;(it=e.ownerSettingsWrite)==null||it.call(e,{teamJoinAllowlist:T.teamJoinAllowlist.filter(je=>je!==re)}).then(()=>Y())}),Ce.appendChild(Ne),x.appendChild(Ce)}const Q=L("div","wb-member-add"),se=L("input","wb-member-manual");se.type="text",se.placeholder="dsh/团队名(精确,无通配)",se.setAttribute("aria-label","新增白名单团队名");const U=L("button","wb-member-submit");U.type="button",U.textContent="加入";const ge=()=>{var Ce;const re=se.value.trim();re===""||T.teamJoinAllowlist.includes(re)||(Ce=e.ownerSettingsWrite)==null||Ce.call(e,{teamJoinAllowlist:[...T.teamJoinAllowlist,re]}).then(()=>Y())};U.addEventListener("click",ge),se.addEventListener("keydown",re=>{re.key==="Enter"&&ge()}),Q.append(se,U),x.appendChild(Q);const De=L("div","wb-side-head");De.textContent="目录可见性(teamScopeInfo)",x.appendChild(De);const Ie=L("div","wb-member-row"),ot=L("button","wb-member-submit");ot.type="button",ot.textContent=T.teamScopeInfo?"已开:仅显示已加入团队(点击放开为全舰队可见)":"已关:全舰队可见(点击收窄为已加入团队)",ot.addEventListener("click",()=>{var re;(re=e.ownerSettingsWrite)==null||re.call(e,{teamScopeInfo:!T.teamScopeInfo}).then(()=>Y())}),Ie.appendChild(ot),x.appendChild(Ie);const xt=L("div","wb-hint");xt.textContent="精度说明:teamScopeInfo 只管「目录显示范围」。关上它不会解锁任何通信准入——会话入网(S3)与目标级路由(F5)规则原样生效。",x.appendChild(xt);const yt=L("div","wb-side-head");yt.textContent="节点发布(announce)",x.appendChild(yt);const Ct=L("div","wb-member-row"),H=L("button","wb-member-submit");if(H.type="button",H.textContent=T.announce?"已开:本节点发布签名卡(点击关闭)":"已关:本节点不发布(点击开启——重启宿主后生效)",H.addEventListener("click",()=>{var re;(re=e.ownerSettingsWrite)==null||re.call(e,{announce:!T.announce}).then(()=>Y())}),Ct.appendChild(H),x.appendChild(Ct),T.announceRestartPending){const re=L("div","wb-hint");re.textContent="有 announce 变更待生效:重启宿主后按新配置发布。",x.appendChild(re)}k.appendChild(x)}function pe(){var A,T,j,Q,se;const k=Oe(ie);if(I){ue.classList.add("is-open"),he(k);return}if(ue.classList.toggle("is-open",s!==void 0),s===void 0)return;const x=s,F=L("div","wb-card");if(x.kind==="canvas"){const U=(((A=n==null?void 0:n.canvas)==null?void 0:A.teams)??[]).find(H=>H.name===x.row.name)??x.row;Hn(F,"Canvas 队",U.name),Hn(F,"路由队",U.team);const ge=L("div","wb-side-head");if(ge.textContent=`成员 · ${U.members.length}`,F.appendChild(ge),U.members.length===0){const H=L("div","wb-muted");H.textContent="空队——用下方表单添加成员",F.appendChild(H)}for(const H of U.members){const re=L("div","wb-member-row"),Ce=H.cliHeld===!0?"本机持有,无需指定":H.remote===!0?H.cliHome===null?"◇ 远端 · home 未确定":"◇ 远端":H.live===!0?"● 现场":H.joined===!0?"○ 冷启":"· 未入网";re.appendChild(L("span","wb-member-dot")).textContent=Ce+(H.provenance?" · 来源未确认"+(H.provenance==="legacy-inferred"?"(兼容推断)":""):"");const Ne=L("span","wb-member-label"),it=((n==null?void 0:n.sessions)??[]).find(Ee=>Ee.id===H.id);Ne.textContent=H.remote===!0?H.id:it!==void 0?mt(it):H.id,Ne.title=H.cliHeld===!0?"本机持有,无需指定":H.cliHome!==void 0?H.cliHome??"home 未确定":H.team??H.id,re.appendChild(Ne);const je=L("button","wb-member-remove");if(je.type="button",je.textContent="移除",je.addEventListener("click",async()=>{je.disabled=!0,await e.canvasOp("remove-member",U.name,H.id)||(je.disabled=!1)}),re.appendChild(je),F.appendChild(re),H.cliHomeCleared===!0){const Ee=L("div","wb-hint");Ee.textContent="本机落户已清除旧 home 钉;户口离线后也不会恢复旧钉。",F.appendChild(Ee)}if(H.cliHome===null&&H.cliHeld!==!0&&e.cliHomeOptions!==void 0){const Ee=JSON.stringify([U.name,H.id]);let ct=l.get(Ee);ct===void 0&&(ct=Wo(()=>e.cliHomeOptions(U.name,H.id),Ft=>e.canvasOp("add-member",U.name,H.id,Ft)),l.set(Ee,ct)),F.appendChild(ct)}}const De=(((T=n==null?void 0:n.canvas)==null?void 0:T.retainedMembers)??[]).filter(H=>H.team===U.name);for(const H of De){const re=L("div","wb-member-row");if(re.appendChild(L("span","wb-member-dot")).textContent=H.suspended?"已暂停 · 不参与路由":"来源未确认 · 窗口关闭",re.appendChild(L("span","wb-member-label")).textContent=H.member,H.suspended&&e.regulateSuspended&&((j=n==null?void 0:n.canvas)==null?void 0:j.revision)!==void 0)for(const Ce of["restore-suspended","delete-suspended"]){const Ne=L("button","wb-member-remove");Ne.type="button",Ne.textContent=Ce==="restore-suspended"?"显式恢复":"删除暂停位";const it=n.canvas.revision;Ne.addEventListener("click",async()=>{Ne.disabled=!0;const je=await e.regulateSuspended(Ce,U.name,H.member,it,H.records);je.ok||(Ne.disabled=!1,Ne.title=je.error??"状态已变,请刷新后重试")}),re.appendChild(Ne)}F.appendChild(re)}for(const H of((Q=n==null?void 0:n.canvas)==null?void 0:Q.memberSlots)??[]){if(H.name!==U.name||H.provenance!=="unknown"||!e.confirmMember||((se=n==null?void 0:n.canvas)==null?void 0:se.revision)===void 0)continue;const re=L("div","wb-hint");re.textContent=H.member+" · 来源未确认"+(H.compatibilityInference?" · 兼容推断中":"")+(H.suspended?" · 已暂停":""),F.appendChild(re);const Ce=(n.sessions??[]).filter(Ee=>Ee.joined===!0).map(Ee=>({replacement:Ee.id,label:mt(Ee)+" — 本机完整会话"}));for(const Ee of n.remote??[])Ee.team.includes("/")&&Ee.via&&Ce.push({replacement:Ee.team,label:mt(Ee)+" — "+Ee.via,peer:Ee.via});const Ne=n.canvas.revision,it=JSON.stringify([U.name,H.member,Ne,H.ownerKey,Ce]);let je=u.get(it);je||(je=Ko(Ce,Ee=>e.confirmMember(U.name,H.member,Ee.replacement,Ne,H.ownerKey,Ee.peer)),u.set(it,je)),F.appendChild(je)}if((c==null?void 0:c.name)!==U.name){const H=L("form","wb-member-add"),re=document.createElement("select");re.className="wb-member-pick",re.setAttribute("aria-label","选择成员");const Ce=document.createElement("input");Ce.type="text",Ce.className="wb-member-manual",Ce.placeholder="或输入远端句柄 zone/id8",Ce.setAttribute("aria-label","远端成员句柄");const Ne=L("button","wb-member-submit");Ne.type="submit",Ne.textContent="添加",H.appendChild(re),H.appendChild(Ce),H.appendChild(Ne),H.addEventListener("submit",async it=>{it.preventDefault();const je=Ce.value.trim(),Ee=je!==""?void 0:re.selectedOptions[0],ct=je!==""?je:(Ee==null?void 0:Ee.dataset.member)??re.value;if(ct==="")return;Ne.disabled=!0;const Ft=await e.canvasOp("add-member",U.name,ct,void 0,Ee==null?void 0:Ee.dataset.peer);Ne.disabled=!1,Ft&&(Ce.value="")}),c={name:U.name,form:H,pick:re,manual:Ce}}const Ie=c.pick,ot=Ie.value;Oe(Ie),Ie.appendChild(new Option("本机会话(现场/冷启动)…","",!0,!0));const xt=new Set(U.members.map(H=>H.id));for(const H of(n==null?void 0:n.sessions)??[])xt.has(H.id)||Ie.appendChild(new Option(`${mt(H)} — 本机`,H.id));let yt=!1;for(const H of(n==null?void 0:n.remote)??[]){if(!H.team.includes("/")||xt.has(H.team))continue;yt||(Ie.appendChild(new Option("远端会话队(目录卡片)…","",!0,!1)),yt=!0);const re=new Option(`${mt(H)} — ${H.via??"来源未确认"}`,JSON.stringify([H.team,H.via]));re.dataset.member=H.team,H.via&&(re.dataset.peer=H.via),Ie.appendChild(re)}yt||Ie.appendChild(new Option("(暂无可拉入的远端会话队——见下方说明)","",!0,!1)),ot!==""&&Array.from(Ie.options).some(H=>H.value===ot)&&(Ie.value=ot),F.appendChild(c.form);const Ct=L("div","wb-hint");Ct.textContent="成员由人类明确分配。本机写完整会话;远端必须通过已链接主机的有效名片核实并记录完整公钥来源。最小卡、离线或第三方无法验证时保留待确认,不能手输裸句柄绕过来源校验。来源确认不恢复暂停;默认兼容窗口不自动关闭。",F.appendChild(Ct),e.dispatchQuick!==void 0&&F.appendChild(me(U.team))}k.appendChild(F)}function we(k){const x=L("form","wb-dispatch-form"),F=document.createElement("textarea");F.className="wb-dispatch-text",F.placeholder="一句话任务…(≤4000 字符,异步送达,回执进台账)",F.setAttribute("aria-label","快派消息");const A=L("button","wb-dispatch-submit");A.type="submit",A.textContent="发送";const T=L("div","wb-dispatch-note");return x.appendChild(F),x.appendChild(A),x.appendChild(T),F.addEventListener("keydown",j=>{j.key!=="Enter"||j.shiftKey||j.ctrlKey||j.altKey||j.metaKey||j.isComposing||(j.preventDefault(),A.disabled||x.requestSubmit())}),x.addEventListener("submit",async j=>{var U;j.preventDefault();const Q=F.value.trim();if(Q===""||A.disabled)return;A.disabled=!0,T.textContent="派发中…";let se;try{se=await(((U=e.dispatchQuick)==null?void 0:U.call(e,k,Q))??Promise.resolve({ok:!1,error:"dispatch unavailable"}))}catch(ge){se={ok:!1,error:ge instanceof Error?ge.message:String(ge)}}A.disabled=!1,se.ok===!0&&(F.value=""),F.focus({preventScroll:!0}),T.textContent=se.ok===!0?`已派发${se.task_id!==void 0?` · ${se.task_id}`:""} · 回执将入台账(待回执)`:`失败:${se.error??"未知原因"}`}),{form:x,text:F,note:T}}function me(k){const x=L("div","wb-dispatch"),F=L("div","wb-side-head");return F.textContent="快派",x.appendChild(F),(h==null?void 0:h.team)!==k&&(h={team:k,...we(k)}),x.appendChild(h.form),x}function Fe(k){ee.open(k),ne.classList.remove("is-rail-open")}function Pe(k){if(n===null)return;const x=(n.sessions??[]).find(A=>A.id===k);if(x!==void 0){Fe({kind:"session",id:k,title:mt(x),sub:x.team,team:x.team,live:x.live});return}if(k.startsWith("peer-")){const A=k.slice(5),T=(n.peers??[]).find(j=>j.url.includes(A));Fe({kind:"peer",id:k,title:T!==void 0?T.url:A,sub:A,url:T==null?void 0:T.url});return}m.find(A=>A.id===k)!==void 0&&Fe({kind:"log",id:k,title:`…${k.slice(-12)}`,sub:"档案"})}function Je(){var U,ge;S.textContent=(n==null?void 0:n.version)!==void 0?`v${n.version}`:"",S.hidden=(n==null?void 0:n.version)===void 0;const k=Oe(oe);if(n===null)return;const x=[],F=vn(n,e.now()),A=F.deadLetters.length;A>0&&x.push({text:`死信 ${A}`,tone:"danger",title:"超过 24h TTL 仍未结算的任务(unconsumed),需在台账清账",tab:"ledger",group:"死信"});const T=F.stale.length;T>0&&x.push({text:`陈旧 ${T}`,tone:"warn",title:"我方派发、要回执、已等待 ≥1h 仍未回执(可催办;免回执行不算)",tab:"ledger",group:"陈旧"});const j=F.owedOverdue.length;j>0&&x.push({text:`欠回执 ${j}`,tone:"warn",title:"对方投递给本机、已等待本机回执超过 1 小时",tab:"ledger",group:"待本机回执"});const Q=((U=n.idempotency)==null?void 0:U.conflicts)??0;Q>0&&x.push({text:`幂等冲突 ${Q}`,tone:"danger",title:"同一幂等键对应了不同载荷,需人工核查",tab:"ledger",group:"取证"});const se=(((ge=n.reconcile)==null?void 0:ge.rows)??[]).filter(De=>De.needsRepair===!0).length;if(se>0&&x.push({text:`需修复 ${se}`,tone:"danger",title:"reconcile 无法自动恢复的会话,见行动计划",tab:"plan"}),x.length===0){k.appendChild(L("span","wb-header-ok")).textContent="● 无异常";return}for(const De of x){const Ie=L("button",`wb-alert wb-alert-${De.tone}`);Ie.type="button",Ie.textContent=De.text,Ie.title=`${De.title}(点击查看)`,Ie.addEventListener("click",()=>Wt(De.tab,De.group)),k.appendChild(Ie)}}function Wt(k,x){var T;const F=Ke.find(([j])=>j===k)[1];o==="canvas"&&(ne.classList.add("is-rail-open"),M.select(k,{focus:!1}));const A=x===void 0?F:x==="取证"?F.querySelector("details.wb-led-forensics"):Array.from(F.querySelectorAll(".wb-led-group")).find(j=>j.dataset.group===x)??null;A!==null&&(A instanceof HTMLDetailsElement&&(A.open=!0),(T=A.scrollIntoView)==null||T.call(A,{block:"start",behavior:"smooth"}))}function nt(k){var A,T,j;const x=new Set((((A=k==null?void 0:k.canvas)==null?void 0:A.teams)??[]).flatMap(Q=>Q.members.filter(se=>se.cliHome===null&&se.cliHeld!==!0).map(se=>JSON.stringify([Q.name,se.id]))));for(const Q of l.keys())x.has(Q)||l.delete(Q);const F=((T=k==null?void 0:k.canvas)==null?void 0:T.memberSlots)??[];for(const Q of u.keys()){const[se,U,ge]=JSON.parse(Q);(ge!==((j=k==null?void 0:k.canvas)==null?void 0:j.revision)||!F.some(De=>De.name===se&&De.member===U&&De.provenance==="unknown"))&&u.delete(Q)}n=k,e.sessionLogList!==void 0&&!J&&(J=!0,e.sessionLogList().then(Q=>{m=Q.ok&&Q.sessions!==void 0?Q.sessions:[],C=Q.ok?Q.count:void 0}).catch(()=>{}).finally(()=>{J=!1,st()})),Je(),st(),d(),St(),Ze(),ee.update(k),Nt(),Re(),pe(),et()}function pt(k){if(k==="board"){et();return}M.select(k)}return nt(null),{root:ne,update:nt,mode:()=>o,selectTab:pt,openNodeChat:Pe}}const kt=1e6,Nn=.25,$n=3,fo=256,po=96;function _t(e){const t=typeof e=="number"?e:Number.NaN;if(Number.isFinite(t))return Math.max(-kt,Math.min(kt,Math.round(t)))}function ho(e){if(e===null||typeof e!="object")return;const t=e,o=_t(t.x),s=_t(t.y);return o===void 0||s===void 0?void 0:{x:o,y:s}}function rs(e){const t=ho(e);if(t===void 0)return;const o=e,s=_t(o.w),n=_t(o.h);if(!(s===void 0||n===void 0||s<=0||n<=0))return{...t,w:Math.min(s,kt),h:Math.min(n,kt)}}const bo=e=>e!==""&&!e.includes("/")&&(e.startsWith("roster:")?e.length>7&&e.length<=47:e.length<=40);function go(e){if(e===null||typeof e!="object")return;const t=e;if(t.version!==1)return;const o=t.viewport;if(o===null||typeof o!="object")return;const s=o,n=_t(s.x),i=_t(s.y),r=s.scale,c=typeof r=="number"?r:Number.NaN;if(n===void 0||i===void 0||!Number.isFinite(c))return;const l=Math.max(Nn,Math.min($n,c)),u={};if(t.nodes!==null&&typeof t.nodes=="object")for(const[m,C]of Object.entries(t.nodes)){if(typeof m!="string"||m===""||m.length>128)continue;const N=ho(C);if(N!==void 0&&(u[m]=N),Object.keys(u).length>=fo)break}const h={};if(t.frames!==null&&typeof t.frames=="object")for(const[m,C]of Object.entries(t.frames)){if(!bo(m))continue;const N=rs(C);if(N!==void 0&&(h[m]=N),Object.keys(h).length>=po)break}return{version:1,viewport:{x:n,y:i,scale:l},nodes:u,frames:h}}function as(e,t,o){const s=r=>Math.max(-kt,Math.min(kt,Math.round(r))),n={};for(const[r,c]of t)if(!(typeof r!="string"||r===""||r.length>128)&&(n[r]={x:s(c.x),y:s(c.y)},Object.keys(n).length>=fo))break;const i={};for(const[r,c]of o){if(!bo(r))continue;const l=s(c.w),u=s(c.h);if(!(l<=0||u<=0)&&(i[r]={x:s(c.x),y:s(c.y),w:Math.min(l,kt),h:Math.min(u,kt)},Object.keys(i).length>=po))break}return{version:1,viewport:{x:s(e.x),y:s(e.y),scale:Math.max(Nn,Math.min($n,e.scale))},nodes:n,frames:i}}function vo(e){let t=2166136261;for(let o=0;o<e.length;o++)t^=e.charCodeAt(o),t=Math.imul(t,16777619)>>>0;return t>>>0}const ze=172,Be=56,$t=[150,290,430],ut=16;function cs(e){const t=vo(e),o=Math.floor(t/ut)%$t.length,n=t%ut/ut*Math.PI*2+o*(Math.PI/ut),i=$t[o];return{x:Math.round(Math.cos(n)*i),y:Math.round(Math.sin(n)*i*.6)}}function yo(e){const t=new Map;for(const o of e)for(const s of o.members)t.has(s.id)||t.set(s.id,o.name);return t}const jn=64,Bn=24,Yn=20,ls=4,Wn=24,Kn=44,ds=24;function ms(e,t,o=Number.POSITIVE_INFINITY){const s=new Set(t),n=yo(e),i=e.map(m=>[...new Set(m.members.map(C=>C.id))].filter(C=>s.has(C)&&n.get(C)===m.name));i.push(t.filter(m=>!n.has(m)));const r=new Map;let c=0,l=0,u=0,h=0;for(const m of i){if(m.length===0)continue;const C=Math.min(3,Math.max(m.length>1?2:1,Math.ceil(Math.sqrt(m.length)))),N=Math.ceil(m.length/C),J=Math.max(260,C*ze+(C-1)*Bn+Wn*2),ne=Math.max(160,N*Be+(N-1)*Yn+Kn+ds);h>0&&(h%ls===0||c+J>o)&&(c=0,l+=u+jn,u=0),m.forEach((G,$)=>{const E=$%C,S=Math.floor($/C);r.set(G,{x:c+Wn+ze/2+E*(ze+Bn),y:l+Kn+Be/2+S*(Be+Yn)})}),c+=J+jn,u=Math.max(u,ne),h+=1}return r}const Jt=12;function wo(e,t){const o=l=>t.every(u=>Math.abs(u.x-l.x)>=ze+Jt||Math.abs(u.y-l.y)>=Be+Jt),s=cs(e);if(o(s))return s;const n=vo(e),i=ut*$t.length,r=Math.floor(n/ut)%$t.length*ut+n%ut;for(let l=1;l<i;l++){const u=(r+l)%i,h=Math.floor(u/ut),m=u%ut/ut*Math.PI*2+h*(Math.PI/ut),C=$t[h],N={x:Math.round(Math.cos(m)*C),y:Math.round(Math.sin(m)*C*.6)};if(o(N))return N}const c=$t[$t.length-1];for(let l=0;;l++)for(let u=0;u<6;u++){const h={x:Math.round(-c+u*(ze+Jt)),y:Math.round(c*.6+Be*2+l*(Be+Jt))};if(o(h))return h}}function vt(e){return{x:e.x-ze/2,y:e.y-Be/2,w:ze,h:Be}}function Mn(e){if(e.length===0)return{x:0,y:0,w:260,h:160};let t=Number.POSITIVE_INFINITY,o=Number.POSITIVE_INFINITY,s=Number.NEGATIVE_INFINITY,n=Number.NEGATIVE_INFINITY;for(const h of e)t=Math.min(t,h.x),o=Math.min(o,h.y),s=Math.max(s,h.x+h.w),n=Math.max(n,h.y+h.h);const i=24,r=44,c=24,l=Math.max(260,Math.round(s-t+i*2)),u=Math.max(160,Math.round(n-o+r+c));return{x:Math.round(t-i),y:Math.round(o-r),w:l,h:u}}class Sn{constructor(){Lt(this,"revisionCounter",0);Lt(this,"nodes",new Map);Lt(this,"frames",new Map);Lt(this,"selection",new Set);Lt(this,"viewport",{x:0,y:0,scale:1})}get revision(){return this.revisionCounter}getNode(t){return this.nodes.get(t)}allNodes(){return[...this.nodes.values()]}nodeIds(){return[...this.nodes.keys()]}getFrame(t){return this.frames.get(t)}allFrames(){return[...this.frames.entries()]}isSelected(t){return this.selection.has(t)}selectedIds(){return[...this.selection]}bump(){this.revisionCounter+=1}dragNodes(t,o,s){let n=!1;for(const i of t){const r=this.nodes.get(i);r!==void 0&&(r.x+=o,r.y+=s,n=!0)}n&&this.bump()}beginFrameDrag(t){const o=this.frames.get(t);if(o!==void 0)return{name:t,rect:{...o}}}applyFrameDrag(t,o,s){const n=this.frames.get(t.name);n!==void 0&&(n.x=t.rect.x+o,n.y=t.rect.y+s,this.bump())}nudge(t,o,s){this.dragNodes(t,o,s)}marqueeSelect(t,o){o||this.selection.clear();for(const s of this.nodes.values()){const n=vt(s);n.x<t.x+t.w&&n.x+n.w>t.x&&n.y<t.y+t.h&&n.y+n.h>t.y&&this.selection.add(s.id)}this.bump()}setSelection(t){this.selection=new Set(t),this.bump()}upsertNode(t){const o=this.nodes.get(t.id);if(o===void 0){this.nodes.set(t.id,t),this.bump();return}o.label=t.label,o.name=t.name,o.description=t.description,o.live=t.live,o.memberships=t.memberships,this.bump()}removeNode(t){this.nodes.delete(t)&&(this.selection.delete(t),this.bump())}setFrame(t,o){this.frames.set(t,o),this.bump()}removeFrame(t){this.frames.delete(t)&&this.bump()}upsertScore(t,o){const s=this.nodes.get(t);s===void 0||s.score===o||(s.score=o,this.bump())}positions(){const t=new Map;for(const[o,s]of this.nodes)t.set(o,{x:s.x,y:s.y});return t}frameRects(){const t=new Map;for(const[o,s]of this.frames)t.set(o,{...s});return t}teamMemberIds(t){const o=[];for(const s of this.nodes.values()){const n=s.memberships.find(i=>i.team===t);n!==void 0&&o.push({id:s.id,index:n.index})}return o.sort((s,n)=>s.index-n.index).map(s=>s.id)}setTeamMembers(t,o){for(const s of this.nodes.values()){const n=s.memberships.filter(r=>r.team!==t),i=o.indexOf(s.id);i>=0&&n.push({team:t,index:i}),s.memberships=n}this.bump()}contentBounds(){let t=Number.POSITIVE_INFINITY,o=Number.POSITIVE_INFINITY,s=Number.NEGATIVE_INFINITY,n=Number.NEGATIVE_INFINITY;const i=r=>{t=Math.min(t,r.x),o=Math.min(o,r.y),s=Math.max(s,r.x+r.w),n=Math.max(n,r.y+r.h)};for(const r of this.nodes.values())r.remote!==!0&&i(vt(r));for(const r of this.frames.values())i(r);return t===Number.POSITIVE_INFINITY?null:{minX:t,minY:o,maxX:s,maxY:n}}static fromState(t){const o=new Sn,s=go(t.layout),n=new Map;for(const i of t.teams)for(let r=0;r<i.members.length;r++){const c=i.members[r].id,l=n.get(c)??[];l.push({team:i.name,index:r}),n.set(c,l)}for(const i of t.sessions){if(i.joined!==!0)continue;const r=s==null?void 0:s.nodes[i.id];let c,l;if(r!==void 0&&typeof r.x=="number"&&typeof r.y=="number")c=r.x,l=r.y;else{const u=wo(i.id,[...o.nodes.values()]);c=u.x,l=u.y}o.nodes.set(i.id,{id:i.id,x:c,y:l,label:i.label,team:i.team,name:i.name,description:i.description,live:i.live!==!1,memberships:n.get(i.id)??[]})}for(const i of t.teams){const r=s==null?void 0:s.frames[i.name];if(r!==void 0){o.frames.set(i.name,{x:r.x,y:r.y,w:r.w,h:r.h});continue}const c=[];for(const l of i.members){const u=o.nodes.get(l.id);u!==void 0&&c.push(vt(u))}c.length>0&&o.frames.set(i.name,Mn(c))}return o.viewport=s!==void 0?{...s.viewport}:{x:0,y:0,scale:1},o}}const us=24,xo=-13,fs=xo+us;function ps(e,t,o){const s=[],n=new Set;for(const i of e){const r=t.get(i.name);if(r===void 0)continue;const c=r.x+r.w/2,l=r.y+fs;for(const u of i.members){const h=o.get(u.id);if(h===void 0)continue;const m=n.has(u.id);n.add(u.id),s.push({x1:c,y1:l,x2:h.x,y2:h.y-Be/2,dashed:m,team:i.name,id:u.id})}}return s}function hs(e,t){for(;e.firstChild!==null;)e.firstChild.remove();const o=t.allFrames().map(([s])=>({name:s,members:t.teamMemberIds(s).map(n=>({id:n}))}));for(const s of ps(o,new Map(t.allFrames()),t.positions())){const n=document.createElementNS("http://www.w3.org/2000/svg","line");n.setAttribute("class","e-member"+(s.dashed?" dashed":"")),n.setAttribute("x1",String(s.x1)),n.setAttribute("y1",String(s.y1)),n.setAttribute("x2",String(s.x2)),n.setAttribute("y2",String(s.y2)),e.appendChild(n)}}function bs(e){return`peer-${gt(e).replace(/[^A-Za-z0-9.:\[\]-]/g,"-")}`}function gt(e){try{return new URL(e).host}catch{return e}}function gs(e){const t=new Map;for(const o of e){const s=o.via!==void 0&&o.via!==""?gt(o.via):"",n=t.get(s)??[];n.push(o),t.set(s,n)}return t}const vs=140,ys=200,ws=90,xs=20,qt=60;function Cs(e,t){const o=t!==null?t.maxX+vs:ys,s=t!==null?t.minY:0;return e.map((n,i)=>({url:n.url,score:n.score,x:o,y:s+i*ws}))}function ks(e,t,o,s){const n=new Map;for(const r of e){if(!t.has(r.team))continue;const c=`${r.team}\0${r.peer}`,l=n.get(c);l===void 0?n.set(c,{team:r.team,peer:r.peer,startedAt:r.startedAt,count:1}):(l.startedAt=Math.min(l.startedAt,r.startedAt),l.count+=1)}const i=[];for(const r of n.values()){const c=t.get(r.team);if(c===void 0)continue;const l=o.find(h=>{try{return new URL(h.url).host===r.peer}catch{return!1}});if(l===void 0)continue;const u=Math.max(0,Math.round((s-r.startedAt)/1e3));i.push({x1:c.x,y1:c.y,x2:l.x,y2:l.y,label:`a2a_route · ${r.peer} · ${u}s`+(r.count>1?` ×${r.count}`:"")})}return i}function Es(e,t){const o=t!==null?{x:t.maxX+xs,y:e.length>0?(e[0].y+e[e.length-1].y)/2:(t.minY+t.maxY)/2}:{x:-80,y:0};return e.map((s,n)=>({x1:o.x,y1:o.y,x2:s.x,y2:s.y,label:n===0?"gns referral":""}))}function Ns(e,t){if(e===null&&t.length===0)return null;let o=e!==null?e.minX:Number.POSITIVE_INFINITY,s=e!==null?e.minY:Number.POSITIVE_INFINITY,n=e!==null?e.maxX:Number.NEGATIVE_INFINITY,i=e!==null?e.maxY:Number.NEGATIVE_INFINITY;for(const r of t)o=Math.min(o,r.x-qt),s=Math.min(s,r.y-qt),n=Math.max(n,r.x+qt),i=Math.max(i,r.y+qt);return{minX:o,minY:s,maxX:n,maxY:i}}const $s=11;function Ms(e,t){let o=[],s=[],n=[];function i(c){for(const h of o)h.remove();o=[];const l=t.allNodes().filter(h=>h.remote===!0).map(h=>({url:h.peerUrl??h.id.slice(5),score:h.score,x:h.x,y:h.y}));s=l;const u=t.contentBounds();if(u!==null){const h=new Map;for(const[m,C]of t.allFrames())h.set(m,{name:m,x:C.x+C.w/2,y:C.y+$s});for(const m of ks(n,h,l,c))o.push(...r(m,"e-activity",m.label));for(const m of Es(l,u))o.push(...r(m,"e-federal",m.label))}}function r(c,l,u){const h=document.createElementNS("http://www.w3.org/2000/svg","line");h.setAttribute("class",l),h.setAttribute("x1",String(c.x1)),h.setAttribute("y1",String(c.y1)),h.setAttribute("x2",String(c.x2)),h.setAttribute("y2",String(c.y2)),e.appendChild(h);const m=[h];if(u!==""){const C=document.createElementNS("http://www.w3.org/2000/svg","text");C.setAttribute("class","edge-label mono"),C.setAttribute("x",String((c.x1+c.x2)/2+14)),C.setAttribute("y",String((c.y1+c.y2)/2+18)),C.textContent=u,e.appendChild(C),m.push(C)}return m}return{render:i,flyTo(c){return c(),s},placements:()=>s,setInFlight:c=>{n=c}}}function Co(e,t){const o=new Map,s=new Set;for(const i of e){if(i.joined!==!0)continue;const r=i.team.lastIndexOf("/");if(r<=0||i.team.slice(r+1)!==i.id.replace(/^session-/,"").slice(0,8))continue;const c=i.team;t.has(c)||s.has(c)||(o.has(c)?(o.delete(c),s.add(c)):o.set(c,i.id))}const n=new Map;for(const i of e)if(i.joined===!0&&i.memberRef){const r=n.get(i.memberRef)??[];r.push(i.id),n.set(i.memberRef,r)}for(const[i,r]of n)r.length===1&&o.set(i,r[0]);return o}function Ss(e,t,o,s){var r;const n=t.get(e);return n!==void 0?n:e.includes("/")?`member-${e.replace(/[^a-z0-9-]/gi,"-")}`:`member-${((r=o==null?void 0:o.find(c=>c.via===s))==null?void 0:r.team.split("/")[0])??"dsh"}-${e.replace(/^session-/,"").slice(0,8)}`}function As(e){const t=new Map;for(const o of e)for(let s=0;s<o.members.length;s++){const n=o.members[s].id,i=t.get(n)??[];i.push({team:o.name,index:s}),t.set(n,i)}return t}function Ls(e,t,o){const s=Co(t,new Set((o??[]).map(i=>i.team))),n=new Set;for(const i of e)for(const r of i.org)for(const c of r.members){const l=s.get(c);l!==void 0&&n.add(l)}return n}const Xn={x:0,y:0,scale:1};function on(e){return Math.max(Nn,Math.min($n,e))}function It(e){const t=Number.isFinite(e.scale)?e.scale:1,o=Number.isFinite(e.x)?e.x:0,s=Number.isFinite(e.y)?e.y:0;return{x:o,y:s,scale:on(t)}}function ht(e,t,o){return{x:e.x+t/e.scale,y:e.y+o/e.scale}}function hn(e,t,o){return{x:e.x+t/e.scale,y:e.y+o/e.scale,scale:e.scale}}function Un(e,t,o,s){const n=on(e.scale*t);return n===e.scale?e:{x:e.x+o/e.scale-o/n,y:e.y+s/e.scale-s/n,scale:n}}const Is=680,Ts=.8,_s=.6,Jn=16;function An(e,t,o,s=Number.POSITIVE_INFINITY){if(e===null||t<=0||o<=0)return Xn;const n=e.maxX-e.minX,i=e.maxY-e.minY;if(!(n>0)||!(i>0))return Xn;const r=.9*Math.min(t/n,o/i),c=Math.min(s,r),l=t<Is?Ts:_s;if(r<l){const h=on(Math.min(s,l));return{x:e.minX-Jn/h,y:e.minY-Jn/h,scale:h}}const u=on(c);return{x:(e.minX+e.maxX)/2-t/(2*u),y:(e.minY+e.maxY)/2-o/(2*u),scale:u}}function Os(e){return`translate(${-e.x*e.scale}px, ${-e.y*e.scale}px) scale(${e.scale})`}function qn(e,t){let o=e===null?null:{...e,minY:e.minY+xo};for(const s of t){if(s.remote!==!0)continue;const n=vt(s);o=o===null?{minX:n.x,minY:n.y,maxX:n.x+n.w,maxY:n.y+n.h}:{minX:Math.min(o.minX,n.x),minY:Math.min(o.minY,n.y),maxX:Math.max(o.maxX,n.x+n.w),maxY:Math.max(o.maxY,n.y+n.h)}}return o}function zn(e,t,o,s){const n=s>0&&s<o/2?s:0,i=An(e,t,o-n,1);return n===0||e===null?i:{...i,y:i.y-n/i.scale}}function Vn(...e){const t=Math.max(0,...e.map(o=>o.offsetHeight>0?o.offsetTop+o.offsetHeight:0));return t>0?t+8:0}function Yt(e){return e.type==="join-network"||e.type==="leave-network"?"$network":e.type==="create-team"||e.type==="remove-team"?e.name:e.team}function Fs(e,t){if(t.type==="create-team"){const n=t.ids.map(i=>e.getNode(i)).filter(i=>i!==void 0).map(i=>vt(i));return n.length>0&&e.setFrame(t.name,Mn(n)),e.setTeamMembers(t.name,t.ids),()=>{e.setTeamMembers(t.name,e.teamMemberIds(t.name).filter(i=>!t.ids.includes(i))),e.removeFrame(t.name)}}if(t.type==="add-member"){const n=e.teamMemberIds(t.team),i=t.ids.filter(r=>!n.includes(r));return e.setTeamMembers(t.team,[...n,...i]),()=>{e.setTeamMembers(t.team,e.teamMemberIds(t.team).filter(r=>!i.includes(r)))}}if(t.type==="remove-member"){const n=e.teamMemberIds(t.team);return e.setTeamMembers(t.team,n.filter(i=>!t.ids.includes(i))),()=>{const i=e.teamMemberIds(t.team);e.setTeamMembers(t.team,[...i,...t.ids.filter(r=>!i.includes(r))])}}if(t.type==="remove-team"){const n=e.teamMemberIds(t.name),i=e.getFrame(t.name),r=i!==void 0?{...i}:void 0;return e.setTeamMembers(t.name,[]),e.removeFrame(t.name),()=>{r!==void 0&&e.setFrame(t.name,r),e.setTeamMembers(t.name,n)}}if(t.type==="join-network"||t.type==="leave-network")return()=>{};const o=e.teamMemberIds(t.team);let s=[...o];for(const n of t.ops)n.op==="remove"?s=s.filter(i=>i!==n.id):s.push(n.id);return e.setTeamMembers(t.team,s),()=>{let n=e.teamMemberIds(t.team);for(let i=0;i<o.length;i++){const r=o[i];n[i]!==r&&n.includes(r)&&(n=n.filter(c=>c!==r),n.push(r))}e.setTeamMembers(t.team,n)}}function Gn(e,t,o,s,n){if(o||s(),!(t.type==="remove-team"&&o||t.type==="create-team"&&!o&&t.created===!0)||n===void 0||e.getFrame(Yt(t))!==void 0)return n;const r={...n.frames};return delete r[Yt(t)],{...n,frames:r}}function xn(e,t){const o=[...e],s=[];for(let n=0;n<t.length;n++){const i=t[n];o[n]!==i&&o.includes(i)&&(s.push({op:"remove",id:i}),s.push({op:"add",id:i}),o.splice(o.indexOf(i),1),o.push(i))}return s}function Ps(e,t){return e.teamMemberIds(t).map(o=>{var s;return{id:o,y:((s=e.getNode(o))==null?void 0:s.y)??0}}).sort((o,s)=>o.y-s.y).map(o=>o.id)}function zt(e,t){let o,s=Number.POSITIVE_INFINITY;for(const[n,i]of e){if(t.x<i.x||t.x>i.x+i.w||t.y<i.y||t.y>i.y+i.h)continue;const r=i.w*i.h;r<s&&(o=n,s=r)}return o}const Qn=[9133302,3900150,1357990,16096779,15485081,8702998];function Rs(e){let t=0;for(let c=0;c<e.length;c++)t=(t*31+e.charCodeAt(c)&268435455)>>>0;const o=Qn[t%Qn.length],s="#"+o.toString(16).padStart(6,"0"),n=o>>16&255,i=o>>8&255,r=o&255;return{line:s,bg:`rgba(${n},${i},${r},0.05)`}}const sn="roster:",ko=e=>e.startsWith(sn)?e.slice(sn.length):void 0,Ht=e=>sn+e,rn=e=>{const t=ko(e);return t===void 0?e:`网络队 · roster · ${t}`};function Ds(e,t){return e.flatMap(o=>{if(t===""||!o.team.startsWith(t+"/")||!Array.isArray(o.members))return[];const s=o.team.slice(t.length+1);return s===""||s.length>40||s.includes("/")||s.startsWith(sn)||s.includes("*")?[]:[{name:Ht(s),team:o.team,kind:"roster",members:o.members.filter(n=>typeof n=="string"&&n!=="").map(n=>({id:n}))}]})}function Hs(e){const{root:t,netBtn:o,signal:s,model:n}=e,i=y=>e.isRoster(y)?rn(y):y;function r(){return n.selectedIds().map(y=>{var b;return{id:y,y:((b=n.getNode(y))==null?void 0:b.y)??0}}).sort((y,b)=>y.y-b.y).map(y=>y.id)}function c(){if(l!==null)return;const y=r().filter(b=>{const M=n.getNode(b);return M===void 0?!1:M.remote!==!0||M.remoteHandle!==void 0&&M.remoteHandle!==""});if(y.length<2){e.notice("info","框选至少 2 个会话节点");return}u(y)}let l=null;function u(y){const b=document.createElement("div");b.className="p-dialog";const M=document.createElement("div");M.className="p-dialog-panel",M.setAttribute("role","dialog"),M.setAttribute("aria-modal","true"),M.setAttribute("aria-labelledby","p-dialog-title");const f=document.createElement("div");f.id="p-dialog-title",f.className="p-dialog-title",f.textContent=`组建团队(${y.length} 个节点,自上而下即优先级)`;const D={value:"canvas"},K=document.createElement("div");K.className="p-dialog-kind",K.setAttribute("role","radiogroup"),K.setAttribute("aria-label","团队类型");const X=document.createElement("div");X.className="p-dialog-hint";const ye={canvas:"canvas 队:画布上的协作组,可以加入远端成员。",roster:"roster 网络队:只收本机已入网的会话;队名会写进属主的精确允许名单。"},Se=["canvas","roster"].map(ie=>{const ee=document.createElement("button");return ee.type="button",ee.dataset.kind=ie,ee.setAttribute("role","radio"),ee.textContent=ie==="canvas"?"canvas 队":"roster 网络队",ee.addEventListener("click",()=>R(ie)),K.appendChild(ee),ee});function R(ie){D.value=ie;for(const ee of Se){const ke=ee.dataset.kind===ie;ee.setAttribute("aria-checked",String(ke)),ee.tabIndex=ke?0:-1}X.textContent=ye[ie],le.textContent=""}K.addEventListener("keydown",ie=>{var ke;const ee=ie;["ArrowLeft","ArrowRight","ArrowUp","ArrowDown"].includes(ee.key)&&(ee.preventDefault(),R(D.value==="canvas"?"roster":"canvas"),(ke=Se.find(et=>et.dataset.kind===D.value))==null||ke.focus())});const q=document.createElement("input");q.className="p-dialog-input",q.maxLength=40,q.setAttribute("aria-label","团队名");const le=document.createElement("div");le.className="p-dialog-err",le.setAttribute("aria-live","polite");const Ke=document.createElement("div");Ke.className="p-dialog-row";const Me=document.createElement("button");Me.type="button",Me.textContent="组建";const de=document.createElement("button");de.type="button",de.textContent="取消",Ke.append(Me,de),R("canvas"),M.append(f,K,X,q,le,Ke),b.appendChild(M),t.appendChild(b);const Ue=document.activeElement,ue=()=>{b.remove(),l=null,Ue==null||Ue.focus()},V=()=>{const ie=q.value.trim();return ie===""||ie.length>40||ie.includes("/")||ie.startsWith("roster:")||D.value==="roster"&&ie.includes("*")||/^\d+$/.test(ie)?"队名需 1..40 字,不含“/”、通配符或保留前缀,不为纯数字":D.value==="roster"&&n.getFrame(ie)!==void 0?"同名 canvas 队已存在,不能创建 roster 队":D.value==="roster"&&n.getFrame(Ht(ie))!==void 0&&!e.isRoster(Ht(ie))?"roster 框名已被 canvas 或镜像队占用":D.value==="canvas"&&n.getFrame(Ht(ie))!==void 0?"同名 roster 队已存在,不能创建 canvas 队":D.value==="roster"&&y.some(ee=>{var ke;return((ke=n.getNode(ee))==null?void 0:ke.remote)===!0||!e.joined(ee)})?"roster 仅接受本机已入网的会话":null},ce=()=>{const ie=V();if(ie!==null){le.textContent=ie,q.focus();return}const ee=D.value==="roster"?Ht(q.value.trim()):q.value.trim();if(ue(),n.getFrame(ee)!==void 0){e.notice("info",`已加入现有团队「${D.value==="roster"?rn(ee):ee}」`),e.emit({type:"add-member",team:ee,ids:y});return}e.emit({type:"create-team",name:ee,ids:y,created:!0,...D.value==="roster"?{roster:!0}:{}})};Me.addEventListener("click",ce),de.addEventListener("click",ue),q.addEventListener("keydown",ie=>{const ee=ie;ee.key==="Enter"&&(ee.preventDefault(),ce()),ee.key==="Escape"&&(ee.preventDefault(),ue())}),b.addEventListener("keydown",ie=>{const ee=ie;if(ee.key==="Escape"){ee.preventDefault(),ee.stopPropagation(),ue();return}if(ee.key!=="Tab")return;ee.preventDefault();const ke=Array.from(M.querySelectorAll('input, select, button:not([tabindex="-1"])')),et=ke.indexOf(document.activeElement),Oe=ee.shiftKey?ke[(et-1+ke.length)%ke.length]:ke[(et+1)%ke.length];Oe==null||Oe.focus()},s),l={wrap:b,restoreFocus:Ue},q.focus()}let h=null,m="root",C=null,N=null,J=[];function ne(){N==null||N.remove(),N=null}function G(){var M;if(N!==null){ne();return}if(J.length===0)return;const y=document.createElement("div");y.className="p-menu p-netmenu",y.setAttribute("role","menu"),y.setAttribute("aria-label","未入网会话");for(const f of J)y.appendChild(E(`${f.name!==void 0&&f.name!==""?f.name:f.label} — 入网`,!0,()=>{ne(),e.emit({type:"join-network",id:f.id})}));N=y,t.appendChild(y);const b=o.getBoundingClientRect();y.style.left=`${String(Math.min(b.left,window.innerWidth-220))}px`,y.style.top=`${String(Math.max(8,b.top-(J.length*30+10)))}px`,y.addEventListener("keydown",f=>{f.key==="Escape"&&(f.stopPropagation(),ne(),o.focus())}),(M=y.querySelector("button"))==null||M.focus(),document.addEventListener("pointerdown",f=>{if(N===null)return;const D=f.target;D!==null&&(D.closest(".p-netmenu")!==null||D===o||o.contains(D))||ne()},s)}function $(){h==null||h.remove(),h=null,m="root",C!==null&&C.isConnected?C.focus():t.focus(),C=null}function E(y,b,M){const f=document.createElement("button");return f.type="button",f.setAttribute("role","menuitem"),f.textContent=y,b?f.addEventListener("click",()=>{$(),M()}):(f.disabled=!0,f.setAttribute("aria-disabled","true")),f}function S(y,b,M,f="root",D){var Se,R,q,le,Ke,Me,de,Ue;D!==void 0&&(C=D),C===null&&(C=e.anchorFor(M)),h==null||h.remove(),m=f;const K=document.createElement("div");K.className="p-menu",K.setAttribute("role","menu"),K.setAttribute("aria-label","团队操作");let X=[];if(M.kind==="frame")X=[E(`解散团队「${i(M.name)}」`,!0,()=>e.emit({type:"remove-team",name:M.name}))];else{const ue=M.id;if(f==="root"){const V=E("组成团队…",n.selectedIds().length>=2,()=>u(r()));V.title="先框选或 Shift 加选至少 2 个节点",X.push(V);const ce=((Se=n.getNode(ue))==null?void 0:Se.memberships.map(ie=>ie.team))??[];e.teams().length>0&&(X.push(E("加入团队 ▸",!0,()=>S(y,b,M,"join"))),ce.length>0&&X.push(E("置顶路由 ▸",!0,()=>S(y,b,M,"promote")))),ce.length>0&&X.push(E("离队 ▸",!0,()=>S(y,b,M,"leave"))),((R=n.getNode(ue))==null?void 0:R.remote)!==!0&&X.push(E("退网",!0,()=>e.emit({type:"leave-network",id:ue})))}else{X.push(E("‹ 返回",!0,()=>S(y,b,M,"root")));for(const V of e.teams())if(f==="join"){const ce=((q=n.getNode(ue))==null?void 0:q.memberships.some(ke=>ke.team===V.name))??!0,ie=!e.isRoster(V.name)||e.joined(ue)&&((le=n.getNode(ue))==null?void 0:le.remote)!==!0,ee=E(ce?`${i(V.name)}(已加入)`:i(V.name),!ce&&ie,()=>e.emit({type:"add-member",team:V.name,ids:[ue]}));ie||(ee.title="roster 只接受本机已入网会话"),X.push(ee)}else if(f==="leave"){const ce=((Ke=n.getNode(ue))==null?void 0:Ke.memberships.some(ie=>ie.team===V.name))??!1;X.push(E(i(V.name),ce,()=>e.emit({type:"remove-member",team:V.name,ids:[ue]})))}else{const ce=((Me=n.getNode(ue))==null?void 0:Me.memberships.some(ie=>ie.team===V.name))??!1;if(e.isRoster(V.name))continue;X.push(E(i(V.name),ce,()=>{const ie=n.teamMemberIds(V.name),ee=[ue,...ie.filter(ke=>ke!==ue)];e.emit({type:"reorder",team:V.name,ops:xn(ie,ee)})}))}if(f==="leave"){const V=new Set(e.teams().map(ce=>ce.name));for(const ce of((de=n.getNode(ue))==null?void 0:de.memberships)??[])V.has(ce.team)||X.push(E(i(ce.team),!0,()=>e.emit({type:"remove-member",team:ce.team,ids:[ue]})))}}}K.append(...X),K.style.left=`${Math.min(y,window.innerWidth-200)}px`;const ye=X.length*30+8;K.style.top=`${Math.max(8,Math.min(b,window.innerHeight-ye-8))}px`,K.addEventListener("keydown",ue=>{var ee,ke,et,Oe;const V=ue,ce=Array.from(K.querySelectorAll("[role=menuitem]")),ie=ce.indexOf(document.activeElement);V.key==="ArrowDown"?(V.preventDefault(),(ee=ce[(ie+1+ce.length)%ce.length])==null||ee.focus()):V.key==="ArrowUp"?(V.preventDefault(),(ke=ce[(ie-1+ce.length)%ce.length])==null||ke.focus()):V.key==="Home"?(V.preventDefault(),(et=ce[0])==null||et.focus()):V.key==="End"?(V.preventDefault(),(Oe=ce[ce.length-1])==null||Oe.focus()):V.key==="Escape"&&(V.preventDefault(),V.stopPropagation(),m!=="root"?S(y,b,M,"root"):$())}),t.appendChild(K),h=K,(Ue=X[0])==null||Ue.focus()}function w(y,b,M){if(l!==null)return;const f=(M==null?void 0:M.closest(".p-node"))??null;if(f!==null){const X=n.getNode(f.dataset.id??"");if((X==null?void 0:X.remote)===!0&&(X.remoteHandle===void 0||X.remoteHandle===""))return}const D=f,K=(M==null?void 0:M.closest(".p-frame-head"))??null;if(D!==null){const X=D.dataset.id??"";n.isSelected(X)||n.setSelection([X]),C=D,S(y,b,{kind:"node",id:X})}else K!==null&&(C=K,S(y,b,{kind:"frame",name:K.dataset.frame??""}))}function oe(y){J=y,o.textContent=`未入网${J.length>0?`(${String(J.length)})`:""}`,o.disabled=J.length===0,o.setAttribute("aria-disabled",String(J.length===0)),J.length===0&&ne()}return{menuItem:E,isMenuOpen:()=>h!==null,isDialogOpen:()=>l!==null,closeMenu:$,openMenu:S,contextMenuAt:w,openNameDialog:u,startCreateFromSelection:c,toggleNetMenu:G,setUnjoined:oe}}function js(e,t){const o=t.trim().toLowerCase();return o===""?[]:e.filter(s=>s.name.toLowerCase().includes(o)||s.team.toLowerCase().includes(o)||(s.host??"").toLowerCase().includes(o)).slice(0,8)}function Bs(e,t){return e.allNodes().map(o=>{const s=o.id.slice(5),n=o.id.startsWith("member-")?o.name!==void 0&&o.name!==""?o.name:o.team:o.remote===!0?s:t(o);return{id:o.id,name:n,team:o.team,...o.remote===!0?{host:s}:{}}})}function Ys(e,t=1200){e!==void 0&&(e.classList.add("pulse"),setTimeout(()=>e.classList.remove("pulse"),t))}function Ws(e){return t=>{const o=e.model.getNode(t);if(o===void 0)return;const s=e.viewSize();e.setVp(An({minX:o.x,minY:o.y,maxX:o.x+ze,maxY:o.y+Be},s.w,s.h,1)),e.applyViewport(),e.markDirty(),Ys(e.cardEl(t))}}function Ks(e,t,o,s){const n=Xs({onPick:s});return e.appendChild(n.root),{...n,refresh:()=>n.setIndex(Bs(t,o))}}function Xs(e){const t=document.createElement("div");t.className="p-search";const o=document.createElement("input");o.type="search",o.className="p-search-input",o.placeholder="🔍 搜索(Ctrl+K)",o.title="搜索名字 / 句柄 / 宿主(Ctrl+K 聚焦,Esc 清空)",o.setAttribute("aria-label","搜索画板节点:名字、句柄或宿主");const s=document.createElement("div");s.className="p-search-list";let n=[],i=[],r=0;const c=()=>{s.style.display="none",s.textContent=""},l=()=>{if(s.textContent="",i.length===0){c();return}i.forEach((m,C)=>{const N=document.createElement("div");N.className="p-search-hit"+(C===r?" active":""),N.dataset.id=m.id,N.textContent=m.name===m.team?m.name:`${m.name} · ${m.team}`,N.addEventListener("mousedown",J=>{J.preventDefault(),e.onPick(m.id),u()}),s.appendChild(N)}),s.style.display="block"},u=()=>{o.value="",i=[],c()},h=()=>{i=js(n,o.value),r=0,l()};return o.addEventListener("input",h),o.addEventListener("keydown",m=>{if(m.key==="Escape"){u(),o.blur(),m.stopPropagation();return}if(m.key==="ArrowDown"||m.key==="ArrowUp"){if(i.length===0)return;m.preventDefault(),r=(r+(m.key==="ArrowDown"?1:i.length-1))%i.length,l();return}m.key==="Enter"&&i.length>0&&(m.preventDefault(),e.onPick(i[r].id),u())}),t.append(o,s),{root:t,setIndex(m){n=m,o.value!==""&&h()},focus(){o.focus(),o.select()},clear(){u()}}}const Vt=28,Zn=16,eo=14,to=48,Us=4,Js=180,qs=90,zs=1600;function Vs(e){const t=e.wrapWidth??zs,o=e.frames.map(l=>{const u=Math.max(l.soleIds.length,1),h=Math.min(Us,Math.max(1,Math.ceil(Math.sqrt(u)))),m=Math.ceil(u/h),C=Math.max(Js,Vt*2+h*ze+(h-1)*Zn),N=Math.max(qs,Vt*2+m*Be+(m-1)*eo);return{name:l.name,w:C,h:N,rows:m,perRow:h,soleIds:l.soleIds}}),s=[],n=[];let i=0,r=0,c=0;for(const l of o){i>0&&i+l.w>t&&(i=0,r+=c+to,c=0);const u={x:i,y:r,w:l.w,h:l.h};s.push({name:l.name,rect:u});const h=u.x+Vt+ze/2;let m=u.y+Vt+Be/2;l.soleIds.forEach((C,N)=>{const J=N%l.perRow;N>0&&J===0&&(m+=Be+eo),n.push({id:C,x:h+J*(ze+Zn),y:m})}),i+=l.w+to,c=Math.max(c,l.h)}return{frames:s,seats:n}}function Gs(e,t){const o=[];for(const[n,i]of e.allFrames()){if(t.has(n))continue;const r=e.teamMemberIds(n).map(c=>e.getNode(c)).filter(c=>c!==void 0).filter(c=>c.memberships.length===1).map(c=>c.id);o.push({name:n,rect:i,soleIds:r})}if(o.length===0)return!1;const s=Vs({frames:o});for(const n of s.frames)e.setFrame(n.name,n.rect);for(const n of s.seats){const i=e.getNode(n.id);i!==void 0&&e.dragNodes([n.id],n.x-i.x,n.y-i.y)}return!0}function Qs(e,t){if(e===void 0)return;const o=gt(e);return{text:t?`同步中… · ${o}`:`镜像 · ${o}`,title:t?`已把改动交给属主 ${o},等待它确认`:`这个团队属于 ${o},这里显示的是它的镜像;拖入或移出成员会经中继交给 ${o} 执行`,syncing:t}}const Zs=1e4;function ei(e=Date.now){const t=(s,n)=>`${s}\0${n}`,o=new Map;return{fork(s,n){return o.set(t(n,s.name),{url:n,name:s.name}),{...s,fleetPeer:n}},settled(s,n){if(s.type!=="remove-team"||s.name===void 0||s.fleetPeer===void 0)return;const i=o.get(t(s.fleetPeer,s.name));i!==void 0&&(n?i.acceptedAt=e():o.delete(t(s.fleetPeer,s.name)))},hides(s,n){return o.has(t(n,s))},sweep(s){var n;for(const[i,r]of o)(!(((n=s.find(l=>l.url===r.url))==null?void 0:n.org.some(l=>l.name===r.name))===!0)||r.acceptedAt!==void 0&&e()-r.acceptedAt>Zs)&&o.delete(i)}}}const Mt=24,ti=200,Zt=(e,t)=>e.x<t.x+t.w&&t.x<e.x+e.w&&e.y<t.y+t.h&&t.y<e.y+e.h;function ni(e,t){const o=t.x+t.w+Mt-e.x,s=t.x-Mt-(e.x+e.w),n=t.y+t.h+Mt-e.y,i=t.y-Mt-(e.y+e.h),r=Math.abs(o)<=Math.abs(s)?o:s,c=Math.abs(n)<=Math.abs(i)?n:i;return Math.abs(r)<=Math.abs(c)?{dx:r,dy:0}:{dx:0,dy:c}}function oi(e,t,o,s){const n=e.beginFrameDrag(t);n!==void 0&&e.applyFrameDrag(n,o,s)}function si(e,t,o){let s=!1;for(let n=0;n<ti;n++){const i=e.allFrames();let r;for(let $=0;$<i.length&&r===void 0;$++)for(let E=$+1;E<i.length;E++){const[S,w]=i[$],[oe,y]=i[E];if(!(t.has(S)&&t.has(oe))&&Zt(w,y)){r=[S,w,oe,y];break}}if(r===void 0)return s;const[c,l,u,h]=r,m=$=>t.has($)?2:$===o?1:0,[C,N,J]=m(c)<m(u)?[c,l,h]:[u,h,l],{dx:ne,dy:G}=ni(N,J);oi(e,C,ne,G),s=!0}return s}const Et=28,en=16,an=14;function ii(e){const t=[];for(let o=e.y+Et;o+Be<=e.y+e.h-Et;o+=Be+an)for(let s=e.x+Et;s+ze<=e.x+e.w-Et;s+=ze+en)t.push({x:s+ze/2,y:o+Be/2});return t}function ri(e){let t=!1;const o=e.allFrames(),s=new Map(o);for(const n of e.allNodes()){const i=new Set(n.memberships.map(G=>G.team)),r=o.find(([G,$])=>!i.has(G)&&Zt(vt(n),$));if(r===void 0)continue;const c=r[1],l=G=>{const $=vt(G);return o.every(([E,S])=>i.has(E)||!Zt($,S))&&e.allNodes().every(E=>E.id===n.id||!Zt($,vt(E)))},h=n.memberships.map(G=>s.get(G.team)).filter(G=>G!==void 0).flatMap(ii).find(l),m={x:c.x+c.w+Mt+ze/2,y:n.y},C={x:n.x,y:c.y+c.h+Mt+Be/2},N=Math.max(...o.map(([,G])=>G.x+G.w))+Mt+ze/2,J=Array.from({length:2*e.allNodes().length+1},(G,$)=>({x:N,y:c.y+Be/2+$*(Be+an)})),ne=h??[m,C,...J].find(l)??J[J.length-1];e.dragNodes([n.id],ne.x-n.x,ne.y-n.y),t=!0}return t}function Gt(e,t,o){const s=si(e,t,o),n=ri(e);return s||n}function ai(e){for(const[t,o]of e.allFrames()){const s=e.teamMemberIds(t).map(u=>e.getNode(u)).filter(u=>u!==void 0).filter(u=>u.memberships.length===1);if(s.length===0)continue;const n=Math.max(1,Math.floor((o.w-2*Et+en)/(ze+en))),i=Math.ceil(s.length/n),r=Et*2+i*Be+(i-1)*an;r>o.h&&e.setFrame(t,{...o,h:Math.min(r,o.h+400)});const c=o.x+Et+ze/2;let l=o.y+Et+Be/2;s.forEach((u,h)=>{const m=h%n;h>0&&m===0&&(l+=Be+an);const C=c+m*(ze+en);e.dragNodes([u.id],C-u.x,l-u.y)})}}const ci=30;function li(e){const t=[],o=()=>({nodes:new Map(e.allNodes().map(i=>[i.id,{x:i.x,y:i.y}])),frames:new Map(e.allFrames().map(([i,r])=>[i,{...r}]))}),s=i=>e.allNodes().some(r=>{const c=i.nodes.get(r.id);return c!==void 0&&(c.x!==r.x||c.y!==r.y)})||e.allFrames().some(([r,c])=>{const l=i.frames.get(r);return l!==void 0&&(l.x!==c.x||l.y!==c.y||l.w!==c.w||l.h!==c.h)}),n=i=>{for(const r of e.allNodes()){const c=i.nodes.get(r.id);c!==void 0&&(c.x!==r.x||c.y!==r.y)&&e.dragNodes([r.id],c.x-r.x,c.y-r.y)}for(const[r,c]of e.allFrames()){const l=i.frames.get(r);l!==void 0&&(l.x!==c.x||l.y!==c.y||l.w!==c.w||l.h!==c.h)&&e.setFrame(r,{...l})}};return{capture:o,commit(i){s(i)&&(t.push(i),t.length>ci&&t.shift())},undo(){const i=t.pop();return i===void 0?!1:(n(i),!0)},revert(i){return s(i)?(n(i),!0):!1},get depth(){return t.length}}}function di(e){const{root:t,trigger:o,signal:s,model:n}=e;let i=null,r="",c=null;function l(){c==null||c.remove(),c=null}function u(){l(),i==null||i.remove(),i=null}function h(){if(i!==null){u();return}const E=document.createElement("div");E.className="p-menu p-nodelist",E.setAttribute("role","dialog"),E.setAttribute("aria-label","节点清单"),i=E,t.appendChild(E);const S=o.getBoundingClientRect();E.style.left=`${String(Math.min(S.left,window.innerWidth-340))}px`,E.style.top=`${String(Math.max(8,S.top-320))}px`,E.addEventListener("keydown",w=>{w.key==="Escape"&&(w.stopPropagation(),u(),o.focus())}),m()}function m(){var M;const E=i;if(E===null)return;l(),E.textContent="";const S=document.createElement("div");S.className="p-nodelist-head";const w=document.createElement("span");w.className="p-nodelist-title",w.textContent="节点";const oe=document.createElement("select");oe.className="p-nodesel",oe.setAttribute("aria-label","选择 host 或对等节点");const y=document.createElement("option");y.value="",y.textContent="本机",oe.appendChild(y);for(const[f,D]of e.facts().remoteTeams){if(f==="")continue;const K=document.createElement("option");K.value=f,K.textContent=((M=D[0])==null?void 0:M.origin)!==void 0&&D[0].origin!==""?`${D[0].origin}(${f})`:f,oe.appendChild(K)}r!==""&&!e.facts().remoteTeams.has(r)&&(r=""),oe.value=r,oe.addEventListener("change",()=>{r=oe.value,m()}),S.append(w,oe);const b=document.createElement("div");b.className="p-nodelist-body",E.append(S,b),r===""?G(b):$(b,e.facts().remoteTeams.get(r)??[])}function C(E,S){const w=document.createElement("span");return w.className="p-nodedot"+(S!==!0?" off":E===!1?" cold":""),w}function N(E,S){const w=document.createElement("button");return w.type="button",w.className="p-listbtn",w.textContent=E,w.addEventListener("click",oe=>{oe.stopPropagation(),S()}),w}function J(E,S){const w=document.createElement("div");if(w.className="p-nodelist-group",w.textContent=E,S!==void 0){const oe=document.createElement("span");oe.className="p-nodelist-note",oe.textContent=S,w.appendChild(oe)}return w}function ne(E,S){var y,b;l();const w=document.createElement("div");w.className="p-menu",w.setAttribute("role","menu"),w.setAttribute("aria-label","加入团队");for(const M of e.facts().teams){const f=((y=n.getNode(S))==null?void 0:y.memberships.some(D=>D.team===M.name))??!1;w.appendChild(e.menuItem(f?`${M.name}(已加入)`:M.name,!f,()=>{u(),e.emit({type:"add-member",team:M.name,ids:[S]})}))}w.appendChild(e.menuItem("新团队…",!0,()=>{u(),e.openNameDialog([S])})),c=w,t.appendChild(w);const oe=E.getBoundingClientRect();w.style.left=`${String(Math.min(oe.right+4,window.innerWidth-180))}px`,w.style.top=`${String(Math.max(8,oe.top-60))}px`,w.addEventListener("keydown",M=>{M.key==="Escape"&&(M.stopPropagation(),l(),E.focus())}),(b=w.querySelector("button"))==null||b.focus()}function G(E){var b,M;const S=new Set(e.facts().canvasMemberIds);for(const f of e.facts().sessions)f.teams!==void 0&&f.teams.length>0&&S.add(f.id);const w=e.facts().sessions.filter(f=>f.joined===!0&&!S.has(f.id)),oe=e.facts().sessions.filter(f=>f.joined!==!0),y=e.facts().sessions.filter(f=>f.joined===!0&&S.has(f.id));E.appendChild(J(`未组队 (${String(w.length)})`,"无网络能力"));for(const f of w){const D=document.createElement("div");D.className="p-noderow";const K=document.createElement("span");K.className="p-nodename",K.textContent=f.name!==void 0&&f.name!==""?f.name:f.label,K.title=f.team;const X=document.createElement("span");X.className="p-nonet",X.textContent="无网络能力";const ye=N("入队▸",()=>ne(ye,f.id));D.append(C(f.live,!0),K,X,ye,N("退网",()=>{u(),e.emit({type:"leave-network",id:f.id})})),E.appendChild(D)}E.appendChild(J(`未入网 (${String(oe.length)})`));for(const f of oe){const D=document.createElement("div");D.className="p-noderow";const K=document.createElement("span");K.className="p-nodename",K.textContent=f.name!==void 0&&f.name!==""?f.name:f.label,K.title=f.id,D.append(C(f.live,!1),K,N("入网",()=>{u(),e.emit({type:"join-network",id:f.id})})),E.appendChild(D)}E.appendChild(J(`已组队 (${String(y.length)})`,"画布展示"));for(const f of y){const D=document.createElement("div");D.className="p-noderow";const K=document.createElement("span");K.className="p-nodename",K.textContent=f.name!==void 0&&f.name!==""?f.name:f.label,K.title=f.team;const X=((b=n.getNode(f.id))==null?void 0:b.memberships.length)??0,ye=((M=f.teams)==null?void 0:M.length)??0,Se=document.createElement("span");Se.className="p-teamcount",Se.textContent=`队×${String(Math.max(X,0)+ye)}`,D.append(C(f.live,!0),K,Se,N("定位",()=>{e.locate(f.id)})),E.appendChild(D)}if(e.facts().sessions.length===0){const f=document.createElement("div");f.className="p-nodelist-empty",f.textContent="无会话节点",E.appendChild(f)}}function $(E,S){var y;const w=S.filter(b=>b.teams===void 0||b.teams.length===0),oe=S.filter(b=>b.teams!==void 0&&b.teams.length>0);E.appendChild(J(`未组队 (${String(w.length)})`,"无网络能力 · 只读"));for(const b of w){const M=document.createElement("div");M.className="p-noderow";const f=document.createElement("span");f.className="p-nodename",f.textContent=b.name!==void 0&&b.name!==""?b.name:b.team,f.title=b.team;const D=document.createElement("span");D.className="p-nonet",D.textContent="无网络能力",M.append(C(!0,!0),f,D),E.appendChild(M)}E.appendChild(J(`已组队 (${String(oe.length)})`,"只读"));for(const b of oe){const M=document.createElement("div");M.className="p-noderow";const f=document.createElement("span");f.className="p-nodename",f.textContent=b.name!==void 0&&b.name!==""?b.name:b.team,f.title=b.team;const D=document.createElement("span");D.className="p-teamcount",D.textContent=`队×${String(((y=b.teams)==null?void 0:y.length)??0)}`,M.append(C(!0,!0),f,D),E.appendChild(M)}if(S.length===0){const b=document.createElement("div");b.className="p-nodelist-empty",b.textContent="该节点未发布会话",E.appendChild(b)}}return document.addEventListener("pointerdown",E=>{if(i===null)return;const S=E.target;if(S===null){u();return}S.closest(".p-nodelist")!==null||S.closest(".p-menu")!==null||S===o||o.contains(S)||u()},s),{toggle:h,close:u,refresh:()=>{i!==null&&m()}}}function mi(e){let t=e;const o=t.search(/\|| ```|^```/);return o>=0&&(t=t.slice(0,o)),t.replace(/\[([^\]]*)\]\([^)]*\)/g,"$1").replace(/(^|\s)#{1,6}\s+/g,"$1").replace(/\*\*|__|`/g,"").replace(/\s+/g," ").trim()}function ui(e,t){const o=e.map(i=>i.name!==void 0&&i.name!==""?i.name:i.team),s=o.slice(0,2).join("、"),n=o.length>2?` +${o.length-2}`:"";return(t!==void 0?`score ${t} · `:"")+`${e.length} 远端团队`+(s!==""?`:${s}${n}`:"")}function fi(e,t,o){if(e.id.startsWith("member-"))return{title:e.name!==void 0&&e.name!==""?e.name:e.team,sub:e.team,tip:e.team};if(e.remote===!0){const l=e.id.slice(5),u=t.length===1&&t[0].name!==void 0&&t[0].name!==""?t[0].name:void 0,h=ui(t,o);return u!==void 0?{title:u,sub:`${l} · ${h}`,tip:`${u}
6
+ ${l}
7
+ ${h}`}:{title:l,sub:h,tip:`${l}
8
+ ${h}`}}const s=bt(e),n=e.team+(e.name!==void 0&&e.name!==""?" · "+e.name:""),i=mi(e.description??""),r=i!==""?i:n===s?"":e.team,c=(e.memberships.length>1?` · 跨队×${e.memberships.length}`:"")+(e.teams!==void 0&&e.teams.length>0?` · 网络队×${e.teams.length}`:"");return{title:s,sub:r+c,tip:i!==""?`${n}
9
+ ${i}`:n}}function pi(e){if((e==null?void 0:e.status)===void 0)return"";const t=e.status==="running"?"工作中":"空闲";return typeof e.queued=="number"&&e.queued>0?`${t} · 排队 ${String(e.queued)}`:t}function hi(e){const t=document.createElement("div");t.className="p-node",t.dataset.id=e,t.tabIndex=0;const o=document.createElement("div");o.className="nm";const s=document.createElement("span");s.className="dot";const n=document.createElement("span");n.className="nm-text",o.append(s,n);const i=document.createElement("div");i.className="sub mono";const r=document.createElement("span");r.className="prio mono";const c=document.createElement("span");c.className="work";const l=document.createElement("div");return l.className="sub-row",l.append(i,c),t.append(o,l,r),t}function bi(e,t,o){if(t.remote===!0){const s=(o==null?void 0:o.link)==="linked"?"lnk-linked":(o==null?void 0:o.link)==="stranger"?"lnk-stranger":"";e.className!==`prio mono ${s}`.trim()&&(e.className=`prio mono ${s}`.trim());const n=o===void 0?"":o.verified===!0?"✓":"✗",i=(t.id.startsWith("member-")?"成员":(o==null?void 0:o.link)??"peer")+n;e.textContent!==i&&(e.textContent=i)}else{e.className!=="prio mono"&&(e.className="prio mono");const s=t.memberships[0]!==void 0?`P${t.memberships[0].index}`:"";e.textContent!==s&&(e.textContent=s)}}const no="dsh-a2a.board.legend";function gi(){const e=document.createElement("details");e.className="p-legend";const t=document.createElement("summary");t.textContent="图例",t.title="边的含义(点击展开 / 收起)";const o=document.createElement("div");o.className="p-legend-rows";const s=(n,i,r)=>{const c=document.createElement("span"),l=document.createElement("i");n&&(l.className="dashed"),r!==void 0&&(l.style.borderTopColor=r),c.append(l,document.createTextNode(i)),o.appendChild(c)};s(!1,"成员边(星形,框→成员)"),s(!0,"跨队多属(虚线)"),s(!0,"roster 网络队框(双线边框)"),s(!1,"活动边(inFlight 路由,瞬时)","var(--accent)"),s(!0,"联邦线(→peer)","var(--federal)"),e.append(t,o);try{e.open=window.localStorage.getItem(no)==="open"}catch{}return e.addEventListener("toggle",()=>{try{window.localStorage.setItem(no,e.open?"open":"closed")}catch{}}),e}const tn="对端未应答(显示的是最后已知状态)";function oo(e){const t=new Set;for(const s of e.remoteTeams??[])s.unreachable===!0&&s.via&&t.add(gt(s.via));for(const s of e.peerOrg??[])s.unreachable===!0&&t.add(gt(s.url));const o=new Set;for(const s of e.remoteTeams??[])s.via&&t.has(gt(s.via))&&o.add(`member-${s.team.replace(/[^a-z0-9-]/gi,"-")}`);return{hosts:t,members:o}}function vi(e,t){e.classList.toggle("is-unreachable",t);const o=e.querySelector(".p-frame-unreachable");if(t&&o===null){const s=document.createElement("span");s.className="p-frame-unreachable",s.textContent=tn,e.appendChild(s)}else t||o==null||o.remove()}function yi(e){return e<680?"narrow":e<1024?"medium":"wide"}function wi(e){const t=new Sn;let o,s={...t.viewport},n={kind:"none"},i=!1,r=-1,c=!0,l=!1;const u=li(t);let h,m=!1;const C=()=>yi(globalThis.innerWidth||tt),N=()=>{var a;(a=e.viewportStore)==null||a.set(C(),s),e.onDirty()},J=e.now??Date.now,ne=new AbortController,G=[];let $=null,E=!1;const S={signal:ne.signal},w=document.createElement("section");w.id="dsh-plan",w.setAttribute("role","tabpanel"),w.setAttribute("aria-label","A2A 规划画布"),w.tabIndex=0,w.style.display="none";const oe=document.createElement("div");oe.className="p-grid";const y=document.createElement("div");y.className="p-world";const b=document.createElementNS("http://www.w3.org/2000/svg","svg");b.setAttribute("class","p-edges");const M=document.createElement("div");M.className="p-layer p-frames";let f;const D=a=>{var p,g;f!==void 0&&((p=Ye.get(f))==null||p.classList.remove("selected")),f=a,a!==void 0&&((g=Ye.get(a))==null||g.classList.add("selected"))},K=document.createElement("div");K.className="p-layer p-nodes",K.setAttribute("role","listbox"),K.setAttribute("aria-multiselectable","true"),K.setAttribute("aria-label","会话节点"),y.append(b,M,K);const X=document.createElement("div");X.className="p-marquee";const ye=document.createElement("div");ye.className="p-toolbar";const Se=document.createElement("span");Se.className="p-zoom mono",Se.textContent="100%";const R=(a,p,g)=>{const O=document.createElement("button");return O.type="button",O.textContent=a,O.title=p,O.addEventListener("click",g,S),O},q=()=>{const a=document.createElement("span");return a.className="p-sep",a.setAttribute("role","separator"),a.setAttribute("aria-orientation","vertical"),a};ye.append(R("适配","适配视图(快捷键 0)",()=>Ce()),R("-","缩小",()=>H(1/1.2)),Se,R("+","放大",()=>H(1.2)),q(),R("建队","组成团队(G):先框选至少 2 个节点",()=>T.startCreateFromSelection()),R("整理成员","每队框内仅属一队的成员自动排齐(多队成员不动)",()=>Nt()),R("一键重排","全板队框+成员重排:框尺寸随内容自适应、框位行流式平铺(远端队框与多归属成员不动)",()=>Ot()),R("撤销","撤销上一次布局改动:拖动、缩放、整理、重排、载入时避让(Ctrl+Z;入队离队不撤销)",()=>re()));const le=R("未入网","未入网会话(点击选择入网)",()=>T.toggleNetMenu());le.className="p-netbtn",le.setAttribute("aria-haspopup","menu"),ye.append(q(),le);const Ke=Ks(ye,t,bt,a=>me(a)),Me=R("节点","节点清单:本机与对等节点(未组队/未入网在此管理)",()=>se.toggle());Me.className="p-nodebtn",Me.setAttribute("aria-haspopup","dialog"),ye.appendChild(Me);const de=document.createElement("span");de.setAttribute("aria-live","polite"),de.className="p-lamp";const Ue=document.createElement("i"),ue=document.createElement("span");ue.textContent="布局",de.append(Ue,ue),de.addEventListener("click",()=>{de.classList.contains("error")&&e.onLampClick()},S),de.addEventListener("keydown",a=>{const p=a;(p.key==="Enter"||p.key===" ")&&de.classList.contains("error")&&(p.preventDefault(),e.onLampClick())},S),ye.appendChild(de);const V=document.createElement("div");V.className="p-status";const ce=document.createElement("span"),ie=document.createElement("span"),ee=document.createElement("span");ee.className="mut";const ke=document.createElement("span");ke.className="mut",V.append(ce,ie,ee,ke),V.tabIndex=0,V.setAttribute("role","button"),V.setAttribute("aria-label","定位在途路由与联邦对端"),V.title="定位在途与联邦(回车)",V.addEventListener("click",()=>we(),S),V.addEventListener("keydown",a=>{const p=a;(p.key==="Enter"||p.key===" ")&&(p.preventDefault(),we())},S);const et=gi(),Oe=document.createElement("div");Oe.className="p-notice-stack",Oe.setAttribute("role","log"),Oe.setAttribute("aria-live","polite"),w.append(oe,y,X,ye,V,et,Oe);let tt=0,st=0;const St=()=>e.viewSize?e.viewSize():{w:w.clientWidth,h:w.clientHeight},Ze=()=>{const a=St();tt=a.w,st=a.h};function Ve(){y.style.transform=Os(s);const a=24*s.scale;oe.style.backgroundSize=`${a}px ${a}px`,oe.style.backgroundPosition=`${-s.x*s.scale}px ${-s.y*s.scale}px`,Se.textContent=`${Math.round(s.scale*100)}%`}function Nt(){const a=u.capture();ai(t),Gt(t,new Set(nt.keys())),u.commit(a),N(),Re()}function Ot(){const a=u.capture();Gs(t,new Set(nt.keys()))&&(Gt(t,new Set(nt.keys())),u.commit(a),N(),Re())}function Re(){Ve(),t.revision!==r&&(r=t.revision,ft(),wt(),hs(b,t)),pe()}const Ye=new Map,Ge=new Map;function ft(){var p;const a=new Set;for(const[g,O]of t.allFrames()){a.add(g);let P=Ye.get(g);if(P===void 0){P=document.createElement("div"),P.className="p-frame",P.dataset.name=g;const te=document.createElement("div");te.className="p-frame-head",te.dataset.frame=g,te.tabIndex=0,te.setAttribute("role","button"),te.setAttribute("aria-haspopup","menu"),te.setAttribute("aria-label",`团队框 ${g}(拖动整组,回车菜单)`);const He=document.createElement("span");He.className="ttl";const Qe=document.createElement("span");Qe.className="cnt mono";const lt=document.createElement("span");lt.className="route mono",te.append(He,Qe,lt),P.appendChild(te);for(const dt of["n","s","e","w","ne","nw","se","sw"]){const At=document.createElement("div");At.className=`p-frame-handle p-h-${dt}`,At.dataset.frame=g,At.dataset.dir=dt,P.appendChild(At)}M.appendChild(P),Ye.set(g,P)}const fe=Rs(g);P.style.setProperty("--frame-line",fe.line),P.style.setProperty("--frame-bg",fe.bg),P.style.left=`${O.x}px`,P.style.top=`${O.y}px`,P.style.width=`${O.w}px`,P.style.height=`${O.h}px`;const W=P.querySelector(".ttl"),B=P.querySelector(".cnt"),z=P.querySelector(".route"),ae=pt.has(g),Te=ae?rn(g):g;W.textContent!==Te&&(W.textContent=Te),P.classList.toggle("is-roster",ae);let _e=0,Ae=0;for(const te of t.allNodes())te.memberships.find(Qe=>Qe.team===g)!==void 0&&(_e+=1,te.memberships.length>1&&(Ae+=1));const qe=`${_e} 成员`+(Ae>0?` +${Ae} 跨队`:"");B.textContent!==qe&&(B.textContent=qe);const v=Qs(nt.get(g),Pe.has(g)),ve=v!==void 0&&k.hosts.has(gt(nt.get(g))),be=(v==null?void 0:v.text)??((p=ct.find(te=>te.name===g))==null?void 0:p.team)??g;z.textContent!==be&&(z.textContent=be),z.title=`${(v==null?void 0:v.title)??""}${ve?` · ${tn}`:""}`,vi(P,ve),P.classList.toggle("is-mirror",v!==void 0),P.classList.toggle("is-syncing",(v==null?void 0:v.syncing)===!0);const We=`团队框 ${g}${v!==void 0?`(${v.text})`:""}${ve?`(${tn})`:""}(拖动整组,回车菜单)`,Le=P.querySelector(".p-frame-head");Le.getAttribute("aria-label")!==We&&Le.setAttribute("aria-label",We)}for(const[g,O]of[...Ye])a.has(g)||(O.remove(),Ye.delete(g))}function wt(){const a=new Set;for(const p of t.allNodes()){a.add(p.id);let g=Ge.get(p.id);g===void 0&&(g=hi(p.id),K.appendChild(g),Ge.set(p.id,g));const O=vt(p);g.style.left=`${O.x}px`,g.style.top=`${O.y}px`,g.classList.toggle("cold",!p.live),g.classList.toggle("remote",p.remote===!0);const P=p.live&&p.remote!==!0?I.get(p.id):void 0;g.classList.toggle("is-working",(P==null?void 0:P.status)==="running");const fe=pi(P),W=g.querySelector(".work");W.textContent!==fe&&(W.textContent=fe),g.classList.toggle("selected",t.isSelected(p.id)),g.setAttribute("aria-selected",String(t.isSelected(p.id)));const B=p.id.slice(5),z=fi(p,p.remote===!0?_.get(B)??[]:[],Z.get(B)),ae=p.remote===!0&&(p.id.startsWith("member-")?k.members.has(p.id):k.hosts.has(B));g.classList.toggle("is-unreachable",ae);const Te=g.querySelector(".nm-text");Te.textContent!==z.title&&(Te.textContent=z.title);const _e=g.querySelector(".sub"),Ae=ae?`未应答 · ${z.sub}`:z.sub;_e.textContent!==Ae&&(_e.textContent=Ae);const qe=ae?`${z.tip} · ${tn}`:z.tip;g.title!==qe&&(g.title=qe);const v=p.id.startsWith("member-")?he.get(p.remoteHandle??""):B;bi(g.querySelector(".prio"),p,p.remote===!0&&v!==void 0?Y.get(v):void 0)}for(const[p,g]of[...Ge])a.has(p)||(g.remove(),Ge.delete(p));Ke.refresh()}const d=Ms(b,t);let _=new Map,I=new Map;const Z=new Map,Y=new Map;let he=new Map;function pe(){d.render(J())}function we(){s=An(Ns(t.contentBounds(),d.placements()),w.clientWidth||tt,w.clientHeight||st),Ve(),N()}const me=Ws({model:t,viewSize:St,setVp:a=>{s=a},applyViewport:Ve,markDirty:N,cardEl:a=>Ge.get(a)});function Fe(a){var O;const p=a.sessions.filter(P=>P.live!==!1).length,g=(P,fe,W)=>{const B=document.createElement("b");B.className=fe,B.textContent=W,P.replaceChildren(B)};g(ce,"ok",`● ${p} live`),g(ie,"warn",`● ${a.sessions.length-p} cold`),ee.textContent=`${((O=a.inFlight)==null?void 0:O.length)??0} inFlight`,ke.className="mut",ke.textContent=`${a.teams.length} 队 · ${a.peerCount} peer`}const Pe=new Map,Je=a=>{Pe.set(a,(Pe.get(a)??0)+1),r=-1},Wt=a=>{r=-1;const p=(Pe.get(a)??0)-1;p<=0?Pe.delete(a):Pe.set(a,p)};let nt=new Map,pt=new Set,k=oo({});const x=ei(e.now);function F(a){const p=a.type==="create-team"&&a.roster===!0||pt.has(Yt(a));if(p&&a.type==="remove-team"&&!window.confirm(`解散网络队「${rn(a.name)}」并撤回成员与白名单?`))return;if(p&&a.type==="reorder"){A("error","roster 队不支持置顶路由");return}if(p&&(a.type==="create-team"||a.type==="add-member")&&a.ids.some(W=>{var B;return((B=t.getNode(W))==null?void 0:B.remote)===!0||!j.some(z=>z.id===W&&z.joined===!0)})){A("error","roster 只接受本机已入网会话,远端或未入网成员未写入");return}function g(W){const B=z=>{var Te;const ae=[];for(const _e of z){if(!_e.startsWith("peer-")&&!_e.startsWith("member-")){ae.push(_e);continue}const Ae=(Te=t.getNode(_e))==null?void 0:Te.remoteHandle;Ae!==void 0&&Ae!==""&&ae.push(Ae)}return ae};if(W.type==="add-member"||W.type==="remove-member"||W.type==="create-team"){const z=B(W.ids),ae=W.type!=="create-team"?nt.get(W.team):void 0;return z.length>0||ae!==void 0?{...W,ids:z,...ae!==void 0?{fleetPeer:ae}:{}}:W}return W.type==="remove-team"&&nt.has(W.name)?x.fork(W,nt.get(W.name)):W}if(a.type==="add-member"||a.type==="remove-member"||a.type==="reorder"||a.type==="create-team"){const W=a.type==="reorder"?a.ops.map(B=>B.id):[...a.ids];for(const B of W){if(B===""||B.startsWith("peer-")||B.startsWith("member-")||t.getNode(B)!==void 0)continue;const z=j.find(_e=>_e.id===B);if(z===void 0)continue;const ae=o==null?void 0:o.nodes[B],Te=ae!==void 0?{x:ae.x,y:ae.y}:Ln(B);t.upsertNode({id:B,x:Te.x,y:Te.y,label:z.label,team:z.team,name:z.name,description:z.description,live:z.live!==!1,memberships:[],...z.teams!==void 0&&z.teams.length>0?{teams:z.teams}:{}})}}p&&a.type==="create-team"&&pt.add(a.name);const O=Fs(t,a),P=Yt(a);Je(P),Re();const fe=g(p?{...a,roster:!0}:a);e.onCanvasAction(fe).then(W=>{Wt(P),!W&&a.type==="create-team"&&p&&pt.delete(P),o=Gn(t,a,W,O,o),N(),x.settled(fe,W),Re()},()=>{Wt(P),a.type==="create-team"&&p&&pt.delete(P),o=Gn(t,a,!1,O,o),N(),x.settled(fe,!1),A("error","操作通道异常,已回滚"),Re()})}function A(a,p){var O;for(;Oe.childElementCount>=3;)(O=Oe.firstElementChild)==null||O.remove();const g=document.createElement("div");g.className="p-notice"+(a==="error"?" error":""),g.setAttribute("role",a==="error"?"alert":"status"),g.textContent=p,Oe.appendChild(g),G.push(setTimeout(()=>g.remove(),4e3))}const T=Hs({root:w,netBtn:le,signal:S,model:t,teams:()=>ct,joined:a=>j.some(p=>p.id===a&&p.joined===!0),isRoster:a=>pt.has(a),anchorFor:a=>(a.kind==="node"?Ge.get(a.id):Ye.get(a.name))??null,emit:F,notice:A});let j=[],Q=new Set;const se=di({root:w,trigger:Me,signal:S,model:t,facts:()=>({sessions:j,canvasMemberIds:Q,remoteTeams:_,teams:ct}),menuItem:T.menuItem,emit:F,openNameDialog:T.openNameDialog,locate:U});zo(w,{signal:S,frames:()=>Ye,frameAt:(a,p)=>{const g=ge({clientX:a,clientY:p});return zt(new Map(t.allFrames()),ht(s,g.x,g.y))},drop:(a,p)=>{var g;return((g=t.getNode(p))==null?void 0:g.memberships.some(O=>O.team===a))===!0?A("info","该会话已在这个队里"):F({type:"add-member",team:a,ids:[p]})}});function U(a){var O;const p=t.getNode(a);if(p===void 0)return;se.close();const g=((O=e.viewSize)==null?void 0:O.call(e))??{w:w.clientWidth>0?w.clientWidth:800,h:w.clientHeight>0?w.clientHeight:600};s=It({scale:s.scale,x:p.x-g.w/(2*s.scale),y:p.y-g.h/(2*s.scale)}),Ve(),r=-1,Re()}function ge(a){const p=w.getBoundingClientRect();return{x:a.clientX-p.left,y:a.clientY-p.top}}function De(a,p){var W;const g=ge(p),O=ht(s,g.x,g.y),P=zt(new Map(t.allFrames()),O),fe=a.ids.filter(B=>{const z=t.getNode(B);return z===void 0?!1:z.remote!==!0?!0:z.remoteHandle!==void 0&&z.remoteHandle!==""});if(P!==void 0){const B=fe.filter(z=>{var ae;return!((ae=t.getNode(z))!=null&&ae.memberships.some(Te=>Te.team===P))});if(B.length>0){F({type:"add-member",team:P,ids:B});return}if(a.ids.length===1&&((W=t.getNode(a.clicked))==null?void 0:W.remote)!==!0){const z=t.teamMemberIds(P),ae=Ps(t,P);ae.join("\0")!==z.join("\0")&&F({type:"reorder",team:P,ops:xn(z,ae)})}}if(a.rosterOrigin!==void 0&&P!==a.rosterOrigin){const B=a.ids.filter(z=>t.teamMemberIds(a.rosterOrigin).includes(z));B.length>0&&F({type:"remove-member",team:a.rosterOrigin,ids:B})}}function Ie(a){if(tt===0&&Ze(),T.isDialogOpen()){a.preventDefault();return}const p=a.target;if(T.isMenuOpen()){if(p!==null&&p.closest(".p-menu")!==null)return;T.closeMenu(),a.preventDefault();return}if(p!==null&&p.closest("button, input, textarea, select, .p-toolbar, .p-search, .p-lamp, .p-status, .p-legend")!==null)return;h=u.capture();const g=ge(a);if(a.button===2){$={x:g.x,y:g.y,target:a.target,moved:!1},a.preventDefault();try{w.setPointerCapture(a.pointerId??0)}catch{}return}const O=p!==null?p.closest(".p-node"):null,P=p!==null?p.closest(".p-frame-head"):null;if((O!==null||P!==null)&&a.button===1){n={kind:"pan",last:g,moved:!1},a.preventDefault();try{w.setPointerCapture(a.pointerId??0)}catch{}return}const fe=p!==null?p.closest(".p-frame-handle"):null;if(f!==void 0){const W=Ye.get(f),B=p!==null&&W!==void 0&&(W.contains(p)||W===p),z=P!==null&&P.dataset.frame===f;!B&&!z&&D(void 0)}if(fe!==null&&a.button===0){const W=fe.dataset.frame??"";D(W);const B=t.getFrame(W);if(B===void 0)return;n={kind:"frame-resize",name:W,dir:fe.dataset.dir??"se",startRect:{...B},origin:ht(s,g.x,g.y),moved:!1},a.preventDefault();try{w.setPointerCapture(a.pointerId??0)}catch{}return}if(O!==null){if(a.button!==0)return;const W=O.dataset.id??"",B=t.isSelected(W);!B&&!a.shiftKey&&t.setSelection([W]);const z=a.shiftKey||B?t.isSelected(W)?t.selectedIds():[...t.selectedIds(),W]:[W],ae=zt(new Map(t.allFrames()),ht(s,g.x,g.y));n={kind:"node",clicked:W,ids:z,...ae&&pt.has(ae)&&t.teamMemberIds(ae).includes(W)?{rosterOrigin:ae}:{},last:ht(s,g.x,g.y),moved:!1,el:O},O.classList.add("dragging")}else if(P!==null){if(a.button!==0)return;const W=P.dataset.frame??"";D(W);const B=t.beginFrameDrag(W);if(B===void 0)return;n={kind:"frame",name:W,snap:B,origin:ht(s,g.x,g.y),moved:!1}}else if(a.button===1||a.button===0&&i)n={kind:"pan",last:g,moved:!1};else if(a.button===0)n={kind:"marquee",origin:g,last:g,additive:a.shiftKey},X.style.display="block",X.style.left=`${g.x}px`,X.style.top=`${g.y}px`,X.style.width="0px",X.style.height="0px";else return;a.preventDefault();try{w.setPointerCapture(a.pointerId??0)}catch{}}function ot(a){const p=ge(a);if($!==null){const g=p.x-$.x,O=p.y-$.y;Math.hypot(g,O)>4&&($.moved=!0,s=It(hn(s,-g,-O)),$.x=p.x,$.y=p.y,Ve());return}if(n.kind==="node"){const g=ht(s,p.x,p.y),O=g.x-n.last.x,P=g.y-n.last.y;if(O===0&&P===0)return;n.moved=!0,n.last=g,t.dragNodes(n.ids,O,P);const fe=zt(new Map(t.allFrames()),g),W=n.ids.filter(z=>{const ae=t.getNode(z);return ae===void 0?!1:ae.remote!==!0||ae.remoteHandle!==void 0&&ae.remoteHandle!==""}),B=fe!==void 0&&W.length>0;for(const[z,ae]of Ye)ae.classList.toggle("drop-target",B&&z===fe);Re()}else if(n.kind==="frame"){const g=ht(s,p.x,p.y),O=g.x-n.origin.x,P=g.y-n.origin.y;if(!n.moved&&O===0&&P===0)return;n.moved=!0,t.applyFrameDrag(n.snap,O,P),Re()}else if(n.kind==="frame-resize"){const g=ht(s,p.x,p.y),O=g.x-n.origin.x,P=g.y-n.origin.y;if(!n.moved&&O===0&&P===0)return;n.moved=!0;const fe=220,W=120,B={...n.startRect};let{x:z,y:ae,w:Te,h:_e}=B;n.dir.includes("e")&&(Te=Math.max(fe,B.w+O)),n.dir.includes("s")&&(_e=Math.max(W,B.h+P)),n.dir.includes("w")&&(Te=Math.max(fe,B.w-O),z=B.x+(B.w-Te)),n.dir.includes("n")&&(_e=Math.max(W,B.h-P),ae=B.y+(B.h-_e)),t.setFrame(n.name,{x:Math.round(z),y:Math.round(ae),w:Math.round(Te),h:Math.round(_e)}),Re()}else if(n.kind==="pan")s=hn(s,p.x-n.last.x,p.y-n.last.y),n.last=p,n.moved=!0,Ve();else if(n.kind==="marquee"){const g=Math.min(n.origin.x,p.x),O=Math.min(n.origin.y,p.y);X.style.left=`${g}px`,X.style.top=`${O}px`,X.style.width=`${Math.abs(p.x-n.origin.x)}px`,X.style.height=`${Math.abs(p.y-n.origin.y)}px`,n.last=p}}function xt(a){var p,g;if($!==null){const O=$.moved,P=$.target,fe=$.x,W=$.y;$=null,O?(E=!0,N()):P!==null&&T.contextMenuAt(fe,W,P);return}if(n.kind==="node"){const O=n.clicked;if(n.moved)De(n,a),N();else if(a.shiftKey){const P=t.selectedIds();t.setSelection(P.includes(O)?P.filter(fe=>fe!==O):[...P,O])}else t.setSelection([O]),(p=e.onNodePick)==null||p.call(e,O);for(const P of Ye.values())P.classList.remove("drop-target");(g=n.el)==null||g.classList.remove("dragging"),Re()}else if(n.kind==="frame"||n.kind==="frame-resize")n.moved&&(Gt(t,new Set(nt.keys()),n.name),N(),Re());else if(n.kind==="pan")n.moved&&N();else if(n.kind==="marquee"){const O=n.last,P=ht(s,Math.min(n.origin.x,O.x),Math.min(n.origin.y,O.y)),fe=ht(s,Math.max(n.origin.x,O.x),Math.max(n.origin.y,O.y));t.marqueeSelect({x:P.x,y:P.y,w:fe.x-P.x,h:fe.y-P.y},n.additive),X.style.display="none",Re()}n={kind:"none"},h!==void 0&&(u.commit(h),h=void 0);try{w.releasePointerCapture(a.pointerId??0)}catch{}}function yt(a){var g;for(const O of Ye.values())O.classList.remove("drop-target");n.kind==="node"&&((g=n.el)==null||g.classList.remove("dragging"));const p=n.kind==="pan"&&n.moved||($==null?void 0:$.moved)===!0;X.style.display="none",$=null,n={kind:"none"},h!==void 0&&u.revert(h)&&Re(),p&&N(),h=void 0;try{w.releasePointerCapture(a.pointerId??0)}catch{}}function Ct(a){T.isMenuOpen()&&T.closeMenu();const p=ge(a);if(a.shiftKey&&!a.ctrlKey){const g=a.deltaMode===1?16:1;s=It(hn(s,(a.deltaX??0)*g,(a.deltaY??0)*g))}else{const g=a.deltaMode===1?16:1,O=Math.exp(-((a.deltaY??0)*g)*.0015);s=Un(s,O,p.x,p.y)}a.preventDefault(),Ve(),N()}function H(a){Ze(),s=Un(s,a,tt/2,st/2),Ve(),N()}function re(){u.undo()?(N(),Re()):A("info","没有可撤销的布局改动")}function Ce(){Ze(),s=zn(qn(t.contentBounds(),t.allNodes()),tt,st,Vn(ye,V)),Ve(),N()}function Ne(a){var fe,W,B,z,ae,Te,_e;if(T.isDialogOpen()||((W=(fe=a.target)==null?void 0:fe.closest)==null?void 0:W.call(fe,".p-search"))!==null)return;if((a.ctrlKey||a.metaKey)&&a.key.toLowerCase()==="k"){a.preventDefault(),Ke.focus();return}if((a.ctrlKey||a.metaKey)&&!a.shiftKey&&a.key.toLowerCase()==="z"){a.preventDefault(),re();return}if(a.ctrlKey||a.metaKey)return;if(T.isMenuOpen()){a.key==="Escape"&&(T.closeMenu(),a.preventDefault());return}if(a.key===" "&&a.target===w){i=!0,a.preventDefault();return}const p=((z=(B=a.target)==null?void 0:B.closest)==null?void 0:z.call(B,".p-frame-head"))??null;if((a.key==="Enter"||a.key===" ")&&p!==null){a.preventDefault();const Ae=p.getBoundingClientRect();T.contextMenuAt(Ae.left+Ae.width/2,Ae.top+Ae.height/2,p);return}if(a.key===" "&&((Te=(ae=a.target)==null?void 0:ae.classList)!=null&&Te.contains("p-node"))){const qe=a.target.dataset.id??"",v=t.selectedIds();t.setSelection(v.includes(qe)?v.filter(ve=>ve!==qe):[...v,qe]),Re(),a.preventDefault();return}if(a.key==="F10"&&a.shiftKey||a.key==="ContextMenu"){a.preventDefault();const Ae=document.activeElement??null,qe=((_e=Ae==null?void 0:Ae.getBoundingClientRect)==null?void 0:_e.call(Ae))??{left:0,top:0,width:0,height:0};T.contextMenuAt(qe.left+qe.width/2,qe.top+qe.height/2,Ae);return}if(a.key==="Delete"||a.key==="Backspace"){a.preventDefault(),it();return}if(a.altKey&&(a.key==="ArrowUp"||a.key==="ArrowDown")){a.preventDefault(),je(a.key==="ArrowUp");return}if(a.key==="g"||a.key==="G"){T.startCreateFromSelection();return}if(a.key==="0"){Ce();return}if(a.key==="="||a.key==="+"){H(1.2);return}if(a.key==="-"){H(1/1.2);return}if(a.key==="Escape"){if(T.isMenuOpen()){T.closeMenu(),Re();return}t.setSelection([]),Re();return}const g=a.shiftKey?40:8,P={ArrowLeft:[-g,0],ArrowRight:[g,0],ArrowUp:[0,-g],ArrowDown:[0,g]}[a.key];if(P!==void 0){a.preventDefault();const Ae=t.selectedIds();if(Ae.length>0){const qe=u.capture();t.nudge(Ae,P[0],P[1]),u.commit(qe),Re(),N()}}}function it(){var O,P,fe;const a=document.activeElement,p=((O=a==null?void 0:a.closest)==null?void 0:O.call(a,".p-frame-head"))??null,g=((P=a==null?void 0:a.closest)==null?void 0:P.call(a,".p-node"))??null;if(p!==null){F({type:"remove-team",name:p.dataset.frame??""});return}if(g!==null){const W=g.dataset.id??"",B=((fe=t.getNode(W))==null?void 0:fe.memberships.map(z=>z.team))??[];if(B.length===0){A("info","该节点未加入任何团队");return}if(B.length===1){F({type:"remove-member",team:B[0],ids:[W]});return}T.openMenu(window.innerWidth/2,window.innerHeight/2,{kind:"node",id:W},"leave",g);return}A("info","焦点不在节点或团队框上")}function je(a){var Te,_e;const p=document.activeElement,g=((Te=p==null?void 0:p.closest)==null?void 0:Te.call(p,".p-node"))??null;if(g===null)return;const O=g.dataset.id??"",P=((_e=t.getNode(O))==null?void 0:_e.memberships)??[];if(P.length!==1)return;const fe=P[0].team,W=t.teamMemberIds(fe),B=W.indexOf(O),z=a?Math.max(0,B-1):Math.min(W.length-1,B+1);if(z===B)return;const ae=[...W];ae.splice(B,1),ae.splice(z,0,O),F({type:"reorder",team:fe,ops:xn(W,ae)})}function Ee(a){a.key===" "&&(i=!1)}w.addEventListener("pointerdown",a=>Ie(a),S),w.addEventListener("pointermove",a=>ot(a),S),w.addEventListener("pointerup",a=>xt(a),S),w.addEventListener("pointercancel",a=>yt(a),S),w.addEventListener("wheel",a=>Ct(a),{...S,passive:!1}),w.addEventListener("keydown",a=>Ne(a),S),w.addEventListener("keyup",a=>Ee(a),S),w.addEventListener("contextmenu",a=>{var g,O;const p=a;if(((O=(g=p.target)==null?void 0:g.closest)==null?void 0:O.call(g,"input, textarea, .p-search"))==null){if(p.preventDefault(),E){E=!1;return}T.contextMenuAt(p.clientX,p.clientY,p.target)}},S);let ct=[];function Ft(a){var qe;ct=a.teams,pt=new Set([...a.teams.filter(v=>v.kind==="roster").map(v=>v.name),...[...pt].filter(v=>Pe.has(v))]),a.peers,d.setInFlight(a.inFlight??[]),j=a.sessions,T.setUnjoined(a.sessions.filter(v=>v.joined!==!0&&!v.id.startsWith("peer-")));const p=As(a.teams);Q=new Set(p.keys());const g=new Set,O=v=>{const ve=p.get(v)??[];if(Pe.size===0)return ve;const be=ve.filter(Le=>!Pe.has(Le.team)),We=[];for(const[Le]of Pe){const He=t.teamMemberIds(Le).indexOf(v);He>=0&&We.push({team:Le,index:He})}return[...be,...We]};let P;if(o===void 0&&!t.allNodes().some(v=>v.remote!==!0)){const v=a.sessions.filter(ve=>{var be;return ve.joined===!0&&(O(ve.id).length>0||(((be=ve.teams)==null?void 0:be.length)??0)>0)}).map(ve=>ve.id);Ze(),P=ms(a.teams,v,tt>0?tt:void 0)}const fe=a.peerOrg!==void 0?Ls(a.peerOrg,a.sessions,a.remoteTeams):new Set;a.peerOrg!==void 0&&(Q=new Set([...Q,...fe]));for(const v of a.sessions){if(v.joined!==!0)continue;const ve=O(v.id);if(!(ve.length===0&&(v.teams===void 0||v.teams.length===0)&&!fe.has(v.id)))if(g.add(v.id),t.getNode(v.id)!==void 0)t.upsertNode({id:v.id,x:t.getNode(v.id).x,y:t.getNode(v.id).y,label:v.label,team:v.team,name:v.name,description:v.description,live:v.live!==!1,memberships:ve,...v.teams!==void 0&&v.teams.length>0?{teams:v.teams}:{}});else{const be=o==null?void 0:o.nodes[v.id];let We,Le;if(be!==void 0)We=be.x,Le=be.y;else{const te=(P==null?void 0:P.get(v.id))??Ln(v.id);We=te.x,Le=te.y}t.upsertNode({id:v.id,x:We,y:Le,label:v.label,team:v.team,name:v.name,description:v.description,live:v.live!==!1,memberships:ve,...v.teams!==void 0&&v.teams.length>0?{teams:v.teams}:{}})}}for(const v of t.nodeIds())!g.has(v)&&!v.startsWith("peer-")&&!v.startsWith("member-")&&t.removeNode(v);const W=new Set;_=gs(a.remoteTeams??[]),he=new Map([..._].flatMap(([v,ve])=>ve.map(be=>[be.team,v]))),I=new Map(a.sessions.map(v=>[v.id,{status:v.status,queued:v.queued}])),k=oo(a),Z.clear();for(const v of a.peers??[])Z.set(gt(v.url),v.score),Y.set(gt(v.url),{link:v.link,verified:v.verified});if(a.peers!==void 0){const v=t.contentBounds(),ve=Cs(a.peers,v);a.peers.forEach((be,We)=>{var In,Tn,_n;const Le=bs(be.url);W.add(Le);const te=o==null?void 0:o.nodes[Le],He=t.getNode(Le),Qe=He!==void 0?{x:He.x,y:He.y}:te!==void 0?{x:te.x,y:te.y}:{x:((In=ve[We])==null?void 0:In.x)??200,y:((Tn=ve[We])==null?void 0:Tn.y)??0},lt=gt(be.url),dt=(_n=_.get(lt))==null?void 0:_n.find(Io=>Io.team.includes("/")),At=(dt==null?void 0:dt.memberRef)??(dt==null?void 0:dt.team);t.upsertNode({id:Le,x:Qe.x,y:Qe.y,label:be.url,team:"",name:be.url,peerUrl:be.url,remoteHandle:At,live:!0,remote:!0,memberships:[]}),t.upsertScore(Le,be.score)})}for(const v of t.nodeIds())v.startsWith("peer-")&&!W.has(v)&&t.removeNode(v);const B=new Set;for(const[v,ve]of _){const be=t.allNodes().find(te=>te.remote===!0&&gt(te.peerUrl??"")===v&&!te.id.startsWith("member-")),We=((be==null?void 0:be.x)??400)+190;let Le=(be==null?void 0:be.y)??0;for(const te of ve){if(!te.team.includes("/"))continue;const He=`member-${(te.memberRef??te.team).replace(/[^a-z0-9-]/gi,"-")}`;if(B.has(He))continue;B.add(He);const Qe=o==null?void 0:o.nodes[He],lt=t.getNode(He),dt=lt!==void 0?{x:lt.x,y:lt.y}:Qe!==void 0?{x:Qe.x,y:Qe.y}:{x:We,y:Le};Le+=92,t.upsertNode({id:He,x:dt.x,y:dt.y,label:te.team,team:te.team,name:te.name!==void 0&&te.name!==""?te.name:te.team,remoteHandle:te.memberRef??te.team,live:!0,remote:!0,memberships:[]})}}for(const v of t.nodeIds())v.startsWith("member-")&&!B.has(v)&&t.removeNode(v);const z=new Map;for(const v of t.allNodes())v.remote!==!0||v.remoteHandle===void 0||v.remoteHandle===""||(!z.has(v.remoteHandle)||v.id.startsWith("member-"))&&z.set(v.remoteHandle,v.id);for(const v of a.teams){if(Pe.has(v.name))continue;const ve=[];for(const Le of v.members){const te=z.get(Le.id)??Le.id;t.getNode(te)!==void 0&&ve.push(te)}const be=[...t.teamMemberIds(v.name)].sort().join("|"),We=[...ve].sort().join("|");be!==We&&t.setTeamMembers(v.name,ve)}const ae=new Map,Te=nt;if(nt=ae,a.peerOrg!==void 0){let v=0;const ve=new Set(a.teams.map(be=>be.name));x.sweep(a.peerOrg);for(const be of a.peerOrg){const We=new Set((a.remoteTeams??[]).map(te=>te.team)),Le=Co(a.sessions,We);for(const te of be.org){if(te.name===""||ve.has(te.name)||x.hides(te.name,be.url))continue;const He=te.members.map(lt=>Ss(lt,Le,a.remoteTeams,be.url)).filter(lt=>t.getNode(lt)!==void 0),Qe=(qe=o==null?void 0:o.frames)==null?void 0:qe[te.name];t.getFrame(te.name)===void 0&&t.setFrame(te.name,Qe!==void 0?{x:Qe.x,y:Qe.y,w:Qe.w,h:Qe.h}:{x:200+v%4*280,y:940+Math.floor(v/4)*160,w:250,h:130}),t.setTeamMembers(te.name,He),ae.set(te.name,be.url),v+=1}}}for(const[v,ve]of Te)ae.has(v)||t.removeFrame(v);const _e=new Map;for(const v of t.allNodes())v.remote===!0&&v.remoteHandle!==void 0&&v.remoteHandle!==""&&_e.set(v.remoteHandle,v.id);const Ae=yo(a.teams);for(const v of a.teams){if(t.getFrame(v.name)!==void 0||Pe.has(v.name))continue;const ve=o==null?void 0:o.frames[v.name];if(ve!==void 0){t.setFrame(v.name,{...ve});continue}const be=[],We=[];for(const te of v.members){const He=t.getNode(_e.get(te.id)??te.id);He!==void 0&&(We.push(vt(He)),Ae.get(He.id)===v.name&&be.push(vt(He)))}const Le=be.length>0?be:We;Le.length>0&&t.setFrame(v.name,Mn(Le))}for(const[v]of t.allFrames())Pe.has(v)||!a.teams.some(ve=>ve.name===v)&&!ae.has(v)&&t.removeFrame(v);if(se.refresh(),Fe(a),!l&&n.kind==="none"&&t.nodeIds().length>0){l=!0;const v=u.capture();Gt(t,new Set(nt.keys())),u.commit(v)}c&&n.kind==="none"&&t.nodeIds().length>0&&(Ze(),tt>0&&st>0&&(c=!1,s=zn(qn(t.contentBounds(),t.allNodes()),tt,st,Vn(ye,V)))),Re()}function Ln(a){return wo(a,t.allNodes().filter(p=>p.remote!==!0))}function No(a){const p=go(a);if(p===void 0)return;o=p;const g=e.viewportStore;if(g===void 0)c=!1,n.kind==="none"&&(s=It({...p.viewport}));else if(!m&&n.kind==="none"){m=!0;const O=g.get(C());O!=null&&Number.isFinite(O.x)&&Number.isFinite(O.y)&&Number.isFinite(O.scale)?(s=It({x:O.x,y:O.y,scale:O.scale}),c=!1):C()==="wide"&&(s=It({...p.viewport}),c=!1)}r=-1,Re()}function $o(){return as(s,t.positions(),t.frameRects())}function Mo(a,p){de.classList.remove("pending","saved","error"),a==="pending"&&de.classList.add("pending"),a==="saved"&&de.classList.add("saved"),a==="error"&&de.classList.add("error"),a==="error"?(de.tabIndex=0,de.setAttribute("role","button"),de.setAttribute("aria-label","布局保存失败,按回车重试")):(de.removeAttribute("tabindex"),de.removeAttribute("role"),de.removeAttribute("aria-label"));const g=a==="pending"?"布局待保存…":a==="saved"?`布局已保存 ${p??""}`.trimEnd():a==="error"?"保存失败 · 回车重试":"布局";ue.textContent=g}function So(){w.style.display="block",Ze(),Ve(),w.focus()}function Ao(){w.style.display="none"}function Lo(){ne.abort();for(const a of G)clearTimeout(a)}return{root:w,reconcile:Ft,activate:So,deactivate:Ao,adoptExternalLayout:No,snapshotDoc:$o,setLamp:Mo,notice:A,destroy:Lo,seam:{pointerDown:Ie,pointerMove:ot,pointerUp:xt,pointerCancel:yt,wheel:Ct,key:Ne,keyUp:Ee,contextMenu(a){a.preventDefault(),T.contextMenuAt(a.clientX,a.clientY,a.target)}}}}const xi=800;function Ci(e){let t,o=!1,s=!1,n=!1,i="idle";function r(h){h!==i&&(i=h,e.onLamp(h))}function c(){t!==void 0&&(t(),t=void 0)}function l(){c(),t=e.schedule(()=>{t=void 0,u(!1)},xi)}async function u(h){if(o){s=!0;return}o=!0,c();const m=e.snapshot();let C;try{C=JSON.stringify(m)}catch{o=!1,r("error"),e.onHttpError("layout document is not JSON-serializable");return}try{const N=await e.send(m,{keepalive:h});if(N===null||typeof N!="object"||N.ok!==!0){r("error");const J=N!==null&&typeof N=="object"&&typeof N.error=="string"?N.error:"layout save refused";e.onHttpError(`layout save: ${J}`)}else JSON.stringify(e.snapshot())===C&&(e.onAdopt(N.layout),r("saved"))}catch(N){r("error"),e.onHttpError(`layout save unreachable: ${String((N==null?void 0:N.message)??N).slice(0,80)}`)}if(o=!1,i==="error"){n=!1;return}if(n){n=!1,u(!0);return}s&&(s=!1,r("pending"),l())}return{markDirty(){if(s=!1,r("pending"),o){s=!0;return}l()},retry(){i!=="error"||o||(r("pending"),u(!1))},flush(){if(o){n=!0,s=!0;return}c(),u(!0)},isBusy(){return o},dispose(){c()}}}function so(e){return e!=null&&typeof e.error=="string"?e.error:void 0}function ki(e){const t=new Map;let o=0;function s(r,c){o+=1;const l=t.get(r)??Promise.resolve(),u=async()=>{try{return await c()}finally{o-=1}},h=l.then(u,u);return t.set(r,h.then(()=>{},()=>{})),h}async function n(r){var ne,G,$,E;let c;try{c=await e.send(r)}catch(S){const w=String((S==null?void 0:S.message)??S).slice(0,80);return e.onNotice("error",`画布不可达:${w}`),!1}if(c.status>=400)return e.onNotice("error",so(c.body)??`HTTP ${c.status}`),!1;if(((ne=c.body)==null?void 0:ne.ok)===!0)return!0;const l=c.body!=null&&typeof c.body=="object"?so(c.body):void 0;if(l!==void 0)return e.onNotice("error",l),!1;const u=String(r.name??""),h=String(r.id??""),m=(G=c.body)==null?void 0:G.members,C=($=c.body)==null?void 0:$.teams,N=Array.isArray(m)&&m.every(S=>typeof S=="string"),J=Array.isArray(C)&&C.every(S=>typeof S=="string");return((E=c.body)==null?void 0:E.ok)===!1&&(r.action==="add-member"&&N&&m.includes(h)||r.action==="remove-member"&&N&&!m.includes(h)||r.action==="remove"&&J&&!C.includes(u))?!0:(e.onNotice("error","画布操作未确认:"+String(r.action)+"(可能队伍/成员已达上限,请重试)"),!1)}async function i(r,c){for(const l of c)if(!await n({...r,id:l}))return!1;return!0}return{createTeam(r,c){return s(r,async()=>{if(!await n({action:"create",name:r}))return!1;for(let l=0;l<c.length;l++)if(!await n({action:"add-member",name:r,id:c[l]}))return!1;return!0})},addMembers(r,c){return s(r,()=>i({action:"add-member",name:r},c))},removeMembers(r,c){return s(r,()=>i({action:"remove-member",name:r},c))},runRosterOps(r,c){return s(r,async()=>{for(const l of c){const u=l.op==="remove"?{action:"remove-member",name:r,id:l.id}:{action:"add-member",name:r,id:l.id};if(!await n(u))return!1}return!0})},removeTeam(r){return s(r,()=>n({action:"remove",name:r}))},hasPending(){return o>0}}}const Eo=document.getElementById("app"),Ei=(()=>{try{return window.sessionStorage.getItem("dsh_a2a_key")??""}catch{return""}})(),Cn=window.__DSH_A2A_KEY__??Ei,Xe=(e,t={})=>fetch(e,{...t,headers:{...t.headers??{},...Cn!==""?{"X-API-Key":Cn}:{}}});Cn===""&&Xe("/__dsh_a2a/owner-settings").then(e=>{if(e.status!==401)return;const t=document.createElement("div");t.className="nexus-keygate",t.style.cssText="position:fixed;inset:0;display:flex;align-items:center;justify-content:center;flex-direction:column;gap:10px;background:#fff;z-index:9999;font:14px/1.5 system-ui,sans-serif;color:#000";const o=document.createElement("div");o.textContent="此面板经远程面打开(密钥不随页面下发)——输入控制密钥";const s=document.createElement("input");s.type="password",s.placeholder="X-API-Key",s.setAttribute("aria-label","控制密钥");const n=document.createElement("button");n.type="button",n.textContent="进入面板";const i=document.createElement("div");i.style.color="#b00";const r=()=>{const c=s.value.trim();c!==""&&fetch("/__dsh_a2a/owner-settings",{headers:{"X-API-Key":c}}).then(l=>{if(l.status===401){i.textContent="密钥不对,再试一次";return}try{window.sessionStorage.setItem("dsh_a2a_key",c)}catch{}window.location.reload()})};n.addEventListener("click",r),s.addEventListener("keydown",c=>{c.key==="Enter"&&r()}),t.append(o,s,n,i),document.body.appendChild(t)});const jt=document.createElement("div");jt.className="nexus-fault";Eo.appendChild(jt);const{fault:kn,clear:Ni}=Oo({show(e){jt.textContent=e,jt.style.display="block"},hide(){jt.style.display="none"}},e=>console.error(e));let nn;const io="dsh-a2a.viewport.",$i={get(e){try{const t=window.localStorage.getItem(io+e);return t===null?void 0:JSON.parse(t)}catch{return}},set(e,t){try{window.localStorage.setItem(io+e,JSON.stringify({x:t.x,y:t.y,scale:t.scale}))}catch{}}},at=wi({viewportStore:$i,onDirty:()=>cn.markDirty(),onLampClick:()=>cn.retry(),onNodePick:e=>{nn==null||nn(e)},onCanvasAction:async e=>{const t=await Si(e);return mn(),t}}),cn=Ci({snapshot:()=>at.snapshotDoc(),send:(e,t)=>Xe("/__dsh_a2a/canvas-layout",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:"save",layout:e}),cache:"no-store",keepalive:t.keepalive}).then(async o=>await o.json()),schedule:(e,t)=>{const o=setTimeout(e,t);return()=>{clearTimeout(o)}},now:Date.now,onLamp:e=>{En=e;const t=new Date,o=String(t.getHours()).padStart(2,"0")+":"+String(t.getMinutes()).padStart(2,"0");at.setLamp(e,o)},onAdopt:e=>{at.adoptExternalLayout(e)},onHttpError:e=>kn(e)});window.addEventListener("pagehide",()=>cn.flush());const Dt=ki({send:async e=>{const t=await Xe("/__dsh_a2a/canvas",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e),cache:"no-store"});return{status:t.status,body:await t.json()}},onNotice:(e,t)=>at.notice(e,t)});async function ro(e,t,o,s){const n=await Xe("/__dsh_a2a/fleet-canvas-op",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({peer:e,op:t,name:o,...s!==void 0?{id:s}:{}}),cache:"no-store"}).catch(()=>{}),i=n!==void 0?await n.json().catch(()=>{}):void 0;return(i==null?void 0:i.ok)===!0&&t==="remove"&&i.removed===!1&&at.notice("info",`属主那边已没有「${o}」,无需解散`),(i==null?void 0:i.ok)===!0?!0:(at.notice("error",`跨主机团队操作失败:${String((i==null?void 0:i.error)??"对端无响应")}`),!1)}async function Mi(e,t){const o=async s=>{const n=await Xe("/__dsh_a2a/roster-op",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:t,...s})}).catch(()=>{}),i=n!==void 0?await n.json().catch(()=>{}):void 0;return n!=null&&n.ok&&(i==null?void 0:i.ok)===!0?!0:(at.notice("error",`roster 操作失败:${String((i==null?void 0:i.error)??(n?`HTTP ${n.status}`:"无响应"))}`),!1)};if(e.type==="create-team")return o({op:"create",ids:e.ids});if(e.type==="remove-team")return o({op:"dissolve"});if(e.type==="add-member"||e.type==="remove-member"){for(const s of e.ids)if(!await o({op:e.type,id:s}))return!1;return!0}return at.notice("error","roster 不支持该操作"),!1}function Si(e){if((e.type==="add-member"||e.type==="remove-member")&&e.fleetPeer!==void 0){const t=e.fleetPeer;return(async()=>{for(const o of e.ids)if(!await ro(t,e.type,e.team,o))return!1;return!0})()}if(e.type==="remove-team"&&e.fleetPeer!==void 0)return ro(e.fleetPeer,"remove",e.name);if(e.roster===!0){const t=ko(Yt(e));return t!==void 0?Mi(e,t):(at.notice("error","无效的 roster 框名"),Promise.resolve(!1))}switch(e.type){case"create-team":return Dt.createTeam(e.name,e.ids,e.created);case"add-member":return Dt.addMembers(e.team,e.ids);case"remove-member":return Dt.removeMembers(e.team,e.ids);case"remove-team":return Dt.removeTeam(e.name);case"reorder":return Dt.runRosterOps(e.team,e.ops);case"join-network":case"leave-network":return Ai(e.type==="join-network"?"join":"leave",e.id)}}async function Ai(e,t){const o=await Xe(`/__dsh_a2a/${e}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:t}),cache:"no-store"}).catch(()=>{});return o!==void 0&&o.ok}let En="idle",bn=new Set,ao=0,ln=!1,co,gn=!1;async function Li(){const e=await Xe("/__dsh_a2a/canvas-layout",{cache:"no-store"});if(!e.ok)throw new Error(`/__dsh_a2a/canvas-layout ${e.status}`);return(await e.json()).layout??null}const dn=is({now:()=>Date.now(),async ownerSettingsRead(){try{return await(await Xe("/__dsh_a2a/owner-settings")).json()}catch{return{ok:!1,error:"unreachable"}}},async ownerSettingsWrite(e){try{return await(await Xe("/__dsh_a2a/owner-settings",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(e)})).json()}catch{return{ok:!1,error:"unreachable"}}},async abandon(e,t){try{return(await Xe("/__dsh_a2a/tasks/abandon",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({task_id:e,reason:t})})).ok}catch{return!1}},copy(e){var t;(t=navigator.clipboard)==null||t.writeText(e).catch(()=>{})},async cliHomeOptions(e,t){try{const o=await Xe("/__dsh_a2a/canvas",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({action:"cli-home-options",name:e,id:t})}),s=await o.json();return{...s,ok:o.ok&&s.ok===!0}}catch(o){return{ok:!1,error:String(o)}}},async confirmMember(e,t,o,s,n,i){try{const r=await Xe("/__dsh_a2a/canvas",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({action:"confirm-member",name:e,id:t,replacement:o,revision:s,expectedOwner:n,...i?{peer:i}:{}})}),c=await r.json();return{ok:r.ok&&c.ok===!0,error:c.error}}catch(r){return{ok:!1,error:String(r)}}},async regulateSuspended(e,t,o,s,n){try{const i=await Xe("/__dsh_a2a/canvas",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({action:e,name:t,id:o,revision:s,expected:n})}),r=await i.json();return{ok:i.ok&&r.ok===!0,error:r.error}}catch(i){return{ok:!1,error:String(i)}}},async canvasOp(e,t,o,s,n){try{const i=await Xe("/__dsh_a2a/canvas",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({action:e,name:t,id:o,...s===void 0?{}:{home:s},...n===void 0?{}:{peer:n}})}),r=await i.json().catch(()=>({}));return i.ok&&r.ok!==!1?!0:(console.warn(`canvas ${e} ${t}: ${r.error??`HTTP ${i.status}`}`),!1)}catch{return!1}},async dispatchQuick(e,t){try{const o=await Xe("/__dsh_a2a/dispatch",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({team:e,message:t})}),s=await o.json().catch(()=>({}));return{ok:o.ok&&s.ok===!0,task_id:s.task_id,reply:s.reply,error:s.error??`HTTP ${o.status}`}}catch(o){return{ok:!1,error:o instanceof Error?o.message:String(o)}}},async sessionLog(e){try{const t=await Xe(`/__dsh_a2a/session-log?id=${encodeURIComponent(e)}`),o=await t.json().catch(()=>({}));return{ok:t.ok&&o.ok===!0,messages:o.messages,error:o.error??(t.ok?void 0:`HTTP ${t.status}`)}}catch(t){return{ok:!1,error:t instanceof Error?t.message:String(t)}}},async sessionLogList(){try{const e=await Xe("/__dsh_a2a/session-log"),t=await e.json().catch(()=>({}));return{ok:e.ok&&t.ok===!0,sessions:t.sessions,count:typeof t.count=="number"?t.count:void 0,error:t.error??(e.ok?void 0:`HTTP ${e.status}`)}}catch(e){return{ok:!1,error:e instanceof Error?e.message:String(e)}}},async remoteSessionLog(e){try{const t=new URLSearchParams;e.team!==void 0&&t.set("team",e.team),e.peer!==void 0&&t.set("peer",e.peer),e.id!==void 0&&t.set("id",e.id),e.limit!==void 0&&t.set("limit",String(e.limit));const o=await Xe(`/__dsh_a2a/remote-session-log?${t.toString()}`),s=await o.json().catch(()=>({}));return{ok:o.ok&&s.ok===!0,messages:s.messages,sessions:s.sessions,error:s.error??(o.ok?void 0:`HTTP ${o.status}`),via:s.via}}catch(t){return{ok:!1,error:t instanceof Error?t.message:String(t)}}},board:{root:at.root,activate:()=>at.activate(),deactivate:()=>at.deactivate(),available:()=>ln}});Eo.appendChild(dn.root);nn=e=>{dn.openNodeChat(e)};if(new URLSearchParams(window.location.search).get("mode")==="plan"){const e=window.setInterval(()=>{ln&&(dn.selectTab("board"),window.clearInterval(e))},300);window.setTimeout(()=>window.clearInterval(e),3e4)}async function mn(){var e,t;try{const o=await Xe("/__dsh_a2a/state",{cache:"no-store"});if(!o.ok)throw new Error(`/__dsh_a2a/state ${o.status}`);const s=await o.json();if(Date.now()-ao>=15e3){ao=Date.now();try{const m=await Xe("/__dsh_a2a/nodes",{cache:"no-store"});if(!m.ok)throw new Error(`nodes ${m.status}`);const C=await m.json();bn=new Set((C.bindings??[]).filter(N=>N.mounted!==null&&N.effective!==null&&(N.effective.core===!1||N.effective.mutable===!1)).map(N=>N.session))}catch{bn.clear()}}const n={...s,sessions:(s.sessions??[]).map(m=>({...m,...bn.has(m.id)?{nodePromptMissing:!0}:{}}))};if(Ni(),ln=s.canvas!==void 0,dn.update(n),ln)try{const m=await Li(),C=JSON.stringify(m??null);C!==co&&(co=C,(En==="idle"||En==="saved")&&!cn.isBusy()&&at.adoptExternalLayout(m)),gn=!0}catch(m){if(!gn){kn(`canvas layout 获取失败:${String(m)}`);return}}else gn=!0;const i=(s.sessions??[]).map(m=>({...m,joined:m.joined===!0})),r=[...((e=s.canvas)==null?void 0:e.teams)??[],...Ds(((t=s.registry)==null?void 0:t.teams)??[],s.zone??"")],c=(s.peers??[]).filter(m=>m!==null&&typeof m=="object"&&typeof m.url=="string"),l=(s.inFlight??[]).filter(m=>m!==null&&typeof m=="object"&&typeof m.team=="string"&&typeof m.peer=="string"&&Number.isFinite(m.startedAt)),u=(s.remote??[]).filter(m=>m!==null&&typeof m=="object"&&typeof m.team=="string"&&typeof m.via=="string").map(m=>({team:m.team,memberRef:m.memberRef,name:m.name,via:m.via,workspace:m.workspace,...m.unreachable===!0?{unreachable:!0}:{},...typeof m.origin=="string"&&m.origin!==""?{origin:m.origin}:{},...Array.isArray(m.teams)&&m.teams.length>0?{teams:m.teams.filter(C=>typeof C=="string"&&C!=="")}:{}})),h=(s.peerOrg??[]).filter(m=>m!==null&&typeof m=="object").filter(m=>typeof m.url=="string"&&Array.isArray(m.org)).map(m=>({url:m.url,...m.unreachable===!0?{unreachable:!0}:{},org:m.org.filter(C=>C!==null&&typeof C=="object").filter(C=>typeof C.team=="string"&&C.team!=="").map(C=>({name:typeof C.name=="string"?C.name:"",team:C.team,members:Array.isArray(C.members)?C.members.filter(N=>typeof N=="string"):[]}))}));at.reconcile({sessions:i,teams:r,peerCount:c.length,peers:c,inFlight:l,remoteTeams:u,peerOrg:h})}catch(o){kn(`state 轮询失败:${String(o)}`)}}mn();window.setInterval(()=>{document.hidden||mn()},3e3);document.addEventListener("visibilitychange",()=>{document.hidden||mn()});
@@ -18,7 +18,7 @@ html,body{margin:0;height:100%;background:var(--n-bg);color:var(--n-ink);
18
18
  font-family:"Segoe UI",system-ui,sans-serif;}
19
19
  #app{width:100%;height:100%;position:relative}
20
20
  </style>
21
- <script type="module" crossorigin src="./assets/index-CaA76j0F.js"></script>
21
+ <script type="module" crossorigin src="./assets/index-CA_YZTWG.js"></script>
22
22
  <link rel="stylesheet" crossorigin href="./assets/index-C7HagaGy.css">
23
23
  </head>
24
24
  <body>
package/cli/a2a.mjs CHANGED
@@ -890,6 +890,7 @@ async function printDelivery(verb, res) {
890
890
  return
891
891
  }
892
892
  if (res.status === 401 || res.status === 403) die(`[${verb}] ${keyHint(res.status)}${out.error !== undefined ? ` (${String(out.error)})` : ''}`)
893
+ if(out.delivered===true&&out.receiverBookkeeping==='failed'){console.log(`[${verb}] 已送达、接收方记账失败,请对账,不要重派 · task ${String(out.task_id)} — delivered; receiver bookkeeping failed; reconcile, do not redispatch`);return}
893
894
  // A sync round answers with the target's reply instead of a delivery marker.
894
895
  if (out.routed === true && typeof out.result?.text === 'string') {
895
896
  console.log(`[${verb}] reply from ${String(out.team)} · task ${String(out.task_id)}${typeof out.context_id === 'string' && out.context_id !== '' ? ` · context ${out.context_id}` : ''}`)
@@ -1020,11 +1021,11 @@ async function main() {
1020
1021
  const archived = s.archived ?? []
1021
1022
  if (has('--json')) { console.log(JSON.stringify({ pending, dead, archived, ...(s.settlement === undefined ? {} : { settlement: s.settlement }), ...(s.conservation === undefined ? {} : { conservation: s.conservation }) }, null, 2)); return }
1022
1023
  console.log(`pending (${String(pending.length)}):`)
1023
- listCapped(pending, 20, t => ` ${String(t.taskId)} → ${String(t.team)} ${String(t.direction ?? '')}${senderTail(t)}`)
1024
+ listCapped(pending, 20, t => ` ${String(t.taskId)} → ${String(t.team)} ${String(t.direction ?? '')}${t.consumed===undefined?'':t.consumed?' consumed':' delivered-unconsumed'}${t.receiptDelivery?' '+String(t.receiptDelivery):''}${senderTail(t)}${t.reminderAttempts!==undefined?` reminders=${t.reminderDelivered??0}/${t.reminderAttempts} last=${t.reminderLastAt??'?'}${t.repeatedlyUnreconciled?' 多次提醒未对账':''}`:''}`)
1024
1025
  console.log(`dead (${String(dead.length)}):`)
1025
- listCapped(dead, 20, t => ` ${String(t.taskId)} → ${String(t.team)} (${String(t.reason ?? '?')})${senderTail(t)}`)
1026
+ listCapped(dead, 20, t => ` ${String(t.taskId)} → ${String(t.team)} (${String(t.reason ?? '?')})${senderTail(t)}${t.reminderAttempts!==undefined?` reminders=${t.reminderDelivered??0}/${t.reminderAttempts} last=${t.reminderLastAt??'?'}${t.repeatedlyUnreconciled?' 多次提醒未对账':''}`:''}`)
1026
1027
  console.log(`archived (${String(archived.length)}):`)
1027
- listCapped(archived, 20, t => ` ${String(t.taskId)} ${String(t.outcome ?? '?')}${t.endedBy !== undefined && t.endedBy !== 'receipt' ? ` (${String(t.endedBy)})` : ''}${senderTail(t)}`)
1028
+ listCapped(archived, 20, t => ` ${String(t.taskId)} ${String(t.outcome ?? '?')}${t.endedBy !== undefined && t.endedBy !== 'receipt' ? ` (${String(t.endedBy)})` : ''}${t.withdrawalResult?` withdrawal=${String(t.withdrawalResult)}`:''}${senderTail(t)}${t.reminderAttempts!==undefined?` reminders=${t.reminderDelivered??0}/${t.reminderAttempts} last=${t.reminderLastAt??'?'}${t.repeatedlyUnreconciled?' 多次提醒未对账':''}`:''}`)
1028
1029
  if (s.conservation != null) console.log(`conservation: conserved=${String(s.conservation.conserved)} delta=${String(s.conservation.delta)}`)
1029
1030
  if (s.settlement != null) console.log(`settlement: mode=${String(s.settlement.mode)} refusalsTotal=${String(s.settlement.refusalsTotal)} offChain=${String(s.settlement.offChain)}`)
1030
1031
  if (s.settlement?.enforceRefused) console.log(`enforce refused: ${String(s.settlement.enforceRefused.reason)}; blockers=${JSON.stringify(s.settlement.enforceRefused.blockers)}`)
@@ -1033,6 +1034,17 @@ async function main() {
1033
1034
  if (cmd === 'status') {
1034
1035
  const s = await state()
1035
1036
  const list = await control({ action: 'list' })
1037
+ const safeCode=value=>typeof value==='string'&&['EACCES','EPERM','EBUSY','ENOSPC','ENOENT','EIO','EROFS','EMFILE','ENFILE','ETIMEDOUT','ECONNRESET','ECONNREFUSED','ABORT_ERR','LEDGER_WRITE_FAILED','NUDGE_QUEUE_FAILED','PROMPT_UNAVAILABLE'].includes(value)?value:'UNKNOWN_ERROR'
1038
+ const time=value=>typeof value==='number'&&Number.isFinite(value)&&value>=0?value:undefined
1039
+ const ledgerPersistence=s.ledgerPersistence&&typeof s.ledgerPersistence.ok==='boolean'?{ok:s.ledgerPersistence.ok,...(!s.ledgerPersistence.ok&&s.ledgerPersistence.lastError?{lastError:{at:time(s.ledgerPersistence.lastError.at),code:safeCode(s.ledgerPersistence.lastError.code)}}:{})}:undefined
1040
+ const n=s.nudgeEscalations
1041
+ const nudgeEscalations=n?{queued:Number.isSafeInteger(n.queued)&&n.queued>=0?n.queued:0,unavailable:Number.isSafeInteger(n.unavailable)&&n.unavailable>=0?n.unavailable:0,failed:Number.isSafeInteger(n.failed)&&n.failed>=0?n.failed:0,...(time(n.lastAt)===undefined?{}:{lastAt:n.lastAt}),...(n.lastError?{lastError:safeCode(n.lastError)}:{})}:undefined
1042
+ if(has('--json')){const {ledgerPersistence:_lp,nudgeEscalations:_ne,...snapshot}=s;console.log(JSON.stringify({...snapshot,...(ledgerPersistence?{ledgerPersistence}:{}),...(nudgeEscalations?{nudgeEscalations}:{}),deposit:list},null,2));return}
1043
+ if(ledgerPersistence)console.log(`ledger ${ledgerPersistence.ok?'ok':'!!! FAILED !!!'}${ledgerPersistence.lastError?` at=${String(ledgerPersistence.lastError.at??'?')} code=${ledgerPersistence.lastError.code}`:''}`)
1044
+ if(nudgeEscalations)console.log(`nudges queued=${nudgeEscalations.queued} unavailable=${nudgeEscalations.unavailable} failed=${nudgeEscalations.failed}${nudgeEscalations.lastAt===undefined?'':` lastAt=${nudgeEscalations.lastAt}`}${nudgeEscalations.lastError?` code=${nudgeEscalations.lastError}`:''}`)
1045
+ if(s.deliveryBookkeeping)console.log(`bookkeeping orphaned=${String(s.deliveryBookkeeping.orphaned??0)} failures=${String(s.deliveryBookkeeping.failures??0)}${s.deliveryBookkeeping.lastError?' code='+safeCode(s.deliveryBookkeeping.lastError.code):''}`)
1046
+ const reminders=(s.tasks??[]).filter(t=>t.reminderAttempts!==undefined)
1047
+ if(reminders.length)console.log(`reconcile ${reminders.length} task(s) reminded; ${reminders.filter(t=>t.repeatedlyUnreconciled).length} 多次提醒未对账; wait for target reconciliation, no automatic settlement`)
1036
1048
  console.log(`host ${home()} version=${String(s.version ?? '?')} peers=${String((s.peers ?? []).length)}`)
1037
1049
  if (s.settlement?.enforceRefused) console.log(`settlement mode=${String(s.settlement.mode)}; enforce refused: ${String(s.settlement.enforceRefused.reason)}; blockers=${JSON.stringify(s.settlement.enforceRefused.blockers)}`)
1038
1050
  for (const p of s.peers ?? []) console.log(` peer ${String(p.url).padEnd(34)} link=${String(p.link ?? 'stranger')}`)
@@ -1049,6 +1061,10 @@ async function main() {
1049
1061
  for (const m of (Array.isArray(s.boundMissRecent) ? s.boundMissRecent : []).slice(0, 5)) {
1050
1062
  console.log(` miss ${String(m.caller)} dialled ${String(m.audience) || '(no origin)'} ×${String(m.count)}`)
1051
1063
  }
1064
+ // Present but unverifiable: bad-ts is the sender's clock (±5 min); the caller fields are its own claim.
1065
+ for (const r of (Array.isArray(s.claimRejectsRecent) ? s.claimRejectsRecent : []).slice(0, 5)) {
1066
+ console.log(` reject ${String(r.reason)} from ${String(r.caller) || '(no caller)'} ${String(r.callerUrl) || ''} ×${String(r.count)}`)
1067
+ }
1052
1068
  }
1053
1069
  console.log(`deposit ${depositLine(list, identity().handle, 'OFFLINE')}`)
1054
1070
  return
package/lib/a2a-client.js CHANGED
@@ -5,6 +5,8 @@
5
5
  * tests drive them without a network.
6
6
  * @module @nelsonlongxiang/dsh-open-a2a-net/a2a-client
7
7
  */
8
+ import { ADMITTED_BOOKKEEPING_NOTE } from "./admitted-bookkeeping.js";
9
+ import { RECEIPT_RETRYABLE } from "./receipt-retry.js";
8
10
  import { verifyCard } from "./card.js";
9
11
  import { MAX_ROUTE_BODY_BYTES, WIRE_ERROR_PAYLOAD_TOO_LARGE, withinRouteBodyCap } from "./transport-caps.js";
10
12
  /** Direct-route HTTP budget. */
@@ -156,10 +158,12 @@ export class A2aClient {
156
158
  * @param callerSession - caller label overriding the node's label (the calling session's node label).
157
159
  * @returns the canonical route result (success or explicit failure).
158
160
  */
159
- async routeDirect(baseUrl, team, message, contextId, signal, callerSession, asyncMode = false, taskIdFromCaller, callbackAddress, guard) {
161
+ async routeDirect(baseUrl, team, message, contextId, signal, callerSession, asyncMode = false, taskIdFromCaller, callbackAddress, guard, cancelTaskId) {
160
162
  const args = { team, message, caller_session: callerSession ?? this.options.sessionId };
161
163
  if (contextId !== undefined)
162
164
  args.context_id = contextId;
165
+ if (cancelTaskId !== undefined)
166
+ args.cancel_task_id = cancelTaskId;
163
167
  // wait:false asks the peer to steer and answer delivered immediately —
164
168
  // the async half of the receipt contract for cross-host long tasks.
165
169
  if (asyncMode)
@@ -237,7 +241,10 @@ export class A2aClient {
237
241
  /* prose body — keep the generic code */
238
242
  }
239
243
  }
244
+ const status = error?.statusCode;
245
+ const transient = status === 503 && typeof bodyText === 'string' && bodyText.includes('task ledger write failed') || status === undefined && (abortClass || error instanceof TypeError || /ECONNREFUSED|ECONNRESET|ETIMEDOUT|EHOSTUNREACH|ENETUNREACH/.test(String(error) + ' ' + String(error?.code ?? '') + ' ' + String(error?.cause?.code ?? '')));
240
246
  const failure = {
247
+ ...(transient ? { [RECEIPT_RETRYABLE]: true } : {}),
241
248
  ok: false,
242
249
  error: `direct route to peer failed: ${String(error)}`,
243
250
  code,
@@ -273,7 +280,8 @@ export class A2aClient {
273
280
  return {
274
281
  ok: true,
275
282
  team,
276
- reply: bridge !== undefined
283
+ ...(raw.receiverBookkeeping === 'failed' ? { receiverBookkeeping: 'failed' } : {}),
284
+ reply: raw.receiverBookkeeping === 'failed' ? ADMITTED_BOOKKEEPING_NOTE : bridge !== undefined
277
285
  ? `Delivered to ${team} (async native-teams round). It settles through the team's own routing chain and routes no A2A receipt in this slice — reconcile via context_id follow-ups.`
278
286
  : consumed === false
279
287
  ? `Delivered to ${team} (async), but the target had not started a turn on it yet — the message is queued behind the session's current turn. Watch a2a_status activity or follow up with the context id; do not resend.`
@@ -0,0 +1,7 @@
1
+ /** Observation of accepted input whose task birth did not commit; not a task status. */
2
+ import { safeObservationCode } from "./nudge-observability.js";
3
+ export const ADMITTED_BOOKKEEPING_NOTE = '已送达、接收方记账失败,请对账,不要重派。Delivered, but receiver bookkeeping failed; reconcile the original task, do not redispatch.';
4
+ export class AdmittedBookkeepingError extends Error {
5
+ code;
6
+ constructor(error) { super(ADMITTED_BOOKKEEPING_NOTE); this.code = safeObservationCode(error, 'LEDGER_WRITE_FAILED'); }
7
+ }
@@ -1,5 +1,6 @@
1
1
  /** Read-only canvas ownership projection; never authorizes or selects a dispatch candidate. */
2
2
  import { advertisedCanvasTeams } from "./peer-directory.js";
3
+ import { splitQualifiedMember } from "./canvas-member.js";
3
4
  export function canvasOwners(local, ownUrl, peers) {
4
5
  const rows = local.map(row => ({ ...row, owner: ownUrl, memberCount: row.members.length, local: true }));
5
6
  const seen = new Set();
@@ -14,7 +15,16 @@ export function canvasOwners(local, ownUrl, peers) {
14
15
  return rows;
15
16
  }
16
17
  export function canvasMemberships(owners, handle, localId, resolveLocal) {
17
- return owners.filter(row => ((row.scopeMembers ?? row.members).includes(handle) && (row.local || resolveLocal === undefined || resolveLocal(handle) === localId)) || (row.local && localId !== undefined && row.members.includes(localId))).map(({ members: _members, scopeMembers: _scopeMembers, ...row }) => row);
18
+ return owners.flatMap(row => {
19
+ const matched = (row.scopeMembers ?? row.members).filter(ref => (row.local && localId !== undefined && ref === localId) ||
20
+ (resolveLocal !== undefined && localId !== undefined && (ref === handle || splitQualifiedMember(ref)?.handle === handle) && resolveLocal(ref) === localId) ||
21
+ (resolveLocal === undefined && ref === handle));
22
+ if (!matched.length)
23
+ return [];
24
+ const inferred = matched.some(ref => ref === handle && splitQualifiedMember(ref) === undefined);
25
+ const { members: _members, scopeMembers: _scopeMembers, ...detail } = row;
26
+ return [{ ...detail, provenance: inferred ? 'unknown' : 'confirmed', ...(inferred ? { compatibilityInference: true } : {}) }];
27
+ });
18
28
  }
19
29
  export function canvasFailure(team, owners, reason) {
20
30
  if (!new RegExp('^.+/canvas/[^/]+$').test(team))