@nelsonlongxiang/dsh-open-a2a-net 0.6.34 → 0.6.36

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.
@@ -83,11 +83,16 @@ host_prefix = 'dsh'
83
83
  for _t in _BASE.get('canvas', {}).get('teams', []):
84
84
  teams[_t['name']] = [m['id'] for m in _t.get('members', [])]
85
85
  for _m in _t.get('members', []):
86
- member_rows[_m['id']] = _m
86
+ member_rows[_m['id']] = _m # every member row, not only the first
87
87
  _p = _m.get('team', '').split('/')[0]
88
- if _p:
88
+ if _p and '/' not in _m['id']:
89
89
  host_prefix = _p
90
- break
90
+
91
+
92
+ def valid_remote_ref(mid):
93
+ """Mirror of canvas-store.validRemoteMemberRef: a '/'-qualified handle, no whitespace, no empty side."""
94
+ return (isinstance(mid, str) and '/' in mid and mid == mid.strip() and not any(c.isspace() for c in mid)
95
+ and not mid.startswith('/') and not mid.endswith('/') and '//' not in mid)
91
96
 
92
97
 
93
98
  def valid_name(raw):
@@ -118,7 +123,9 @@ def build_state(demo: bool = False) -> bytes:
118
123
  for mid in ids:
119
124
  row = member_rows.get(mid)
120
125
  if row is None:
121
- row = {'id': mid, 'team': f'{host_prefix}/{mid[:8]}', 'joined': True, 'live': True}
126
+ # A remote ref renders as the real state face does: { id, team: the handle, remote: true }.
127
+ row = ({'id': mid, 'team': mid, 'remote': True} if '/' in mid
128
+ else {'id': mid, 'team': f'{host_prefix}/{mid[8:16] if mid.startswith("session-") else mid[:8]}', 'joined': True, 'live': True})
122
129
  member_rows[mid] = row
123
130
  members.append(row)
124
131
  team_rows.append({'name': name, 'team': f'{host_prefix}/canvas/{name}', 'members': members})
@@ -208,8 +215,9 @@ class MockHost(SimpleHTTPRequestHandler):
208
215
  elif action == 'add-member':
209
216
  name = valid_name(body.get('name'))
210
217
  mid = body.get('id')
211
- if name is None or not isinstance(mid, str) or mid not in joined_ids:
212
- self._json(b'{"ok":false,"error":"name and a joined session id are required"}')
218
+ # Dual member shape, as the real host: a joined local session id, or a remote team handle.
219
+ if name is None or not isinstance(mid, str) or not (mid in joined_ids or valid_remote_ref(mid)):
220
+ self._json(b'{"ok":false,"error":"name and a member (joined session id, or a zone-qualified remote team handle like zone/a1b2c3d4) are required"}')
213
221
  return
214
222
  roster = teams.setdefault(name, [])
215
223
  if mid in roster:
@@ -43,15 +43,17 @@ export function createCardElement(id: string): HTMLDivElement {
43
43
 
44
44
  /**
45
45
  * The right-hand chip. Peer cards show the link badge (gh#20 W-A: linked green / stranger gray, then the
46
- * verified tick/cross; an absent link field from an older host renders the neutral 'peer'); session cards show
47
- * their first membership priority `P<n>`. Writes only on change.
46
+ * verified tick/cross; an absent link field from an older host renders the neutral 'peer'). A remote MEMBER card
47
+ * (gh#38) is one session on that host, not the host: it reads 成员, colored and ticked by its host's link
48
+ * (it used to fall through to 'peer' and looked like a host card). Session cards show their first membership
49
+ * priority `P<n>`. Writes only on change.
48
50
  */
49
51
  export function paintPrio(prioEl: HTMLElement, n: WorldNode, info: { link?: 'linked' | 'stranger'; verified?: boolean } | undefined): void {
50
52
  if (n.remote === true) {
51
53
  const cls = info?.link === 'linked' ? 'lnk-linked' : info?.link === 'stranger' ? 'lnk-stranger' : ''
52
54
  if (prioEl.className !== `prio mono ${cls}`.trim()) prioEl.className = `prio mono ${cls}`.trim()
53
55
  const mark = info === undefined ? '' : info.verified === true ? '✓' : '✗'
54
- const badge = (info?.link ?? 'peer') + mark
56
+ const badge = (n.id.startsWith('member-') ? '成员' : info?.link ?? 'peer') + mark
55
57
  if (prioEl.textContent !== badge) prioEl.textContent = badge
56
58
  } else {
57
59
  if (prioEl.className !== 'prio mono') prioEl.className = 'prio mono'
@@ -431,7 +431,9 @@ export function createPlanningView(deps: PlanningDeps): PlanningView {
431
431
  if (subEl.textContent !== subText) subEl.textContent = subText
432
432
  const tip = unavailable ? `${txt.tip} · ${UNREACHABLE_HINT}` : txt.tip
433
433
  if (el.title !== tip) el.title = tip
434
- paintPrio(el.querySelector<HTMLElement>('.prio')!, n, n.remote === true ? peerInfoByHost.get(host) : undefined)
434
+ // A member card's chip follows the link of the host that publishes its handle.
435
+ const linkHost = n.id.startsWith('member-') ? memberHostByHandle.get(n.remoteHandle ?? '') : host
436
+ paintPrio(el.querySelector<HTMLElement>('.prio')!, n, n.remote === true && linkHost !== undefined ? peerInfoByHost.get(linkHost) : undefined)
435
437
  }
436
438
  for (const [id, el] of [...nodeEls]) {
437
439
  if (!seen.has(id)) { el.remove(); nodeEls.delete(id) }
@@ -454,6 +456,7 @@ export function createPlanningView(deps: PlanningDeps): PlanningView {
454
456
  const peerScoreByText = new Map<string, number | undefined>()
455
457
  /** gh#20 W-A: per-host link/verified info for the peer badges. */
456
458
  const peerInfoByHost = new Map<string, { link?: 'linked' | 'stranger'; verified?: boolean }>()
459
+ let memberHostByHandle: ReadonlyMap<string, string> = new Map()
457
460
 
458
461
  function renderFederation(): void {
459
462
  federation.render(clock())
@@ -1202,6 +1205,7 @@ export function createPlanningView(deps: PlanningDeps): PlanningView {
1202
1205
  // excluded from bounds, so the column cannot feed back into itself).
1203
1206
  const peerSeen = new Set<string>()
1204
1207
  lastRemoteTeams = groupRemoteTeams(input.remoteTeams ?? [])
1208
+ memberHostByHandle = new Map([...lastRemoteTeams].flatMap(([h, rows]) => rows.map(row => [row.team, h] as const)))
1205
1209
  lastWork = new Map(input.sessions.map(s => [s.id, { status: s.status, queued: s.queued }]))
1206
1210
  reachability = unreachableRefs(input)
1207
1211
  peerScoreByText.clear()
@@ -1226,7 +1230,9 @@ export function createPlanningView(deps: PlanningDeps): PlanningView {
1226
1230
  // team row's zone/id8 handle (canvas remote refs are exact handles
1227
1231
  // per the D1 ruling). Absent until the first remote team row lands.
1228
1232
  const host = peerHostOf(p.url)
1229
- const handle = lastRemoteTeams.get(host)?.[0]?.team
1233
+ // Owner report 2026-11-04: the host's rows now lead with its bare process team (e.g. 'dsh'), which the
1234
+ // server reads as a local session id and refuses — take the first zone/id8 SESSION handle instead.
1235
+ const handle = lastRemoteTeams.get(host)?.find(row => row.team.includes('/'))?.team
1230
1236
  model.upsertNode({
1231
1237
  id, x: base.x, y: base.y,
1232
1238
  label: p.url, team: '', name: p.url, peerUrl: p.url,
@@ -134,6 +134,7 @@ export interface CanvasMemberRow {
134
134
  /** Present only for CLI refs: null means the linked home is ambiguous or unknown. */
135
135
  readonly cliHome?: string | null
136
136
  readonly cliHeld?: boolean
137
+ readonly cliHomeCleared?: boolean
137
138
  }
138
139
 
139
140
  /** One canvas team from /state `canvas.teams`. */
@@ -984,6 +985,11 @@ export function createWorkbench(deps: WorkbenchDeps): Workbench {
984
985
  })
985
986
  row.appendChild(remove)
986
987
  card.appendChild(row)
988
+ if (member.cliHomeCleared === true) {
989
+ const notice = el('div', 'wb-hint')
990
+ notice.textContent = '本机落户已清除旧 home 钉;户口离线后也不会恢复旧钉。'
991
+ card.appendChild(notice)
992
+ }
987
993
  if (member.cliHome === null && member.cliHeld !== true && deps.cliHomeOptions !== undefined) {
988
994
  const key = JSON.stringify([fresh.name, member.id])
989
995
  let form = cliHomeForms.get(key)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nelsonlongxiang/dsh-open-a2a-net",
3
- "version": "0.6.34",
3
+ "version": "0.6.36",
4
4
  "description": "Open A2A network plugin for DeepSeek Harness: signed agent cards, decentralized peer/zone discovery, direct routing model tools, and joinable session nodes with a sidebar control",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -1,9 +0,0 @@
1
- var Mo=Object.defineProperty;var So=(e,t,n)=>t in e?Mo(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var kt=(e,t,n)=>So(e,typeof t!="symbol"?t+"":t,n);(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))s(o);new MutationObserver(o=>{for(const i of o)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 n(o){const i={};return o.integrity&&(i.integrity=o.integrity),o.referrerPolicy&&(i.referrerPolicy=o.referrerPolicy),o.crossOrigin==="use-credentials"?i.credentials="include":o.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function s(o){if(o.ep)return;o.ep=!0;const i=n(o);fetch(o.href,i)}})();const an=6e4;function Ao(e,t,n=Date.now){let s=-an;return{fault(o){const i=n();i-s>=an&&(t(`[nexus] ${o}`),s=i),e.show(o)},clear(){e.hide(),s=-an}}}function rt(e){return e.name??e.team??e.label??""}function so(e,t){var i,r;const n=(c,d)=>c!==void 0&&c.trim()!==""?{name:c,remote:d}:void 0,s=(e.sessions??[]).find(c=>c.team===t);if(s!==void 0)return n(rt(s),!1);const o=(e.remote??[]).find(c=>c.team===t);return o!==void 0?n(rt(o),!0):n((r=(((i=e.canvas)==null?void 0:i.teams)??[]).find(c=>c.team===t))==null?void 0:r.name,!1)}function Lo(e,t){const n=so(e,t);return n===void 0?t:n.remote?`${n.name}(远端)`:n.name}function Ut(e,t,n,s=""){const o=so(t,n);if(e.textContent=`${s}${(o==null?void 0:o.name)??n}`,e.title=n,(o==null?void 0:o.remote)===!0){const i=e.appendChild(document.createElement("span"));i.className="wb-row-remote",i.textContent="远端",i.title="名字由对端自行发布"}}const Io=60*6e4;function $t(e){var t;return e.direction==="inbound"||e.direction===void 0&&((t=e.peer)==null?void 0:t.startsWith("local:"))===!0}function An(e){var t;return((t=e.peer)==null?void 0:t.startsWith("local:"))===!0?e.peer.slice(6):void 0}function Pt(e,t){return e.settleable!==void 0?e.settleable===!1:t-e.startedAt>=Io}function pn(e,t){const n=(e.tasks??[]).filter(r=>r.receiptExpected!==!1),s=n.filter(r=>!$t(r)&&Pt(r,t)),o=n.filter(r=>$t(r)&&Pt(r,t)),i=e.tasksDead??[];return{stale:s,owedOverdue:o,deadLetters:i.filter(r=>r.reason!=="fire-forget"),expired:i.filter(r=>r.reason==="fire-forget")}}function $e(e,t){const n=document.createElement(e);return t!==void 0&&(n.className=t),n}function Ln(e,t){const n=Math.max(0,Math.round((t-e)/1e3));if(n<90)return`${n}s`;const s=Math.round(n/60);if(s<90)return`${s}m`;const o=Math.round(s/60);return o<48?`${o}h`:`${Math.round(o/24)}d`}function Ht(e,t,n,s,o){const i=$e("div",`wb-led-tile${o!==void 0?` is-${o}`:""}`);i.title=s,i.appendChild($e("span","wb-led-tile-v")).textContent=String(n),i.appendChild($e("span","wb-led-tile-k")).textContent=t,e.appendChild(i)}const hn=[{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 To(e,t,n){const s=$e("div","wb-led-split"),o=$e("div","wb-led-split-bar");o.setAttribute("role","img");const i=$e("div","wb-led-split-legend"),r=new Set(hn.map(m=>m.key)),c=hn.map(m=>[m.tone,m.label,t[m.key]??0]);for(const[m,b]of Object.entries(t))r.has(m)||c.push(["other",m,b]);const d=[];for(const[m,b,u]of c){if(u<=0)continue;const E=$e("span",`wb-led-seg is-${m}`);E.style.width=`${Math.max(2,u/n*100)}%`,o.appendChild(E);const M=$e("span","wb-led-split-item");M.appendChild($e("i",`wb-led-swatch is-${m}`)),M.appendChild(document.createTextNode(`${b} ${u}`)),i.appendChild(M),d.push(`${b} ${u}`)}o.setAttribute("aria-label",`归档结局:${d.join(",")}`),s.append(o,i),e.appendChild(s)}function _o(e,t){var Le;e.replaceChildren();const{state:n,now:s}=t,o=n.tasks??[],i=n.tasksDead??[],r=n.archivedCount??0,c=pn(n,s),d=o.filter(R=>R.receiptExpected===!1),m=o.filter(R=>R.receiptExpected!==!1),b=m.filter(R=>$t(R)),u=m.filter(R=>!$t(R)),E=c.stale,M=u.filter(R=>!Pt(R,s)),q=c.stale.length,fe=$e("div","wb-led-tiles");Ht(fe,"待回执",m.length,`要回执、仍未结算的任务(含陈旧与本机欠对方的入站行)${d.length>0?`;另有免回执 ${d.length} 条不计`:""}`),Ht(fe,"陈旧",q,"我方派发、要回执、已等待 ≥1h 仍未回执(可催办);本机欠对方的入站行在「待本机回执」组另计,免回执行不算陈旧",q>0?"warn":void 0),Ht(fe,"死信",c.deadLetters.length,"超过 24h TTL 仍未结算(unconsumed);需清账(abandon)才能移出。免回执到期另列,不算死信",c.deadLetters.length>0?"danger":void 0),Ht(fe,"已归档",r,"已离开台账并留档的任务(结算、拒绝或放弃),用于审计"),e.appendChild(fe),r>0&&n.archivedSplit!==void 0&&To(e,n.archivedSplit,r);const ee=(R,X)=>{const se=$e("div",`wb-led-card is-${X.tone}`),He=$e("div","wb-led-card-head");He.appendChild($e("span",`wb-led-dir${X.inbound?" is-in":""}`)).textContent=X.inbound?"↙":"↗";const Ne=$e("span","wb-led-brief");Ne.textContent=X.brief!==void 0&&X.brief!==""?X.brief:"(无摘要——派发未带 brief)",(X.brief===void 0||X.brief==="")&&Ne.classList.add("is-missing"),He.appendChild(Ne),se.appendChild(He);const ie=$e("div","wb-led-meta"),Ce=ie.appendChild($e("span","wb-led-team"));X.inbound?X.sender!==void 0?Ut(Ce,n,X.sender,"来自 "):Ce.textContent="来自 对端":Ut(Ce,n,X.team,"发往 "),X.inbound&&Ut(ie.appendChild($e("span","wb-led-to")),n,X.team,"至 "),ie.appendChild($e("span")).textContent=X.atText,ie.appendChild($e("span","wb-led-task")).textContent=X.taskId;for(const G of X.chips)ie.appendChild($e("span","wb-led-chip")).textContent=G;if(se.appendChild(ie),se.title=`${X.taskId}
2
- ${X.team}`,X.dead!==void 0){const G=X.dead,ne=G.reason==="fire-forget",we=$e("button",`wb-btn wb-led-abandon${ne?" is-quiet":""}`);we.type="button",we.textContent=ne?"移出":"清账",we.title=ne?"可选:把这条已过期的免回执记录移出台账(不是失败,不处理也无妨)":"从台账移出这条死信(abandon)",we.addEventListener("click",ce=>{ce.stopPropagation(),we.disabled=!0,t.abandon(G.taskId,"workbench dead-letter cleanup").then(Z=>{we.disabled=!1,we.textContent=Z?"已清":"失败"})}),se.appendChild(we)}if(t.canOpenTeam(X.team)){se.classList.add("is-link"),se.setAttribute("role","button"),se.tabIndex=0,se.setAttribute("aria-label",`${Ne.textContent},打开 ${X.team} 的对话`);const G=()=>{t.openTeam(X.team)};se.addEventListener("click",G),se.addEventListener("keydown",ne=>{(ne.key==="Enter"||ne.key===" ")&&(ne.preventDefault(),G())})}R.appendChild(se)},S=(R,X,se,He)=>{if(X===0)return null;const Ne=$e("div",`wb-led-group is-${se}`);Ne.dataset.group=R;const ie=$e("div","wb-led-group-head");return ie.appendChild($e("span")).textContent=`${R} · ${X}`,ie.appendChild($e("span","wb-led-group-hint")).textContent=He,Ne.appendChild(ie),e.appendChild(Ne),Ne},C=(R,X)=>{const se=$t(R);return{brief:R.brief,team:R.team,sender:An(R),taskId:R.taskId,atText:`${Ln(R.startedAt,s)} 前${se?"收到":"派发"}`,inbound:se,tone:X,chips:[...R.settleable===!0?["可结算"]:[],...R.receiptExpected===!1?["无回执债"]:[],...se?["入站"]:[],...R.status!=="pending"?[R.status]:[]]}},N=(R,X,se)=>({brief:R.brief,team:R.team,sender:An(R),taskId:R.taskId,atText:`${Ln(R.deadAt,s)} 前${se}`,inbound:$t(R),tone:X,dead:R,chips:R.reason!==void 0&&R.reason!==""&&R.reason!=="unspecified"&&R.reason!=="fire-forget"?[R.reason]:[]}),k=S("死信",c.deadLetters.length,"danger","需清账");if(k!==null)for(const R of[...c.deadLetters].sort((X,se)=>se.deadAt-X.deadAt))ee(k,N(R,"danger","死信"));const J=S("陈旧",E.length,"warn","我方派发 ≥1 小时仍无回执,可催办");if(J!==null)for(const R of[...E].sort((X,se)=>X.startedAt-se.startedAt))ee(J,C(R,"warn"));const y=c.owedOverdue.length,f=S("待本机回执",b.length,y>0?"warn":"quiet",y>0?`对方在等本机回执 · ${y} 条超过 1 小时`:"对方在等本机回执");if(f!==null)for(const R of[...b].sort((X,se)=>X.startedAt-se.startedAt))ee(f,C(R,Pt(R,s)?"warn":"quiet"));const T=S("等待回执",M.length,"quiet","1 小时内");if(T!==null)for(const R of[...M].sort((X,se)=>se.startedAt-X.startedAt))ee(T,C(R,"quiet"));const p=S("免回执",d.length,"muted","不等回执,24h 后自动归档");if(p!==null)for(const R of d)ee(p,C(R,"muted"));const D=S("已过期(免回执)",c.expired.length,"muted","正常记账,不是失败");if(D!==null)for(const R of[...c.expired].sort((X,se)=>se.deadAt-X.deadAt))ee(D,N(R,"muted","过期"));o.length+i.length===0&&(e.appendChild($e("div","wb-led-empty")).textContent="台账为空——没有待回执的任务");const j=n.idempotency,K=(Le=n.reconcile)==null?void 0:Le.state;if(j!==void 0||K!==void 0){const R=$e("details","wb-led-forensics wb-forensics");R.appendChild($e("summary")).textContent="取证";const X=$e("div","wb-led-forensics-body");j!==void 0&&(X.appendChild($e("div")).textContent=`幂等 claims ${j.claimsFresh??0} · replays ${j.replays??0} · conflicts ${j.conflicts??0}`),K!==void 0&&(X.appendChild($e("div")).textContent=`reconcile ${K}`),R.appendChild(X),e.appendChild(R)}const ye=m.length+c.deadLetters.length;return{badge:ye>0?String(ye):"",tone:c.deadLetters.length>0?"danger":q>0||y>0?"warn":void 0}}const It=4e3,Oo=32;function ve(e,t){const n=document.createElement(e);return t!==void 0&&(n.className=t),n}function jt(e,t,n=""){const s=ve("button",`wb-icon-btn wb-chat-act ${n}`.trim());return s.type="button",s.setAttribute("aria-label",e),s.title=e,s.textContent=t,s}function cn(e,t){const n=Math.max(0,Math.round((t-e)/1e3));if(n<60)return"刚刚";const s=Math.round(n/60);if(s<60)return`${s} 分钟前`;const o=Math.round(s/60);return o<48?`${o} 小时前`:`${Math.round(o/24)} 天前`}function Fo(e){return e>=1e6?`${(e/1e6).toFixed(1)} MB`:e>=1e3?`${Math.round(e/1e3)} KB`:`${e} B`}function ln(e){const t=e.kind==="session"||e.kind==="remote"?e.team:void 0;return t!==void 0&&t!==""?t:void 0}function In(e){return e.kind==="remote"?`remote:${e.team}`:`${e.kind}:${e.id}`}function Po(e){let t=null,n=null,s=!1,o=!1;const i=new Map,r=new Map,c=new Map,d=new Map,m=new Set,b=new Map,u=new Map,E=ve("aside","wb-chat");E.setAttribute("aria-label","对话");const M=ve("div","wb-chat-head"),q=jt("返回会话列表","‹","wb-chat-back"),fe=ve("span","wb-chat-dot"),ee=ve("div","wb-chat-titles"),S=ve("span","wb-chat-title"),C=ve("span","wb-chat-sub");ee.append(S,C);const N=jt("刷新对话","↻","wb-chat-refresh"),k=jt("会话详情","ⓘ","wb-chat-info-btn");k.setAttribute("aria-expanded","false");const J=jt("关闭对话","✕","wb-chat-close");M.append(q,fe,ee,N,k,J);const y=ve("div","wb-chat-info");y.hidden=!0;const f=ve("div","wb-chat-thread");f.setAttribute("role","log"),f.setAttribute("aria-live","polite"),f.tabIndex=0;const T=ve("div","wb-chat-notice"),p=ve("div","wb-chat-log"),D=ve("div","wb-chat-sent");f.append(T,p,D);const j=ve("div","wb-chat-foot");E.append(M,y,f,j),q.addEventListener("click",()=>{(t==null?void 0:t.kind)==="peer"&&(t.picked=void 0,Oe())}),N.addEventListener("click",()=>{if(t===null)return;const l=K(t);l!==void 0&&i.delete(l),t.kind==="peer"&&t.picked===void 0&&t.url!==void 0&&c.delete(`peer:${t.url}`),we(!0)}),k.addEventListener("click",()=>{o=!o,y.hidden=!o,k.setAttribute("aria-expanded",String(o))}),J.addEventListener("click",()=>dt()),f.addEventListener("scroll",()=>{const l=t!==null?K(t):void 0;l!==void 0&&r.set(l,f.scrollTop)}),document.addEventListener("keydown",l=>{if(l.key!=="Escape"||!E.classList.contains("is-open"))return;const A=l.target;if(A instanceof HTMLElement){if(!E.contains(A)){const L=A instanceof HTMLTextAreaElement||A instanceof HTMLInputElement||A.isContentEditable,Q=A.closest(".wb-stage-board")!==null;if(L||Q)return}dt()}});function K(l){if(l.kind==="session"||l.kind==="log")return e.sessionLog!==void 0?`local:${l.id}`:void 0;if(l.kind==="remote")return e.remoteSessionLog!==void 0?`remote:${l.team}`:void 0;if(l.picked!==void 0&&l.url!==void 0&&e.remoteSessionLog!==void 0)return`peer:${l.url}:${l.picked}`}function ye(l){var A,L,Q;return l.kind==="session"||l.kind==="log"?((A=e.sessionLog)==null?void 0:A.call(e,l.id))??Promise.resolve({ok:!1,error:"sessionLog unavailable"}):l.kind==="remote"?((L=e.remoteSessionLog)==null?void 0:L.call(e,{team:l.team}))??Promise.resolve({ok:!1,error:"remoteSessionLog unavailable"}):((Q=e.remoteSessionLog)==null?void 0:Q.call(e,{peer:l.url,id:l.picked}))??Promise.resolve({ok:!1,error:"remoteSessionLog unavailable"})}function Le(){const l=t;if(l===null)return;const A=l.kind==="log"||l.kind==="remote"||l.kind==="session"&&l.live===!1;fe.className=`wb-chat-dot ${l.kind==="peer"?"is-peer":A?"is-cold":"is-live"}`,fe.title=l.kind==="peer"?"对端主机":l.kind==="log"?"只读日志":l.kind==="remote"?"远端会话":l.live===!1?"冷会话":"在线",S.textContent=l.kind==="peer"&&l.picked!==void 0?`…${l.picked.slice(-12)}`:l.title,C.textContent=l.kind==="peer"&&l.picked!==void 0?l.title:l.sub,q.hidden=!(l.kind==="peer"&&l.picked!==void 0)}function R(l,A){const L=ve("div","wb-kv");L.appendChild(ve("span","wb-kv-k")).textContent=l,L.appendChild(ve("span","wb-kv-v")).textContent=A,y.appendChild(L)}function X(){var A,L,Q;y.replaceChildren();const l=t;l!==null&&(l.kind==="session"?(R("会话",l.id),l.team!==void 0&&R("路由",l.team),R("来源","本机会话日志")):l.kind==="log"?(R("会话",l.id),R("来源","本机会话日志(不在网络目录)")):l.kind==="remote"?(R("路由",l.team),((A=l.row)==null?void 0:A.origin)!==void 0&&R("来源",l.row.origin),((L=l.row)==null?void 0:L.via)!==void 0&&R("经",l.row.via),((Q=l.row)==null?void 0:Q.workspace)!==void 0&&R("工作区",l.row.workspace)):(R("对端",l.url??l.sub),l.picked!==void 0&&R("会话",l.picked),R("来源","经本机代理读取对端 /a2a/log")))}function se(l){return l.kind==="log"?"只读日志 —— 此会话当前不在网络目录(可能已归档或未入网)。":l.kind==="remote"?e.remoteSessionLog!==void 0?"远端会话 —— 经本机代理从对端 /a2a/log 读取最近对话。":"远端节点的对话记录在对端机器上;本页的代理读取面未启用。":l.kind==="peer"?l.url===void 0||e.remoteSessionLog===void 0?`对端主机节点(${l.sub})—— 会话记录存放在对端机器上,本页只读本机会话日志。`:l.picked===void 0?"对端主机 —— 选择一个会话阅读(经本机代理读取对端 /a2a/log)。":"":e.sessionLog===void 0?"本页未接入会话日志读取,只显示从这里发出的消息。":""}function He(){return f.scrollHeight-f.scrollTop-f.clientHeight<=Oo}function Ne(l){const A=()=>{f.scrollTop=f.scrollHeight};A(),requestAnimationFrame(A)}function ie(l,A){const L=ve("div",`wb-chat-empty${A==="error"?" is-error":""}`);return L.textContent=l,L}function Ce(l,A){const L=l==="user",Q=ve("div",`wb-msg ${L?"wb-msg-user":"wb-msg-assistant"}`),B=ve("span","wb-msg-who");B.textContent=L?"问":"答";const he=ve("div","wb-msg-text");return he.textContent=A,Q.append(B,he),Q}function G(l){if(p.replaceChildren(),l===void 0){p.appendChild(ie("读取中…"));return}if(l.ok!==!0||l.messages===void 0){p.appendChild(ie(`无法读取(${l.error??"未知错误"})`,"error"));return}if(l.messages.length===0){p.appendChild(ie("暂无对话记录"));return}for(const A of l.messages)p.appendChild(Ce(A.role,A.text))}function ne(l,A){if(p.replaceChildren(),A===void 0){p.appendChild(ie("读取中…"));return}if(A.ok!==!0||A.sessions===void 0){p.appendChild(ie(`无法读取(${A.error??"未知错误"})`,"error"));return}if(A.sessions.length===0){p.appendChild(ie("对端没有可读会话"));return}const L=ve("div","wb-chat-sessions"),Q=e.now();for(const B of A.sessions){const he=ve("button","wb-chat-session");he.type="button",he.appendChild(ve("span","wb-chat-session-id")).textContent=`…${B.id.slice(-12)}`;const be=[B.mtimeMs!==void 0?cn(B.mtimeMs,Q):"",Fo(B.sizeBytes)].filter(Boolean).join(" · ");he.appendChild(ve("span","wb-chat-session-meta")).textContent=be,he.title=B.id,he.addEventListener("click",()=>{(t==null?void 0:t.kind)!=="peer"||t.url!==l||(t.picked=B.id,Oe())}),L.appendChild(he)}p.appendChild(L)}function we(l=!1){const A=t;if(A===null)return;if(T.textContent=se(A),T.hidden=T.textContent==="",A.kind==="peer"&&A.picked===void 0){if(A.url===void 0||e.remoteSessionLog===void 0){p.replaceChildren();return}const B=A.url,he=`peer:${B}`;if(!l&&c.has(he)){ne(B,c.get(he));return}c.set(he,void 0),ne(B,void 0),e.remoteSessionLog({peer:B}).then(be=>{c.set(he,be),(t==null?void 0:t.kind)==="peer"&&t.url===B&&t.picked===void 0&&ne(B,be)},be=>{const pe={ok:!1,error:be instanceof Error?be.message:String(be)};c.set(he,pe),(t==null?void 0:t.kind)==="peer"&&t.url===B&&t.picked===void 0&&ne(B,pe)});return}const L=K(A);if(L===void 0){p.replaceChildren(),Ue(!0);return}const Q=()=>{const B=r.get(L);B===void 0||l?Ne():(f.scrollTop=B,requestAnimationFrame(()=>{t!==null&&K(t)===L&&(f.scrollTop=B)}))};if(!l&&i.has(L)&&i.get(L)!==void 0){G(i.get(L)),Ue(!0),Q();return}l&&r.delete(L),i.set(L,void 0),G(void 0),Ue(!0),ye(A).then(B=>{var he;i.set(L,B),(B==null?void 0:B.ok)===!0&&B.messages!==void 0&&((he=e.onTranscript)==null||he.call(e,A,B.messages)),!(t===null||K(t)!==L)&&(G(B),Ue(),Q())},B=>{const he={ok:!1,error:B instanceof Error?B.message:String(B)};i.set(L,he),t!==null&&K(t)===L&&G(he)})}function ce(l){return((n==null?void 0:n.tasks)??[]).filter(A=>A.team===l)}function Z(l){return((n==null?void 0:n.tasksDead)??[]).filter(A=>A.team===l)}let Me="";function Be(l){return l.reason==="fire-forget"?{text:"已过期(免回执)",tone:"muted",hint:"免回执消息到 24h TTL 归档,属正常记账"}:{text:"死信",tone:"danger",hint:l.reason!==void 0&&l.reason!=="unspecified"?`${l.reason}:超过 24h TTL 仍未结算,需在台账清账`:"超过 24h TTL 仍未结算,需在台账清账"}}function Xe(l,A){const L=l.direction==="inbound";if(l.receiptExpected===!1)return{text:L?"来信 · 无需回执":"已送达 · 无回执",tone:"muted",hint:"免回执消息:不等回执,24h 后自动归档"};const Q=Pt(l,A),B=L?Q?"待本机回执 · 超 1 小时":"待本机回执":Q?"陈旧":"待回执",he=l.status!=="pending"?` · ${l.status}`:"";return{text:`${B}${he}`,tone:Q?"warn":"wait",hint:`${L?"对方等待本机回执;":""}${L?"收到":"派发"}于 ${cn(l.startedAt,A)}`}}function We(l,A){const L=`结算于 ${cn(l.resolvedAt,A)}`;if(l.receiptExpected===!1&&l.endedBy==="abandoned")return l.late===!0?{text:"已移出(免回执) · 回执迟到",tone:"warn",hint:`${L};免回执消息本机移出后对方回执才到,结局不改写`}:{text:"已移出(免回执)",tone:"muted",hint:`${L};免回执消息,本机移出台账,不是失败`};if(l.endedBy==="abandoned"||l.endedBy==="cancelled"){const be=l.endedBy==="cancelled"?"撤回":"放弃";return l.late===!0?{text:`已${be} · 回执迟到`,tone:"warn",hint:`${L};本机${be}之后对方回执才到,结局不改写`}:{text:`已${be}`,tone:"muted",hint:`${L};本机${be},未等到回执`}}if(l.endedBy==="echo")return{text:"已结算 · 内容回显",tone:"ok",hint:`${L};对方回了内容但未带正式回执,按内容回显结算`};if(l.endedBy===void 0&&l.outcome==="abandoned")return{text:"已放弃(本机或对方)",tone:"muted",hint:`${L};本机放弃或撤回,或对方回执报告放弃`};const Q=l.summary!==void 0&&l.summary!==""?` · ${l.summary}`:"";if(l.outcome==="abandoned")return{text:"已回执 · 对方放弃",tone:"warn",hint:`${L};对方回执报告放弃${Q}`};const B=hn.find(be=>be.key===l.outcome),he=(B==null?void 0:B.tone)==="completed"?"ok":(B==null?void 0:B.tone)==="failed"?"danger":(B==null?void 0:B.tone)==="rejected"?"warn":"muted";return l.outcome==="unclassified"?{text:"已回执",tone:"ok",hint:`${L};回执未带结论${Q}`}:{text:`已回执 · ${(B==null?void 0:B.label)??l.outcome}`,tone:he,hint:`${L}${Q}`}}function lt(l,A,L){const Q=Z(A).find(be=>be.taskId===l);if(Q!==void 0)return Be(Q);const B=ce(A).find(be=>be.taskId===l);if(B!==void 0)return Xe(B,L);const he=((n==null?void 0:n.archived)??[]).find(be=>be.taskId===l&&be.team===A);return he!==void 0?We(he,L):m.has(l)?{text:"已离开台账",tone:"muted",hint:"已结算、放弃或撤回之一;主机未给出这条的结局(旧主机,或已超出最近 64 条归档)"}:{text:"已派发",tone:"muted",hint:"异步送达;回执到达后进台账"}}function Ct(l){const A=e.now(),L=d.get(l)??[],Q=new Set(L.map(re=>re.taskId).filter(re=>re!==void 0)),B=re=>re!==void 0&&re!==""?re:"(无摘要)",he=ce(l).filter(re=>!Q.has(re.taskId)).map(re=>({at:re.startedAt,side:re.direction==="inbound"?"theirs":"mine",text:B(re.brief),status:Xe(re,A),taskId:re.taskId})),be=Z(l).filter(re=>!Q.has(re.taskId)).map(re=>{var st;const Ee=re.direction??b.get(re.taskId)??(((st=re.peer)==null?void 0:st.startsWith("local:"))===!0?"inbound":void 0);return{at:re.startedAt,side:Ee==="inbound"?"theirs":Ee==="outbound"?"mine":"system",text:B(re.brief),status:Be(re),taskId:re.taskId}}),pe=L.map(re=>({at:re.at,side:"mine",text:re.text,status:re.state==="sending"?{text:"发送中…",tone:"muted"}:re.state==="failed"?{text:`失败:${re.error??"未知原因"}`,tone:"danger"}:re.taskId!==void 0?lt(re.taskId,l,A):{text:"已派发",tone:"muted"},taskId:re.taskId}));return[...he,...be,...pe].sort((re,Ee)=>re.at-Ee.at)}function Ue(l=!1){const A=t,L=A!==null?ln(A):void 0,Q=L!==void 0?Ct(L):[],B=JSON.stringify([L??"",...Q.map(pe=>[pe.taskId??"",pe.side,pe.text,pe.status.text])]);if(!l&&B===Me)return;Me=B;const he=He();if(D.replaceChildren(),Q.length===0)return;const be=ve("div","wb-chat-divider");be.textContent="台账往来 · 异步送达,回执进台账",D.appendChild(be);for(const pe of Q){const re=pe.side==="mine"?"wb-msg wb-msg-user wb-msg-out":pe.side==="theirs"?"wb-msg wb-msg-assistant wb-msg-in":"wb-msg wb-msg-ledger",Ee=ve("div",re);Ee.appendChild(ve("span","wb-msg-who")).textContent=pe.side==="mine"?"我":pe.side==="theirs"?"对方":"台账记录",Ee.appendChild(ve("div","wb-msg-text")).textContent=pe.text;const st=ve("div","wb-msg-meta");pe.taskId!==void 0&&(st.appendChild(ve("span","wb-msg-task")).textContent=pe.taskId);const je=ve("span",`wb-msg-status is-${pe.status.tone}`);je.textContent=pe.status.text,pe.status.hint!==void 0&&(je.title=pe.status.hint),st.appendChild(je),Ee.appendChild(st),D.appendChild(Ee)}he&&Ne()}function ze(l){const A=l.text.value.length;l.note.classList.remove("is-error"),l.note.textContent=A>It*.9?`${A}/${It}`:"Enter 发送 · Shift+Enter 换行",A>It&&l.note.classList.add("is-error"),l.submit.disabled=l.text.value.trim()===""||A>It}function gt(l){l.style.height="auto",l.style.height=`${Math.min(l.scrollHeight,160)}px`}function Mt(l){const A=ve("form","wb-dispatch-form wb-chat-composer"),L=document.createElement("textarea");L.className="wb-dispatch-text",L.rows=1,L.placeholder="发一句话任务给这个节点…",L.setAttribute("aria-label","发送消息");const Q=ve("button","wb-dispatch-submit");Q.type="submit",Q.textContent="发送",Q.setAttribute("aria-label","发送");const B=ve("div","wb-dispatch-note");B.setAttribute("aria-live","polite");const he=ve("div","wb-chat-composer-row");he.append(L,Q),A.append(he,B);const be={team:l,form:A,text:L,note:B,submit:Q};return L.addEventListener("input",()=>{gt(L),ze(be)}),L.addEventListener("keydown",pe=>{pe.key!=="Enter"||pe.shiftKey||pe.ctrlKey||pe.altKey||pe.metaKey||pe.isComposing||(pe.preventDefault(),A.requestSubmit())}),A.addEventListener("submit",pe=>{pe.preventDefault();const re=L.value.trim();if(re===""||re.length>It||e.dispatchQuick===void 0)return;const Ee={text:re,at:e.now(),state:"sending"},st=d.get(l)??[];st.push(Ee),d.set(l,st),L.value="",gt(L),ze(be),L.focus({preventScroll:!0}),Ue(),Ne(),e.dispatchQuick(l,re).then(je=>je,je=>({ok:!1,error:je instanceof Error?je.message:String(je)})).then(je=>{je.ok===!0?(Ee.state="sent",Ee.taskId=je.task_id,B.classList.remove("is-error"),B.textContent=`已派发${je.task_id!==void 0?` · ${je.task_id}`:""} · 回执将入台账`):(Ee.state="failed",Ee.error=je.error??"未知原因",L.value===""&&(L.value=re,gt(L)),B.classList.add("is-error"),B.textContent=`失败:${Ee.error}`,Q.disabled=L.value.trim()===""),t!==null&&ln(t)===l&&Ue()})}),ze(be),be}function Ie(){const l=t;if(j.replaceChildren(),l===null)return;const A=ln(l);if(A!==void 0&&e.dispatchQuick!==void 0){let Q=u.get(A);Q===void 0&&(Q=Mt(A),u.set(A,Q)),j.appendChild(Q.form),s&&(s=!1,Q.text.focus({preventScroll:!0}));return}s=!1;const L=ve("div","wb-chat-readonly");L.textContent=l.kind==="log"?"只读日志:此会话不在网络目录,不能从这里派发。":l.kind==="peer"?"对端主机:选择会话阅读;要派发请打开它的远端会话节点。":"此节点没有可派发的路由。",j.appendChild(L)}function Oe(){Le(),X(),we(),Ie()}function Ze(l){const A=t!==null&&In(t)===In(l);t=l,A||(s=!0),Oe(),E.classList.add("is-open")}function dt(){t=null,E.classList.remove("is-open")}function St(l){n=l;for(const L of(l==null?void 0:l.tasks)??[])m.add(L.taskId),b.set(L.taskId,L.direction==="inbound"?"inbound":"outbound");const A=t;if(A!==null){if(A.kind==="session"&&l!==null){const L=(l.sessions??[]).find(Q=>Q.id===A.id);L!==void 0&&(A.title=rt(L),A.live=L.live)}Le(),Ue()}}return{root:E,open:Ze,close:dt,isOpen:()=>t!==null,update:St}}function Ro(e,t){const n=document.createElement("form");n.className="wb-cli-home";const s=document.createElement("button");s.type="button",s.textContent="指定 home",s.className="wb-member-submit";const o=document.createElement("select");o.className="wb-member-pick",o.setAttribute("aria-label","选择 CLI home 主机"),o.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 d;if(!c){c=!0,s.disabled=!0,i.disabled=!0,r.textContent="正在现读主机名片…";try{const m=await e();if(!m.ok)throw Error(m.error??"候选读取失败");if(m.held){s.hidden=!0,o.hidden=!0,i.hidden=!0,o.replaceChildren(),r.textContent="本机持有,无需指定";return}o.replaceChildren(new Option("请选择 home 主机…","",!0,!0));for(const u of m.homes??[])o.appendChild(new Option(u,u));o.hidden=!1,i.hidden=!1,s.textContent="刷新候选";const b=((d=m.homes)==null?void 0:d.length)??0;r.textContent=(m.unreadable?"有 "+m.unreadable+" 台对端名片读不到;":"")+(b>1?"多台已链接主机列出该句柄,请显式选择。":b===1?"找到 1 台已链接主机;仍需你显式确认。":"当前没有已链接且列出该句柄的可选主机。")}catch(m){r.textContent="读取失败:"+String(m),o.hidden=!0,i.hidden=!0}finally{c=!1,s.disabled=!1}}}),o.addEventListener("change",()=>{i.disabled=c||o.value===""}),n.addEventListener("submit",async d=>{if(d.preventDefault(),!(c||o.value==="")){c=!0,s.disabled=!0,o.disabled=!0,i.disabled=!0;try{r.textContent=await t(o.value)?"home 已指定:"+o.value:"指定失败:主机可能已离线或不再列出该句柄,请刷新后重选。"}catch(m){r.textContent="指定失败:"+String(m)}finally{c=!1,s.disabled=!1,o.disabled=!1,i.disabled=o.value===""}}}),n.append(s,o,i,r),n}const io="dsh-a2a.rail.tab";function Do(){try{return window.localStorage.getItem(io)}catch{return null}}function Ho(e){try{window.localStorage.setItem(io,e)}catch{}}function jo(e,t={}){var ee;const n=document.createElement("aside");n.className="wb-rail";const s=document.createElement("div");s.className="wb-tabs",s.setAttribute("role","tablist"),s.setAttribute("aria-label","工作台侧栏");const o=document.createElement("div");o.className="wb-tabpanels",n.append(s,o);const i=new Map,r=new Map,c=new Map,d=new Set;for(const S of e){const C=document.createElement("button");C.type="button",C.className="wb-tab",C.id=`wb-tab-${S.key}`,C.dataset.sec=S.key,C.setAttribute("role","tab"),C.setAttribute("aria-controls",`wb-panel-${S.key}`);const N=document.createElement("span");N.className="wb-tab-label",N.textContent=S.label;const k=document.createElement("span");k.className="wb-tab-badge",C.append(N,k),C.addEventListener("click",()=>M(S.key)),s.appendChild(C);const J=document.createElement("section");J.className="wb-tabpanel",J.id=`wb-panel-${S.key}`,J.dataset.sec=S.key,J.setAttribute("role","tabpanel"),J.setAttribute("aria-labelledby",C.id),J.tabIndex=-1,o.appendChild(J),i.set(S.key,C),r.set(S.key,J),c.set(S.key,k)}const m=()=>e.map(S=>S.key).filter(S=>!d.has(S)),b=Do();let u=((ee=e.find(S=>S.key===b))==null?void 0:ee.key)??e[0].key;s.addEventListener("keydown",S=>{const C=m(),N=C.indexOf(u);let k;S.key==="ArrowRight"?k=C[(N+1)%C.length]:S.key==="ArrowLeft"?k=C[(N-1+C.length)%C.length]:S.key==="Home"?k=C[0]:S.key==="End"&&(k=C[C.length-1]),k!==void 0&&(S.preventDefault(),M(k,{focus:!0}))});function E(){for(const S of e){const C=S.key===u,N=i.get(S.key);N.setAttribute("aria-selected",String(C)),N.tabIndex=C?0:-1,N.classList.toggle("is-active",C),N.hidden=d.has(S.key),r.get(S.key).hidden=!C}}function M(S,C={}){var k;if(d.has(S))return;const N=S!==u;u=S,Ho(S),E(),C.focus===!0&&i.get(S).focus(),N&&((k=t.onChange)==null||k.call(t,S))}function q(S,C,N){const k=c.get(S);k.textContent=C,k.className=`wb-tab-badge${N!==void 0?` is-${N}`:""}`}function fe(S,C){C?d.add(S):d.delete(S),d.has(u)&&(u=m()[0]??e[0].key),E()}return E(),{root:n,panel:S=>r.get(S),select:M,selected:()=>u,setBadge:q,setHidden:fe}}const Bo=[{key:"all",label:"全部",hint:"不过滤:目录全部条目"},{key:"local",label:"本机",hint:"本机会话节点(现场 + 冷启动)"},{key:"canvas",label:"队",hint:"画布队(人类手工分配的组队)"},{key:"remote",label:"远端",hint:"远端会话队(来自对端卡片)"},{key:"logs",label:"日志",hint:"本机日志:不在网络目录里的会话档案"}];function nt(e,t){const n=document.createElement(e);return t!==void 0&&(n.className=t),n}function Bt(...e){const t=[];for(const n of e)n!==void 0&&(typeof n=="string"?t.push(n):t.push(...n));return t.join(" ").toLowerCase()}function Yo(e,t){const n=Math.max(0,Math.round((t-e)/1e3));if(n<60)return"刚刚";const s=Math.round(n/60);if(s<60)return`${s} 分钟前`;const o=Math.round(s/60);return o<48?`${o} 小时前`:`${Math.round(o/24)} 天前`}function Tn(e){return e>=1e6?`${(e/1e6).toFixed(1)} MB`:e>=1e3?`${Math.round(e/1e3)} KB`:`${e} B`}function Wo(e,t){const n=new Date(t);n.setHours(0,0,0,0);const s=n.getTime();return e>=s?"今天":e>=s-864e5?"昨天":"更早"}function Ko(e,t){var N,k,J;e.replaceChildren();const{state:n,search:s,filter:o}=t,i=s!==""||o!=="all",r=(y,f)=>(o==="all"||o===y)&&(s===""||f.includes(s)),c=(y,f,T)=>{const p=nt("div","wb-dir-group"),D=nt("div","wb-dir-head");return D.appendChild(nt("span","wb-dir-head-label")).textContent=`${y} · ${f}`,T!==void 0&&(D.appendChild(nt("span","wb-dir-head-note")).textContent=T),p.appendChild(D),e.appendChild(p),p},d=(y,f,T,p,D,j,K)=>{const ye=nt("button","wb-item");ye.type="button",ye.appendChild(nt("span",`wb-dot ${f}`)).textContent=T;const Le=nt("span","wb-item-text");return Le.appendChild(nt("span","wb-item-label")).textContent=p,D!==""&&(Le.appendChild(nt("span","wb-item-sub")).textContent=D),ye.appendChild(Le),K!==void 0&&(ye.title=K),ye.addEventListener("click",j),y.appendChild(ye),ye},m=(y,f)=>{if(f===void 0||f.length===0)return;const T=nt("span","wb-item-badge"),p=f.map(D=>D.slice(D.lastIndexOf("/")+1));T.textContent=`▤ ${p.slice(0,2).join(" ")}${p.length>2?` +${p.length-2}`:""}`,T.title=`画布队:${f.join(" · ")}`,y.appendChild(T)},b=(n.sessions??[]).filter(y=>r("local",Bt(rt(y),y.team,y.label,y.id,y.canvasTeams))),u=b.filter(y=>y.live===!0),E=b.filter(y=>y.live!==!0);if(b.length>0){const y=c("本机会话",b.length,E.length>0?`${u.length} 在线 · ${E.length} 冷`:void 0);for(const f of[...u,...E]){const T=f.live===!0,p=f.nodePromptMissing===!0,D=d(y,T?"wb-dot-live":"wb-dot-cold",T?"●":"○",rt(f),T?f.team:`冷 · ${f.team}`,()=>t.openChat({kind:"session",id:f.id,title:rt(f),sub:f.team,team:f.team,live:f.live}),f.id);if(p){D.classList.add("is-node-prompt-missing");const j=nt("span","wb-node-warning");j.textContent="本会话的组装不含节点段",(N=D.querySelector(".wb-item-text"))==null||N.appendChild(j)}m(D,f.canvasTeams)}}const M=(((k=n.canvas)==null?void 0:k.teams)??[]).filter(y=>r("canvas",Bt(y.name,y.team,y.members.map(f=>f.team??f.id))));if(M.length>0){const y=c("画布队",M.length);for(const f of M){const T=f.members.filter(p=>p.remote===!0).length;d(y,"wb-dot-canvas","▤",f.name,`${f.members.length} 成员${T>0?` · ${T} 远端`:""}`,()=>t.selectCanvas(f),f.team)}}const q=(n.remote??[]).filter(y=>r("remote",Bt(rt(y),y.team,y.origin,y.workspace,y.canvasTeams)));if(q.length>0){const y=c("远端节点",q.length);for(const f of q){const T=d(y,"wb-dot-remote","◇",rt(f),f.origin!==void 0&&f.origin!==""?f.origin:f.team,()=>t.openChat({kind:"remote",team:f.team,title:rt(f),sub:f.team,row:f}),f.team);if(f.unreachable===!0){T.classList.add("is-unreachable");const p=nt("span","wb-unreachable-note");p.textContent="对端未应答(显示的是最后已知状态)",(J=T.querySelector(".wb-item-text"))==null||J.appendChild(p)}m(T,f.canvasTeams)}}const fe=new Set((n.sessions??[]).map(y=>y.id)),ee=t.logs.filter(y=>!fe.has(y.id)&&r("logs",Bt(y.id,t.titles.get(y.id))));if(ee.length>0){const y=t.logTotal!==void 0&&t.logTotal>t.logs.length,f=c("本机日志",ee.length,y?`显示 ${t.logs.length} / 共 ${t.logTotal}`:void 0);let T="";for(const p of[...ee].sort((D,j)=>j.mtimeMs-D.mtimeMs)){const D=Wo(p.mtimeMs,t.now);D!==T&&(T=D,f.appendChild(nt("div","wb-dir-day")).textContent=D);const j=t.titles.get(p.id),K=d(f,"wb-dot-log","❐",j??`会话 …${p.id.slice(-12)}`,`${Yo(p.mtimeMs,t.now)} · ${Tn(p.sizeBytes)}`,()=>t.openChat({kind:"log",id:p.id,title:j??`…${p.id.slice(-12)}`,sub:"本机日志"}),`${p.id}
3
- ${new Date(p.mtimeMs).toLocaleString()} · ${Tn(p.sizeBytes)}`);j===void 0&&K.classList.add("is-untitled")}}b.length+M.length+q.length+ee.length===0&&(e.appendChild(nt("div","wb-dir-empty")).textContent=i?"无匹配条目":"目录为空");const S=n.sessions??[];return`${S.filter(y=>y.live===!0).length}/${S.length}`}const ro="dsh-a2a.logtitles",Xo=300,_n=60;function Uo(){try{const e=window.localStorage.getItem(ro),t=e===null?null:JSON.parse(e);if(t!==null&&typeof t=="object")return new Map(Object.entries(t).filter(n=>typeof n[1]=="string"))}catch{}return new Map}function qo(e,t,n){const s=n.find(r=>r.role==="user"&&r.text.trim()!=="")??n.find(r=>r.text.trim()!=="");if(s===void 0)return!1;const o=s.text.trim().split(`
4
- `)[0].trim(),i=o.length>_n?`${o.slice(0,_n-1)}…`:o;if(e.get(t)===i)return!1;for(e.delete(t),e.set(t,i);e.size>Xo;)e.delete(e.keys().next().value);try{window.localStorage.setItem(ro,JSON.stringify(Object.fromEntries(e)))}catch{}return!0}function mt(e){return e.name??e.team??e.label??""}function Tt(e,t){const n=Math.max(0,Math.round((t-e)/1e3));if(n<90)return`${n}s`;const s=Math.round(n/60);if(s<90)return`${s}m`;const o=Math.round(s/60);return o<48?`${o}h`:`${Math.round(o/24)}d`}function _(e,t){const n=document.createElement(e);return t!==void 0&&(n.className=t),n}function On(e,t,n){const s=_("div","wb-kv");s.appendChild(_("span","wb-kv-k")).textContent=t,s.appendChild(_("span","wb-kv-v")).textContent=n,e.appendChild(s)}function zo(e){try{return new URL(e).host}catch{return e}}const Jo=[{key:"directory",label:"目录"},{key:"hosts",label:"主机"},{key:"ledger",label:"台账"},{key:"activity",label:"活动"},{key:"plan",label:"规划"}];function Vo(e){const t=e.board;let n="data",s,o=null,i="",r="all",c=null;const d=new Map;let m=null,b=[],u;const E=Uo();let M=!1;const q=_("div","wb");q.setAttribute("data-testid","wb-root");const fe=_("header","wb-header"),ee=_("button","wb-icon-btn wb-menu");ee.type="button",ee.dataset.testid="wb-menu",ee.setAttribute("aria-label","打开目录抽屉"),ee.textContent="☰",ee.addEventListener("click",()=>q.classList.toggle("is-rail-open")),fe.appendChild(ee);const S=_("div","wb-title");S.appendChild(_("span","wb-title-main")).textContent="A2A 工作台";const C=_("span","wb-badge");S.appendChild(C),fe.appendChild(S);const N=_("button","wb-icon-btn wb-owner-btn");N.type="button",N.dataset.testid="wb-owner-btn",N.setAttribute("aria-label","主人设置(三键面板)"),N.title="主人设置:入网白名单 / 可见性 / 发布",N.textContent="⚙",N.addEventListener("click",()=>{l=!l,L()}),fe.appendChild(N);const k=_("div","wb-header-stats");fe.appendChild(k);const J=_("button","wb-icon-btn wb-rail-toggle");J.type="button",J.dataset.testid="wb-rail-toggle",J.setAttribute("aria-label","折叠/展开侧栏"),J.textContent="◧",J.addEventListener("click",()=>{q.classList.toggle("is-rail-collapsed"),n==="canvas"&&t!==void 0&&t.activate()}),fe.appendChild(J);const y=_("div","wb-body"),f=jo(Jo),T=f.root,p=_("div","wb-directory"),D=_("div","wb-dir-tools"),j=document.createElement("input");j.className="wb-search",j.type="search",j.placeholder="搜索:名称 / 队 / 会话 / 节点",j.setAttribute("aria-label","统一搜索目录"),j.addEventListener("input",()=>{i=j.value.trim().toLowerCase(),We()}),D.appendChild(j);const K=_("div","wb-filters");for(const x of Bo){const w=_("button","wb-filter");w.type="button",w.textContent=x.label,w.dataset.filter=x.key,w.title=x.hint,w.addEventListener("click",()=>{r=x.key,We()}),K.appendChild(w)}D.appendChild(K),f.panel("directory").appendChild(D),f.panel("directory").appendChild(p);const ye=_("section","wb-pane"),Le=_("section","wb-pane"),R=_("section","wb-pane"),X=_("section","wb-pane"),se=[["ledger",ye],["activity",Le],["plan",R],["hosts",X]],He=_("main","wb-stage"),Ne=_("section","wb-stage-board");t!==void 0&&(Ne.appendChild(t.root),He.appendChild(Ne));const ie=_("div","wb-data"),Ce=_("aside","wb-inspector"),G=_("div","wb-inspector-head");G.appendChild(_("span","wb-inspector-title")).textContent="详情";const ne=_("button","wb-icon-btn");ne.type="button",ne.setAttribute("aria-label","关闭详情"),ne.textContent="✕",ne.addEventListener("click",()=>Xe(void 0)),G.appendChild(ne),Ce.appendChild(G);const we=_("div","wb-inspector-body");Ce.appendChild(we);const ce=Po({now:e.now,sessionLog:e.sessionLog,remoteSessionLog:e.remoteSessionLog,dispatchQuick:e.dispatchQuick,onTranscript:(x,w)=>{x.kind!=="log"&&x.kind!=="session"||qo(E,x.id,w)&&We()}});He.appendChild(ie),y.appendChild(T),y.appendChild(He),y.appendChild(Ce),y.appendChild(ce.root),q.appendChild(fe),q.appendChild(y);function Z(x){for(const[w,H]of se){const $=x==="canvas"?f.panel(w):ie;f.setHidden(w,x!=="canvas"),H.parentElement!==$&&$.appendChild(H)}}function Me(){const w=t!==void 0&&t.available()?"canvas":"data";q.dataset.mode=w,Ne.classList.toggle("is-hidden",w!=="canvas"),ie.classList.toggle("is-hidden",w==="canvas"),Z(w),w!==n&&(t!==void 0&&(w==="canvas"?t.activate():t.deactivate()),n=w)}function Be(x){for(;x.firstChild!==null;)x.removeChild(x.firstChild);return x}function Xe(x){s=x,((x==null?void 0:x.kind)!=="canvas"||(c==null?void 0:c.name)!==x.row.name)&&(c=null),(x==null?void 0:x.kind)!=="canvas"&&(m=null),B(),q.classList.remove("is-rail-open")}function We(){for(let w=0;w<K.children.length;w++){const H=K.children[w];H.classList.toggle("is-active",H.dataset.filter===r)}if(o===null){p.replaceChildren(_("div","wb-muted")),p.firstElementChild.textContent="载入中…",f.setBadge("directory","");return}const x=Ko(p,{state:o,logs:b,logTotal:u,titles:E,search:i,filter:r,now:e.now(),openChat:pe,selectCanvas:w=>Xe({kind:"canvas",row:w})});f.setBadge("directory",x)}function lt(){const x=Be(X);if(o===null){f.setBadge("hosts","");return}const w=e.now(),H=[...o.peers??[]].sort(($,I)=>{const O=oe=>oe.link==="linked"?0:1;return O($)-O(I)||(I.score??0)-($.score??0)});if(f.setBadge("hosts",H.length>0?`${H.filter($=>$.link==="linked").length}/${H.length}`:""),H.length===0){x.appendChild(_("div","wb-nodelist-empty")).textContent="暂无 tracked peer——配 peers 种子或等 referral 到达";return}for(const $ of H){const I=zo($.url),O=_("div","wb-host-row"),oe=_("span","wb-host-lamp"),le=$.lastContactAt,V=le===void 0?void 0:w-le,xe=$.lastContactOk;V===void 0?oe.classList.add("is-unknown"):xe===!1&&V<=5*6e4?oe.classList.add("is-fail"):V<=6e4?oe.classList.add("is-live"):V<=5*6e4?oe.classList.add("is-warm"):oe.classList.add("is-cold"),oe.title=le===void 0?"尚无接触记录":`最近接触 ${Tt(le,w)}${xe===!1?"(失败)":xe===!0?"(成功)":""}`,O.appendChild(oe),O.appendChild(_("span","wb-host-name")).textContent=$.name!==void 0&&$.name!==""?$.name:I;const Fe=_("span",`wb-host-badge ${$.link==="linked"?"is-linked":"is-stranger"}`);Fe.textContent=`${$.link==="linked"?"linked":"stranger"} ${$.verified===!0?"✓":"✗"}`,Fe.title=$.link==="linked"?`已建立运营者链接(互种或 canvas 引用);${$.verified===!0?"验签有效":"尚未持有验签通过的卡片"}`:"无运营者关系(验签 ≠ 关系)",O.appendChild(Fe),$.version!==void 0&&$.version!==""&&(O.appendChild(_("span","wb-host-ver")).textContent=$.version),O.appendChild(_("span","wb-host-url mono")).textContent=I,O.setAttribute("role","button"),O.tabIndex=0,O.title=`${$.url} · score ${String($.score??0)}`;const z=()=>{pe({kind:"peer",id:`peer-${I}`,title:$.name!==void 0&&$.name!==""?$.name:I,sub:I,url:$.url})};O.addEventListener("click",z),O.addEventListener("keydown",Re=>{(Re.key==="Enter"||Re.key===" ")&&(Re.preventDefault(),z())}),x.appendChild(O)}}function Ct(){if(o===null){ye.replaceChildren(),f.setBadge("ledger","");return}const x=o,w=$=>{const I=(x.sessions??[]).find(oe=>oe.team===$);if(I!==void 0)return{kind:"session",id:I.id,title:mt(I),sub:I.team,team:I.team,live:I.live};const O=(x.remote??[]).find(oe=>oe.team===$);if(O!==void 0)return{kind:"remote",team:O.team,title:mt(O),sub:O.team,row:O}},H=_o(ye,{state:x,now:e.now(),abandon:($,I)=>e.abandon($,I),canOpenTeam:$=>w($)!==void 0,openTeam:$=>{const I=w($);return I===void 0?!1:(pe(I),!0)}});f.setBadge("ledger",H.badge,H.tone)}function Ue(x,w,H){Ut(x.appendChild(_("span","wb-row-team")),w,H)}function ze(){var oe;const x=Be(Le);if(o===null)return;const w=e.now(),H=o.inFlight??[];f.setBadge("activity",H.length>0?String(H.length):"",H.length>0?"accent":void 0);const $=_("div","wb-pane-head");if($.textContent=`在途 ${H.length} · 活动 ${((oe=o.activity)==null?void 0:oe.length)??0}`,x.appendChild($),H.length>0){const le=_("div","wb-pane-subhead");le.textContent="在途路由",x.appendChild(le);for(const V of H){const xe=_("div","wb-row");xe.appendChild(_("span","wb-row-dir")).textContent="→",Ue(xe,o,V.team),xe.appendChild(_("span","wb-row-meta")).textContent=`${V.peer} · ${Tt(V.startedAt,w)}`,x.appendChild(xe)}}const I=_("div","wb-pane-subhead");I.textContent="活动环(最新在前)",x.appendChild(I);const O=o.activity??[];if(O.length===0){x.appendChild(_("div","wb-muted")).textContent="暂无活动";return}for(const le of O){const V=_("div","wb-row"),xe=_("span","wb-row-dir");xe.textContent=le.dir==="fwd"?"⇢":le.dir==="out"?"→":"←",le.ok!==!0&&xe.classList.add("is-fail"),V.appendChild(xe),Ue(V,o,le.team),V.appendChild(_("span","wb-row-meta")).textContent=`${le.peer} · ${Tt(le.ts,w)}`,V.appendChild(_("span","wb-row-badges")).textContent=le.ok===!0?"":"失败",x.appendChild(V)}}function gt(x){var oe,le;const w=e.now(),H=[],$=pn(x,w);$.deadLetters.length>0&&H.push({severity:"high",text:`清账 ${$.deadLetters.length} 条死信(目标早已离开或死信化,无回执可期)`});for(const V of $.stale){const xe=V.brief===void 0||V.brief===""?"":`「${V.brief}」`;H.push({severity:"normal",text:`催办 ${V.taskId} → ${Lo(x,V.team)}(等待 ${Tt(V.startedAt,w)} 无回执)${xe}`,brief:`a2a_route 催收回执:task ${V.taskId}(team ${V.team})${xe===""?"":`原任务「${V.brief}」`}已派发 ${Tt(V.startedAt,w)},请回报结果或回执。`})}const I=(x.sessions??[]).filter(V=>V.live!==!0).map(V=>mt(V));if(I.length>0){const V=I.slice(0,3).join("、")+(I.length>3?` 等 ${I.length} 个`:"");H.push({severity:"normal",text:`冷会话 ${I.length} 个(${V}):在 GUI 打开即可唤醒加入面`})}for(const V of((oe=x.reconcile)==null?void 0:oe.rows)??[])if(V.needsRepair===!0){const xe=(x.sessions??[]).find(z=>z.id===V.id),Fe=xe!==void 0?`${mt(xe)}(${V.id})`:V.id;H.push({severity:"high",text:`reconcile 需修复:${Fe} ${V.error}`})}const O=((le=x.idempotency)==null?void 0:le.conflicts)??0;return O>0&&H.push({severity:"high",text:`幂等冲突 ${O} 例:人工核查 UNIQUE-ization 流量`}),H}function Mt(){const x=Be(R);if(o===null)return;const w=gt(o);f.setBadge("plan",w.length>0?String(w.length):"",w.some(I=>I.severity==="high")?"danger":void 0);const H=_("div","wb-pane-head");H.textContent=w.length===0?"网络健康——无待办行动":`待办行动 ${w.length}`,x.appendChild(H);for(const I of w){const O=_("div",`wb-action${I.severity==="high"?" wb-action-high":""}`);if(O.appendChild(_("span","wb-action-text")).textContent=I.text,I.brief!==void 0){const oe=_("button","wb-btn");oe.type="button",oe.textContent="复制催办",oe.addEventListener("click",()=>e.copy(I.brief??"")),O.appendChild(oe)}x.appendChild(O)}const $=_("div","wb-pane-subhead");$.textContent="派单起草(复制后在任一会话粘贴执行)",x.appendChild($),x.appendChild(Ie)}const Ie=_("div","wb-draft"),Oe=document.createElement("select");Oe.className="wb-select";const Ze=document.createElement("textarea");Ze.className="wb-textarea",Ze.rows=3,Ze.placeholder="任务正文:目标、验收、期限…";const dt=_("button","wb-btn wb-btn-primary");dt.type="button",dt.textContent="复制任务书",dt.addEventListener("click",()=>{const x=Oe.value,w=Ze.value.trim();x===""||w===""||e.copy(`a2a_route 派单 → ${x}:
5
- ${w}`)}),Ie.appendChild(Oe),Ie.appendChild(Ze),Ie.appendChild(dt);function St(){var I;const x=Oe.value;Be(Oe);const w=document.createElement("option");if(w.value="",w.textContent="选择目标队…",Oe.appendChild(w),o===null)return;const H=o,$=new Map;for(const O of H.sessions??[])O.team!==void 0&&O.team!==""&&$.set(O.team,`${mt(O)}(会话队)`);for(const O of((I=H.canvas)==null?void 0:I.teams)??[])$.set(O.team,`${O.name}(canvas 队)`);for(const O of H.remote??[])$.set(O.team,`${mt(O)}(远端)`);for(const[O,oe]of $){const le=document.createElement("option");le.value=O,le.textContent=`${oe} · ${O}`,Oe.appendChild(le)}x!==""&&$.has(x)&&(Oe.value=x)}let l=!1,A=null;function L(){var x;B(),l&&((x=e.ownerSettingsRead)==null||x.call(e).then(w=>{if(l){if(w.ok!==!0){A=null,B();return}A={teamJoinAllowlist:w.teamJoinAllowlist??[],teamScopeInfo:w.teamScopeInfo!==!1,announce:w.announce===!0,announceRestartPending:w.announceRestartPending===!0},B()}}))}function Q(x){const w=_("div","wb-card"),H=_("div","wb-inspector-head");H.appendChild(_("span","wb-inspector-title")).textContent="主人设置";const $=_("button","wb-icon-btn");if($.type="button",$.setAttribute("aria-label","关闭主人设置"),$.textContent="✕",$.addEventListener("click",()=>{l=!1,B()}),H.appendChild($),w.appendChild(H),e.ownerSettingsRead===void 0){const ge=_("div","wb-hint");ge.textContent="此宿主未提供主人设置面(旧版本)——升级后可用。",w.appendChild(ge),x.appendChild(w);return}if(A===null){const ge=_("div","wb-hint");ge.textContent="读取中…",w.appendChild(ge),x.appendChild(w);return}const I=A,O=_("div","wb-side-head");O.textContent="入网白名单(精确团队名)",w.appendChild(O);for(const ge of I.teamJoinAllowlist){const Ve=_("div","wb-member-row");Ve.appendChild(_("span","wb-member-label")).textContent=ge;const pt=_("button","wb-member-remove");pt.type="button",pt.textContent="移除",pt.addEventListener("click",()=>{var At;(At=e.ownerSettingsWrite)==null||At.call(e,{teamJoinAllowlist:I.teamJoinAllowlist.filter(rn=>rn!==ge)}).then(()=>L())}),Ve.appendChild(pt),w.appendChild(Ve)}const oe=_("div","wb-member-add"),le=_("input","wb-member-manual");le.type="text",le.placeholder="dsh/团队名(精确,无通配)",le.setAttribute("aria-label","新增白名单团队名");const V=_("button","wb-member-submit");V.type="button",V.textContent="加入";const xe=()=>{var Ve;const ge=le.value.trim();ge===""||I.teamJoinAllowlist.includes(ge)||(Ve=e.ownerSettingsWrite)==null||Ve.call(e,{teamJoinAllowlist:[...I.teamJoinAllowlist,ge]}).then(()=>L())};V.addEventListener("click",xe),le.addEventListener("keydown",ge=>{ge.key==="Enter"&&xe()}),oe.append(le,V),w.appendChild(oe);const Fe=_("div","wb-side-head");Fe.textContent="目录可见性(teamScopeInfo)",w.appendChild(Fe);const z=_("div","wb-member-row"),Re=_("button","wb-member-submit");Re.type="button",Re.textContent=I.teamScopeInfo?"已开:仅显示已加入团队(点击放开为全舰队可见)":"已关:全舰队可见(点击收窄为已加入团队)",Re.addEventListener("click",()=>{var ge;(ge=e.ownerSettingsWrite)==null||ge.call(e,{teamScopeInfo:!I.teamScopeInfo}).then(()=>L())}),z.appendChild(Re),w.appendChild(z);const Je=_("div","wb-hint");Je.textContent="精度说明:teamScopeInfo 只管「目录显示范围」。关上它不会解锁任何通信准入——会话入网(S3)与目标级路由(F5)规则原样生效。",w.appendChild(Je);const Qe=_("div","wb-side-head");Qe.textContent="节点发布(announce)",w.appendChild(Qe);const ut=_("div","wb-member-row"),qe=_("button","wb-member-submit");if(qe.type="button",qe.textContent=I.announce?"已开:本节点发布签名卡(点击关闭)":"已关:本节点不发布(点击开启——重启宿主后生效)",qe.addEventListener("click",()=>{var ge;(ge=e.ownerSettingsWrite)==null||ge.call(e,{announce:!I.announce}).then(()=>L())}),ut.appendChild(qe),w.appendChild(ut),I.announceRestartPending){const ge=_("div","wb-hint");ge.textContent="有 announce 变更待生效:重启宿主后按新配置发布。",w.appendChild(ge)}x.appendChild(w)}function B(){var $;const x=Be(we);if(l){Ce.classList.add("is-open"),Q(x);return}if(Ce.classList.toggle("is-open",s!==void 0),s===void 0)return;const w=s,H=_("div","wb-card");if(w.kind==="canvas"){const I=((($=o==null?void 0:o.canvas)==null?void 0:$.teams)??[]).find(z=>z.name===w.row.name)??w.row;On(H,"Canvas 队",I.name),On(H,"路由队",I.team);const O=_("div","wb-side-head");if(O.textContent=`成员 · ${I.members.length}`,H.appendChild(O),I.members.length===0){const z=_("div","wb-muted");z.textContent="空队——用下方表单添加成员",H.appendChild(z)}for(const z of I.members){const Re=_("div","wb-member-row"),Je=z.cliHeld===!0?"本机持有,无需指定":z.remote===!0?z.cliHome===null?"◇ 远端 · home 未确定":"◇ 远端":z.live===!0?"● 现场":z.joined===!0?"○ 冷启":"· 未入网";Re.appendChild(_("span","wb-member-dot")).textContent=Je;const Qe=_("span","wb-member-label"),ut=((o==null?void 0:o.sessions)??[]).find(ge=>ge.id===z.id);Qe.textContent=z.remote===!0?z.id:ut!==void 0?mt(ut):z.id,Qe.title=z.cliHeld===!0?"本机持有,无需指定":z.cliHome!==void 0?z.cliHome??"home 未确定":z.team??z.id,Re.appendChild(Qe);const qe=_("button","wb-member-remove");if(qe.type="button",qe.textContent="移除",qe.addEventListener("click",async()=>{qe.disabled=!0,await e.canvasOp("remove-member",I.name,z.id)||(qe.disabled=!1)}),Re.appendChild(qe),H.appendChild(Re),z.cliHome===null&&z.cliHeld!==!0&&e.cliHomeOptions!==void 0){const ge=JSON.stringify([I.name,z.id]);let Ve=d.get(ge);Ve===void 0&&(Ve=Ro(()=>e.cliHomeOptions(I.name,z.id),pt=>e.canvasOp("add-member",I.name,z.id,pt)),d.set(ge,Ve)),H.appendChild(Ve)}}if((c==null?void 0:c.name)!==I.name){const z=_("form","wb-member-add"),Re=document.createElement("select");Re.className="wb-member-pick",Re.setAttribute("aria-label","选择成员");const Je=document.createElement("input");Je.type="text",Je.className="wb-member-manual",Je.placeholder="或输入远端句柄 zone/id8",Je.setAttribute("aria-label","远端成员句柄");const Qe=_("button","wb-member-submit");Qe.type="submit",Qe.textContent="添加",z.appendChild(Re),z.appendChild(Je),z.appendChild(Qe),z.addEventListener("submit",async ut=>{ut.preventDefault();const qe=Je.value.trim(),ge=qe!==""?qe:Re.value;if(ge==="")return;Qe.disabled=!0;const Ve=await e.canvasOp("add-member",I.name,ge);Qe.disabled=!1,Ve&&(Je.value="")}),c={name:I.name,form:z,pick:Re,manual:Je}}const oe=c.pick,le=oe.value;Be(oe),oe.appendChild(new Option("本机会话(现场/冷启动)…","",!0,!0));const V=new Set(I.members.map(z=>z.id));for(const z of(o==null?void 0:o.sessions)??[])V.has(z.id)||oe.appendChild(new Option(`${mt(z)} — 本机`,z.id));let xe=!1;for(const z of(o==null?void 0:o.remote)??[])z.team.includes("/")&&(V.has(z.team)||(xe||(oe.appendChild(new Option("远端会话队(目录卡片)…","",!0,!1)),xe=!0),oe.appendChild(new Option(`${mt(z)} — 远端`,z.team))));xe||oe.appendChild(new Option("(暂无可拉入的远端会话队——见下方说明)","",!0,!1)),le!==""&&Array.from(oe.options).some(z=>z.value===le)&&(oe.value=le),H.appendChild(c.form);const Fe=_("div","wb-hint");Fe.textContent="成员由人类在此手工分配(agent 不可自组队)。远端成员走对端目录路由,不做本机冷唤醒;地址由目录在派发时重解析。远端下拉只列 zone/id8 会话句柄——若为空,说明目录里还没有已链接对端的会话队(未链接的对端只给最小卡);此时可在输入框手输句柄(如 dsh/xxxxxxxx)先把人拉进来,句柄本身即链接手势。",H.appendChild(Fe),e.dispatchQuick!==void 0&&H.appendChild(be(I.team))}x.appendChild(H)}function he(x){const w=_("form","wb-dispatch-form"),H=document.createElement("textarea");H.className="wb-dispatch-text",H.placeholder="一句话任务…(≤4000 字符,异步送达,回执进台账)",H.setAttribute("aria-label","快派消息");const $=_("button","wb-dispatch-submit");$.type="submit",$.textContent="发送";const I=_("div","wb-dispatch-note");return w.appendChild(H),w.appendChild($),w.appendChild(I),H.addEventListener("keydown",O=>{O.key!=="Enter"||O.shiftKey||O.ctrlKey||O.altKey||O.metaKey||O.isComposing||(O.preventDefault(),$.disabled||w.requestSubmit())}),w.addEventListener("submit",async O=>{var V;O.preventDefault();const oe=H.value.trim();if(oe===""||$.disabled)return;$.disabled=!0,I.textContent="派发中…";let le;try{le=await(((V=e.dispatchQuick)==null?void 0:V.call(e,x,oe))??Promise.resolve({ok:!1,error:"dispatch unavailable"}))}catch(xe){le={ok:!1,error:xe instanceof Error?xe.message:String(xe)}}$.disabled=!1,le.ok===!0&&(H.value=""),H.focus({preventScroll:!0}),I.textContent=le.ok===!0?`已派发${le.task_id!==void 0?` · ${le.task_id}`:""} · 回执将入台账(待回执)`:`失败:${le.error??"未知原因"}`}),{form:w,text:H,note:I}}function be(x){const w=_("div","wb-dispatch"),H=_("div","wb-side-head");return H.textContent="快派",w.appendChild(H),(m==null?void 0:m.team)!==x&&(m={team:x,...he(x)}),w.appendChild(m.form),w}function pe(x){ce.open(x),q.classList.remove("is-rail-open")}function re(x){if(o===null)return;const w=(o.sessions??[]).find($=>$.id===x);if(w!==void 0){pe({kind:"session",id:x,title:mt(w),sub:w.team,team:w.team,live:w.live});return}if(x.startsWith("peer-")){const $=x.slice(5),I=(o.peers??[]).find(O=>O.url.includes($));pe({kind:"peer",id:x,title:I!==void 0?I.url:$,sub:$,url:I==null?void 0:I.url});return}b.find($=>$.id===x)!==void 0&&pe({kind:"log",id:x,title:`…${x.slice(-12)}`,sub:"档案"})}function Ee(){var V,xe;C.textContent=(o==null?void 0:o.version)!==void 0?`v${o.version}`:"",C.hidden=(o==null?void 0:o.version)===void 0;const x=Be(k);if(o===null)return;const w=[],H=pn(o,e.now()),$=H.deadLetters.length;$>0&&w.push({text:`死信 ${$}`,tone:"danger",title:"超过 24h TTL 仍未结算的任务(unconsumed),需在台账清账",tab:"ledger",group:"死信"});const I=H.stale.length;I>0&&w.push({text:`陈旧 ${I}`,tone:"warn",title:"我方派发、要回执、已等待 ≥1h 仍未回执(可催办;免回执行不算)",tab:"ledger",group:"陈旧"});const O=H.owedOverdue.length;O>0&&w.push({text:`欠回执 ${O}`,tone:"warn",title:"对方投递给本机、已等待本机回执超过 1 小时",tab:"ledger",group:"待本机回执"});const oe=((V=o.idempotency)==null?void 0:V.conflicts)??0;oe>0&&w.push({text:`幂等冲突 ${oe}`,tone:"danger",title:"同一幂等键对应了不同载荷,需人工核查",tab:"ledger",group:"取证"});const le=(((xe=o.reconcile)==null?void 0:xe.rows)??[]).filter(Fe=>Fe.needsRepair===!0).length;if(le>0&&w.push({text:`需修复 ${le}`,tone:"danger",title:"reconcile 无法自动恢复的会话,见行动计划",tab:"plan"}),w.length===0){x.appendChild(_("span","wb-header-ok")).textContent="● 无异常";return}for(const Fe of w){const z=_("button",`wb-alert wb-alert-${Fe.tone}`);z.type="button",z.textContent=Fe.text,z.title=`${Fe.title}(点击查看)`,z.addEventListener("click",()=>st(Fe.tab,Fe.group)),x.appendChild(z)}}function st(x,w){var I;const H=se.find(([O])=>O===x)[1];n==="canvas"&&(q.classList.add("is-rail-open"),f.select(x,{focus:!1}));const $=w===void 0?H:w==="取证"?H.querySelector("details.wb-led-forensics"):Array.from(H.querySelectorAll(".wb-led-group")).find(O=>O.dataset.group===w)??null;$!==null&&($ instanceof HTMLDetailsElement&&($.open=!0),(I=$.scrollIntoView)==null||I.call($,{block:"start",behavior:"smooth"}))}function je(x){var H;const w=new Set((((H=x==null?void 0:x.canvas)==null?void 0:H.teams)??[]).flatMap($=>$.members.filter(I=>I.cliHome===null&&I.cliHeld!==!0).map(I=>JSON.stringify([$.name,I.id]))));for(const $ of d.keys())w.has($)||d.delete($);o=x,e.sessionLogList!==void 0&&!M&&(M=!0,e.sessionLogList().then($=>{b=$.ok&&$.sessions!==void 0?$.sessions:[],u=$.ok?$.count:void 0}).catch(()=>{}).finally(()=>{M=!1,We()})),Ee(),We(),St(),lt(),Ct(),ce.update(x),ze(),Mt(),B(),Me()}function et(x){if(x==="board"){Me();return}f.select(x)}return je(null),{root:q,update:je,mode:()=>n,selectTab:et,openNodeChat:re}}const ht=1e6,wn=.25,xn=3,ao=256,co=96;function Nt(e){const t=typeof e=="number"?e:Number.NaN;if(Number.isFinite(t))return Math.max(-ht,Math.min(ht,Math.round(t)))}function lo(e){if(e===null||typeof e!="object")return;const t=e,n=Nt(t.x),s=Nt(t.y);return n===void 0||s===void 0?void 0:{x:n,y:s}}function Go(e){const t=lo(e);if(t===void 0)return;const n=e,s=Nt(n.w),o=Nt(n.h);if(!(s===void 0||o===void 0||s<=0||o<=0))return{...t,w:Math.min(s,ht),h:Math.min(o,ht)}}const uo=e=>e!==""&&!e.includes("/")&&(e.startsWith("roster:")?e.length>7&&e.length<=47:e.length<=40);function mo(e){if(e===null||typeof e!="object")return;const t=e;if(t.version!==1)return;const n=t.viewport;if(n===null||typeof n!="object")return;const s=n,o=Nt(s.x),i=Nt(s.y),r=s.scale,c=typeof r=="number"?r:Number.NaN;if(o===void 0||i===void 0||!Number.isFinite(c))return;const d=Math.max(wn,Math.min(xn,c)),m={};if(t.nodes!==null&&typeof t.nodes=="object")for(const[u,E]of Object.entries(t.nodes)){if(typeof u!="string"||u===""||u.length>128)continue;const M=lo(E);if(M!==void 0&&(m[u]=M),Object.keys(m).length>=ao)break}const b={};if(t.frames!==null&&typeof t.frames=="object")for(const[u,E]of Object.entries(t.frames)){if(!uo(u))continue;const M=Go(E);if(M!==void 0&&(b[u]=M),Object.keys(b).length>=co)break}return{version:1,viewport:{x:o,y:i,scale:d},nodes:m,frames:b}}function Qo(e,t,n){const s=r=>Math.max(-ht,Math.min(ht,Math.round(r))),o={};for(const[r,c]of t)if(!(typeof r!="string"||r===""||r.length>128)&&(o[r]={x:s(c.x),y:s(c.y)},Object.keys(o).length>=ao))break;const i={};for(const[r,c]of n){if(!uo(r))continue;const d=s(c.w),m=s(c.h);if(!(d<=0||m<=0)&&(i[r]={x:s(c.x),y:s(c.y),w:Math.min(d,ht),h:Math.min(m,ht)},Object.keys(i).length>=co))break}return{version:1,viewport:{x:s(e.x),y:s(e.y),scale:Math.max(wn,Math.min(xn,e.scale))},nodes:o,frames:i}}function fo(e){let t=2166136261;for(let n=0;n<e.length;n++)t^=e.charCodeAt(n),t=Math.imul(t,16777619)>>>0;return t>>>0}const Ye=172,De=56,wt=[150,290,430],it=16;function Zo(e){const t=fo(e),n=Math.floor(t/it)%wt.length,o=t%it/it*Math.PI*2+n*(Math.PI/it),i=wt[n];return{x:Math.round(Math.cos(o)*i),y:Math.round(Math.sin(o)*i*.6)}}function po(e){const t=new Map;for(const n of e)for(const s of n.members)t.has(s.id)||t.set(s.id,n.name);return t}const Fn=64,Pn=24,Rn=20,es=4,Dn=24,Hn=44,ts=24;function ns(e,t,n=Number.POSITIVE_INFINITY){const s=new Set(t),o=po(e),i=e.map(u=>[...new Set(u.members.map(E=>E.id))].filter(E=>s.has(E)&&o.get(E)===u.name));i.push(t.filter(u=>!o.has(u)));const r=new Map;let c=0,d=0,m=0,b=0;for(const u of i){if(u.length===0)continue;const E=Math.min(3,Math.max(u.length>1?2:1,Math.ceil(Math.sqrt(u.length)))),M=Math.ceil(u.length/E),q=Math.max(260,E*Ye+(E-1)*Pn+Dn*2),fe=Math.max(160,M*De+(M-1)*Rn+Hn+ts);b>0&&(b%es===0||c+q>n)&&(c=0,d+=m+Fn,m=0),u.forEach((ee,S)=>{const C=S%E,N=Math.floor(S/E);r.set(ee,{x:c+Dn+Ye/2+C*(Ye+Pn),y:d+Hn+De/2+N*(De+Rn)})}),c+=q+Fn,m=Math.max(m,fe),b+=1}return r}const Yt=12;function ho(e,t){const n=d=>t.every(m=>Math.abs(m.x-d.x)>=Ye+Yt||Math.abs(m.y-d.y)>=De+Yt),s=Zo(e);if(n(s))return s;const o=fo(e),i=it*wt.length,r=Math.floor(o/it)%wt.length*it+o%it;for(let d=1;d<i;d++){const m=(r+d)%i,b=Math.floor(m/it),u=m%it/it*Math.PI*2+b*(Math.PI/it),E=wt[b],M={x:Math.round(Math.cos(u)*E),y:Math.round(Math.sin(u)*E*.6)};if(n(M))return M}const c=wt[wt.length-1];for(let d=0;;d++)for(let m=0;m<6;m++){const b={x:Math.round(-c+m*(Ye+Yt)),y:Math.round(c*.6+De*2+d*(De+Yt))};if(n(b))return b}}function ct(e){return{x:e.x-Ye/2,y:e.y-De/2,w:Ye,h:De}}function Cn(e){if(e.length===0)return{x:0,y:0,w:260,h:160};let t=Number.POSITIVE_INFINITY,n=Number.POSITIVE_INFINITY,s=Number.NEGATIVE_INFINITY,o=Number.NEGATIVE_INFINITY;for(const b of e)t=Math.min(t,b.x),n=Math.min(n,b.y),s=Math.max(s,b.x+b.w),o=Math.max(o,b.y+b.h);const i=24,r=44,c=24,d=Math.max(260,Math.round(s-t+i*2)),m=Math.max(160,Math.round(o-n+r+c));return{x:Math.round(t-i),y:Math.round(n-r),w:d,h:m}}class kn{constructor(){kt(this,"revisionCounter",0);kt(this,"nodes",new Map);kt(this,"frames",new Map);kt(this,"selection",new Set);kt(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,n,s){let o=!1;for(const i of t){const r=this.nodes.get(i);r!==void 0&&(r.x+=n,r.y+=s,o=!0)}o&&this.bump()}beginFrameDrag(t){const n=this.frames.get(t);if(n!==void 0)return{name:t,rect:{...n}}}applyFrameDrag(t,n,s){const o=this.frames.get(t.name);o!==void 0&&(o.x=t.rect.x+n,o.y=t.rect.y+s,this.bump())}nudge(t,n,s){this.dragNodes(t,n,s)}marqueeSelect(t,n){n||this.selection.clear();for(const s of this.nodes.values()){const o=ct(s);o.x<t.x+t.w&&o.x+o.w>t.x&&o.y<t.y+t.h&&o.y+o.h>t.y&&this.selection.add(s.id)}this.bump()}setSelection(t){this.selection=new Set(t),this.bump()}upsertNode(t){const n=this.nodes.get(t.id);if(n===void 0){this.nodes.set(t.id,t),this.bump();return}n.label=t.label,n.name=t.name,n.description=t.description,n.live=t.live,n.memberships=t.memberships,this.bump()}removeNode(t){this.nodes.delete(t)&&(this.selection.delete(t),this.bump())}setFrame(t,n){this.frames.set(t,n),this.bump()}removeFrame(t){this.frames.delete(t)&&this.bump()}upsertScore(t,n){const s=this.nodes.get(t);s===void 0||s.score===n||(s.score=n,this.bump())}positions(){const t=new Map;for(const[n,s]of this.nodes)t.set(n,{x:s.x,y:s.y});return t}frameRects(){const t=new Map;for(const[n,s]of this.frames)t.set(n,{...s});return t}teamMemberIds(t){const n=[];for(const s of this.nodes.values()){const o=s.memberships.find(i=>i.team===t);o!==void 0&&n.push({id:s.id,index:o.index})}return n.sort((s,o)=>s.index-o.index).map(s=>s.id)}setTeamMembers(t,n){for(const s of this.nodes.values()){const o=s.memberships.filter(r=>r.team!==t),i=n.indexOf(s.id);i>=0&&o.push({team:t,index:i}),s.memberships=o}this.bump()}contentBounds(){let t=Number.POSITIVE_INFINITY,n=Number.POSITIVE_INFINITY,s=Number.NEGATIVE_INFINITY,o=Number.NEGATIVE_INFINITY;const i=r=>{t=Math.min(t,r.x),n=Math.min(n,r.y),s=Math.max(s,r.x+r.w),o=Math.max(o,r.y+r.h)};for(const r of this.nodes.values())r.remote!==!0&&i(ct(r));for(const r of this.frames.values())i(r);return t===Number.POSITIVE_INFINITY?null:{minX:t,minY:n,maxX:s,maxY:o}}static fromState(t){const n=new kn,s=mo(t.layout),o=new Map;for(const i of t.teams)for(let r=0;r<i.members.length;r++){const c=i.members[r].id,d=o.get(c)??[];d.push({team:i.name,index:r}),o.set(c,d)}for(const i of t.sessions){if(i.joined!==!0)continue;const r=s==null?void 0:s.nodes[i.id];let c,d;if(r!==void 0&&typeof r.x=="number"&&typeof r.y=="number")c=r.x,d=r.y;else{const m=ho(i.id,[...n.nodes.values()]);c=m.x,d=m.y}n.nodes.set(i.id,{id:i.id,x:c,y:d,label:i.label,team:i.team,name:i.name,description:i.description,live:i.live!==!1,memberships:o.get(i.id)??[]})}for(const i of t.teams){const r=s==null?void 0:s.frames[i.name];if(r!==void 0){n.frames.set(i.name,{x:r.x,y:r.y,w:r.w,h:r.h});continue}const c=[];for(const d of i.members){const m=n.nodes.get(d.id);m!==void 0&&c.push(ct(m))}c.length>0&&n.frames.set(i.name,Cn(c))}return n.viewport=s!==void 0?{...s.viewport}:{x:0,y:0,scale:1},n}}const os=24,bo=-13,ss=bo+os;function is(e,t,n){const s=[],o=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,d=r.y+ss;for(const m of i.members){const b=n.get(m.id);if(b===void 0)continue;const u=o.has(m.id);o.add(m.id),s.push({x1:c,y1:d,x2:b.x,y2:b.y-De/2,dashed:u,team:i.name,id:m.id})}}return s}function rs(e,t){for(;e.firstChild!==null;)e.firstChild.remove();const n=t.allFrames().map(([s])=>({name:s,members:t.teamMemberIds(s).map(o=>({id:o}))}));for(const s of is(n,new Map(t.allFrames()),t.positions())){const o=document.createElementNS("http://www.w3.org/2000/svg","line");o.setAttribute("class","e-member"+(s.dashed?" dashed":"")),o.setAttribute("x1",String(s.x1)),o.setAttribute("y1",String(s.y1)),o.setAttribute("x2",String(s.x2)),o.setAttribute("y2",String(s.y2)),e.appendChild(o)}}function as(e){return`peer-${at(e).replace(/[^A-Za-z0-9.:\[\]-]/g,"-")}`}function at(e){try{return new URL(e).host}catch{return e}}function cs(e){const t=new Map;for(const n of e){const s=n.via!==void 0&&n.via!==""?at(n.via):"",o=t.get(s)??[];o.push(n),t.set(s,o)}return t}const ls=140,ds=200,us=90,ms=20,Wt=60;function fs(e,t){const n=t!==null?t.maxX+ls:ds,s=t!==null?t.minY:0;return e.map((o,i)=>({url:o.url,score:o.score,x:n,y:s+i*us}))}function ps(e,t,n,s){const o=new Map;for(const r of e){if(!t.has(r.team))continue;const c=`${r.team}\0${r.peer}`,d=o.get(c);d===void 0?o.set(c,{team:r.team,peer:r.peer,startedAt:r.startedAt,count:1}):(d.startedAt=Math.min(d.startedAt,r.startedAt),d.count+=1)}const i=[];for(const r of o.values()){const c=t.get(r.team);if(c===void 0)continue;const d=n.find(b=>{try{return new URL(b.url).host===r.peer}catch{return!1}});if(d===void 0)continue;const m=Math.max(0,Math.round((s-r.startedAt)/1e3));i.push({x1:c.x,y1:c.y,x2:d.x,y2:d.y,label:`a2a_route · ${r.peer} · ${m}s`+(r.count>1?` ×${r.count}`:"")})}return i}function hs(e,t){const n=t!==null?{x:t.maxX+ms,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,o)=>({x1:n.x,y1:n.y,x2:s.x,y2:s.y,label:o===0?"gns referral":""}))}function bs(e,t){if(e===null&&t.length===0)return null;let n=e!==null?e.minX:Number.POSITIVE_INFINITY,s=e!==null?e.minY:Number.POSITIVE_INFINITY,o=e!==null?e.maxX:Number.NEGATIVE_INFINITY,i=e!==null?e.maxY:Number.NEGATIVE_INFINITY;for(const r of t)n=Math.min(n,r.x-Wt),s=Math.min(s,r.y-Wt),o=Math.max(o,r.x+Wt),i=Math.max(i,r.y+Wt);return{minX:n,minY:s,maxX:o,maxY:i}}const gs=11;function vs(e,t){let n=[],s=[],o=[];function i(c){for(const b of n)b.remove();n=[];const d=t.allNodes().filter(b=>b.remote===!0).map(b=>({url:b.peerUrl??b.id.slice(5),score:b.score,x:b.x,y:b.y}));s=d;const m=t.contentBounds();if(m!==null){const b=new Map;for(const[u,E]of t.allFrames())b.set(u,{name:u,x:E.x+E.w/2,y:E.y+gs});for(const u of ps(o,b,d,c))n.push(...r(u,"e-activity",u.label));for(const u of hs(d,m))n.push(...r(u,"e-federal",u.label))}}function r(c,d,m){const b=document.createElementNS("http://www.w3.org/2000/svg","line");b.setAttribute("class",d),b.setAttribute("x1",String(c.x1)),b.setAttribute("y1",String(c.y1)),b.setAttribute("x2",String(c.x2)),b.setAttribute("y2",String(c.y2)),e.appendChild(b);const u=[b];if(m!==""){const E=document.createElementNS("http://www.w3.org/2000/svg","text");E.setAttribute("class","edge-label mono"),E.setAttribute("x",String((c.x1+c.x2)/2+14)),E.setAttribute("y",String((c.y1+c.y2)/2+18)),E.textContent=m,e.appendChild(E),u.push(E)}return u}return{render:i,flyTo(c){return c(),s},placements:()=>s,setInFlight:c=>{o=c}}}function ys(e,t){const n=new Map,s=new Set;for(const o of e){if(o.joined!==!0)continue;const i=o.team.lastIndexOf("/");if(i<=0||o.team.slice(i+1)!==o.id.replace(/^session-/,"").slice(0,8))continue;const r=o.team;t.has(r)||s.has(r)||(n.has(r)?(n.delete(r),s.add(r)):n.set(r,o.id))}return n}function ws(e,t,n,s){var r;const o=t.get(e);return o!==void 0?o:e.includes("/")?`member-${e.replace(/[^a-z0-9-]/gi,"-")}`:`member-${((r=n==null?void 0:n.find(c=>c.via===s))==null?void 0:r.team.split("/")[0])??"dsh"}-${e.replace(/^session-/,"").slice(0,8)}`}const jn={x:0,y:0,scale:1};function Gt(e){return Math.max(wn,Math.min(xn,e))}function Et(e){const t=Number.isFinite(e.scale)?e.scale:1,n=Number.isFinite(e.x)?e.x:0,s=Number.isFinite(e.y)?e.y:0;return{x:n,y:s,scale:Gt(t)}}function ft(e,t,n){return{x:e.x+t/e.scale,y:e.y+n/e.scale}}function dn(e,t,n){return{x:e.x+t/e.scale,y:e.y+n/e.scale,scale:e.scale}}function Bn(e,t,n,s){const o=Gt(e.scale*t);return o===e.scale?e:{x:e.x+n/e.scale-n/o,y:e.y+s/e.scale-s/o,scale:o}}const xs=680,Cs=.8,ks=.6,Yn=16;function En(e,t,n,s=Number.POSITIVE_INFINITY){if(e===null||t<=0||n<=0)return jn;const o=e.maxX-e.minX,i=e.maxY-e.minY;if(!(o>0)||!(i>0))return jn;const r=.9*Math.min(t/o,n/i),c=Math.min(s,r),d=t<xs?Cs:ks;if(r<d){const b=Gt(Math.min(s,d));return{x:e.minX-Yn/b,y:e.minY-Yn/b,scale:b}}const m=Gt(c);return{x:(e.minX+e.maxX)/2-t/(2*m),y:(e.minY+e.maxY)/2-n/(2*m),scale:m}}function Es(e){return`translate(${-e.x*e.scale}px, ${-e.y*e.scale}px) scale(${e.scale})`}function Wn(e,t){let n=e===null?null:{...e,minY:e.minY+bo};for(const s of t){if(s.remote!==!0)continue;const o=ct(s);n=n===null?{minX:o.x,minY:o.y,maxX:o.x+o.w,maxY:o.y+o.h}:{minX:Math.min(n.minX,o.x),minY:Math.min(n.minY,o.y),maxX:Math.max(n.maxX,o.x+o.w),maxY:Math.max(n.maxY,o.y+o.h)}}return n}function Kn(e,t,n,s){const o=s>0&&s<n/2?s:0,i=En(e,t,n-o,1);return o===0||e===null?i:{...i,y:i.y-o/i.scale}}function Xn(...e){const t=Math.max(0,...e.map(n=>n.offsetHeight>0?n.offsetTop+n.offsetHeight:0));return t>0?t+8:0}function Rt(e){return e.type==="join-network"||e.type==="leave-network"?"$network":e.type==="create-team"||e.type==="remove-team"?e.name:e.team}function $s(e,t){if(t.type==="create-team"){const o=t.ids.map(i=>e.getNode(i)).filter(i=>i!==void 0).map(i=>ct(i));return o.length>0&&e.setFrame(t.name,Cn(o)),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 o=e.teamMemberIds(t.team),i=t.ids.filter(r=>!o.includes(r));return e.setTeamMembers(t.team,[...o,...i]),()=>{e.setTeamMembers(t.team,e.teamMemberIds(t.team).filter(r=>!i.includes(r)))}}if(t.type==="remove-member"){const o=e.teamMemberIds(t.team);return e.setTeamMembers(t.team,o.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 o=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,o)}}if(t.type==="join-network"||t.type==="leave-network")return()=>{};const n=e.teamMemberIds(t.team);let s=[...n];for(const o of t.ops)o.op==="remove"?s=s.filter(i=>i!==o.id):s.push(o.id);return e.setTeamMembers(t.team,s),()=>{let o=e.teamMemberIds(t.team);for(let i=0;i<n.length;i++){const r=n[i];o[i]!==r&&o.includes(r)&&(o=o.filter(c=>c!==r),o.push(r))}e.setTeamMembers(t.team,o)}}function Un(e,t,n,s,o){if(n||s(),!(t.type==="remove-team"&&n||t.type==="create-team"&&!n&&t.created===!0)||o===void 0||e.getFrame(Rt(t))!==void 0)return o;const r={...o.frames};return delete r[Rt(t)],{...o,frames:r}}function bn(e,t){const n=[...e],s=[];for(let o=0;o<t.length;o++){const i=t[o];n[o]!==i&&n.includes(i)&&(s.push({op:"remove",id:i}),s.push({op:"add",id:i}),n.splice(n.indexOf(i),1),n.push(i))}return s}function Ns(e,t){return e.teamMemberIds(t).map(n=>{var s;return{id:n,y:((s=e.getNode(n))==null?void 0:s.y)??0}}).sort((n,s)=>n.y-s.y).map(n=>n.id)}function un(e,t){let n,s=Number.POSITIVE_INFINITY;for(const[o,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&&(n=o,s=r)}return n}const qn=[9133302,3900150,1357990,16096779,15485081,8702998];function Ms(e){let t=0;for(let c=0;c<e.length;c++)t=(t*31+e.charCodeAt(c)&268435455)>>>0;const n=qn[t%qn.length],s="#"+n.toString(16).padStart(6,"0"),o=n>>16&255,i=n>>8&255,r=n&255;return{line:s,bg:`rgba(${o},${i},${r},0.05)`}}const Qt="roster:",go=e=>e.startsWith(Qt)?e.slice(Qt.length):void 0,Ot=e=>Qt+e,Zt=e=>{const t=go(e);return t===void 0?e:`网络队 · roster · ${t}`};function Ss(e,t){return e.flatMap(n=>{if(t===""||!n.team.startsWith(t+"/")||!Array.isArray(n.members))return[];const s=n.team.slice(t.length+1);return s===""||s.length>40||s.includes("/")||s.startsWith(Qt)||s.includes("*")?[]:[{name:Ot(s),team:n.team,kind:"roster",members:n.members.filter(o=>typeof o=="string"&&o!=="").map(o=>({id:o}))}]})}function As(e){const{root:t,netBtn:n,signal:s,model:o}=e,i=y=>e.isRoster(y)?Zt(y):y;function r(){return o.selectedIds().map(y=>{var f;return{id:y,y:((f=o.getNode(y))==null?void 0:f.y)??0}}).sort((y,f)=>y.y-f.y).map(y=>y.id)}function c(){if(d!==null)return;const y=r().filter(f=>{const T=o.getNode(f);return T===void 0?!1:T.remote!==!0||T.remoteHandle!==void 0&&T.remoteHandle!==""});if(y.length<2){e.notice("info","框选至少 2 个会话节点");return}m(y)}let d=null;function m(y){const f=document.createElement("div");f.className="p-dialog";const T=document.createElement("div");T.className="p-dialog-panel",T.setAttribute("role","dialog"),T.setAttribute("aria-modal","true"),T.setAttribute("aria-labelledby","p-dialog-title");const p=document.createElement("div");p.id="p-dialog-title",p.className="p-dialog-title",p.textContent=`组建团队(${y.length} 个节点,自上而下即优先级)`;const D={value:"canvas"},j=document.createElement("div");j.className="p-dialog-kind",j.setAttribute("role","radiogroup"),j.setAttribute("aria-label","团队类型");const K=document.createElement("div");K.className="p-dialog-hint";const ye={canvas:"canvas 队:画布上的协作组,可以加入远端成员。",roster:"roster 网络队:只收本机已入网的会话;队名会写进属主的精确允许名单。"},Le=["canvas","roster"].map(ce=>{const Z=document.createElement("button");return Z.type="button",Z.dataset.kind=ce,Z.setAttribute("role","radio"),Z.textContent=ce==="canvas"?"canvas 队":"roster 网络队",Z.addEventListener("click",()=>R(ce)),j.appendChild(Z),Z});function R(ce){D.value=ce;for(const Z of Le){const Me=Z.dataset.kind===ce;Z.setAttribute("aria-checked",String(Me)),Z.tabIndex=Me?0:-1}K.textContent=ye[ce],se.textContent=""}j.addEventListener("keydown",ce=>{var Me;const Z=ce;["ArrowLeft","ArrowRight","ArrowUp","ArrowDown"].includes(Z.key)&&(Z.preventDefault(),R(D.value==="canvas"?"roster":"canvas"),(Me=Le.find(Be=>Be.dataset.kind===D.value))==null||Me.focus())});const X=document.createElement("input");X.className="p-dialog-input",X.maxLength=40,X.setAttribute("aria-label","团队名");const se=document.createElement("div");se.className="p-dialog-err",se.setAttribute("aria-live","polite");const He=document.createElement("div");He.className="p-dialog-row";const Ne=document.createElement("button");Ne.type="button",Ne.textContent="组建";const ie=document.createElement("button");ie.type="button",ie.textContent="取消",He.append(Ne,ie),R("canvas"),T.append(p,j,K,X,se,He),f.appendChild(T),t.appendChild(f);const Ce=document.activeElement,G=()=>{f.remove(),d=null,Ce==null||Ce.focus()},ne=()=>{const ce=X.value.trim();return ce===""||ce.length>40||ce.includes("/")||ce.startsWith("roster:")||D.value==="roster"&&ce.includes("*")||/^\d+$/.test(ce)?"队名需 1..40 字,不含“/”、通配符或保留前缀,不为纯数字":D.value==="roster"&&o.getFrame(ce)!==void 0?"同名 canvas 队已存在,不能创建 roster 队":D.value==="roster"&&o.getFrame(Ot(ce))!==void 0&&!e.isRoster(Ot(ce))?"roster 框名已被 canvas 或镜像队占用":D.value==="canvas"&&o.getFrame(Ot(ce))!==void 0?"同名 roster 队已存在,不能创建 canvas 队":D.value==="roster"&&y.some(Z=>{var Me;return((Me=o.getNode(Z))==null?void 0:Me.remote)===!0||!e.joined(Z)})?"roster 仅接受本机已入网的会话":null},we=()=>{const ce=ne();if(ce!==null){se.textContent=ce,X.focus();return}const Z=D.value==="roster"?Ot(X.value.trim()):X.value.trim();if(G(),o.getFrame(Z)!==void 0){e.notice("info",`已加入现有团队「${D.value==="roster"?Zt(Z):Z}」`),e.emit({type:"add-member",team:Z,ids:y});return}e.emit({type:"create-team",name:Z,ids:y,created:!0,...D.value==="roster"?{roster:!0}:{}})};Ne.addEventListener("click",we),ie.addEventListener("click",G),X.addEventListener("keydown",ce=>{const Z=ce;Z.key==="Enter"&&(Z.preventDefault(),we()),Z.key==="Escape"&&(Z.preventDefault(),G())}),f.addEventListener("keydown",ce=>{const Z=ce;if(Z.key==="Escape"){Z.preventDefault(),Z.stopPropagation(),G();return}if(Z.key!=="Tab")return;Z.preventDefault();const Me=Array.from(T.querySelectorAll('input, select, button:not([tabindex="-1"])')),Be=Me.indexOf(document.activeElement),Xe=Z.shiftKey?Me[(Be-1+Me.length)%Me.length]:Me[(Be+1)%Me.length];Xe==null||Xe.focus()},s),d={wrap:f,restoreFocus:Ce},X.focus()}let b=null,u="root",E=null,M=null,q=[];function fe(){M==null||M.remove(),M=null}function ee(){var T;if(M!==null){fe();return}if(q.length===0)return;const y=document.createElement("div");y.className="p-menu p-netmenu",y.setAttribute("role","menu"),y.setAttribute("aria-label","未入网会话");for(const p of q)y.appendChild(C(`${p.name!==void 0&&p.name!==""?p.name:p.label} — 入网`,!0,()=>{fe(),e.emit({type:"join-network",id:p.id})}));M=y,t.appendChild(y);const f=n.getBoundingClientRect();y.style.left=`${String(Math.min(f.left,window.innerWidth-220))}px`,y.style.top=`${String(Math.max(8,f.top-(q.length*30+10)))}px`,y.addEventListener("keydown",p=>{p.key==="Escape"&&(p.stopPropagation(),fe(),n.focus())}),(T=y.querySelector("button"))==null||T.focus(),document.addEventListener("pointerdown",p=>{if(M===null)return;const D=p.target;D!==null&&(D.closest(".p-netmenu")!==null||D===n||n.contains(D))||fe()},s)}function S(){b==null||b.remove(),b=null,u="root",E!==null&&E.isConnected?E.focus():t.focus(),E=null}function C(y,f,T){const p=document.createElement("button");return p.type="button",p.setAttribute("role","menuitem"),p.textContent=y,f?p.addEventListener("click",()=>{S(),T()}):(p.disabled=!0,p.setAttribute("aria-disabled","true")),p}function N(y,f,T,p="root",D){var Le,R,X,se,He,Ne,ie;D!==void 0&&(E=D),E===null&&(E=e.anchorFor(T)),b==null||b.remove(),u=p;const j=document.createElement("div");j.className="p-menu",j.setAttribute("role","menu"),j.setAttribute("aria-label","团队操作");let K=[];if(T.kind==="frame")K=[C(`解散团队「${i(T.name)}」`,!0,()=>e.emit({type:"remove-team",name:T.name}))];else{const Ce=T.id;if(p==="root"){const G=C("组成团队…",o.selectedIds().length>=2,()=>m(r()));G.title="先框选或 Shift 加选至少 2 个节点",K.push(G),e.teams().length>0&&(K.push(C("加入团队 ▸",!0,()=>N(y,f,T,"join"))),(((Le=o.getNode(Ce))==null?void 0:Le.memberships.map(we=>we.team))??[]).length>0&&(K.push(C("置顶路由 ▸",!0,()=>N(y,f,T,"promote"))),K.push(C("离队 ▸",!0,()=>N(y,f,T,"leave"))))),((R=o.getNode(Ce))==null?void 0:R.remote)!==!0&&K.push(C("退网",!0,()=>e.emit({type:"leave-network",id:Ce})))}else{K.push(C("‹ 返回",!0,()=>N(y,f,T,"root")));for(const G of e.teams())if(p==="join"){const ne=((X=o.getNode(Ce))==null?void 0:X.memberships.some(Z=>Z.team===G.name))??!0,we=!e.isRoster(G.name)||e.joined(Ce)&&((se=o.getNode(Ce))==null?void 0:se.remote)!==!0,ce=C(ne?`${i(G.name)}(已加入)`:i(G.name),!ne&&we,()=>e.emit({type:"add-member",team:G.name,ids:[Ce]}));we||(ce.title="roster 只接受本机已入网会话"),K.push(ce)}else if(p==="leave"){const ne=((He=o.getNode(Ce))==null?void 0:He.memberships.some(we=>we.team===G.name))??!1;K.push(C(i(G.name),ne,()=>e.emit({type:"remove-member",team:G.name,ids:[Ce]})))}else{const ne=((Ne=o.getNode(Ce))==null?void 0:Ne.memberships.some(we=>we.team===G.name))??!1;if(e.isRoster(G.name))continue;K.push(C(i(G.name),ne,()=>{const we=o.teamMemberIds(G.name),ce=[Ce,...we.filter(Z=>Z!==Ce)];e.emit({type:"reorder",team:G.name,ops:bn(we,ce)})}))}}}j.append(...K),j.style.left=`${Math.min(y,window.innerWidth-200)}px`;const ye=K.length*30+8;j.style.top=`${Math.max(8,Math.min(f,window.innerHeight-ye-8))}px`,j.addEventListener("keydown",Ce=>{var ce,Z,Me,Be;const G=Ce,ne=Array.from(j.querySelectorAll("[role=menuitem]")),we=ne.indexOf(document.activeElement);G.key==="ArrowDown"?(G.preventDefault(),(ce=ne[(we+1+ne.length)%ne.length])==null||ce.focus()):G.key==="ArrowUp"?(G.preventDefault(),(Z=ne[(we-1+ne.length)%ne.length])==null||Z.focus()):G.key==="Home"?(G.preventDefault(),(Me=ne[0])==null||Me.focus()):G.key==="End"?(G.preventDefault(),(Be=ne[ne.length-1])==null||Be.focus()):G.key==="Escape"&&(G.preventDefault(),G.stopPropagation(),u!=="root"?N(y,f,T,"root"):S())}),t.appendChild(j),b=j,(ie=K[0])==null||ie.focus()}function k(y,f,T){if(d!==null)return;const p=(T==null?void 0:T.closest(".p-node"))??null;if(p!==null){const K=o.getNode(p.dataset.id??"");if((K==null?void 0:K.remote)===!0&&(K.remoteHandle===void 0||K.remoteHandle===""))return}const D=p,j=(T==null?void 0:T.closest(".p-frame-head"))??null;if(D!==null){const K=D.dataset.id??"";o.isSelected(K)||o.setSelection([K]),E=D,N(y,f,{kind:"node",id:K})}else j!==null&&(E=j,N(y,f,{kind:"frame",name:j.dataset.frame??""}))}function J(y){q=y,n.textContent=`未入网${q.length>0?`(${String(q.length)})`:""}`,n.disabled=q.length===0,n.setAttribute("aria-disabled",String(q.length===0)),q.length===0&&fe()}return{menuItem:C,isMenuOpen:()=>b!==null,isDialogOpen:()=>d!==null,closeMenu:S,openMenu:N,contextMenuAt:k,openNameDialog:m,startCreateFromSelection:c,toggleNetMenu:ee,setUnjoined:J}}function Ls(e,t){const n=t.trim().toLowerCase();return n===""?[]:e.filter(s=>s.name.toLowerCase().includes(n)||s.team.toLowerCase().includes(n)||(s.host??"").toLowerCase().includes(n)).slice(0,8)}function Is(e,t){return e.allNodes().map(n=>{const s=n.id.slice(5),o=n.id.startsWith("member-")?n.name!==void 0&&n.name!==""?n.name:n.team:n.remote===!0?s:t(n);return{id:n.id,name:o,team:n.team,...n.remote===!0?{host:s}:{}}})}function Ts(e,t=1200){e!==void 0&&(e.classList.add("pulse"),setTimeout(()=>e.classList.remove("pulse"),t))}function _s(e){return t=>{const n=e.model.getNode(t);if(n===void 0)return;const s=e.viewSize();e.setVp(En({minX:n.x,minY:n.y,maxX:n.x+Ye,maxY:n.y+De},s.w,s.h,1)),e.applyViewport(),e.markDirty(),Ts(e.cardEl(t))}}function Os(e,t,n,s){const o=Fs({onPick:s});return e.appendChild(o.root),{...o,refresh:()=>o.setIndex(Is(t,n))}}function Fs(e){const t=document.createElement("div");t.className="p-search";const n=document.createElement("input");n.type="search",n.className="p-search-input",n.placeholder="🔍 搜索(Ctrl+K)",n.title="搜索名字 / 句柄 / 宿主(Ctrl+K 聚焦,Esc 清空)",n.setAttribute("aria-label","搜索画板节点:名字、句柄或宿主");const s=document.createElement("div");s.className="p-search-list";let o=[],i=[],r=0;const c=()=>{s.style.display="none",s.textContent=""},d=()=>{if(s.textContent="",i.length===0){c();return}i.forEach((u,E)=>{const M=document.createElement("div");M.className="p-search-hit"+(E===r?" active":""),M.dataset.id=u.id,M.textContent=u.name===u.team?u.name:`${u.name} · ${u.team}`,M.addEventListener("mousedown",q=>{q.preventDefault(),e.onPick(u.id),m()}),s.appendChild(M)}),s.style.display="block"},m=()=>{n.value="",i=[],c()},b=()=>{i=Ls(o,n.value),r=0,d()};return n.addEventListener("input",b),n.addEventListener("keydown",u=>{if(u.key==="Escape"){m(),n.blur(),u.stopPropagation();return}if(u.key==="ArrowDown"||u.key==="ArrowUp"){if(i.length===0)return;u.preventDefault(),r=(r+(u.key==="ArrowDown"?1:i.length-1))%i.length,d();return}u.key==="Enter"&&i.length>0&&(u.preventDefault(),e.onPick(i[r].id),m())}),t.append(n,s),{root:t,setIndex(u){o=u,n.value!==""&&b()},focus(){n.focus(),n.select()},clear(){m()}}}const Kt=28,zn=16,Jn=14,Vn=48,Ps=4,Rs=180,Ds=90,Hs=1600;function js(e){const t=e.wrapWidth??Hs,n=e.frames.map(d=>{const m=Math.max(d.soleIds.length,1),b=Math.min(Ps,Math.max(1,Math.ceil(Math.sqrt(m)))),u=Math.ceil(m/b),E=Math.max(Rs,Kt*2+b*Ye+(b-1)*zn),M=Math.max(Ds,Kt*2+u*De+(u-1)*Jn);return{name:d.name,w:E,h:M,rows:u,perRow:b,soleIds:d.soleIds}}),s=[],o=[];let i=0,r=0,c=0;for(const d of n){i>0&&i+d.w>t&&(i=0,r+=c+Vn,c=0);const m={x:i,y:r,w:d.w,h:d.h};s.push({name:d.name,rect:m});const b=m.x+Kt+Ye/2;let u=m.y+Kt+De/2;d.soleIds.forEach((E,M)=>{const q=M%d.perRow;M>0&&q===0&&(u+=De+Jn),o.push({id:E,x:b+q*(Ye+zn),y:u})}),i+=d.w+Vn,c=Math.max(c,d.h)}return{frames:s,seats:o}}function Bs(e,t){const n=[];for(const[o,i]of e.allFrames()){if(t.has(o))continue;const r=e.teamMemberIds(o).map(c=>e.getNode(c)).filter(c=>c!==void 0).filter(c=>c.memberships.length===1).map(c=>c.id);n.push({name:o,rect:i,soleIds:r})}if(n.length===0)return!1;const s=js({frames:n});for(const o of s.frames)e.setFrame(o.name,o.rect);for(const o of s.seats){const i=e.getNode(o.id);i!==void 0&&e.dragNodes([o.id],o.x-i.x,o.y-i.y)}return!0}function Ys(e,t){if(e===void 0)return;const n=at(e);return{text:t?`同步中… · ${n}`:`镜像 · ${n}`,title:t?`已把改动交给属主 ${n},等待它确认`:`这个团队属于 ${n},这里显示的是它的镜像;拖入或移出成员会经中继交给 ${n} 执行`,syncing:t}}const Ws=1e4;function Ks(e=Date.now){const t=(s,o)=>`${s}\0${o}`,n=new Map;return{fork(s,o){return n.set(t(o,s.name),{url:o,name:s.name}),{...s,fleetPeer:o}},settled(s,o){if(s.type!=="remove-team"||s.name===void 0||s.fleetPeer===void 0)return;const i=n.get(t(s.fleetPeer,s.name));i!==void 0&&(o?i.acceptedAt=e():n.delete(t(s.fleetPeer,s.name)))},hides(s,o){return n.has(t(o,s))},sweep(s){var o;for(const[i,r]of n)(!(((o=s.find(d=>d.url===r.url))==null?void 0:o.org.some(d=>d.name===r.name))===!0)||r.acceptedAt!==void 0&&e()-r.acceptedAt>Ws)&&n.delete(i)}}}const xt=24,Xs=200,qt=(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 Us(e,t){const n=t.x+t.w+xt-e.x,s=t.x-xt-(e.x+e.w),o=t.y+t.h+xt-e.y,i=t.y-xt-(e.y+e.h),r=Math.abs(n)<=Math.abs(s)?n:s,c=Math.abs(o)<=Math.abs(i)?o:i;return Math.abs(r)<=Math.abs(c)?{dx:r,dy:0}:{dx:0,dy:c}}function qs(e,t,n,s){const o=e.beginFrameDrag(t);o!==void 0&&e.applyFrameDrag(o,n,s)}function zs(e,t,n){let s=!1;for(let o=0;o<Xs;o++){const i=e.allFrames();let r;for(let S=0;S<i.length&&r===void 0;S++)for(let C=S+1;C<i.length;C++){const[N,k]=i[S],[J,y]=i[C];if(!(t.has(N)&&t.has(J))&&qt(k,y)){r=[N,k,J,y];break}}if(r===void 0)return s;const[c,d,m,b]=r,u=S=>t.has(S)?2:S===n?1:0,[E,M,q]=u(c)<u(m)?[c,d,b]:[m,b,d],{dx:fe,dy:ee}=Us(M,q);qs(e,E,fe,ee),s=!0}return s}const bt=28,zt=16,en=14;function Js(e){const t=[];for(let n=e.y+bt;n+De<=e.y+e.h-bt;n+=De+en)for(let s=e.x+bt;s+Ye<=e.x+e.w-bt;s+=Ye+zt)t.push({x:s+Ye/2,y:n+De/2});return t}function Vs(e){let t=!1;const n=e.allFrames(),s=new Map(n);for(const o of e.allNodes()){const i=new Set(o.memberships.map(ee=>ee.team)),r=n.find(([ee,S])=>!i.has(ee)&&qt(ct(o),S));if(r===void 0)continue;const c=r[1],d=ee=>{const S=ct(ee);return n.every(([C,N])=>i.has(C)||!qt(S,N))&&e.allNodes().every(C=>C.id===o.id||!qt(S,ct(C)))},b=o.memberships.map(ee=>s.get(ee.team)).filter(ee=>ee!==void 0).flatMap(Js).find(d),u={x:c.x+c.w+xt+Ye/2,y:o.y},E={x:o.x,y:c.y+c.h+xt+De/2},M=Math.max(...n.map(([,ee])=>ee.x+ee.w))+xt+Ye/2,q=Array.from({length:2*e.allNodes().length+1},(ee,S)=>({x:M,y:c.y+De/2+S*(De+en)})),fe=b??[u,E,...q].find(d)??q[q.length-1];e.dragNodes([o.id],fe.x-o.x,fe.y-o.y),t=!0}return t}function Xt(e,t,n){const s=zs(e,t,n),o=Vs(e);return s||o}function Gs(e){for(const[t,n]of e.allFrames()){const s=e.teamMemberIds(t).map(m=>e.getNode(m)).filter(m=>m!==void 0).filter(m=>m.memberships.length===1);if(s.length===0)continue;const o=Math.max(1,Math.floor((n.w-2*bt+zt)/(Ye+zt))),i=Math.ceil(s.length/o),r=bt*2+i*De+(i-1)*en;r>n.h&&e.setFrame(t,{...n,h:Math.min(r,n.h+400)});const c=n.x+bt+Ye/2;let d=n.y+bt+De/2;s.forEach((m,b)=>{const u=b%o;b>0&&u===0&&(d+=De+en);const E=c+u*(Ye+zt);e.dragNodes([m.id],E-m.x,d-m.y)})}}const Qs=30;function Zs(e){const t=[],n=()=>({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 d=i.frames.get(r);return d!==void 0&&(d.x!==c.x||d.y!==c.y||d.w!==c.w||d.h!==c.h)}),o=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 d=i.frames.get(r);d!==void 0&&(d.x!==c.x||d.y!==c.y||d.w!==c.w||d.h!==c.h)&&e.setFrame(r,{...d})}};return{capture:n,commit(i){s(i)&&(t.push(i),t.length>Qs&&t.shift())},undo(){const i=t.pop();return i===void 0?!1:(o(i),!0)},revert(i){return s(i)?(o(i),!0):!1},get depth(){return t.length}}}function ei(e){const{root:t,trigger:n,signal:s,model:o}=e;let i=null,r="",c=null;function d(){c==null||c.remove(),c=null}function m(){d(),i==null||i.remove(),i=null}function b(){if(i!==null){m();return}const C=document.createElement("div");C.className="p-menu p-nodelist",C.setAttribute("role","dialog"),C.setAttribute("aria-label","节点清单"),i=C,t.appendChild(C);const N=n.getBoundingClientRect();C.style.left=`${String(Math.min(N.left,window.innerWidth-340))}px`,C.style.top=`${String(Math.max(8,N.top-320))}px`,C.addEventListener("keydown",k=>{k.key==="Escape"&&(k.stopPropagation(),m(),n.focus())}),u()}function u(){var T;const C=i;if(C===null)return;d(),C.textContent="";const N=document.createElement("div");N.className="p-nodelist-head";const k=document.createElement("span");k.className="p-nodelist-title",k.textContent="节点";const J=document.createElement("select");J.className="p-nodesel",J.setAttribute("aria-label","选择 host 或对等节点");const y=document.createElement("option");y.value="",y.textContent="本机",J.appendChild(y);for(const[p,D]of e.facts().remoteTeams){if(p==="")continue;const j=document.createElement("option");j.value=p,j.textContent=((T=D[0])==null?void 0:T.origin)!==void 0&&D[0].origin!==""?`${D[0].origin}(${p})`:p,J.appendChild(j)}r!==""&&!e.facts().remoteTeams.has(r)&&(r=""),J.value=r,J.addEventListener("change",()=>{r=J.value,u()}),N.append(k,J);const f=document.createElement("div");f.className="p-nodelist-body",C.append(N,f),r===""?ee(f):S(f,e.facts().remoteTeams.get(r)??[])}function E(C,N){const k=document.createElement("span");return k.className="p-nodedot"+(N!==!0?" off":C===!1?" cold":""),k}function M(C,N){const k=document.createElement("button");return k.type="button",k.className="p-listbtn",k.textContent=C,k.addEventListener("click",J=>{J.stopPropagation(),N()}),k}function q(C,N){const k=document.createElement("div");if(k.className="p-nodelist-group",k.textContent=C,N!==void 0){const J=document.createElement("span");J.className="p-nodelist-note",J.textContent=N,k.appendChild(J)}return k}function fe(C,N){var y,f;d();const k=document.createElement("div");k.className="p-menu",k.setAttribute("role","menu"),k.setAttribute("aria-label","加入团队");for(const T of e.facts().teams){const p=((y=o.getNode(N))==null?void 0:y.memberships.some(D=>D.team===T.name))??!1;k.appendChild(e.menuItem(p?`${T.name}(已加入)`:T.name,!p,()=>{m(),e.emit({type:"add-member",team:T.name,ids:[N]})}))}k.appendChild(e.menuItem("新团队…",!0,()=>{m(),e.openNameDialog([N])})),c=k,t.appendChild(k);const J=C.getBoundingClientRect();k.style.left=`${String(Math.min(J.right+4,window.innerWidth-180))}px`,k.style.top=`${String(Math.max(8,J.top-60))}px`,k.addEventListener("keydown",T=>{T.key==="Escape"&&(T.stopPropagation(),d(),C.focus())}),(f=k.querySelector("button"))==null||f.focus()}function ee(C){var f,T;const N=new Set(e.facts().canvasMemberIds);for(const p of e.facts().sessions)p.teams!==void 0&&p.teams.length>0&&N.add(p.id);const k=e.facts().sessions.filter(p=>p.joined===!0&&!N.has(p.id)),J=e.facts().sessions.filter(p=>p.joined!==!0),y=e.facts().sessions.filter(p=>p.joined===!0&&N.has(p.id));C.appendChild(q(`未组队 (${String(k.length)})`,"无网络能力"));for(const p of k){const D=document.createElement("div");D.className="p-noderow";const j=document.createElement("span");j.className="p-nodename",j.textContent=p.name!==void 0&&p.name!==""?p.name:p.label,j.title=p.team;const K=document.createElement("span");K.className="p-nonet",K.textContent="无网络能力";const ye=M("入队▸",()=>fe(ye,p.id));D.append(E(p.live,!0),j,K,ye,M("退网",()=>{m(),e.emit({type:"leave-network",id:p.id})})),C.appendChild(D)}C.appendChild(q(`未入网 (${String(J.length)})`));for(const p of J){const D=document.createElement("div");D.className="p-noderow";const j=document.createElement("span");j.className="p-nodename",j.textContent=p.name!==void 0&&p.name!==""?p.name:p.label,j.title=p.id,D.append(E(p.live,!1),j,M("入网",()=>{m(),e.emit({type:"join-network",id:p.id})})),C.appendChild(D)}C.appendChild(q(`已组队 (${String(y.length)})`,"画布展示"));for(const p of y){const D=document.createElement("div");D.className="p-noderow";const j=document.createElement("span");j.className="p-nodename",j.textContent=p.name!==void 0&&p.name!==""?p.name:p.label,j.title=p.team;const K=((f=o.getNode(p.id))==null?void 0:f.memberships.length)??0,ye=((T=p.teams)==null?void 0:T.length)??0,Le=document.createElement("span");Le.className="p-teamcount",Le.textContent=`队×${String(Math.max(K,0)+ye)}`,D.append(E(p.live,!0),j,Le,M("定位",()=>{e.locate(p.id)})),C.appendChild(D)}if(e.facts().sessions.length===0){const p=document.createElement("div");p.className="p-nodelist-empty",p.textContent="无会话节点",C.appendChild(p)}}function S(C,N){var y;const k=N.filter(f=>f.teams===void 0||f.teams.length===0),J=N.filter(f=>f.teams!==void 0&&f.teams.length>0);C.appendChild(q(`未组队 (${String(k.length)})`,"无网络能力 · 只读"));for(const f of k){const T=document.createElement("div");T.className="p-noderow";const p=document.createElement("span");p.className="p-nodename",p.textContent=f.name!==void 0&&f.name!==""?f.name:f.team,p.title=f.team;const D=document.createElement("span");D.className="p-nonet",D.textContent="无网络能力",T.append(E(!0,!0),p,D),C.appendChild(T)}C.appendChild(q(`已组队 (${String(J.length)})`,"只读"));for(const f of J){const T=document.createElement("div");T.className="p-noderow";const p=document.createElement("span");p.className="p-nodename",p.textContent=f.name!==void 0&&f.name!==""?f.name:f.team,p.title=f.team;const D=document.createElement("span");D.className="p-teamcount",D.textContent=`队×${String(((y=f.teams)==null?void 0:y.length)??0)}`,T.append(E(!0,!0),p,D),C.appendChild(T)}if(N.length===0){const f=document.createElement("div");f.className="p-nodelist-empty",f.textContent="该节点未发布会话",C.appendChild(f)}}return document.addEventListener("pointerdown",C=>{if(i===null)return;const N=C.target;if(N===null){m();return}N.closest(".p-nodelist")!==null||N.closest(".p-menu")!==null||N===n||n.contains(N)||m()},s),{toggle:b,close:m,refresh:()=>{i!==null&&u()}}}function ti(e){let t=e;const n=t.search(/\|| ```|^```/);return n>=0&&(t=t.slice(0,n)),t.replace(/\[([^\]]*)\]\([^)]*\)/g,"$1").replace(/(^|\s)#{1,6}\s+/g,"$1").replace(/\*\*|__|`/g,"").replace(/\s+/g," ").trim()}function ni(e,t){const n=e.map(i=>i.name!==void 0&&i.name!==""?i.name:i.team),s=n.slice(0,2).join("、"),o=n.length>2?` +${n.length-2}`:"";return(t!==void 0?`score ${t} · `:"")+`${e.length} 远端团队`+(s!==""?`:${s}${o}`:"")}function oi(e,t,n){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 d=e.id.slice(5),m=t.length===1&&t[0].name!==void 0&&t[0].name!==""?t[0].name:void 0,b=ni(t,n);return m!==void 0?{title:m,sub:`${d} · ${b}`,tip:`${m}
6
- ${d}
7
- ${b}`}:{title:d,sub:b,tip:`${d}
8
- ${b}`}}const s=rt(e),o=e.team+(e.name!==void 0&&e.name!==""?" · "+e.name:""),i=ti(e.description??""),r=i!==""?i:o===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!==""?`${o}
9
- ${i}`:o}}function si(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 ii(e){const t=document.createElement("div");t.className="p-node",t.dataset.id=e,t.tabIndex=0;const n=document.createElement("div");n.className="nm";const s=document.createElement("span");s.className="dot";const o=document.createElement("span");o.className="nm-text",n.append(s,o);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 d=document.createElement("div");return d.className="sub-row",d.append(i,c),t.append(n,d,r),t}function ri(e,t,n){if(t.remote===!0){const s=(n==null?void 0:n.link)==="linked"?"lnk-linked":(n==null?void 0:n.link)==="stranger"?"lnk-stranger":"";e.className!==`prio mono ${s}`.trim()&&(e.className=`prio mono ${s}`.trim());const o=n===void 0?"":n.verified===!0?"✓":"✗",i=((n==null?void 0:n.link)??"peer")+o;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 Gn="dsh-a2a.board.legend";function ai(){const e=document.createElement("details");e.className="p-legend";const t=document.createElement("summary");t.textContent="图例",t.title="边的含义(点击展开 / 收起)";const n=document.createElement("div");n.className="p-legend-rows";const s=(o,i,r)=>{const c=document.createElement("span"),d=document.createElement("i");o&&(d.className="dashed"),r!==void 0&&(d.style.borderTopColor=r),c.append(d,document.createTextNode(i)),n.appendChild(c)};s(!1,"成员边(星形,框→成员)"),s(!0,"跨队多属(虚线)"),s(!0,"roster 网络队框(双线边框)"),s(!1,"活动边(inFlight 路由,瞬时)","var(--accent)"),s(!0,"联邦线(→peer)","var(--federal)"),e.append(t,n);try{e.open=window.localStorage.getItem(Gn)==="open"}catch{}return e.addEventListener("toggle",()=>{try{window.localStorage.setItem(Gn,e.open?"open":"closed")}catch{}}),e}const Jt="对端未应答(显示的是最后已知状态)";function Qn(e){const t=new Set;for(const s of e.remoteTeams??[])s.unreachable===!0&&s.via&&t.add(at(s.via));for(const s of e.peerOrg??[])s.unreachable===!0&&t.add(at(s.url));const n=new Set;for(const s of e.remoteTeams??[])s.via&&t.has(at(s.via))&&n.add(`member-${s.team.replace(/[^a-z0-9-]/gi,"-")}`);return{hosts:t,members:n}}function ci(e,t){e.classList.toggle("is-unreachable",t);const n=e.querySelector(".p-frame-unreachable");if(t&&n===null){const s=document.createElement("span");s.className="p-frame-unreachable",s.textContent=Jt,e.appendChild(s)}else t||n==null||n.remove()}function li(e){return e<680?"narrow":e<1024?"medium":"wide"}function di(e){const t=new kn;let n,s={...t.viewport},o={kind:"none"},i=!1,r=-1,c=!0,d=!1;const m=Zs(t);let b,u=!1;const E=()=>li(globalThis.innerWidth||We),M=()=>{var a;(a=e.viewportStore)==null||a.set(E(),s),e.onDirty()},q=e.now??Date.now,fe=new AbortController,ee=[];let S=null,C=!1;const N={signal:fe.signal},k=document.createElement("section");k.id="dsh-plan",k.setAttribute("role","tabpanel"),k.setAttribute("aria-label","A2A 规划画布"),k.tabIndex=0,k.style.display="none";const J=document.createElement("div");J.className="p-grid";const y=document.createElement("div");y.className="p-world";const f=document.createElementNS("http://www.w3.org/2000/svg","svg");f.setAttribute("class","p-edges");const T=document.createElement("div");T.className="p-layer p-frames";let p;const D=a=>{var h,v;p!==void 0&&((h=Oe.get(p))==null||h.classList.remove("selected")),p=a,a!==void 0&&((v=Oe.get(a))==null||v.classList.add("selected"))},j=document.createElement("div");j.className="p-layer p-nodes",j.setAttribute("role","listbox"),j.setAttribute("aria-multiselectable","true"),j.setAttribute("aria-label","会话节点"),y.append(f,T,j);const K=document.createElement("div");K.className="p-marquee";const ye=document.createElement("div");ye.className="p-toolbar";const Le=document.createElement("span");Le.className="p-zoom mono",Le.textContent="100%";const R=(a,h,v)=>{const P=document.createElement("button");return P.type="button",P.textContent=a,P.title=h,P.addEventListener("click",v,N),P},X=()=>{const a=document.createElement("span");return a.className="p-sep",a.setAttribute("role","separator"),a.setAttribute("aria-orientation","vertical"),a};ye.append(R("适配","适配视图(快捷键 0)",()=>pt()),R("-","缩小",()=>ge(1/1.2)),Le,R("+","放大",()=>ge(1.2)),X(),R("建队","组成团队(G):先框选至少 2 个节点",()=>O.startCreateFromSelection()),R("整理成员","每队框内仅属一队的成员自动排齐(多队成员不动)",()=>gt()),R("一键重排","全板队框+成员重排:框尺寸随内容自适应、框位行流式平铺(远端队框与多归属成员不动)",()=>Mt()),R("撤销","撤销上一次布局改动:拖动、缩放、整理、重排、载入时避让(Ctrl+Z;入队离队不撤销)",()=>Ve()));const se=R("未入网","未入网会话(点击选择入网)",()=>O.toggleNetMenu());se.className="p-netbtn",se.setAttribute("aria-haspopup","menu"),ye.append(X(),se);const He=Os(ye,t,rt,a=>pe(a)),Ne=R("节点","节点清单:本机与对等节点(未组队/未入网在此管理)",()=>V.toggle());Ne.className="p-nodebtn",Ne.setAttribute("aria-haspopup","dialog"),ye.appendChild(Ne);const ie=document.createElement("span");ie.setAttribute("aria-live","polite"),ie.className="p-lamp";const Ce=document.createElement("i"),G=document.createElement("span");G.textContent="布局",ie.append(Ce,G),ie.addEventListener("click",()=>{ie.classList.contains("error")&&e.onLampClick()},N),ie.addEventListener("keydown",a=>{const h=a;(h.key==="Enter"||h.key===" ")&&ie.classList.contains("error")&&(h.preventDefault(),e.onLampClick())},N),ye.appendChild(ie);const ne=document.createElement("div");ne.className="p-status";const we=document.createElement("span"),ce=document.createElement("span"),Z=document.createElement("span");Z.className="mut";const Me=document.createElement("span");Me.className="mut",ne.append(we,ce,Z,Me),ne.tabIndex=0,ne.setAttribute("role","button"),ne.setAttribute("aria-label","定位在途路由与联邦对端"),ne.title="定位在途与联邦(回车)",ne.addEventListener("click",()=>be(),N),ne.addEventListener("keydown",a=>{const h=a;(h.key==="Enter"||h.key===" ")&&(h.preventDefault(),be())},N);const Be=ai(),Xe=document.createElement("div");Xe.className="p-notice-stack",Xe.setAttribute("role","log"),Xe.setAttribute("aria-live","polite"),k.append(J,y,K,ye,ne,Be,Xe);let We=0,lt=0;const Ct=()=>e.viewSize?e.viewSize():{w:k.clientWidth,h:k.clientHeight},Ue=()=>{const a=Ct();We=a.w,lt=a.h};function ze(){y.style.transform=Es(s);const a=24*s.scale;J.style.backgroundSize=`${a}px ${a}px`,J.style.backgroundPosition=`${-s.x*s.scale}px ${-s.y*s.scale}px`,Le.textContent=`${Math.round(s.scale*100)}%`}function gt(){const a=m.capture();Gs(t),Xt(t,new Set(et.keys())),m.commit(a),M(),Ie()}function Mt(){const a=m.capture();Bs(t,new Set(et.keys()))&&(Xt(t,new Set(et.keys())),m.commit(a),M(),Ie())}function Ie(){ze(),t.revision!==r&&(r=t.revision,dt(),St(),rs(f,t)),he()}const Oe=new Map,Ze=new Map;function dt(){var h;const a=new Set;for(const[v,P]of t.allFrames()){a.add(v);let F=Oe.get(v);if(F===void 0){F=document.createElement("div"),F.className="p-frame",F.dataset.name=v;const ke=document.createElement("div");ke.className="p-frame-head",ke.dataset.frame=v,ke.tabIndex=0,ke.setAttribute("role","button"),ke.setAttribute("aria-haspopup","menu"),ke.setAttribute("aria-label",`团队框 ${v}(拖动整组,回车菜单)`);const Ge=document.createElement("span");Ge.className="ttl";const tt=document.createElement("span");tt.className="cnt mono";const vt=document.createElement("span");vt.className="route mono",ke.append(Ge,tt,vt),F.appendChild(ke);for(const Lt of["n","s","e","w","ne","nw","se","sw"]){const yt=document.createElement("div");yt.className=`p-frame-handle p-h-${Lt}`,yt.dataset.frame=v,yt.dataset.dir=Lt,F.appendChild(yt)}T.appendChild(F),Oe.set(v,F)}const de=Ms(v);F.style.setProperty("--frame-line",de.line),F.style.setProperty("--frame-bg",de.bg),F.style.left=`${P.x}px`,F.style.top=`${P.y}px`,F.style.width=`${P.w}px`,F.style.height=`${P.h}px`;const Y=F.querySelector(".ttl"),W=F.querySelector(".cnt"),U=F.querySelector(".route"),ae=x.has(v),Te=ae?Zt(v):v;Y.textContent!==Te&&(Y.textContent=Te),F.classList.toggle("is-roster",ae);let _e=0,Se=0;for(const ke of t.allNodes())ke.memberships.find(tt=>tt.team===v)!==void 0&&(_e+=1,ke.memberships.length>1&&(Se+=1));const g=`${_e} 成员`+(Se>0?` +${Se} 跨队`:"");W.textContent!==g&&(W.textContent=g);const te=Ys(et.get(v),Ee.has(v)),ue=te!==void 0&&w.hosts.has(at(et.get(v))),Pe=(te==null?void 0:te.text)??((h=Dt.find(ke=>ke.name===v))==null?void 0:h.team)??v;U.textContent!==Pe&&(U.textContent=Pe),U.title=`${(te==null?void 0:te.title)??""}${ue?` · ${Jt}`:""}`,ci(F,ue),F.classList.toggle("is-mirror",te!==void 0),F.classList.toggle("is-syncing",(te==null?void 0:te.syncing)===!0);const Ae=`团队框 ${v}${te!==void 0?`(${te.text})`:""}${ue?`(${Jt})`:""}(拖动整组,回车菜单)`,me=F.querySelector(".p-frame-head");me.getAttribute("aria-label")!==Ae&&me.setAttribute("aria-label",Ae)}for(const[v,P]of[...Oe])a.has(v)||(P.remove(),Oe.delete(v))}function St(){const a=new Set;for(const h of t.allNodes()){a.add(h.id);let v=Ze.get(h.id);v===void 0&&(v=ii(h.id),j.appendChild(v),Ze.set(h.id,v));const P=ct(h);v.style.left=`${P.x}px`,v.style.top=`${P.y}px`,v.classList.toggle("cold",!h.live),v.classList.toggle("remote",h.remote===!0);const F=h.live&&h.remote!==!0?L.get(h.id):void 0;v.classList.toggle("is-working",(F==null?void 0:F.status)==="running");const de=si(F),Y=v.querySelector(".work");Y.textContent!==de&&(Y.textContent=de),v.classList.toggle("selected",t.isSelected(h.id)),v.setAttribute("aria-selected",String(t.isSelected(h.id)));const W=h.id.slice(5),U=oi(h,h.remote===!0?A.get(W)??[]:[],Q.get(W)),ae=h.remote===!0&&(h.id.startsWith("member-")?w.members.has(h.id):w.hosts.has(W));v.classList.toggle("is-unreachable",ae);const Te=v.querySelector(".nm-text");Te.textContent!==U.title&&(Te.textContent=U.title);const _e=v.querySelector(".sub"),Se=ae?`未应答 · ${U.sub}`:U.sub;_e.textContent!==Se&&(_e.textContent=Se);const g=ae?`${U.tip} · ${Jt}`:U.tip;v.title!==g&&(v.title=g),ri(v.querySelector(".prio"),h,h.remote===!0?B.get(W):void 0)}for(const[h,v]of[...Ze])a.has(h)||(v.remove(),Ze.delete(h));He.refresh()}const l=vs(f,t);let A=new Map,L=new Map;const Q=new Map,B=new Map;function he(){l.render(q())}function be(){s=En(bs(t.contentBounds(),l.placements()),k.clientWidth||We,k.clientHeight||lt),ze(),M()}const pe=_s({model:t,viewSize:Ct,setVp:a=>{s=a},applyViewport:ze,markDirty:M,cardEl:a=>Ze.get(a)});function re(a){var P;const h=a.sessions.filter(F=>F.live!==!1).length,v=(F,de,Y)=>{const W=document.createElement("b");W.className=de,W.textContent=Y,F.replaceChildren(W)};v(we,"ok",`● ${h} live`),v(ce,"warn",`● ${a.sessions.length-h} cold`),Z.textContent=`${((P=a.inFlight)==null?void 0:P.length)??0} inFlight`,Me.className="mut",Me.textContent=`${a.teams.length} 队 · ${a.peerCount} peer`}const Ee=new Map,st=a=>{Ee.set(a,(Ee.get(a)??0)+1),r=-1},je=a=>{r=-1;const h=(Ee.get(a)??0)-1;h<=0?Ee.delete(a):Ee.set(a,h)};let et=new Map,x=new Set,w=Qn({});const H=Ks(e.now);function $(a){const h=a.type==="create-team"&&a.roster===!0||x.has(Rt(a));if(h&&a.type==="remove-team"&&!window.confirm(`解散网络队「${Zt(a.name)}」并撤回成员与白名单?`))return;if(h&&a.type==="reorder"){I("error","roster 队不支持置顶路由");return}if(h&&(a.type==="create-team"||a.type==="add-member")&&a.ids.some(Y=>{var W;return((W=t.getNode(Y))==null?void 0:W.remote)===!0||!oe.some(U=>U.id===Y&&U.joined===!0)})){I("error","roster 只接受本机已入网会话,远端或未入网成员未写入");return}function v(Y){const W=U=>{var Te;const ae=[];for(const _e of U){if(!_e.startsWith("peer-")&&!_e.startsWith("member-")){ae.push(_e);continue}const Se=(Te=t.getNode(_e))==null?void 0:Te.remoteHandle;Se!==void 0&&Se!==""&&ae.push(Se)}return ae};if(Y.type==="add-member"||Y.type==="remove-member"||Y.type==="create-team"){const U=W(Y.ids),ae=Y.type!=="create-team"?et.get(Y.team):void 0;return U.length>0||ae!==void 0?{...Y,ids:U,...ae!==void 0?{fleetPeer:ae}:{}}:Y}return Y.type==="remove-team"&&et.has(Y.name)?H.fork(Y,et.get(Y.name)):Y}if(a.type==="add-member"||a.type==="remove-member"||a.type==="reorder"||a.type==="create-team"){const Y=a.type==="reorder"?a.ops.map(W=>W.id):[...a.ids];for(const W of Y){if(W===""||W.startsWith("peer-")||W.startsWith("member-")||t.getNode(W)!==void 0)continue;const U=oe.find(_e=>_e.id===W);if(U===void 0)continue;const ae=n==null?void 0:n.nodes[W],Te=ae!==void 0?{x:ae.x,y:ae.y}:Nn(W);t.upsertNode({id:W,x:Te.x,y:Te.y,label:U.label,team:U.team,name:U.name,description:U.description,live:U.live!==!1,memberships:[],...U.teams!==void 0&&U.teams.length>0?{teams:U.teams}:{}})}}h&&a.type==="create-team"&&x.add(a.name);const P=$s(t,a),F=Rt(a);st(F),Ie();const de=v(h?{...a,roster:!0}:a);e.onCanvasAction(de).then(Y=>{je(F),!Y&&a.type==="create-team"&&h&&x.delete(F),n=Un(t,a,Y,P,n),M(),H.settled(de,Y),Ie()},()=>{je(F),a.type==="create-team"&&h&&x.delete(F),n=Un(t,a,!1,P,n),M(),H.settled(de,!1),I("error","操作通道异常,已回滚"),Ie()})}function I(a,h){var P;for(;Xe.childElementCount>=3;)(P=Xe.firstElementChild)==null||P.remove();const v=document.createElement("div");v.className="p-notice"+(a==="error"?" error":""),v.setAttribute("role",a==="error"?"alert":"status"),v.textContent=h,Xe.appendChild(v),ee.push(setTimeout(()=>v.remove(),4e3))}const O=As({root:k,netBtn:se,signal:N,model:t,teams:()=>Dt,joined:a=>oe.some(h=>h.id===a&&h.joined===!0),isRoster:a=>x.has(a),anchorFor:a=>(a.kind==="node"?Ze.get(a.id):Oe.get(a.name))??null,emit:$,notice:I});let oe=[],le=new Set;const V=ei({root:k,trigger:Ne,signal:N,model:t,facts:()=>({sessions:oe,canvasMemberIds:le,remoteTeams:A,teams:Dt}),menuItem:O.menuItem,emit:$,openNameDialog:O.openNameDialog,locate:xe});function xe(a){var P;const h=t.getNode(a);if(h===void 0)return;V.close();const v=((P=e.viewSize)==null?void 0:P.call(e))??{w:k.clientWidth>0?k.clientWidth:800,h:k.clientHeight>0?k.clientHeight:600};s=Et({scale:s.scale,x:h.x-v.w/(2*s.scale),y:h.y-v.h/(2*s.scale)}),ze(),r=-1,Ie()}function Fe(a){const h=k.getBoundingClientRect();return{x:a.clientX-h.left,y:a.clientY-h.top}}function z(a,h){var Y;const v=Fe(h),P=ft(s,v.x,v.y),F=un(new Map(t.allFrames()),P),de=a.ids.filter(W=>{const U=t.getNode(W);return U===void 0?!1:U.remote!==!0?!0:U.remoteHandle!==void 0&&U.remoteHandle!==""});if(F!==void 0){const W=de.filter(U=>{var ae;return!((ae=t.getNode(U))!=null&&ae.memberships.some(Te=>Te.team===F))});if(W.length>0){$({type:"add-member",team:F,ids:W});return}if(a.ids.length===1&&((Y=t.getNode(a.clicked))==null?void 0:Y.remote)!==!0){const U=t.teamMemberIds(F),ae=Ns(t,F);ae.join("\0")!==U.join("\0")&&$({type:"reorder",team:F,ops:bn(U,ae)})}}if(a.rosterOrigin!==void 0&&F!==a.rosterOrigin){const W=a.ids.filter(U=>t.teamMemberIds(a.rosterOrigin).includes(U));W.length>0&&$({type:"remove-member",team:a.rosterOrigin,ids:W})}}function Re(a){if(We===0&&Ue(),O.isDialogOpen()){a.preventDefault();return}const h=a.target;if(O.isMenuOpen()){if(h!==null&&h.closest(".p-menu")!==null)return;O.closeMenu(),a.preventDefault();return}if(h!==null&&h.closest("button, input, textarea, select, .p-toolbar, .p-search, .p-lamp, .p-status, .p-legend")!==null)return;b=m.capture();const v=Fe(a);if(a.button===2){S={x:v.x,y:v.y,target:a.target,moved:!1},a.preventDefault();try{k.setPointerCapture(a.pointerId??0)}catch{}return}const P=h!==null?h.closest(".p-node"):null,F=h!==null?h.closest(".p-frame-head"):null;if((P!==null||F!==null)&&a.button===1){o={kind:"pan",last:v,moved:!1},a.preventDefault();try{k.setPointerCapture(a.pointerId??0)}catch{}return}const de=h!==null?h.closest(".p-frame-handle"):null;if(p!==void 0){const Y=Oe.get(p),W=h!==null&&Y!==void 0&&(Y.contains(h)||Y===h),U=F!==null&&F.dataset.frame===p;!W&&!U&&D(void 0)}if(de!==null&&a.button===0){const Y=de.dataset.frame??"";D(Y);const W=t.getFrame(Y);if(W===void 0)return;o={kind:"frame-resize",name:Y,dir:de.dataset.dir??"se",startRect:{...W},origin:ft(s,v.x,v.y),moved:!1},a.preventDefault();try{k.setPointerCapture(a.pointerId??0)}catch{}return}if(P!==null){if(a.button!==0)return;const Y=P.dataset.id??"",W=t.isSelected(Y);!W&&!a.shiftKey&&t.setSelection([Y]);const U=a.shiftKey||W?t.isSelected(Y)?t.selectedIds():[...t.selectedIds(),Y]:[Y],ae=un(new Map(t.allFrames()),ft(s,v.x,v.y));o={kind:"node",clicked:Y,ids:U,...ae&&x.has(ae)&&t.teamMemberIds(ae).includes(Y)?{rosterOrigin:ae}:{},last:ft(s,v.x,v.y),moved:!1,el:P},P.classList.add("dragging")}else if(F!==null){if(a.button!==0)return;const Y=F.dataset.frame??"";D(Y);const W=t.beginFrameDrag(Y);if(W===void 0)return;o={kind:"frame",name:Y,snap:W,origin:ft(s,v.x,v.y),moved:!1}}else if(a.button===1||a.button===0&&i)o={kind:"pan",last:v,moved:!1};else if(a.button===0)o={kind:"marquee",origin:v,last:v,additive:a.shiftKey},K.style.display="block",K.style.left=`${v.x}px`,K.style.top=`${v.y}px`,K.style.width="0px",K.style.height="0px";else return;a.preventDefault();try{k.setPointerCapture(a.pointerId??0)}catch{}}function Je(a){const h=Fe(a);if(S!==null){const v=h.x-S.x,P=h.y-S.y;Math.hypot(v,P)>4&&(S.moved=!0,s=Et(dn(s,-v,-P)),S.x=h.x,S.y=h.y,ze());return}if(o.kind==="node"){const v=ft(s,h.x,h.y),P=v.x-o.last.x,F=v.y-o.last.y;if(P===0&&F===0)return;o.moved=!0,o.last=v,t.dragNodes(o.ids,P,F);const de=un(new Map(t.allFrames()),v),Y=o.ids.filter(U=>{const ae=t.getNode(U);return ae===void 0?!1:ae.remote!==!0||ae.remoteHandle!==void 0&&ae.remoteHandle!==""}),W=de!==void 0&&Y.length>0;for(const[U,ae]of Oe)ae.classList.toggle("drop-target",W&&U===de);Ie()}else if(o.kind==="frame"){const v=ft(s,h.x,h.y),P=v.x-o.origin.x,F=v.y-o.origin.y;if(!o.moved&&P===0&&F===0)return;o.moved=!0,t.applyFrameDrag(o.snap,P,F),Ie()}else if(o.kind==="frame-resize"){const v=ft(s,h.x,h.y),P=v.x-o.origin.x,F=v.y-o.origin.y;if(!o.moved&&P===0&&F===0)return;o.moved=!0;const de=220,Y=120,W={...o.startRect};let{x:U,y:ae,w:Te,h:_e}=W;o.dir.includes("e")&&(Te=Math.max(de,W.w+P)),o.dir.includes("s")&&(_e=Math.max(Y,W.h+F)),o.dir.includes("w")&&(Te=Math.max(de,W.w-P),U=W.x+(W.w-Te)),o.dir.includes("n")&&(_e=Math.max(Y,W.h-F),ae=W.y+(W.h-_e)),t.setFrame(o.name,{x:Math.round(U),y:Math.round(ae),w:Math.round(Te),h:Math.round(_e)}),Ie()}else if(o.kind==="pan")s=dn(s,h.x-o.last.x,h.y-o.last.y),o.last=h,o.moved=!0,ze();else if(o.kind==="marquee"){const v=Math.min(o.origin.x,h.x),P=Math.min(o.origin.y,h.y);K.style.left=`${v}px`,K.style.top=`${P}px`,K.style.width=`${Math.abs(h.x-o.origin.x)}px`,K.style.height=`${Math.abs(h.y-o.origin.y)}px`,o.last=h}}function Qe(a){var h,v;if(S!==null){const P=S.moved,F=S.target,de=S.x,Y=S.y;S=null,P?(C=!0,M()):F!==null&&O.contextMenuAt(de,Y,F);return}if(o.kind==="node"){const P=o.clicked;if(o.moved)z(o,a),M();else if(a.shiftKey){const F=t.selectedIds();t.setSelection(F.includes(P)?F.filter(de=>de!==P):[...F,P])}else t.setSelection([P]),(h=e.onNodePick)==null||h.call(e,P);for(const F of Oe.values())F.classList.remove("drop-target");(v=o.el)==null||v.classList.remove("dragging"),Ie()}else if(o.kind==="frame"||o.kind==="frame-resize")o.moved&&(Xt(t,new Set(et.keys()),o.name),M(),Ie());else if(o.kind==="pan")o.moved&&M();else if(o.kind==="marquee"){const P=o.last,F=ft(s,Math.min(o.origin.x,P.x),Math.min(o.origin.y,P.y)),de=ft(s,Math.max(o.origin.x,P.x),Math.max(o.origin.y,P.y));t.marqueeSelect({x:F.x,y:F.y,w:de.x-F.x,h:de.y-F.y},o.additive),K.style.display="none",Ie()}o={kind:"none"},b!==void 0&&(m.commit(b),b=void 0);try{k.releasePointerCapture(a.pointerId??0)}catch{}}function ut(a){var v;for(const P of Oe.values())P.classList.remove("drop-target");o.kind==="node"&&((v=o.el)==null||v.classList.remove("dragging"));const h=o.kind==="pan"&&o.moved||(S==null?void 0:S.moved)===!0;K.style.display="none",S=null,o={kind:"none"},b!==void 0&&m.revert(b)&&Ie(),h&&M(),b=void 0;try{k.releasePointerCapture(a.pointerId??0)}catch{}}function qe(a){O.isMenuOpen()&&O.closeMenu();const h=Fe(a);if(a.shiftKey&&!a.ctrlKey){const v=a.deltaMode===1?16:1;s=Et(dn(s,(a.deltaX??0)*v,(a.deltaY??0)*v))}else{const v=a.deltaMode===1?16:1,P=Math.exp(-((a.deltaY??0)*v)*.0015);s=Bn(s,P,h.x,h.y)}a.preventDefault(),ze(),M()}function ge(a){Ue(),s=Bn(s,a,We/2,lt/2),ze(),M()}function Ve(){m.undo()?(M(),Ie()):I("info","没有可撤销的布局改动")}function pt(){Ue(),s=Kn(Wn(t.contentBounds(),t.allNodes()),We,lt,Xn(ye,ne)),ze(),M()}function At(a){var de,Y,W,U,ae,Te,_e;if(O.isDialogOpen()||((Y=(de=a.target)==null?void 0:de.closest)==null?void 0:Y.call(de,".p-search"))!==null)return;if((a.ctrlKey||a.metaKey)&&a.key.toLowerCase()==="k"){a.preventDefault(),He.focus();return}if((a.ctrlKey||a.metaKey)&&!a.shiftKey&&a.key.toLowerCase()==="z"){a.preventDefault(),Ve();return}if(a.ctrlKey||a.metaKey)return;if(O.isMenuOpen()){a.key==="Escape"&&(O.closeMenu(),a.preventDefault());return}if(a.key===" "&&a.target===k){i=!0,a.preventDefault();return}const h=((U=(W=a.target)==null?void 0:W.closest)==null?void 0:U.call(W,".p-frame-head"))??null;if((a.key==="Enter"||a.key===" ")&&h!==null){a.preventDefault();const Se=h.getBoundingClientRect();O.contextMenuAt(Se.left+Se.width/2,Se.top+Se.height/2,h);return}if(a.key===" "&&((Te=(ae=a.target)==null?void 0:ae.classList)!=null&&Te.contains("p-node"))){const g=a.target.dataset.id??"",te=t.selectedIds();t.setSelection(te.includes(g)?te.filter(ue=>ue!==g):[...te,g]),Ie(),a.preventDefault();return}if(a.key==="F10"&&a.shiftKey||a.key==="ContextMenu"){a.preventDefault();const Se=document.activeElement??null,g=((_e=Se==null?void 0:Se.getBoundingClientRect)==null?void 0:_e.call(Se))??{left:0,top:0,width:0,height:0};O.contextMenuAt(g.left+g.width/2,g.top+g.height/2,Se);return}if(a.key==="Delete"||a.key==="Backspace"){a.preventDefault(),rn();return}if(a.altKey&&(a.key==="ArrowUp"||a.key==="ArrowDown")){a.preventDefault(),yo(a.key==="ArrowUp");return}if(a.key==="g"||a.key==="G"){O.startCreateFromSelection();return}if(a.key==="0"){pt();return}if(a.key==="="||a.key==="+"){ge(1.2);return}if(a.key==="-"){ge(1/1.2);return}if(a.key==="Escape"){if(O.isMenuOpen()){O.closeMenu(),Ie();return}t.setSelection([]),Ie();return}const v=a.shiftKey?40:8,F={ArrowLeft:[-v,0],ArrowRight:[v,0],ArrowUp:[0,-v],ArrowDown:[0,v]}[a.key];if(F!==void 0){a.preventDefault();const Se=t.selectedIds();if(Se.length>0){const g=m.capture();t.nudge(Se,F[0],F[1]),m.commit(g),Ie(),M()}}}function rn(){var P,F,de;const a=document.activeElement,h=((P=a==null?void 0:a.closest)==null?void 0:P.call(a,".p-frame-head"))??null,v=((F=a==null?void 0:a.closest)==null?void 0:F.call(a,".p-node"))??null;if(h!==null){$({type:"remove-team",name:h.dataset.frame??""});return}if(v!==null){const Y=v.dataset.id??"",W=((de=t.getNode(Y))==null?void 0:de.memberships.map(U=>U.team))??[];if(W.length===0){I("info","该节点未加入任何团队");return}if(W.length===1){$({type:"remove-member",team:W[0],ids:[Y]});return}O.openMenu(window.innerWidth/2,window.innerHeight/2,{kind:"node",id:Y},"leave",v);return}I("info","焦点不在节点或团队框上")}function yo(a){var Te,_e;const h=document.activeElement,v=((Te=h==null?void 0:h.closest)==null?void 0:Te.call(h,".p-node"))??null;if(v===null)return;const P=v.dataset.id??"",F=((_e=t.getNode(P))==null?void 0:_e.memberships)??[];if(F.length!==1)return;const de=F[0].team,Y=t.teamMemberIds(de),W=Y.indexOf(P),U=a?Math.max(0,W-1):Math.min(Y.length-1,W+1);if(U===W)return;const ae=[...Y];ae.splice(W,1),ae.splice(U,0,P),$({type:"reorder",team:de,ops:bn(Y,ae)})}function $n(a){a.key===" "&&(i=!1)}k.addEventListener("pointerdown",a=>Re(a),N),k.addEventListener("pointermove",a=>Je(a),N),k.addEventListener("pointerup",a=>Qe(a),N),k.addEventListener("pointercancel",a=>ut(a),N),k.addEventListener("wheel",a=>qe(a),{...N,passive:!1}),k.addEventListener("keydown",a=>At(a),N),k.addEventListener("keyup",a=>$n(a),N),k.addEventListener("contextmenu",a=>{var v,P;const h=a;if(((P=(v=h.target)==null?void 0:v.closest)==null?void 0:P.call(v,"input, textarea, .p-search"))==null){if(h.preventDefault(),C){C=!1;return}O.contextMenuAt(h.clientX,h.clientY,h.target)}},N);let Dt=[];function wo(a){var Se;Dt=a.teams,x=new Set([...a.teams.filter(g=>g.kind==="roster").map(g=>g.name),...[...x].filter(g=>Ee.has(g))]),a.peers,l.setInFlight(a.inFlight??[]),oe=a.sessions,O.setUnjoined(a.sessions.filter(g=>g.joined!==!0&&!g.id.startsWith("peer-")));const h=new Map;for(const g of a.teams)for(let te=0;te<g.members.length;te++){const ue=g.members[te].id,Pe=h.get(ue)??[];Pe.push({team:g.name,index:te}),h.set(ue,Pe)}le=new Set(h.keys());const v=new Set,P=g=>{const te=h.get(g)??[];if(Ee.size===0)return te;const ue=te.filter(Ae=>!Ee.has(Ae.team)),Pe=[];for(const[Ae]of Ee){const ke=t.teamMemberIds(Ae).indexOf(g);ke>=0&&Pe.push({team:Ae,index:ke})}return[...ue,...Pe]};let F;if(n===void 0&&!t.allNodes().some(g=>g.remote!==!0)){const g=a.sessions.filter(te=>{var ue;return te.joined===!0&&(P(te.id).length>0||(((ue=te.teams)==null?void 0:ue.length)??0)>0)}).map(te=>te.id);Ue(),F=ns(a.teams,g,We>0?We:void 0)}for(const g of a.sessions){if(g.joined!==!0)continue;const te=P(g.id);if(!(te.length===0&&(g.teams===void 0||g.teams.length===0)))if(v.add(g.id),t.getNode(g.id)!==void 0)t.upsertNode({id:g.id,x:t.getNode(g.id).x,y:t.getNode(g.id).y,label:g.label,team:g.team,name:g.name,description:g.description,live:g.live!==!1,memberships:te,...g.teams!==void 0&&g.teams.length>0?{teams:g.teams}:{}});else{const ue=n==null?void 0:n.nodes[g.id];let Pe,Ae;if(ue!==void 0)Pe=ue.x,Ae=ue.y;else{const me=(F==null?void 0:F.get(g.id))??Nn(g.id);Pe=me.x,Ae=me.y}t.upsertNode({id:g.id,x:Pe,y:Ae,label:g.label,team:g.team,name:g.name,description:g.description,live:g.live!==!1,memberships:te,...g.teams!==void 0&&g.teams.length>0?{teams:g.teams}:{}})}}for(const g of t.nodeIds())!v.has(g)&&!g.startsWith("peer-")&&!g.startsWith("member-")&&t.removeNode(g);const de=new Set;A=cs(a.remoteTeams??[]),L=new Map(a.sessions.map(g=>[g.id,{status:g.status,queued:g.queued}])),w=Qn(a),Q.clear();for(const g of a.peers??[])Q.set(at(g.url),g.score),B.set(at(g.url),{link:g.link,verified:g.verified});if(a.peers!==void 0){const g=t.contentBounds(),te=fs(a.peers,g);a.peers.forEach((ue,Pe)=>{var Lt,yt,Mn,Sn;const Ae=as(ue.url);de.add(Ae);const me=n==null?void 0:n.nodes[Ae],ke=t.getNode(Ae),Ge=ke!==void 0?{x:ke.x,y:ke.y}:me!==void 0?{x:me.x,y:me.y}:{x:((Lt=te[Pe])==null?void 0:Lt.x)??200,y:((yt=te[Pe])==null?void 0:yt.y)??0},tt=at(ue.url),vt=(Sn=(Mn=A.get(tt))==null?void 0:Mn[0])==null?void 0:Sn.team;t.upsertNode({id:Ae,x:Ge.x,y:Ge.y,label:ue.url,team:"",name:ue.url,peerUrl:ue.url,remoteHandle:vt,live:!0,remote:!0,memberships:[]}),t.upsertScore(Ae,ue.score)})}for(const g of t.nodeIds())g.startsWith("peer-")&&!de.has(g)&&t.removeNode(g);const Y=new Set;for(const[g,te]of A){const ue=t.allNodes().find(me=>me.remote===!0&&at(me.peerUrl??"")===g&&!me.id.startsWith("member-")),Pe=((ue==null?void 0:ue.x)??400)+190;let Ae=(ue==null?void 0:ue.y)??0;for(const me of te){if(!me.team.includes("/"))continue;const ke=`member-${me.team.replace(/[^a-z0-9-]/gi,"-")}`;if(Y.has(ke))continue;Y.add(ke);const Ge=n==null?void 0:n.nodes[ke],tt=t.getNode(ke),vt=tt!==void 0?{x:tt.x,y:tt.y}:Ge!==void 0?{x:Ge.x,y:Ge.y}:{x:Pe,y:Ae};Ae+=92,t.upsertNode({id:ke,x:vt.x,y:vt.y,label:me.team,team:me.team,name:me.name!==void 0&&me.name!==""?me.name:me.team,remoteHandle:me.team,live:!0,remote:!0,memberships:[]})}}for(const g of t.nodeIds())g.startsWith("member-")&&!Y.has(g)&&t.removeNode(g);const W=new Map;for(const g of t.allNodes())g.remote!==!0||g.remoteHandle===void 0||g.remoteHandle===""||(!W.has(g.remoteHandle)||g.id.startsWith("member-"))&&W.set(g.remoteHandle,g.id);for(const g of a.teams){if(Ee.has(g.name))continue;const te=[];for(const Ae of g.members){const me=W.get(Ae.id)??Ae.id;t.getNode(me)!==void 0&&te.push(me)}const ue=[...t.teamMemberIds(g.name)].sort().join("|"),Pe=[...te].sort().join("|");ue!==Pe&&t.setTeamMembers(g.name,te)}const U=new Map,ae=et;if(et=U,a.peerOrg!==void 0){let g=0;const te=new Set(a.teams.map(ue=>ue.name));H.sweep(a.peerOrg);for(const ue of a.peerOrg){const Pe=new Set((a.remoteTeams??[]).map(me=>me.team)),Ae=ys(a.sessions,Pe);for(const me of ue.org){if(me.name===""||te.has(me.name)||H.hides(me.name,ue.url))continue;const ke=me.members.map(tt=>ws(tt,Ae,a.remoteTeams,ue.url)).filter(tt=>t.getNode(tt)!==void 0),Ge=(Se=n==null?void 0:n.frames)==null?void 0:Se[me.name];t.getFrame(me.name)===void 0&&t.setFrame(me.name,Ge!==void 0?{x:Ge.x,y:Ge.y,w:Ge.w,h:Ge.h}:{x:200+g%4*280,y:940+Math.floor(g/4)*160,w:250,h:130}),t.setTeamMembers(me.name,ke),U.set(me.name,ue.url),g+=1}}}for(const[g,te]of ae)U.has(g)||t.removeFrame(g);const Te=new Map;for(const g of t.allNodes())g.remote===!0&&g.remoteHandle!==void 0&&g.remoteHandle!==""&&Te.set(g.remoteHandle,g.id);const _e=po(a.teams);for(const g of a.teams){if(t.getFrame(g.name)!==void 0||Ee.has(g.name))continue;const te=n==null?void 0:n.frames[g.name];if(te!==void 0){t.setFrame(g.name,{...te});continue}const ue=[],Pe=[];for(const me of g.members){const ke=t.getNode(Te.get(me.id)??me.id);ke!==void 0&&(Pe.push(ct(ke)),_e.get(ke.id)===g.name&&ue.push(ct(ke)))}const Ae=ue.length>0?ue:Pe;Ae.length>0&&t.setFrame(g.name,Cn(Ae))}for(const[g]of t.allFrames())Ee.has(g)||!a.teams.some(te=>te.name===g)&&!U.has(g)&&t.removeFrame(g);if(V.refresh(),re(a),!d&&o.kind==="none"&&t.nodeIds().length>0){d=!0;const g=m.capture();Xt(t,new Set(et.keys())),m.commit(g)}c&&o.kind==="none"&&t.nodeIds().length>0&&(Ue(),We>0&&lt>0&&(c=!1,s=Kn(Wn(t.contentBounds(),t.allNodes()),We,lt,Xn(ye,ne)))),Ie()}function Nn(a){return ho(a,t.allNodes().filter(h=>h.remote!==!0))}function xo(a){const h=mo(a);if(h===void 0)return;n=h;const v=e.viewportStore;if(v===void 0)c=!1,o.kind==="none"&&(s=Et({...h.viewport}));else if(!u&&o.kind==="none"){u=!0;const P=v.get(E());P!=null&&Number.isFinite(P.x)&&Number.isFinite(P.y)&&Number.isFinite(P.scale)?(s=Et({x:P.x,y:P.y,scale:P.scale}),c=!1):E()==="wide"&&(s=Et({...h.viewport}),c=!1)}r=-1,Ie()}function Co(){return Qo(s,t.positions(),t.frameRects())}function ko(a,h){ie.classList.remove("pending","saved","error"),a==="pending"&&ie.classList.add("pending"),a==="saved"&&ie.classList.add("saved"),a==="error"&&ie.classList.add("error"),a==="error"?(ie.tabIndex=0,ie.setAttribute("role","button"),ie.setAttribute("aria-label","布局保存失败,按回车重试")):(ie.removeAttribute("tabindex"),ie.removeAttribute("role"),ie.removeAttribute("aria-label"));const v=a==="pending"?"布局待保存…":a==="saved"?`布局已保存 ${h??""}`.trimEnd():a==="error"?"保存失败 · 回车重试":"布局";G.textContent=v}function Eo(){k.style.display="block",Ue(),ze(),k.focus()}function $o(){k.style.display="none"}function No(){fe.abort();for(const a of ee)clearTimeout(a)}return{root:k,reconcile:wo,activate:Eo,deactivate:$o,adoptExternalLayout:xo,snapshotDoc:Co,setLamp:ko,notice:I,destroy:No,seam:{pointerDown:Re,pointerMove:Je,pointerUp:Qe,pointerCancel:ut,wheel:qe,key:At,keyUp:$n,contextMenu(a){a.preventDefault(),O.contextMenuAt(a.clientX,a.clientY,a.target)}}}}const ui=800;function mi(e){let t,n=!1,s=!1,o=!1,i="idle";function r(b){b!==i&&(i=b,e.onLamp(b))}function c(){t!==void 0&&(t(),t=void 0)}function d(){c(),t=e.schedule(()=>{t=void 0,m(!1)},ui)}async function m(b){if(n){s=!0;return}n=!0,c();const u=e.snapshot();let E;try{E=JSON.stringify(u)}catch{n=!1,r("error"),e.onHttpError("layout document is not JSON-serializable");return}try{const M=await e.send(u,{keepalive:b});if(M===null||typeof M!="object"||M.ok!==!0){r("error");const q=M!==null&&typeof M=="object"&&typeof M.error=="string"?M.error:"layout save refused";e.onHttpError(`layout save: ${q}`)}else JSON.stringify(e.snapshot())===E&&(e.onAdopt(M.layout),r("saved"))}catch(M){r("error"),e.onHttpError(`layout save unreachable: ${String((M==null?void 0:M.message)??M).slice(0,80)}`)}if(n=!1,i==="error"){o=!1;return}if(o){o=!1,m(!0);return}s&&(s=!1,r("pending"),d())}return{markDirty(){if(s=!1,r("pending"),n){s=!0;return}d()},retry(){i!=="error"||n||(r("pending"),m(!1))},flush(){if(n){o=!0,s=!0;return}c(),m(!0)},isBusy(){return n},dispose(){c()}}}function Zn(e){return e!=null&&typeof e.error=="string"?e.error:void 0}function fi(e){const t=new Map;let n=0;function s(r,c){n+=1;const d=t.get(r)??Promise.resolve(),m=async()=>{try{return await c()}finally{n-=1}},b=d.then(m,m);return t.set(r,b.then(()=>{},()=>{})),b}async function o(r){var fe,ee,S,C;let c;try{c=await e.send(r)}catch(N){const k=String((N==null?void 0:N.message)??N).slice(0,80);return e.onNotice("error",`画布不可达:${k}`),!1}if(c.status>=400)return e.onNotice("error",Zn(c.body)??`HTTP ${c.status}`),!1;if(((fe=c.body)==null?void 0:fe.ok)===!0)return!0;const d=c.body!=null&&typeof c.body=="object"?Zn(c.body):void 0;if(d!==void 0)return e.onNotice("error",d),!1;const m=String(r.name??""),b=String(r.id??""),u=(ee=c.body)==null?void 0:ee.members,E=(S=c.body)==null?void 0:S.teams,M=Array.isArray(u)&&u.every(N=>typeof N=="string"),q=Array.isArray(E)&&E.every(N=>typeof N=="string");return((C=c.body)==null?void 0:C.ok)===!1&&(r.action==="add-member"&&M&&u.includes(b)||r.action==="remove-member"&&M&&!u.includes(b)||r.action==="remove"&&q&&!E.includes(m))?!0:(e.onNotice("error","画布操作未确认:"+String(r.action)+"(可能队伍/成员已达上限,请重试)"),!1)}async function i(r,c){for(const d of c)if(!await o({...r,id:d}))return!1;return!0}return{createTeam(r,c){return s(r,async()=>{if(!await o({action:"create",name:r}))return!1;for(let d=0;d<c.length;d++)if(!await o({action:"add-member",name:r,id:c[d]}))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 d of c){const m=d.op==="remove"?{action:"remove-member",name:r,id:d.id}:{action:"add-member",name:r,id:d.id};if(!await o(m))return!1}return!0})},removeTeam(r){return s(r,()=>o({action:"remove",name:r}))},hasPending(){return n>0}}}const vo=document.getElementById("app"),pi=(()=>{try{return window.sessionStorage.getItem("dsh_a2a_key")??""}catch{return""}})(),gn=window.__DSH_A2A_KEY__??pi,Ke=(e,t={})=>fetch(e,{...t,headers:{...t.headers??{},...gn!==""?{"X-API-Key":gn}:{}}});gn===""&&Ke("/__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 n=document.createElement("div");n.textContent="此面板经远程面打开(密钥不随页面下发)——输入控制密钥";const s=document.createElement("input");s.type="password",s.placeholder="X-API-Key",s.setAttribute("aria-label","控制密钥");const o=document.createElement("button");o.type="button",o.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(d=>{if(d.status===401){i.textContent="密钥不对,再试一次";return}try{window.sessionStorage.setItem("dsh_a2a_key",c)}catch{}window.location.reload()})};o.addEventListener("click",r),s.addEventListener("keydown",c=>{c.key==="Enter"&&r()}),t.append(n,s,o,i),document.body.appendChild(t)});const Ft=document.createElement("div");Ft.className="nexus-fault";vo.appendChild(Ft);const{fault:vn,clear:hi}=Ao({show(e){Ft.textContent=e,Ft.style.display="block"},hide(){Ft.style.display="none"}},e=>console.error(e));let Vt;const eo="dsh-a2a.viewport.",bi={get(e){try{const t=window.localStorage.getItem(eo+e);return t===null?void 0:JSON.parse(t)}catch{return}},set(e,t){try{window.localStorage.setItem(eo+e,JSON.stringify({x:t.x,y:t.y,scale:t.scale}))}catch{}}},ot=di({viewportStore:bi,onDirty:()=>tn.markDirty(),onLampClick:()=>tn.retry(),onNodePick:e=>{Vt==null||Vt(e)},onCanvasAction:async e=>{const t=await vi(e);return sn(),t}}),tn=mi({snapshot:()=>ot.snapshotDoc(),send:(e,t)=>Ke("/__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 n=>await n.json()),schedule:(e,t)=>{const n=setTimeout(e,t);return()=>{clearTimeout(n)}},now:Date.now,onLamp:e=>{yn=e;const t=new Date,n=String(t.getHours()).padStart(2,"0")+":"+String(t.getMinutes()).padStart(2,"0");ot.setLamp(e,n)},onAdopt:e=>{ot.adoptExternalLayout(e)},onHttpError:e=>vn(e)});window.addEventListener("pagehide",()=>tn.flush());const _t=fi({send:async e=>{const t=await Ke("/__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)=>ot.notice(e,t)});async function to(e,t,n,s){const o=await Ke("/__dsh_a2a/fleet-canvas-op",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({peer:e,op:t,name:n,...s!==void 0?{id:s}:{}}),cache:"no-store"}).catch(()=>{}),i=o!==void 0?await o.json().catch(()=>{}):void 0;return(i==null?void 0:i.ok)===!0&&t==="remove"&&i.removed===!1&&ot.notice("info",`属主那边已没有「${n}」,无需解散`),(i==null?void 0:i.ok)===!0?!0:(ot.notice("error",`跨主机团队操作失败:${String((i==null?void 0:i.error)??"对端无响应")}`),!1)}async function gi(e,t){const n=async s=>{const o=await Ke("/__dsh_a2a/roster-op",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:t,...s})}).catch(()=>{}),i=o!==void 0?await o.json().catch(()=>{}):void 0;return o!=null&&o.ok&&(i==null?void 0:i.ok)===!0?!0:(ot.notice("error",`roster 操作失败:${String((i==null?void 0:i.error)??(o?`HTTP ${o.status}`:"无响应"))}`),!1)};if(e.type==="create-team")return n({op:"create",ids:e.ids});if(e.type==="remove-team")return n({op:"dissolve"});if(e.type==="add-member"||e.type==="remove-member"){for(const s of e.ids)if(!await n({op:e.type,id:s}))return!1;return!0}return ot.notice("error","roster 不支持该操作"),!1}function vi(e){if((e.type==="add-member"||e.type==="remove-member")&&e.fleetPeer!==void 0){const t=e.fleetPeer;return(async()=>{for(const n of e.ids)if(!await to(t,e.type,e.team,n))return!1;return!0})()}if(e.type==="remove-team"&&e.fleetPeer!==void 0)return to(e.fleetPeer,"remove",e.name);if(e.roster===!0){const t=go(Rt(e));return t!==void 0?gi(e,t):(ot.notice("error","无效的 roster 框名"),Promise.resolve(!1))}switch(e.type){case"create-team":return _t.createTeam(e.name,e.ids,e.created);case"add-member":return _t.addMembers(e.team,e.ids);case"remove-member":return _t.removeMembers(e.team,e.ids);case"remove-team":return _t.removeTeam(e.name);case"reorder":return _t.runRosterOps(e.team,e.ops);case"join-network":case"leave-network":return yi(e.type==="join-network"?"join":"leave",e.id)}}async function yi(e,t){const n=await Ke(`/__dsh_a2a/${e}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:t}),cache:"no-store"}).catch(()=>{});return n!==void 0&&n.ok}let yn="idle",mn=new Set,no=0,nn=!1,oo,fn=!1;async function wi(){const e=await Ke("/__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 on=Vo({now:()=>Date.now(),async ownerSettingsRead(){try{return await(await Ke("/__dsh_a2a/owner-settings")).json()}catch{return{ok:!1,error:"unreachable"}}},async ownerSettingsWrite(e){try{return await(await Ke("/__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 Ke("/__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 n=await Ke("/__dsh_a2a/canvas",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({action:"cli-home-options",name:e,id:t})}),s=await n.json();return{...s,ok:n.ok&&s.ok===!0}}catch(n){return{ok:!1,error:String(n)}}},async canvasOp(e,t,n,s){try{const o=await Ke("/__dsh_a2a/canvas",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({action:e,name:t,id:n,...s===void 0?{}:{home:s}})}),i=await o.json().catch(()=>({}));return o.ok&&i.ok!==!1?!0:(console.warn(`canvas ${e} ${t}: ${i.error??`HTTP ${o.status}`}`),!1)}catch{return!1}},async dispatchQuick(e,t){try{const n=await Ke("/__dsh_a2a/dispatch",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({team:e,message:t})}),s=await n.json().catch(()=>({}));return{ok:n.ok&&s.ok===!0,task_id:s.task_id,reply:s.reply,error:s.error??`HTTP ${n.status}`}}catch(n){return{ok:!1,error:n instanceof Error?n.message:String(n)}}},async sessionLog(e){try{const t=await Ke(`/__dsh_a2a/session-log?id=${encodeURIComponent(e)}`),n=await t.json().catch(()=>({}));return{ok:t.ok&&n.ok===!0,messages:n.messages,error:n.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 Ke("/__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 n=await Ke(`/__dsh_a2a/remote-session-log?${t.toString()}`),s=await n.json().catch(()=>({}));return{ok:n.ok&&s.ok===!0,messages:s.messages,sessions:s.sessions,error:s.error??(n.ok?void 0:`HTTP ${n.status}`),via:s.via}}catch(t){return{ok:!1,error:t instanceof Error?t.message:String(t)}}},board:{root:ot.root,activate:()=>ot.activate(),deactivate:()=>ot.deactivate(),available:()=>nn}});vo.appendChild(on.root);Vt=e=>{on.openNodeChat(e)};if(new URLSearchParams(window.location.search).get("mode")==="plan"){const e=window.setInterval(()=>{nn&&(on.selectTab("board"),window.clearInterval(e))},300);window.setTimeout(()=>window.clearInterval(e),3e4)}async function sn(){var e,t;try{const n=await Ke("/__dsh_a2a/state",{cache:"no-store"});if(!n.ok)throw new Error(`/__dsh_a2a/state ${n.status}`);const s=await n.json();if(Date.now()-no>=15e3){no=Date.now();try{const u=await Ke("/__dsh_a2a/nodes",{cache:"no-store"});if(!u.ok)throw new Error(`nodes ${u.status}`);const E=await u.json();mn=new Set((E.bindings??[]).filter(M=>M.mounted!==null&&M.effective!==null&&(M.effective.core===!1||M.effective.mutable===!1)).map(M=>M.session))}catch{mn.clear()}}const o={...s,sessions:(s.sessions??[]).map(u=>({...u,...mn.has(u.id)?{nodePromptMissing:!0}:{}}))};if(hi(),nn=s.canvas!==void 0,on.update(o),nn)try{const u=await wi(),E=JSON.stringify(u??null);E!==oo&&(oo=E,(yn==="idle"||yn==="saved")&&!tn.isBusy()&&ot.adoptExternalLayout(u)),fn=!0}catch(u){if(!fn){vn(`canvas layout 获取失败:${String(u)}`);return}}else fn=!0;const i=(s.sessions??[]).map(u=>({...u,joined:u.joined===!0})),r=[...((e=s.canvas)==null?void 0:e.teams)??[],...Ss(((t=s.registry)==null?void 0:t.teams)??[],s.zone??"")],c=(s.peers??[]).filter(u=>u!==null&&typeof u=="object"&&typeof u.url=="string"),d=(s.inFlight??[]).filter(u=>u!==null&&typeof u=="object"&&typeof u.team=="string"&&typeof u.peer=="string"&&Number.isFinite(u.startedAt)),m=(s.remote??[]).filter(u=>u!==null&&typeof u=="object"&&typeof u.team=="string"&&typeof u.via=="string").map(u=>({team:u.team,name:u.name,via:u.via,workspace:u.workspace,...u.unreachable===!0?{unreachable:!0}:{},...typeof u.origin=="string"&&u.origin!==""?{origin:u.origin}:{},...Array.isArray(u.teams)&&u.teams.length>0?{teams:u.teams.filter(E=>typeof E=="string"&&E!=="")}:{}})),b=(s.peerOrg??[]).filter(u=>u!==null&&typeof u=="object").filter(u=>typeof u.url=="string"&&Array.isArray(u.org)).map(u=>({url:u.url,...u.unreachable===!0?{unreachable:!0}:{},org:u.org.filter(E=>E!==null&&typeof E=="object").filter(E=>typeof E.team=="string"&&E.team!=="").map(E=>({name:typeof E.name=="string"?E.name:"",team:E.team,members:Array.isArray(E.members)?E.members.filter(M=>typeof M=="string"):[]}))}));ot.reconcile({sessions:i,teams:r,peerCount:c.length,peers:c,inFlight:d,remoteTeams:m,peerOrg:b})}catch(n){vn(`state 轮询失败:${String(n)}`)}}sn();window.setInterval(()=>{document.hidden||sn()},3e3);document.addEventListener("visibilitychange",()=>{document.hidden||sn()});