@nelsonlongxiang/dsh-open-a2a-net 0.6.32 → 0.6.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -1
- package/README_zh.md +7 -1
- package/assets/nexusDist/assets/index-BACVZe0j.css +1 -0
- package/assets/nexusDist/assets/index-Bbxnpf2p.js +9 -0
- package/assets/nexusDist/index.html +2 -2
- package/cli/a2a.mjs +5 -2
- package/lib/canvas-store.js +6 -0
- package/lib/client.js +63 -63
- package/lib/faces/admin.js +43 -4
- package/lib/faces/wire.js +8 -6
- package/lib/index.js +11 -6
- package/lib/layout-store.js +3 -2
- package/lib/roster-op.js +104 -0
- package/lib/skill/references/cli.md +1 -1
- package/lib/skill/references/router.md +1 -1
- package/lib/team-store.js +49 -1
- package/lib/types/canvas-store.d.ts +4 -0
- package/lib/types/faces/admin.d.ts +1 -0
- package/lib/types/faces/wire.d.ts +1 -0
- package/lib/types/roster-op.d.ts +21 -0
- package/lib/types/team-store.d.ts +7 -0
- package/nexus-stage/src/canvas-ops.ts +2 -1
- package/nexus-stage/src/layout-doc.ts +6 -4
- package/nexus-stage/src/main.ts +27 -2
- package/nexus-stage/src/planning-frame-hue.ts +13 -0
- package/nexus-stage/src/planning-legend.ts +1 -0
- package/nexus-stage/src/planning-menus.ts +28 -12
- package/nexus-stage/src/planning-roster.ts +15 -0
- package/nexus-stage/src/planning-types.ts +1 -1
- package/nexus-stage/src/planning-view.ts +29 -27
- package/nexus-stage/src/planning.css +2 -0
- package/nexus-stage/src/workbench.ts +2 -0
- package/package.json +3 -2
- package/assets/nexusDist/assets/index-D5H8R8de.js +0 -9
- package/assets/nexusDist/assets/index-D9GYZyGZ.css +0 -1
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ shared tool runtime.
|
|
|
35
35
|
|
|
36
36
|
## What you get
|
|
37
37
|
|
|
38
|
-
- **Model tools** (
|
|
38
|
+
- **Model tools** (see the table below) — `a2a_teams` lists the teams this node can see (its own rows
|
|
39
39
|
plus peer teams inside the joined-team scope); `a2a_route`
|
|
40
40
|
sends one message to a team, reuses `context_id` to continue a remote conversation, and fails over across
|
|
41
41
|
candidates when a peer is unreachable. `a2a_tasks` reconciles the receipt contract across three tiers: every route that leaves a
|
|
@@ -82,6 +82,8 @@ this host's joined-team scope: `[this host]` rows plus peers serving a team this
|
|
|
82
82
|
| `a2a_exposure` | How visible is this session? | Sets the session's own tier: `linked` (the default floor) or `fleet` (a voluntary opt-up); a group's visibility follows its strictest member. Requires a joined session. |
|
|
83
83
|
| `a2a_report` | Tell this host's supervision something while off the network. | The one ingress exempt from the join gate: one-way, lands in the state face's reports ring, grants no presence or routing. One report per 30s per session, ≤4000 chars, identical text 3× in 10 min is refused as a loop. |
|
|
84
84
|
| `a2a_status` | What is this node doing right now? | In-scope tracked peers with quality scores, in-flight routes, recent routing activity, and the idempotency window aggregate (occupancy + claim/replay/conflict counters). |
|
|
85
|
+
| `a2a_file_send` | Hand files to a team without putting them in a message. | Stages each file (≤16 per call, ≤64 MiB each) on this host for that team and routes ONE message of `[A2A file]` reference lines; the bytes never ride the message (#91). |
|
|
86
|
+
| `a2a_file_fetch` | Pull a file someone referenced. | Pulls one `[A2A file]` reference from the host that staged it, signed as this session; checks size and sha256 before saving it under `<cwd>/a2a-inbox/`. A grant names one session (or a whole host, or a canvas team's members); the fetch always marks the session as having read peer content. |
|
|
85
87
|
|
|
86
88
|
## a2a-net CLI (callers outside a session)
|
|
87
89
|
|
|
@@ -158,6 +160,7 @@ Row config overlays in the profile's patch layers; every key has a schema defaul
|
|
|
158
160
|
| `originClaimUnboundWindow` | `true` | OriginClaim audience-binding window: also sign and accept the legacy envelope that names no audience (accepted ones counted as `unboundInbound`; those whose bound form missed here also as `boundMissInbound`); `false` signs and accepts the audience-bound form only. |
|
|
159
161
|
| `originClaimAudiences` | `[]` | Extra origins this host answers to as an envelope audience, for port-mapped or proxied hosts whose dialed URL is neither the card URL nor the arrival address. |
|
|
160
162
|
| `gateAgentLessCalls` | `'audit'` | Host-side (agent-less) routing calls: audit them, or `refuse`. |
|
|
163
|
+
| `settlementAuth` | `'observe'` | Settlement authorization (#114): `off`, `observe` (record what would be refused, settle as before), or `enforce`. |
|
|
161
164
|
| `asyncNudgeDelayMs` | `120000` | Delay before a delivered-but-unconsumed async route re-wakes its target with a one-line nudge; `0` disables. |
|
|
162
165
|
| `taskStaleTtlMs` | `86400000` | Owed-task stale TTL (24h): past it a pending row auto-dead-letters (a late receipt can still settle it). |
|
|
163
166
|
| `dshHome` | `''` | DSH home directory override for the plugin's state (`<home>/a2a/…`); `''` resolves the default home. |
|
|
@@ -194,6 +197,7 @@ Set an `apiKey` before exposing the listener beyond loopback.
|
|
|
194
197
|
| `GET /__dsh_a2a/state` | The state face the panel and workbench poll (sessions, canvas, peers, remote rows, activity, ledger). |
|
|
195
198
|
| `POST /__dsh_a2a/join` · `/leave` | Join or leave one session node. |
|
|
196
199
|
| `/__dsh_a2a/canvas` · `/canvas-layout` | Canvas teams (create/remove/add-member/remove-member) and the board layout. |
|
|
200
|
+
| `POST /__dsh_a2a/roster-op` | Owner-controlled roster team creation, member add/remove, dissolution, and exact allowlist maintenance. |
|
|
197
201
|
| `/__dsh_a2a/groups` | Manual session grouping — deprecated since 0.6.6 (canvas teams supersede it), kept for old panels. |
|
|
198
202
|
| `POST /__dsh_a2a/dispatch` | Workbench quick dispatch into a team. |
|
|
199
203
|
| `POST /__dsh_a2a/tasks/abandon` · `/tasks/cancel` | Settle an owed task from the caller side (cancel also steers a stop notice to a live local target); the row lands in `archived[]`. |
|
|
@@ -201,6 +205,8 @@ Set an `apiKey` before exposing the listener beyond loopback.
|
|
|
201
205
|
| `/__dsh_a2a/owner-settings` | The owner panel: read (GET) or write (POST) `teamJoinAllowlist`, `teamScopeInfo` and `announce` into the home patch layer (the first two apply immediately; `announce` on the next restart). |
|
|
202
206
|
| `/__dsh_a2a/fleet-canvas-op` | Relay a canvas operation (`create`, `add-member`, `remove-member`, `remove`) to a peer's `/a2a/canvas-op`, stamped with this node's OriginClaim; the peer's link gate decides. |
|
|
203
207
|
| `/__dsh_a2a/cli-deposit` | Deposit, list, revoke and mailbox reads for `a2a-net` CLI identities. |
|
|
208
|
+
| `GET /__dsh_a2a/nodes` · `POST` | Node identities (docs/design/node-identity.md): GET reads the roster or one node (`?name=`); POST is an identity write and needs the apiKey even on loopback. |
|
|
209
|
+
| `POST /__dsh_a2a/blob` | Stage a file for a recipient (`?to=&name=`) — the file channel's write side; peers pull through `GET /a2a/blob`. |
|
|
204
210
|
|
|
205
211
|
The state face's ledger: `tasks` (pending, each with `settleable`), `tasksStaleCount`, `tasksDead` (with
|
|
206
212
|
`direction` when known), and `archived` — the newest 64 settled rows, newest first, each with `outcome`,
|
package/README_zh.md
CHANGED
|
@@ -33,7 +33,7 @@ dsh plugin --profile web add @nelsonlongxiang/dsh-open-a2a-net
|
|
|
33
33
|
|
|
34
34
|
## 模型工具一览
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
`teamScopeInfo` 开启时(默认),`a2a_teams`、`a2a_status`、`a2a_probe` 只在本宿主的已加入团队作用域内作答:`[this host]` 本机行,加上服务于本宿主节点所声明团队的 peers。`a2a_tasks`(本宿主自己的派单账本)不受作用域限制。
|
|
37
37
|
|
|
38
38
|
| 工具 | 回答什么 | 说明 |
|
|
39
39
|
| --- | --- | --- |
|
|
@@ -47,6 +47,8 @@ dsh plugin --profile web add @nelsonlongxiang/dsh-open-a2a-net
|
|
|
47
47
|
| `a2a_exposure` | 本会话有多可见? | 设置会话自己的暴露档:`linked`(默认下限)或 `fleet`(自愿上调);组的可见性取最严成员。需会话已加入网络。 |
|
|
48
48
|
| `a2a_report` | 不在网时向本宿主监督面报告。 | 唯一不受加入门约束的入口:单向,落入状态面的 reports 环,不授予在场或路由权。每会话 30s 一次、≤4000 字,同文 10 分钟内 3 次按循环拒绝。 |
|
|
49
49
|
| `a2a_status` | 本节点此刻在做什么? | 作用域内受跟踪 peers 及质量分、在途路由、近期路由活动,以及幂等窗口汇总(占用 + claim/replay/conflict 计数)。 |
|
|
50
|
+
| `a2a_file_send` | 把文件交给一个团队,又不把文件塞进消息。 | 每个文件(每次 ≤16 个,单个 ≤64 MiB)暂存在本宿主、授权给该团队,然后只路由**一条**带 `[A2A file]` 引用行的消息;字节从不随消息走(#91)。 |
|
|
51
|
+
| `a2a_file_fetch` | 拉取别人引用的文件。 | 以本会话身份签名,从暂存它的宿主拉取一条 `[A2A file]` 引用;先核对大小和 sha256,再存到 `<cwd>/a2a-inbox/`。授权只对一个会话(或整台宿主、或某画布队的成员);拉取总会把本会话标为读过对端内容。 |
|
|
50
52
|
|
|
51
53
|
## a2a-net CLI(会话之外的调用方)
|
|
52
54
|
|
|
@@ -116,6 +118,7 @@ a2a-net inbox --new # 未读来信;--wait
|
|
|
116
118
|
| `originClaimUnboundWindow` | `true` | OriginClaim 受众绑定过渡窗口:同时签发并接受不带受众的旧信封(接受数计入 `unboundInbound`;其中绑定形式在本机未命中的另计 `boundMissInbound`);`false` 只签发、只接受绑定受众的信封。 |
|
|
117
119
|
| `originClaimAudiences` | `[]` | 本宿主额外认作信封受众的 origin,用于端口映射或反向代理宿主(对端拨号的 URL 既不是卡片 URL 也不是到达地址)。 |
|
|
118
120
|
| `gateAgentLessCalls` | `'audit'` | 宿主侧(无 agent)路由调用:审计,或 `refuse` 拒绝。 |
|
|
121
|
+
| `settlementAuth` | `'observe'` | 结算授权(#114):`off`、`observe`(记下本会拒绝的,照旧结算)或 `enforce`。 |
|
|
119
122
|
| `asyncNudgeDelayMs` | `120000` | 已投递但未被消费的异步路由,在此延迟后用一行催办重新唤醒目标;`0` 关闭。 |
|
|
120
123
|
| `taskStaleTtlMs` | `86400000` | 欠账任务的 stale TTL(24h):过期后 pending 行自动转死信(迟到回执仍可结清)。 |
|
|
121
124
|
| `dshHome` | `''` | 插件状态所用的 DSH home 目录覆盖(`<home>/a2a/…`);`''` 解析默认 home。 |
|
|
@@ -147,6 +150,7 @@ a2a-net inbox --new # 未读来信;--wait
|
|
|
147
150
|
| `GET /__dsh_a2a/state` | 面板与工作台轮询的状态面(会话、画布、peers、远端行、活动、账本)。 |
|
|
148
151
|
| `POST /__dsh_a2a/join` · `/leave` | 加入或退出一个会话节点。 |
|
|
149
152
|
| `/__dsh_a2a/canvas` · `/canvas-layout` | 画布队伍(create/remove/add-member/remove-member)与规划板布局。 |
|
|
153
|
+
| `POST /__dsh_a2a/roster-op` | 属主在画布创建、加减成员、解散 roster 队,并维护精确允许名单。 |
|
|
150
154
|
| `/__dsh_a2a/groups` | 手工会话分组——自 0.6.6 起弃用(被画布队伍取代),为旧面板保留。 |
|
|
151
155
|
| `POST /__dsh_a2a/dispatch` | 工作台快速派单到一个团队。 |
|
|
152
156
|
| `POST /__dsh_a2a/tasks/abandon` · `/tasks/cancel` | 从调用方一侧结清一个欠账任务(cancel 还会向在线的本地目标转达停止通知);该行落入 `archived[]`。 |
|
|
@@ -154,6 +158,8 @@ a2a-net inbox --new # 未读来信;--wait
|
|
|
154
158
|
| `/__dsh_a2a/owner-settings` | 属主面板:读取(GET)或写入(POST)`teamJoinAllowlist`、`teamScopeInfo` 与 `announce` 到 home patch 层(前两项即时生效;`announce` 下次重启生效)。 |
|
|
155
159
|
| `/__dsh_a2a/fleet-canvas-op` | 把画布操作中继到某 peer 的 `/a2a/canvas-op`,盖上本节点的 OriginClaim;由对端的链接门裁决。 |
|
|
156
160
|
| `/__dsh_a2a/cli-deposit` | `a2a-net` CLI 身份的寄存、列表、撤销与信箱读取。 |
|
|
161
|
+
| `GET /__dsh_a2a/nodes` · `POST` | 节点身份(docs/design/node-identity.md):GET 读名册或单个节点(`?name=`);POST 是身份写入,即使在 loopback 也要 apiKey。 |
|
|
162
|
+
| `POST /__dsh_a2a/blob` | 为接收方暂存一个文件(`?to=&name=`)——文件通道的写入面;对端经 `GET /a2a/blob` 拉取。 |
|
|
157
163
|
|
|
158
164
|
状态面的账本:`tasks`(pending,每行带 `settleable`)、`tasksStaleCount`、`tasksDead`(已知时带 `direction`),以及 `archived`——最新 64 条已结清行,最新在前,每行带 `outcome`、`endedBy`(`receipt` | `echo` | `abandoned` | `cancelled`)、回执在调用方结束之后才到时带 `late: true`、已知时带 `direction`——另有 `archivedCount` 与 `archivedSplit`(按结局计数)。
|
|
159
165
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#dsh-plan *,#dsh-plan *:before,#dsh-plan *:after{box-sizing:border-box}#dsh-plan{--uupm-ink-0:var(--n-ink,#dde3f0);--uupm-ink-1:var(--n-ink-muted,#7a86a0);--uupm-bg-0:var(--n-bg,#060a12);--uupm-bg-1:var(--n-panel,#0d1322);--uupm-bg-2:var(--n-raised,#131b2e);--uupm-accent:var(--n-accent,#9673f7);--uupm-live:var(--n-live,#4ade80);--uupm-cold:var(--n-cold,#7a86a0);--uupm-edge-member:var(--n-canvas,#22d3ee);--uupm-warn:var(--n-act,#f59e0b);--uupm-error:var(--n-danger,#f87171);--uupm-indigo:var(--n-federal,#6366f1);--uupm-wash-5:color-mix(in srgb,var(--uupm-accent) 5%,transparent);--uupm-wash-8:color-mix(in srgb,var(--uupm-accent) 8%,transparent);--uupm-wash-12:color-mix(in srgb,var(--uupm-accent) 12%,transparent);--uupm-wash-15:color-mix(in srgb,var(--uupm-accent) 15%,transparent);--uupm-wash-18:color-mix(in srgb,var(--uupm-accent) 18%,transparent);--surface:var(--uupm-bg-1);--ink:var(--uupm-ink-0);--ink-muted:var(--uupm-ink-1);--accent:var(--uupm-accent);--edge-live:var(--uupm-live);--edge-cold:var(--uupm-cold);--federal:var(--uupm-indigo);--card-bg:var(--surface);--card-line:var(--n-card-line,#5c6680);--card-line-hover:var(--uupm-ink-1);--toolbar-bg:color-mix(in srgb,var(--uupm-bg-1) 92%,transparent);--grid-dot:color-mix(in srgb,var(--uupm-ink-1) 22%,transparent);--scrim:color-mix(in srgb,var(--uupm-bg-0) 60%,transparent);--error-ink:var(--n-error-ink,#fecaca);--error-panel:var(--n-error-panel,#2a0d10f2)}#dsh-plan{position:absolute;top:0;right:0;bottom:0;left:0;overflow:hidden;background:var(--uupm-bg-0);color:var(--ink);font-size:13px;line-height:1.5;outline:none}#dsh-plan .mono{font-family:ui-monospace,Cascadia,Consolas,monospace}#dsh-plan:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}#dsh-plan .p-grid{position:absolute;top:0;right:0;bottom:0;left:0;z-index:0;pointer-events:none;background-image:radial-gradient(circle,var(--grid-dot) 1px,transparent 1px);background-size:24px 24px;background-position:0 0}#dsh-plan .p-world{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;transform-origin:0 0}#dsh-plan .p-layer{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none}#dsh-plan .p-edges{position:absolute;overflow:visible;width:100%;height:100%;pointer-events:none}#dsh-plan .p-frame{pointer-events:none}#dsh-plan .p-frame-head,#dsh-plan .p-node{pointer-events:auto}#dsh-plan .e-member{stroke:var(--uupm-edge-member);stroke-opacity:.38;stroke-width:1.5}#dsh-plan .e-member.dashed{stroke-dasharray:3 4}#dsh-plan .p-frame{--frame-ink:var(--frame-line,#8B5CF6)}@media (prefers-color-scheme: light){#dsh-plan .p-frame{--frame-ink:color-mix(in srgb,var(--frame-line,#8B5CF6) 72%,black)}}#dsh-plan .p-frame{position:absolute;border:1px solid var(--frame-ink);border-radius:10px;background:var(--frame-bg,var(--uupm-wash-5));min-width:120px;min-height:60px}#dsh-plan .p-frame-head{position:absolute;top:-13px;left:50%;transform:translate(-50%);height:24px;padding:0 10px;border-radius:6px;display:flex;gap:8px;align-items:center;background:var(--uupm-bg-2);border:1px solid var(--frame-ink);font-size:12px;font-weight:600;letter-spacing:.02em;white-space:nowrap;cursor:grab}#dsh-plan .p-frame-head:active{cursor:grabbing}#dsh-plan .p-frame-head:hover{border-color:var(--card-line-hover)}#dsh-plan .p-frame-head .cnt{color:var(--ink-muted);font-weight:400}#dsh-plan .p-frame-head .route{font-size:10.5px;color:var(--ink-muted)}#dsh-plan .p-frame.is-mirror{border-style:dashed}#dsh-plan .p-frame.is-roster{border-style:double;border-width:3px}#dsh-plan .p-frame.is-roster .p-frame-head{border-style:dashed}#dsh-plan .p-frame.is-syncing .p-frame-head .route{color:var(--accent)}#dsh-plan .p-frame.is-unreachable{opacity:.76;border-style:dashed}#dsh-plan .p-frame-unreachable{position:absolute;left:8px;top:20px;max-width:calc(100% - 16px);color:var(--uupm-error);font-size:11px;pointer-events:none}#dsh-plan .p-node.remote.is-unreachable{opacity:.72;border-left-color:var(--uupm-error)}#dsh-plan .p-node.remote.is-unreachable .sub{color:var(--uupm-error)}#dsh-plan .p-node{position:absolute;width:172px;height:56px;padding:8px 26px 8px 14px;background:var(--card-bg);border:1px solid var(--card-line);border-left:3px solid var(--edge-live);border-radius:8px;cursor:grab;-webkit-user-select:none;user-select:none;transition:border-color .12s cubic-bezier(.2,0,0,1),transform .12s cubic-bezier(.2,0,0,1)}#dsh-plan .p-node:hover{border-color:var(--card-line-hover)}#dsh-plan .p-node:active{cursor:grabbing}#dsh-plan .p-node:focus-visible{outline:2px solid var(--accent);outline-offset:2px}#dsh-plan .p-node.selected{outline:2px solid var(--accent);outline-offset:1px}#dsh-plan .p-node.dragging{transform:scale(1.02);border-color:var(--accent)}#dsh-plan .p-node.cold{border-left-color:var(--edge-cold)}#dsh-plan .p-node .nm{font-weight:600;display:flex;align-items:center;gap:7px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#dsh-plan .p-node .nm-text{min-width:0;overflow:hidden;white-space:normal;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;line-height:1.25}#dsh-plan .p-node.remote .nm-text{overflow-wrap:anywhere}#dsh-plan .p-node .dot{width:8px;height:8px;border-radius:50%;background:var(--edge-live);flex:none}#dsh-plan .p-node.cold .dot{background:transparent;border:1.5px solid var(--edge-cold)}#dsh-plan .p-node .sub{font-size:11px;color:var(--ink-muted);margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#dsh-plan .p-node.pulse{box-shadow:0 0 0 2px var(--accent),0 0 14px 4px var(--uupm-wash-15);border-color:var(--accent)}#dsh-plan .p-search{position:relative}#dsh-plan .p-search-input{width:170px;min-height:28px;padding:2px 8px;font-size:12px;background:transparent;color:var(--ink);border:1px solid var(--card-line);border-radius:6px}#dsh-plan .p-search-input:focus-visible{outline:2px solid var(--accent);outline-offset:1px}#dsh-plan .p-search-list{position:absolute;top:100%;left:0;margin-top:4px;display:none;min-width:240px;max-height:220px;overflow:auto;z-index:9;background:var(--toolbar-bg);border:1px solid var(--card-line);border-radius:6px}#dsh-plan .p-search-hit{padding:5px 10px;font-size:12px;color:var(--ink);cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#dsh-plan .p-search-hit:hover,#dsh-plan .p-search-hit.active{background:var(--uupm-wash-15)}#dsh-plan .p-node .prio{position:absolute;top:6px;right:8px;font-size:10px;color:var(--ink-muted);border:1px solid var(--card-line);border-radius:4px;padding:0 5px}#dsh-plan .p-marquee{position:absolute;z-index:2;display:none;pointer-events:none;border:1px solid var(--accent);background:var(--uupm-wash-8)}#dsh-plan .p-toolbar{position:absolute;top:16px;left:16px;z-index:3;display:flex;gap:6px;align-items:center;background:var(--toolbar-bg);border:1px solid var(--card-line);border-radius:8px;padding:6px 8px}#dsh-plan .p-tabs{position:absolute;top:16px;left:50%;transform:translate(-50%);z-index:3;display:flex;gap:4px;background:var(--toolbar-bg);border:1px solid var(--card-line);border-radius:8px;padding:4px}#dsh-plan .p-tabs [role=tab]{background:transparent;color:var(--ink-muted);border:1px solid transparent;border-radius:6px;padding:4px 12px;font:inherit;cursor:pointer}#dsh-plan .p-tabs [role=tab]:hover{color:var(--ink);border-color:var(--card-line)}#dsh-plan .p-tabs [role=tab][aria-selected=true]{color:var(--ink);border-color:var(--accent);background:var(--uupm-wash-12)}#dsh-plan .p-tabs [role=tab]:focus-visible{outline:2px solid var(--accent);outline-offset:1px}#dsh-plan .p-toolbar button{background:transparent;color:var(--ink);border:1px solid var(--card-line);border-radius:6px;padding:4px 10px;font:inherit;cursor:pointer;white-space:nowrap}#dsh-plan .p-toolbar button:hover{border-color:var(--accent)}#dsh-plan .p-toolbar button:active{background:var(--uupm-wash-15)}#dsh-plan .p-toolbar button:focus-visible{outline:2px solid var(--accent);outline-offset:1px}#dsh-plan .p-zoom{min-width:44px;text-align:center;font-size:11px;color:var(--ink-muted)}#dsh-plan .p-sep{align-self:stretch;width:1px;margin:2px 4px;background:var(--card-line)}#dsh-plan .p-lamp{display:flex;align-items:center;gap:6px;font-size:11px;color:var(--ink-muted);padding:0 6px}#dsh-plan .p-lamp i{width:7px;height:7px;border-radius:50%;background:var(--ink-muted);transition:background .14s ease}#dsh-plan .p-lamp.saved i{background:var(--edge-live)}#dsh-plan .p-lamp.pending i{background:var(--uupm-warn)}#dsh-plan .p-lamp.error{color:var(--uupm-error);cursor:pointer}#dsh-plan .p-lamp.error i{background:var(--uupm-error)}#dsh-plan .p-lamp.error:hover{border:1px solid var(--uupm-error);border-radius:4px}#dsh-plan .p-status{position:absolute;top:16px;right:16px;z-index:3;display:flex;gap:14px;background:var(--toolbar-bg);border:1px solid var(--card-line);border-radius:8px;padding:8px 14px;font-size:12px}#dsh-plan .p-status b{font-weight:600}#dsh-plan .ok{color:var(--edge-live)}#dsh-plan .warn{color:var(--uupm-warn)}#dsh-plan .mut{color:var(--ink-muted)}#dsh-plan .p-legend{position:absolute;bottom:16px;left:16px;z-index:3;font-size:11px;color:var(--ink-muted);background:var(--toolbar-bg);border:1px solid var(--card-line);border-radius:8px;padding:4px 10px}#dsh-plan .p-legend summary{cursor:pointer;padding:2px 0;-webkit-user-select:none;user-select:none}#dsh-plan .p-legend summary:focus-visible{outline:2px solid var(--accent);outline-offset:2px}#dsh-plan .p-legend[open]{padding-bottom:8px}#dsh-plan .p-legend-rows{display:grid;gap:4px;margin-top:4px}#dsh-plan .p-legend i{display:inline-block;width:18px;border-top:2px solid var(--uupm-edge-member);vertical-align:middle;margin-right:6px}#dsh-plan .p-legend i.dashed{border-top-style:dashed}@media (max-width:680px){#dsh-plan .p-toolbar{position:relative;top:auto;left:auto;margin:8px 8px 0;flex-wrap:wrap;row-gap:6px}#dsh-plan .p-toolbar>*{flex:none}#dsh-plan .p-toolbar .p-search{order:-1;flex:1 1 100%}#dsh-plan .p-toolbar .p-sep{display:none}#dsh-plan .p-toolbar .p-search-input{width:100%;box-sizing:border-box}#dsh-plan .p-status{position:relative;top:auto;right:auto;left:auto;width:fit-content;margin:6px 8px 0;padding:6px 10px;gap:10px;flex-wrap:wrap}#dsh-plan .p-legend{display:none}}@media (pointer:coarse){#dsh-plan .p-toolbar button{min-height:36px;min-width:36px}}@media (prefers-reduced-motion: reduce){#dsh-plan *{transition:none!important;animation:none!important}}#dsh-plan .p-frame.drop-target{border-color:var(--accent);border-width:2px;background:var(--uupm-wash-12)}#dsh-plan .p-frame-head:focus-visible{outline:2px solid var(--accent);outline-offset:1px}#dsh-plan .p-node.remote{border-left-color:var(--federal);padding-right:46px}#dsh-plan .p-node.remote .dot{background:var(--federal)}#dsh-plan .p-node.remote .prio{color:var(--ink)}#dsh-plan .p-node .prio.lnk-linked{color:var(--live, #2e9e5b);border-color:var(--live, #2e9e5b)}#dsh-plan .p-node .prio.lnk-stranger{color:var(--ink-muted);border-color:var(--card-line)}#dsh-plan .e-activity{stroke:var(--accent);stroke-width:2;stroke-dasharray:8 6;stroke-opacity:.9}#dsh-plan .e-federal{stroke:var(--federal);stroke-width:1.5;stroke-dasharray:6 5;stroke-opacity:.5}#dsh-plan .edge-label{font-size:10.5px;fill:var(--ink-muted)}@media (prefers-reduced-motion: no-preference){#dsh-plan .e-activity{animation:p-activity-flow 1.1s linear infinite}}@keyframes p-activity-flow{to{stroke-dashoffset:-28}}#dsh-plan .p-status{cursor:pointer}#dsh-plan .p-status:hover{border-color:var(--accent)}#dsh-plan .p-status:active{background:var(--uupm-wash-12)}#dsh-plan .p-status:focus-visible{outline:2px solid var(--accent);outline-offset:2px}#dsh-plan .p-menu{position:fixed;z-index:5;min-width:170px;display:grid;padding:4px;gap:2px;background:var(--toolbar-bg);border:1px solid var(--card-line);border-radius:8px}#dsh-plan .p-menu [role=menuitem]{background:transparent;color:var(--ink);border:1px solid transparent;border-radius:6px;padding:6px 10px;font:inherit;text-align:left;cursor:pointer;white-space:nowrap}#dsh-plan .p-menu [role=menuitem]:hover{border-color:var(--card-line);background:var(--uupm-wash-8)}#dsh-plan .p-menu [role=menuitem]:active{background:var(--uupm-wash-18)}#dsh-plan .p-menu [role=menuitem]:focus-visible{outline:2px solid var(--accent);outline-offset:1px}#dsh-plan .p-menu [role=menuitem][aria-disabled=true]{color:var(--ink-muted);cursor:not-allowed}#dsh-plan .p-dialog{position:absolute;top:0;right:0;bottom:0;left:0;z-index:6;display:grid;place-items:center;background:var(--scrim)}#dsh-plan .p-dialog-panel{min-width:300px;padding:14px 16px;display:grid;gap:10px;background:var(--uupm-bg-2);border:1px solid var(--card-line);border-radius:10px}#dsh-plan .p-dialog-title{font-weight:600;font-size:12.5px;color:var(--ink)}#dsh-plan .p-dialog-input{font:inherit;color:var(--ink);background:var(--uupm-bg-0);border:1px solid var(--card-line);border-radius:6px;padding:7px 10px}#dsh-plan .p-dialog-input:hover{border-color:color-mix(in srgb,var(--uupm-ink-1) 55%,transparent)}#dsh-plan .p-dialog-input:focus-visible{outline:2px solid var(--accent);outline-offset:1px;border-color:var(--accent)}#dsh-plan .p-dialog-err{min-height:1.2em;font-size:11px;color:var(--uupm-error)}#dsh-plan .p-dialog-row{display:flex;gap:8px;justify-content:flex-end}#dsh-plan .p-dialog-row button{background:transparent;color:var(--ink);border:1px solid var(--card-line);border-radius:6px;padding:5px 12px;font:inherit;cursor:pointer}#dsh-plan .p-dialog-row button:hover{border-color:var(--accent)}#dsh-plan .p-dialog-row button:active{background:var(--uupm-wash-15)}#dsh-plan .p-dialog-row button:focus-visible{outline:2px solid var(--accent);outline-offset:1px}#dsh-plan .p-notice-stack{position:absolute;bottom:52px;left:50%;transform:translate(-50%);z-index:5;display:grid;gap:6px;justify-items:center;pointer-events:none}#dsh-plan .p-notice{max-width:60ch;padding:7px 12px;font-size:12px;color:var(--ink);background:var(--toolbar-bg);border:1px solid var(--card-line);border-radius:8px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#dsh-plan .p-notice.error{color:var(--error-ink);border-color:var(--uupm-error);background:var(--error-panel)}#dsh-plan .p-netbtn{color:var(--ink-muted)}#dsh-plan .p-netbtn:not([disabled]){color:var(--ink)}#dsh-plan .p-netmenu{max-height:240px;overflow:auto}#dsh-plan .p-nodebtn{color:var(--ink)}#dsh-plan .p-nodelist{min-width:300px;max-width:340px;max-height:420px;overflow:auto;padding:6px}#dsh-plan .p-nodelist-head{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:2px 4px 6px;border-bottom:1px solid var(--card-line)}#dsh-plan .p-nodelist-title{font-size:12px;font-weight:600;color:var(--ink)}#dsh-plan .p-nodesel{font:inherit;font-size:11.5px;color:var(--ink);background:var(--uupm-bg-0);border:1px solid var(--card-line);border-radius:6px;padding:2px 6px;max-width:220px}#dsh-plan .p-nodesel:focus-visible{outline:2px solid var(--accent);outline-offset:1px}#dsh-plan .p-nodelist-group{font-size:11px;color:var(--ink-muted);padding:8px 4px 3px;display:flex;align-items:baseline;gap:8px}#dsh-plan .p-nodelist-note{font-size:10px;color:var(--ink-muted);opacity:.8}#dsh-plan .p-noderow{display:flex;align-items:center;gap:6px;padding:3px 4px;border-radius:6px;font-size:12px;color:var(--ink)}#dsh-plan .p-noderow:hover{background:var(--uupm-wash-8)}#dsh-plan .p-nodedot{flex:none;width:7px;height:7px;border-radius:50%;background:var(--edge-live)}#dsh-plan .p-nodedot.cold{background:var(--ink-muted)}#dsh-plan .p-nodedot.off{background:transparent;border:1px solid var(--ink-muted)}#dsh-plan .p-nodename{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}#dsh-plan .p-nonet{flex:none;font-size:10px;color:var(--uupm-warn);border:1px solid var(--uupm-warn);border-radius:4px;padding:0 4px}#dsh-plan .p-teamcount{flex:none;font-size:10px;color:var(--ink-muted);border:1px solid var(--card-line);border-radius:4px;padding:0 4px}#dsh-plan .p-listbtn{flex:none;background:transparent;color:var(--ink);border:1px solid var(--card-line);border-radius:5px;padding:1px 7px;font:inherit;font-size:11px;cursor:pointer}#dsh-plan .p-listbtn:hover{border-color:var(--card-line-hover);background:var(--uupm-wash-8)}#dsh-plan .p-listbtn:focus-visible{outline:2px solid var(--accent);outline-offset:1px}#dsh-plan .p-nodelist-empty{padding:10px 4px;font-size:11.5px;color:var(--ink-muted)}#dsh-plan .p-frame{position:absolute}#dsh-plan .p-frame-handle{position:absolute;pointer-events:auto;width:10px;height:10px;z-index:2;opacity:0;transition:opacity .12s ease}#dsh-plan .p-frame:hover .p-frame-handle{opacity:1}#dsh-plan .p-frame-handle:after{content:"";position:absolute;top:2px;right:2px;bottom:2px;left:2px;background:var(--frame-ink);border-radius:2px}#dsh-plan .p-h-n{top:-5px;left:calc(50% - 12px);width:24px;height:8px;cursor:ns-resize}#dsh-plan .p-h-s{bottom:-5px;left:calc(50% - 12px);width:24px;height:8px;cursor:ns-resize}#dsh-plan .p-h-e{right:-5px;top:calc(50% - 12px);width:8px;height:24px;cursor:ew-resize}#dsh-plan .p-h-w{left:-5px;top:calc(50% - 12px);width:8px;height:24px;cursor:ew-resize}#dsh-plan .p-h-ne{top:-5px;right:-5px;cursor:nesw-resize}#dsh-plan .p-h-nw{top:-5px;left:-5px;cursor:nwse-resize}#dsh-plan .p-h-se{bottom:-5px;right:-5px;cursor:nwse-resize}#dsh-plan .p-h-sw{bottom:-5px;left:-5px;cursor:nesw-resize}#dsh-plan .p-h-ne:after,#dsh-plan .p-h-sw:after{transform:rotate(45deg)}#dsh-plan .p-h-nw:after,#dsh-plan .p-h-se:after{transform:rotate(-45deg)}#dsh-plan .p-frame.selected .p-frame-handle{opacity:1}#dsh-plan .p-frame.selected{outline:1px solid var(--frame-ink)}:root{color-scheme:dark;--n-bg:#060a12;--n-ink:#dde3f0;--n-ink-muted:#7a86a0;--n-panel:#0d1322;--n-live:#4ade80;--n-cold:#7a86a0;--n-border:#223052;--n-act:#f59e0b;--n-danger:#f87171;--n-accent:#9673f7;--n-rail-w:300px;--n-canvas:#22d3ee;--n-line:var(--n-border);--n-raised:#131b2e;--n-federal:#6366f1;--n-card-line:#5c6680;--n-error-ink:#fecaca;--n-error-panel:#2a0d10f2;--n-shadow:rgba(0,0,0,.35)}@media (prefers-color-scheme: light){:root{--n-bg:#eef2fa;--n-ink:#1a2438;--n-ink-muted:#5a6580;--n-panel:#ffffff;--n-live:#157a37;--n-border:#c6d0e6;--n-act:#a84d08;--n-danger:#b91c1c;--n-accent:#6d28d9;--n-cold:#636c81;--n-canvas:#0e7490;--n-raised:#ffffff;--n-federal:#4f46e5;--n-card-line:#8a95ae;--n-error-ink:#b91c1c;--n-error-panel:#fef2f2f2;--n-shadow:rgba(26,36,56,.16)}}@media (min-width:1440px){:root{--n-rail-w:340px }}html,body,#app{height:100%;margin:0}body{background:var(--n-bg);color:var(--n-ink);font:13px/1.45 system-ui,Segoe UI,Roboto,PingFang SC,Microsoft YaHei,sans-serif}.wb{display:flex;flex-direction:column;height:100%}.wb-header{display:flex;align-items:center;gap:12px;padding:8px 14px;border-bottom:1px solid var(--n-border);background:var(--n-panel)}.wb-title{display:flex;align-items:center;gap:10px;font-weight:600;font-size:14px;white-space:nowrap}.wb-badge{font-size:11px;font-weight:400;color:var(--n-ink-muted);border:1px solid var(--n-border);border-radius:99px;padding:1px 8px}.wb-badge[hidden]{display:none}.wb-row-remote{margin-left:6px;padding:0 6px;border:1px solid currentColor;border-radius:99px;font-size:10.5px;color:var(--n-ink-muted);vertical-align:1px}.wb-header-stats{display:flex;gap:16px;font-size:12px;color:var(--n-ink-muted);flex-wrap:wrap;min-width:0}.wb-header-stats .wb-kv{display:flex;gap:6px}.wb-header-stats .wb-kv-k{color:var(--n-ink-muted)}.wb-header-stats .wb-kv-v{color:var(--n-ink)}.wb-header-ok{color:var(--n-ink-muted)}.wb-alert{border:1px solid currentColor;border-radius:99px;padding:0 9px;line-height:20px;white-space:nowrap;cursor:pointer;background:transparent;font:inherit}.wb-alert:hover{background:color-mix(in srgb,currentColor 12%,transparent)}.wb-alert:focus-visible{outline:2px solid currentColor;outline-offset:2px}.wb-alert-danger{color:var(--n-danger)}.wb-alert-warn{color:var(--n-act)}.wb-forensics{font-family:ui-monospace,Consolas,monospace;font-size:11px}.wb-icon-btn{background:none;border:1px solid var(--n-border);color:var(--n-ink);border-radius:8px;width:30px;height:30px;display:none;align-items:center;justify-content:center;font:inherit;font-size:14px;cursor:pointer;flex:none}.wb-icon-btn:hover{border-color:var(--n-accent)}.wb-menu{margin-left:0}.wb-rail-toggle{margin-left:auto}.wb.is-rail-collapsed .wb-rail{display:none}.wb-body{position:relative;display:grid;grid-template-columns:minmax(0,var(--n-rail-w)) minmax(0,1fr);flex:1;min-height:0}.wb-rail{border-right:1px solid var(--n-border);min-width:0;min-height:0;display:flex;flex-direction:column;overflow:hidden;background:color-mix(in srgb,var(--n-panel) 60%,var(--n-bg))}.wb-side-head{font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:var(--n-ink-muted);margin:10px 2px 4px}.wb-item{display:flex;gap:7px;align-items:center;width:100%;text-align:left;background:none;border:none;color:var(--n-ink);font:inherit;padding:3px 6px;border-radius:6px;cursor:pointer}.wb-item:hover{background:color-mix(in srgb,var(--n-accent) 14%,transparent)}.wb-dot{font-size:10px}.wb-dot-live{color:var(--n-live)}.wb-dot-cold{color:var(--n-cold)}.wb-dot-canvas{color:var(--n-canvas)}.wb-dot-remote{color:var(--n-act)}.wb-dir-tools{display:flex;flex-direction:column;gap:6px;padding:8px 6px 4px}.wb-search{background:var(--n-panel);border:1px solid var(--n-border);color:var(--n-ink);border-radius:6px;padding:4px 8px;font:inherit;font-size:12.5px;min-width:0}.wb-search:focus{outline:1px solid var(--n-accent)}.wb-filters{display:flex;flex-wrap:wrap;gap:4px}.wb-filter{background:none;border:1px solid var(--n-border);color:var(--n-ink-muted);border-radius:99px;padding:0 10px;min-height:24px;font:inherit;font-size:11.5px;cursor:pointer}.wb-filter:hover{border-color:var(--n-accent);color:var(--n-ink)}.wb-filter.is-active{border-color:var(--n-accent);color:var(--n-ink);background:color-mix(in srgb,var(--n-accent) 16%,transparent)}.wb-item-badge{flex:none;font-size:10.5px;color:var(--n-canvas);border:1px solid color-mix(in srgb,var(--n-canvas) 45%,transparent);border-radius:99px;padding:0 6px;line-height:17px;white-space:nowrap}.wb-item-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wb-member-row{display:flex;align-items:center;gap:8px;padding:3px 2px;border-radius:6px}.wb-member-row:hover{background:color-mix(in srgb,var(--n-accent) 10%,transparent)}.wb-member-dot{flex:none;font-size:11px;color:var(--n-ink-muted);min-width:44px}.wb-member-label{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wb-member-remove,.wb-member-submit{background:none;border:1px solid var(--n-border);color:var(--n-ink);border-radius:6px;padding:1px 8px;font:inherit;font-size:11.5px;cursor:pointer;flex:none}.wb-member-remove:hover:not(:disabled),.wb-member-submit:hover:not(:disabled){border-color:var(--n-danger)}.wb-member-submit:hover:not(:disabled){border-color:var(--n-accent)}.wb-member-add{display:flex;flex-wrap:wrap;gap:6px;margin-top:6px}.wb-member-pick,.wb-member-manual{background:var(--n-panel);border:1px solid var(--n-border);color:var(--n-ink);border-radius:6px;padding:3px 8px;font:inherit;font-size:12px;min-width:0}.wb-member-pick{flex:1 1 150px}.wb-member-manual{flex:1 1 130px}.wb-member-pick:focus,.wb-member-manual:focus{outline:1px solid var(--n-accent)}.wb-hint{margin-top:10px;font-size:11px;color:var(--n-ink-muted);line-height:1.5}.wb-dispatch{margin-top:12px;border-top:1px dashed var(--n-border);padding-top:8px}.wb-dispatch-form{display:flex;flex-direction:column;gap:6px;margin-top:6px}.wb-dispatch-text{background:var(--n-panel);border:1px solid var(--n-border);color:var(--n-ink);border-radius:6px;padding:5px 8px;font:inherit;font-size:12px;min-height:52px;resize:vertical}.wb-dispatch-text:focus{outline:1px solid var(--n-accent)}.wb-dispatch-submit{align-self:flex-end;background:none;border:1px solid var(--n-border);color:var(--n-ink);border-radius:6px;padding:2px 14px;font:inherit;font-size:11.5px;cursor:pointer}.wb-dispatch-submit:hover:not(:disabled){border-color:var(--n-accent)}.wb-dispatch-note{font-size:11px;color:var(--n-ink-muted);line-height:1.4;min-height:0}.wb-stage{position:relative;min-width:0;min-height:0;display:flex;flex-direction:column}.wb-stage-board{position:absolute;top:0;right:0;bottom:0;left:0;overflow:hidden}.wb-stage-board.is-hidden{display:none}.wb-data{display:flex;flex-direction:column;gap:14px;padding:10px 14px;overflow-y:auto;min-height:0}.wb-data.is-hidden{display:none}.wb-pane-head{font-size:12px;color:var(--n-ink-muted);margin:4px 0 8px}.wb-pane-subhead{font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:var(--n-ink-muted);margin:12px 0 6px}.wb-table,.wb-row{display:flex;gap:10px;align-items:baseline}.wb-row{font-family:ui-monospace,Consolas,monospace;font-size:12px;background:color-mix(in srgb,var(--n-panel) 55%,transparent);border:1px solid var(--n-border);border-radius:6px;padding:3px 8px;flex-wrap:wrap}.wb-row-team{color:var(--n-accent);min-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wb-row-meta{color:var(--n-ink-muted)}.wb-row-badges{color:var(--n-live)}.wb-row-dir{min-width:16px}.wb-row-dir.is-fail{color:var(--n-danger)}.wb-btn{background:none;border:1px solid var(--n-border);color:var(--n-ink);border-radius:6px;padding:2px 10px;font:inherit;font-size:12px;cursor:pointer;margin-left:auto}.wb-btn:hover:not(:disabled){border-color:var(--n-accent)}.wb-btn:disabled{opacity:.5;cursor:default}.wb-btn-primary{border-color:var(--n-accent);color:var(--n-ink)}.wb-action{display:flex;gap:10px;align-items:baseline;font-size:12.5px;padding:5px 8px;border-radius:6px;border:1px solid var(--n-border);margin-bottom:4px}.wb-action-high{border-color:var(--n-danger)}.wb-action-text{flex:1}.wb-draft{display:flex;flex-direction:column;gap:8px;max-width:560px;margin-top:6px}.wb-select,.wb-textarea{background:var(--n-panel);border:1px solid var(--n-border);color:var(--n-ink);border-radius:8px;padding:6px 9px;font:inherit}.wb-textarea{resize:vertical}.wb-select:focus,.wb-textarea:focus{outline:1px solid var(--n-accent)}.wb-inspector{position:absolute;top:8px;right:8px;width:280px;max-height:calc(100% - 16px);overflow-y:auto;background:var(--n-panel);border:1px solid var(--n-border);border-radius:10px;padding:10px;z-index:20;box-shadow:0 8px 24px var(--n-shadow);display:none}.wb-inspector.is-open{display:block}.wb-inspector-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px}.wb-inspector-title{font-weight:600;font-size:12.5px}.wb-inspector .wb-icon-btn{display:inline-flex;width:24px;height:24px;font-size:12px}.wb-card{display:flex;flex-direction:column;gap:6px}.wb-kv{display:flex;gap:8px;font-size:12px}.wb-kv-k{color:var(--n-ink-muted);min-width:58px;flex:none}.wb-kv-v{word-break:break-all}.wb-muted{color:var(--n-ink-muted)}.wb-chat{position:absolute;top:8px;right:8px;bottom:8px;width:400px;max-width:calc(100% - 16px);display:flex;flex-direction:column;background:var(--n-panel);border:1px solid var(--n-border);border-radius:12px;z-index:22;box-shadow:0 8px 24px var(--n-shadow);overflow:hidden;transform:translate(calc(100% + 12px));transition:transform .18s ease;pointer-events:none}.wb-chat.is-open{transform:translate(0);pointer-events:auto}.wb-chat-head{display:flex;align-items:center;gap:8px;padding:10px 10px 10px 12px;border-bottom:1px solid var(--n-border);flex:none}.wb-chat-dot{flex:none;width:8px;height:8px;border-radius:50%;background:var(--n-ink-muted)}.wb-chat-dot.is-live{background:var(--n-live)}.wb-chat-dot.is-cold{background:transparent;border:1.5px solid var(--n-ink-muted)}.wb-chat-dot.is-peer{background:var(--n-federal)}.wb-chat-titles{display:flex;flex-direction:column;flex:1 1 auto;min-width:0;line-height:1.3}.wb-chat-title{font-weight:600;font-size:13.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wb-chat-sub{font:11px/1.4 ui-monospace,Consolas,monospace;color:var(--n-ink-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wb-chat .wb-icon-btn{display:inline-flex;width:28px;height:28px;font-size:13px;flex:none;border-color:transparent}.wb-chat .wb-icon-btn:hover{border-color:var(--n-border)}.wb-chat .wb-icon-btn:focus-visible{outline:2px solid var(--n-accent);outline-offset:1px}.wb-chat .wb-chat-back[hidden]{display:none}.wb-chat-info-btn[aria-expanded=true]{border-color:var(--n-accent);color:var(--n-accent)}.wb-chat-info{flex:none;display:flex;flex-direction:column;gap:4px;padding:8px 12px;font-size:12px;border-bottom:1px solid var(--n-border);background:color-mix(in srgb,var(--n-bg) 55%,var(--n-panel))}.wb-chat-info[hidden]{display:none}.wb-chat-info .wb-kv-v{font-family:ui-monospace,Consolas,monospace;font-size:11.5px}.wb-chat-thread{flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;display:flex;flex-direction:column;gap:10px;padding:12px}.wb-chat-thread:focus-visible{outline:2px solid var(--n-accent);outline-offset:-2px}.wb-chat-log,.wb-chat-sent{display:flex;flex-direction:column;gap:10px}.wb-chat-notice{align-self:center;max-width:92%;text-align:center;font-size:11.5px;line-height:1.5;color:var(--n-ink-muted);border:1px dashed var(--n-border);border-radius:8px;padding:6px 10px}.wb-chat-notice[hidden]{display:none}.wb-chat-empty{align-self:center;padding:24px 8px;font-size:12px;color:var(--n-ink-muted);text-align:center}.wb-chat-empty.is-error{color:var(--n-danger)}.wb-msg{display:flex;flex-direction:column;gap:4px;max-width:86%;padding:8px 11px;border-radius:12px;font-size:13px;line-height:1.55}.wb-msg-assistant{align-self:flex-start;background:var(--n-raised);border:1px solid var(--n-border);border-bottom-left-radius:4px}.wb-msg-user{align-self:flex-end;background:color-mix(in srgb,var(--n-accent) 16%,var(--n-panel));border:1px solid color-mix(in srgb,var(--n-accent) 35%,transparent);border-bottom-right-radius:4px}.wb-msg-ledger{align-self:center;max-width:92%;background:transparent;border:1px dashed var(--n-border);font-size:12px}.wb-msg-ledger .wb-msg-text{color:var(--n-ink-muted)}.wb-msg-ledger .wb-msg-meta{justify-content:center}.wb-msg-in .wb-msg-meta{justify-content:flex-start}.wb-msg-who{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}.wb-msg-text{color:var(--n-ink);white-space:pre-wrap;word-break:break-word;overflow-wrap:anywhere}.wb-msg-meta{display:flex;flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:6px;font-size:11px}.wb-msg-task{font-family:ui-monospace,Consolas,monospace;color:var(--n-ink-muted)}.wb-msg-status{border:1px solid currentColor;border-radius:99px;padding:0 7px;line-height:18px;white-space:nowrap}.wb-msg-status.is-wait,.wb-msg-status.is-muted{color:var(--n-ink-muted)}.wb-msg-status.is-ok{color:var(--n-live)}.wb-msg-status.is-warn{color:var(--n-act)}.wb-msg-status.is-danger{color:var(--n-danger)}.wb-chat-divider{display:flex;align-items:center;gap:8px;font-size:11px;color:var(--n-ink-muted);margin-top:4px}.wb-chat-divider:before,.wb-chat-divider:after{content:"";flex:1;border-top:1px solid var(--n-border)}.wb-chat-sessions{display:flex;flex-direction:column;gap:6px}.wb-chat-session{display:flex;flex-direction:column;align-items:flex-start;gap:2px;width:100%;text-align:left;background:var(--n-raised);border:1px solid var(--n-border);border-radius:8px;padding:7px 10px;color:var(--n-ink);font:inherit;cursor:pointer}.wb-chat-session:hover{border-color:var(--n-accent)}.wb-chat-session:focus-visible{outline:2px solid var(--n-accent);outline-offset:1px}.wb-chat-session-id{font:12px ui-monospace,Consolas,monospace}.wb-chat-session-meta{font-size:11px;color:var(--n-ink-muted)}.wb-chat-foot{flex:none;border-top:1px solid var(--n-border);padding:8px 10px 10px;background:var(--n-panel)}.wb-chat-composer{display:flex;flex-direction:column;gap:4px}.wb-chat-composer-row{display:flex;align-items:flex-end;gap:8px}.wb-chat-composer .wb-dispatch-text{flex:1 1 auto;min-height:38px;max-height:160px;resize:none;border-radius:10px;padding:8px 10px;font-size:13px;line-height:1.5}.wb-chat-composer .wb-dispatch-submit{align-self:auto;height:38px;padding:0 16px;border-radius:10px;background:var(--n-accent);border-color:var(--n-accent);color:var(--n-bg);font-size:13px;font-weight:600}.wb-chat-composer .wb-dispatch-submit:hover:not(:disabled){border-color:var(--n-accent);filter:brightness(1.08)}.wb-chat-composer .wb-dispatch-submit:disabled{opacity:.45;cursor:default}.wb-chat-composer .wb-dispatch-note{font-size:11px;padding-left:2px}.wb-chat-composer .wb-dispatch-note.is-error{color:var(--n-danger)}.wb-chat-readonly{font-size:12px;color:var(--n-ink-muted);text-align:center;padding:4px 0}.nexus-fault{display:none;position:fixed;top:10px;right:12px;z-index:50;max-width:420px;font:12px/1.5 ui-monospace,Consolas,monospace;color:var(--n-error-ink);background:var(--n-error-panel);border:1px solid var(--n-danger);border-radius:8px;padding:6px 10px;pointer-events:none}@media (max-width:1023px){.wb-menu{display:inline-flex}.wb-rail-toggle{display:none}.wb-body{grid-template-columns:minmax(0,1fr)}.wb-rail{position:fixed;left:0;top:0;bottom:0;width:min(86vw,320px);z-index:40;background:var(--n-panel);border-right:1px solid var(--n-border);transform:translate(-102%);transition:transform .18s ease;box-shadow:8px 0 24px var(--n-shadow)}.wb.is-rail-open .wb-rail{transform:translate(0)}.wb-inspector{left:8px;right:8px;width:auto;top:auto;bottom:8px;max-height:45%}.wb-chat{left:8px;right:8px;width:auto;top:auto;bottom:8px;height:85%;max-height:85%;transform:translateY(102%)}.wb-chat.is-open{transform:translateY(0)}}@media (pointer:coarse){.wb-filter,.wb-item,.wb-tab{min-height:36px}.wb-icon-btn,.wb-inspector .wb-icon-btn,.wb-chat .wb-icon-btn{width:36px;height:36px}}@media (max-width:680px){.wb-header{flex-wrap:wrap;row-gap:4px}.wb-header-stats{order:3;width:100%}.wb-row-team{min-width:0;flex:1 1 auto}.wb-data{padding:8px}}.wb-host-row{display:flex;align-items:center;gap:7px;padding:4px 6px;border:1px solid var(--n-border);border-radius:7px;margin-bottom:4px;cursor:pointer;font-size:12px}.wb-host-row:hover{border-color:var(--n-accent);background:color-mix(in srgb,var(--n-accent) 8%,transparent)}.wb-host-row:focus-visible{outline:2px solid var(--n-accent);outline-offset:1px}.wb-host-lamp{flex:none;width:8px;height:8px;border-radius:50%;background:var(--n-ink-muted)}.wb-host-lamp.is-live{background:var(--n-live)}.wb-host-lamp.is-warm{background:var(--n-act)}.wb-host-lamp.is-cold{background:var(--n-ink-muted)}.wb-host-lamp.is-fail{background:var(--n-danger)}.wb-host-lamp.is-unknown{background:transparent;border:1px solid var(--n-ink-muted)}.wb-host-name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--n-ink)}.wb-host-badge{flex:none;font-size:10.5px;border-radius:99px;padding:0 7px;line-height:17px;border:1px solid var(--n-border)}.wb-host-badge.is-linked{color:var(--n-live);border-color:var(--n-live)}.wb-host-badge.is-stranger{color:var(--n-ink-muted);border-color:var(--n-border)}.wb-host-ver{flex:none;font-size:10px;color:var(--n-ink-muted);border:1px solid var(--n-border);border-radius:4px;padding:0 4px}.wb-host-url{flex:none;max-width:40%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--n-ink-muted);font-size:10.5px}.wb-tabs{flex:none;display:flex;gap:2px;padding:6px 6px 0;border-bottom:1px solid var(--n-border);overflow-x:auto;scrollbar-width:none}.wb-tab{flex:1 1 auto;display:inline-flex;align-items:center;justify-content:center;gap:5px;min-width:0;background:none;border:none;border-bottom:2px solid transparent;color:var(--n-ink-muted);font:inherit;font-size:12.5px;padding:6px 6px 7px;cursor:pointer;white-space:nowrap}.wb-tab:hover{color:var(--n-ink)}.wb-tab.is-active{color:var(--n-ink);border-bottom-color:var(--n-accent);font-weight:600}.wb-tab:focus-visible{outline:2px solid var(--n-accent);outline-offset:-2px;border-radius:6px 6px 0 0}.wb-tab[hidden]{display:none}.wb-tab-badge{font:10.5px/16px ui-monospace,Consolas,monospace;color:var(--n-ink-muted);font-weight:400}.wb-tab-badge:empty{display:none}.wb-tab-badge.is-danger,.wb-tab-badge.is-warn,.wb-tab-badge.is-accent{padding:0 6px;border-radius:99px;border:1px solid currentColor}.wb-tab-badge.is-danger{color:var(--n-danger)}.wb-tab-badge.is-warn{color:var(--n-act)}.wb-tab-badge.is-accent{color:var(--n-accent)}.wb-tabpanels{flex:1 1 auto;min-height:0;display:flex;flex-direction:column}.wb-tabpanel{flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;padding:8px 10px 16px}.wb-tabpanel[hidden]{display:none}.wb-tabpanel:focus-visible{outline:2px solid var(--n-accent);outline-offset:-2px}.wb-tabpanel .wb-pane{display:flex;flex-direction:column;gap:8px}.wb-tabpanel .wb-dir-tools{padding:0 0 6px}.wb-dir-group{display:flex;flex-direction:column;gap:1px;margin-top:10px}.wb-dir-group:first-child{margin-top:2px}.wb-dir-head{display:flex;align-items:baseline;justify-content:space-between;gap:8px;padding:0 6px 4px;font-size:11px;letter-spacing:.04em;color:var(--n-ink-muted)}.wb-dir-head-label{font-weight:600;color:var(--n-ink)}.wb-dir-head-note{font-size:10.5px}.wb-dir-day{padding:6px 6px 2px;font-size:10.5px;color:var(--n-ink-muted)}.wb-dir-empty{padding:24px 8px;text-align:center;font-size:12px;color:var(--n-ink-muted)}.wb-directory .wb-item{gap:9px;padding:5px 6px;border-radius:8px}.wb-directory .wb-item:focus-visible{outline:2px solid var(--n-accent);outline-offset:-2px}.wb-item-text{display:flex;flex-direction:column;flex:1 1 auto;min-width:0;line-height:1.35}.wb-item-sub{font:11px/1.35 ui-monospace,Consolas,monospace;color:var(--n-ink-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.wb-item.is-untitled .wb-item-label{color:var(--n-ink-muted);font-family:ui-monospace,Consolas,monospace;font-size:12px}.wb-directory .wb-item.is-unreachable{opacity:.78}.wb-unreachable-note,.wb-node-warning{font-size:11px;line-height:1.35;color:var(--n-danger);white-space:normal;overflow-wrap:anywhere}.wb-dot-log{color:var(--n-ink-muted)}.wb-led-tiles{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px}.wb-led-tile{display:flex;flex-direction:column;align-items:flex-start;gap:1px;padding:7px 8px;border-radius:8px;border:1px solid var(--n-border);background:var(--n-raised);cursor:help;min-width:0}.wb-led-tile-v{font:600 17px/1.15 ui-monospace,Consolas,monospace;color:var(--n-ink)}.wb-led-tile-k{font-size:11px;color:var(--n-ink-muted)}.wb-led-tile.is-warn{border-color:var(--n-act)}.wb-led-tile.is-warn .wb-led-tile-v{color:var(--n-act)}.wb-led-tile.is-danger{border-color:var(--n-danger)}.wb-led-tile.is-danger .wb-led-tile-v{color:var(--n-danger)}.wb-led-split{display:flex;flex-direction:column;gap:4px}.wb-led-split-bar{display:flex;height:6px;border-radius:99px;overflow:hidden;background:var(--n-border)}.wb-led-seg{display:block;height:100%}.wb-led-split-legend{display:flex;flex-wrap:wrap;gap:4px 10px;font-size:11px;color:var(--n-ink-muted)}.wb-led-split-item{display:inline-flex;align-items:center;gap:4px}.wb-led-swatch{display:inline-block;width:8px;height:8px;border-radius:2px}.wb-led-seg.is-completed,.wb-led-swatch.is-completed{background:var(--n-live)}.wb-led-seg.is-rejected,.wb-led-swatch.is-rejected{background:var(--n-act)}.wb-led-seg.is-failed,.wb-led-swatch.is-failed{background:var(--n-danger)}.wb-led-seg.is-abandoned,.wb-led-swatch.is-abandoned{background:var(--n-ink-muted)}.wb-led-seg.is-unclassified,.wb-led-swatch.is-unclassified,.wb-led-seg.is-other,.wb-led-swatch.is-other{background:color-mix(in srgb,var(--n-ink-muted) 45%,var(--n-border))}.wb-led-group{display:flex;flex-direction:column;gap:6px;margin-top:4px}.wb-led-group-head{display:flex;align-items:baseline;justify-content:space-between;gap:8px;font-size:11.5px;font-weight:600;color:var(--n-ink)}.wb-led-group-hint{font-size:10.5px;font-weight:400;color:var(--n-ink-muted)}.wb-led-group.is-danger .wb-led-group-head{color:var(--n-danger)}.wb-led-group.is-warn .wb-led-group-head{color:var(--n-act)}.wb-led-card{position:relative;display:flex;flex-direction:column;gap:3px;padding:7px 9px;border-radius:8px;border:1px solid var(--n-border);background:var(--n-raised);min-width:0}.wb-led-card.is-danger{border-color:var(--n-danger)}.wb-led-card.is-warn{border-left:3px solid var(--n-act)}.wb-led-card.is-muted,.wb-led-card.is-quiet{background:transparent}.wb-led-card.is-link{cursor:pointer}.wb-led-card.is-link:hover{border-color:var(--n-accent)}.wb-led-card.is-link:focus-visible{outline:2px solid var(--n-accent);outline-offset:1px}.wb-led-card-head{display:flex;align-items:flex-start;gap:6px;min-width:0}.wb-led-dir{flex:none;font-size:12px;color:var(--n-ink-muted);line-height:1.45}.wb-led-dir.is-in{color:var(--n-federal)}.wb-led-brief{flex:1 1 auto;min-width:0;font-size:12.5px;line-height:1.45;color:var(--n-ink);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;overflow-wrap:anywhere}.wb-led-card.is-muted .wb-led-brief,.wb-led-card.is-quiet .wb-led-brief{color:var(--n-ink-muted)}.wb-led-card.is-danger .wb-led-brief{color:var(--n-danger)}.wb-led-brief.is-missing{font-style:italic}.wb-led-meta{display:flex;flex-wrap:wrap;gap:2px 8px;font:11px/1.45 ui-monospace,Consolas,monospace;color:var(--n-ink-muted);min-width:0}.wb-led-meta>span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:100%}.wb-led-chip{border:1px solid var(--n-border);border-radius:99px;padding:0 6px;font-family:inherit}.wb-led-abandon{position:absolute;top:6px;right:6px;margin-left:0;padding:1px 9px;font-size:11.5px}.wb-led-abandon.is-quiet{border-color:transparent;background:transparent;color:var(--n-ink-muted)}.wb-led-abandon.is-quiet:hover{border-color:var(--n-border);color:var(--n-ink)}.wb-led-card:has(.wb-led-abandon) .wb-led-card-head{padding-right:52px}.wb-led-empty{padding:24px 8px;text-align:center;font-size:12px;color:var(--n-ink-muted)}.wb-led-forensics{font-size:11px;color:var(--n-ink-muted);border-top:1px dashed var(--n-border);padding-top:6px;margin-top:4px}.wb-led-forensics summary{cursor:pointer}.wb-led-forensics summary:focus-visible{outline:2px solid var(--n-accent);outline-offset:1px}.wb-led-forensics-body{display:flex;flex-direction:column;gap:2px;padding:4px 0 0 12px;font-family:ui-monospace,Consolas,monospace}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
var No=Object.defineProperty;var Mo=(e,t,n)=>t in e?No(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var Et=(e,t,n)=>Mo(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 rn=6e4;function So(e,t,n=Date.now){let s=-rn;return{fault(o){const i=n();i-s>=rn&&(t(`[nexus] ${o}`),s=i),e.show(o)},clear(){e.hide(),s=-rn}}}function st(e){return e.name??e.team??e.label??""}function oo(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(st(s),!1);const o=(e.remote??[]).find(c=>c.team===t);return o!==void 0?n(st(o),!0):n((r=(((i=e.canvas)==null?void 0:i.teams)??[]).find(c=>c.team===t))==null?void 0:r.name,!1)}function Ao(e,t){const n=oo(e,t);return n===void 0?t:n.remote?`${n.name}(远端)`:n.name}function Kt(e,t,n,s=""){const o=oo(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 Lo=60*6e4;function Nt(e){var t;return e.direction==="inbound"||e.direction===void 0&&((t=e.peer)==null?void 0:t.startsWith("local:"))===!0}function Sn(e){var t;return((t=e.peer)==null?void 0:t.startsWith("local:"))===!0?e.peer.slice(6):void 0}function Ft(e,t){return e.settleable!==void 0?e.settleable===!1:t-e.startedAt>=Lo}function fn(e,t){const n=(e.tasks??[]).filter(r=>r.receiptExpected!==!1),s=n.filter(r=>!Nt(r)&&Ft(r,t)),o=n.filter(r=>Nt(r)&&Ft(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 An(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 Dt(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 pn=[{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 Io(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(pn.map(f=>f.key)),c=pn.map(f=>[f.tone,f.label,t[f.key]??0]);for(const[f,y]of Object.entries(t))r.has(f)||c.push(["other",f,y]);const d=[];for(const[f,y,m]of c){if(m<=0)continue;const k=$e("span",`wb-led-seg is-${f}`);k.style.width=`${Math.max(2,m/n*100)}%`,o.appendChild(k);const E=$e("span","wb-led-split-item");E.appendChild($e("i",`wb-led-swatch is-${f}`)),E.appendChild(document.createTextNode(`${y} ${m}`)),i.appendChild(E),d.push(`${y} ${m}`)}o.setAttribute("aria-label",`归档结局:${d.join(",")}`),s.append(o,i),e.appendChild(s)}function To(e,t){var Me;e.replaceChildren();const{state:n,now:s}=t,o=n.tasks??[],i=n.tasksDead??[],r=n.archivedCount??0,c=fn(n,s),d=o.filter(P=>P.receiptExpected===!1),f=o.filter(P=>P.receiptExpected!==!1),y=f.filter(P=>Nt(P)),m=f.filter(P=>!Nt(P)),k=c.stale,E=m.filter(P=>!Ft(P,s)),G=c.stale.length,fe=$e("div","wb-led-tiles");Dt(fe,"待回执",f.length,`要回执、仍未结算的任务(含陈旧与本机欠对方的入站行)${d.length>0?`;另有免回执 ${d.length} 条不计`:""}`),Dt(fe,"陈旧",G,"我方派发、要回执、已等待 ≥1h 仍未回执(可催办);本机欠对方的入站行在「待本机回执」组另计,免回执行不算陈旧",G>0?"warn":void 0),Dt(fe,"死信",c.deadLetters.length,"超过 24h TTL 仍未结算(unconsumed);需清账(abandon)才能移出。免回执到期另列,不算死信",c.deadLetters.length>0?"danger":void 0),Dt(fe,"已归档",r,"已离开台账并留档的任务(结算、拒绝或放弃),用于审计"),e.appendChild(fe),r>0&&n.archivedSplit!==void 0&&Io(e,n.archivedSplit,r);const se=(P,z)=>{const ae=$e("div",`wb-led-card is-${z.tone}`),Re=$e("div","wb-led-card-head");Re.appendChild($e("span",`wb-led-dir${z.inbound?" is-in":""}`)).textContent=z.inbound?"↙":"↗";const Se=$e("span","wb-led-brief");Se.textContent=z.brief!==void 0&&z.brief!==""?z.brief:"(无摘要——派发未带 brief)",(z.brief===void 0||z.brief==="")&&Se.classList.add("is-missing"),Re.appendChild(Se),ae.appendChild(Re);const K=$e("div","wb-led-meta"),ie=K.appendChild($e("span","wb-led-team"));z.inbound?z.sender!==void 0?Kt(ie,n,z.sender,"来自 "):ie.textContent="来自 对端":Kt(ie,n,z.team,"发往 "),z.inbound&&Kt(K.appendChild($e("span","wb-led-to")),n,z.team,"至 "),K.appendChild($e("span")).textContent=z.atText,K.appendChild($e("span","wb-led-task")).textContent=z.taskId;for(const U of z.chips)K.appendChild($e("span","wb-led-chip")).textContent=U;if(ae.appendChild(K),ae.title=`${z.taskId}
|
|
2
|
+
${z.team}`,z.dead!==void 0){const U=z.dead,re=U.reason==="fire-forget",be=$e("button",`wb-btn wb-led-abandon${re?" is-quiet":""}`);be.type="button",be.textContent=re?"移出":"清账",be.title=re?"可选:把这条已过期的免回执记录移出台账(不是失败,不处理也无妨)":"从台账移出这条死信(abandon)",be.addEventListener("click",He=>{He.stopPropagation(),be.disabled=!0,t.abandon(U.taskId,"workbench dead-letter cleanup").then(je=>{be.disabled=!1,be.textContent=je?"已清":"失败"})}),ae.appendChild(be)}if(t.canOpenTeam(z.team)){ae.classList.add("is-link"),ae.setAttribute("role","button"),ae.tabIndex=0,ae.setAttribute("aria-label",`${Se.textContent},打开 ${z.team} 的对话`);const U=()=>{t.openTeam(z.team)};ae.addEventListener("click",U),ae.addEventListener("keydown",re=>{(re.key==="Enter"||re.key===" ")&&(re.preventDefault(),U())})}P.appendChild(ae)},N=(P,z,ae,Re)=>{if(z===0)return null;const Se=$e("div",`wb-led-group is-${ae}`);Se.dataset.group=P;const K=$e("div","wb-led-group-head");return K.appendChild($e("span")).textContent=`${P} · ${z}`,K.appendChild($e("span","wb-led-group-hint")).textContent=Re,Se.appendChild(K),e.appendChild(Se),Se},x=(P,z)=>{const ae=Nt(P);return{brief:P.brief,team:P.team,sender:Sn(P),taskId:P.taskId,atText:`${An(P.startedAt,s)} 前${ae?"收到":"派发"}`,inbound:ae,tone:z,chips:[...P.settleable===!0?["可结算"]:[],...P.receiptExpected===!1?["无回执债"]:[],...ae?["入站"]:[],...P.status!=="pending"?[P.status]:[]]}},M=(P,z,ae)=>({brief:P.brief,team:P.team,sender:Sn(P),taskId:P.taskId,atText:`${An(P.deadAt,s)} 前${ae}`,inbound:Nt(P),tone:z,dead:P,chips:P.reason!==void 0&&P.reason!==""&&P.reason!=="unspecified"&&P.reason!=="fire-forget"?[P.reason]:[]}),C=N("死信",c.deadLetters.length,"danger","需清账");if(C!==null)for(const P of[...c.deadLetters].sort((z,ae)=>ae.deadAt-z.deadAt))se(C,M(P,"danger","死信"));const Q=N("陈旧",k.length,"warn","我方派发 ≥1 小时仍无回执,可催办");if(Q!==null)for(const P of[...k].sort((z,ae)=>z.startedAt-ae.startedAt))se(Q,x(P,"warn"));const b=c.owedOverdue.length,h=N("待本机回执",y.length,b>0?"warn":"quiet",b>0?`对方在等本机回执 · ${b} 条超过 1 小时`:"对方在等本机回执");if(h!==null)for(const P of[...y].sort((z,ae)=>z.startedAt-ae.startedAt))se(h,x(P,Ft(P,s)?"warn":"quiet"));const S=N("等待回执",E.length,"quiet","1 小时内");if(S!==null)for(const P of[...E].sort((z,ae)=>ae.startedAt-z.startedAt))se(S,x(P,"quiet"));const u=N("免回执",d.length,"muted","不等回执,24h 后自动归档");if(u!==null)for(const P of d)se(u,x(P,"muted"));const O=N("已过期(免回执)",c.expired.length,"muted","正常记账,不是失败");if(O!==null)for(const P of[...c.expired].sort((z,ae)=>ae.deadAt-z.deadAt))se(O,M(P,"muted","过期"));o.length+i.length===0&&(e.appendChild($e("div","wb-led-empty")).textContent="台账为空——没有待回执的任务");const B=n.idempotency,X=(Me=n.reconcile)==null?void 0:Me.state;if(B!==void 0||X!==void 0){const P=$e("details","wb-led-forensics wb-forensics");P.appendChild($e("summary")).textContent="取证";const z=$e("div","wb-led-forensics-body");B!==void 0&&(z.appendChild($e("div")).textContent=`幂等 claims ${B.claimsFresh??0} · replays ${B.replays??0} · conflicts ${B.conflicts??0}`),X!==void 0&&(z.appendChild($e("div")).textContent=`reconcile ${X}`),P.appendChild(z),e.appendChild(P)}const ge=f.length+c.deadLetters.length;return{badge:ge>0?String(ge):"",tone:c.deadLetters.length>0?"danger":G>0||b>0?"warn":void 0}}const Lt=4e3,_o=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 an(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 Oo(e){return e>=1e6?`${(e/1e6).toFixed(1)} MB`:e>=1e3?`${Math.round(e/1e3)} KB`:`${e} B`}function cn(e){const t=e.kind==="session"||e.kind==="remote"?e.team:void 0;return t!==void 0&&t!==""?t:void 0}function Ln(e){return e.kind==="remote"?`remote:${e.team}`:`${e.kind}:${e.id}`}function Fo(e){let t=null,n=null,s=!1,o=!1;const i=new Map,r=new Map,c=new Map,d=new Map,f=new Set,y=new Map,m=new Map,k=ve("aside","wb-chat");k.setAttribute("aria-label","对话");const E=ve("div","wb-chat-head"),G=jt("返回会话列表","‹","wb-chat-back"),fe=ve("span","wb-chat-dot"),se=ve("div","wb-chat-titles"),N=ve("span","wb-chat-title"),x=ve("span","wb-chat-sub");se.append(N,x);const M=jt("刷新对话","↻","wb-chat-refresh"),C=jt("会话详情","ⓘ","wb-chat-info-btn");C.setAttribute("aria-expanded","false");const Q=jt("关闭对话","✕","wb-chat-close");E.append(G,fe,se,M,C,Q);const b=ve("div","wb-chat-info");b.hidden=!0;const h=ve("div","wb-chat-thread");h.setAttribute("role","log"),h.setAttribute("aria-live","polite"),h.tabIndex=0;const S=ve("div","wb-chat-notice"),u=ve("div","wb-chat-log"),O=ve("div","wb-chat-sent");h.append(S,u,O);const B=ve("div","wb-chat-foot");k.append(E,b,h,B),G.addEventListener("click",()=>{(t==null?void 0:t.kind)==="peer"&&(t.picked=void 0,Fe())}),M.addEventListener("click",()=>{if(t===null)return;const l=X(t);l!==void 0&&i.delete(l),t.kind==="peer"&&t.picked===void 0&&t.url!==void 0&&c.delete(`peer:${t.url}`),be(!0)}),C.addEventListener("click",()=>{o=!o,b.hidden=!o,C.setAttribute("aria-expanded",String(o))}),Q.addEventListener("click",()=>vt()),h.addEventListener("scroll",()=>{const l=t!==null?X(t):void 0;l!==void 0&&r.set(l,h.scrollTop)}),document.addEventListener("keydown",l=>{if(l.key!=="Escape"||!k.classList.contains("is-open"))return;const A=l.target;if(A instanceof HTMLElement){if(!k.contains(A)){const T=A instanceof HTMLTextAreaElement||A instanceof HTMLInputElement||A.isContentEditable,V=A.closest(".wb-stage-board")!==null;if(T||V)return}vt()}});function X(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 ge(l){var A,T,V;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"?((T=e.remoteSessionLog)==null?void 0:T.call(e,{team:l.team}))??Promise.resolve({ok:!1,error:"remoteSessionLog unavailable"}):((V=e.remoteSessionLog)==null?void 0:V.call(e,{peer:l.url,id:l.picked}))??Promise.resolve({ok:!1,error:"remoteSessionLog unavailable"})}function Me(){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?"冷会话":"在线",N.textContent=l.kind==="peer"&&l.picked!==void 0?`…${l.picked.slice(-12)}`:l.title,x.textContent=l.kind==="peer"&&l.picked!==void 0?l.title:l.sub,G.hidden=!(l.kind==="peer"&&l.picked!==void 0)}function P(l,A){const T=ve("div","wb-kv");T.appendChild(ve("span","wb-kv-k")).textContent=l,T.appendChild(ve("span","wb-kv-v")).textContent=A,b.appendChild(T)}function z(){var A,T,V;b.replaceChildren();const l=t;l!==null&&(l.kind==="session"?(P("会话",l.id),l.team!==void 0&&P("路由",l.team),P("来源","本机会话日志")):l.kind==="log"?(P("会话",l.id),P("来源","本机会话日志(不在网络目录)")):l.kind==="remote"?(P("路由",l.team),((A=l.row)==null?void 0:A.origin)!==void 0&&P("来源",l.row.origin),((T=l.row)==null?void 0:T.via)!==void 0&&P("经",l.row.via),((V=l.row)==null?void 0:V.workspace)!==void 0&&P("工作区",l.row.workspace)):(P("对端",l.url??l.sub),l.picked!==void 0&&P("会话",l.picked),P("来源","经本机代理读取对端 /a2a/log")))}function ae(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 Re(){return h.scrollHeight-h.scrollTop-h.clientHeight<=_o}function Se(l){const A=()=>{h.scrollTop=h.scrollHeight};A(),requestAnimationFrame(A)}function K(l,A){const T=ve("div",`wb-chat-empty${A==="error"?" is-error":""}`);return T.textContent=l,T}function ie(l,A){const T=l==="user",V=ve("div",`wb-msg ${T?"wb-msg-user":"wb-msg-assistant"}`),W=ve("span","wb-msg-who");W.textContent=T?"问":"答";const he=ve("div","wb-msg-text");return he.textContent=A,V.append(W,he),V}function U(l){if(u.replaceChildren(),l===void 0){u.appendChild(K("读取中…"));return}if(l.ok!==!0||l.messages===void 0){u.appendChild(K(`无法读取(${l.error??"未知错误"})`,"error"));return}if(l.messages.length===0){u.appendChild(K("暂无对话记录"));return}for(const A of l.messages)u.appendChild(ie(A.role,A.text))}function re(l,A){if(u.replaceChildren(),A===void 0){u.appendChild(K("读取中…"));return}if(A.ok!==!0||A.sessions===void 0){u.appendChild(K(`无法读取(${A.error??"未知错误"})`,"error"));return}if(A.sessions.length===0){u.appendChild(K("对端没有可读会话"));return}const T=ve("div","wb-chat-sessions"),V=e.now();for(const W of A.sessions){const he=ve("button","wb-chat-session");he.type="button",he.appendChild(ve("span","wb-chat-session-id")).textContent=`…${W.id.slice(-12)}`;const pe=[W.mtimeMs!==void 0?an(W.mtimeMs,V):"",Oo(W.sizeBytes)].filter(Boolean).join(" · ");he.appendChild(ve("span","wb-chat-session-meta")).textContent=pe,he.title=W.id,he.addEventListener("click",()=>{(t==null?void 0:t.kind)!=="peer"||t.url!==l||(t.picked=W.id,Fe())}),T.appendChild(he)}u.appendChild(T)}function be(l=!1){const A=t;if(A===null)return;if(S.textContent=ae(A),S.hidden=S.textContent==="",A.kind==="peer"&&A.picked===void 0){if(A.url===void 0||e.remoteSessionLog===void 0){u.replaceChildren();return}const W=A.url,he=`peer:${W}`;if(!l&&c.has(he)){re(W,c.get(he));return}c.set(he,void 0),re(W,void 0),e.remoteSessionLog({peer:W}).then(pe=>{c.set(he,pe),(t==null?void 0:t.kind)==="peer"&&t.url===W&&t.picked===void 0&&re(W,pe)},pe=>{const ye={ok:!1,error:pe instanceof Error?pe.message:String(pe)};c.set(he,ye),(t==null?void 0:t.kind)==="peer"&&t.url===W&&t.picked===void 0&&re(W,ye)});return}const T=X(A);if(T===void 0){u.replaceChildren(),Ke(!0);return}const V=()=>{const W=r.get(T);W===void 0||l?Se():(h.scrollTop=W,requestAnimationFrame(()=>{t!==null&&X(t)===T&&(h.scrollTop=W)}))};if(!l&&i.has(T)&&i.get(T)!==void 0){U(i.get(T)),Ke(!0),V();return}l&&r.delete(T),i.set(T,void 0),U(void 0),Ke(!0),ge(A).then(W=>{var he;i.set(T,W),(W==null?void 0:W.ok)===!0&&W.messages!==void 0&&((he=e.onTranscript)==null||he.call(e,A,W.messages)),!(t===null||X(t)!==T)&&(U(W),Ke(),V())},W=>{const he={ok:!1,error:W instanceof Error?W.message:String(W)};i.set(T,he),t!==null&&X(t)===T&&U(he)})}function He(l){return((n==null?void 0:n.tasks)??[]).filter(A=>A.team===l)}function je(l){return((n==null?void 0:n.tasksDead)??[]).filter(A=>A.team===l)}let Be="";function at(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 T=l.direction==="inbound";if(l.receiptExpected===!1)return{text:T?"来信 · 无需回执":"已送达 · 无回执",tone:"muted",hint:"免回执消息:不等回执,24h 后自动归档"};const V=Ft(l,A),W=T?V?"待本机回执 · 超 1 小时":"待本机回执":V?"陈旧":"待回执",he=l.status!=="pending"?` · ${l.status}`:"";return{text:`${W}${he}`,tone:V?"warn":"wait",hint:`${T?"对方等待本机回执;":""}${T?"收到":"派发"}于 ${an(l.startedAt,A)}`}}function Ge(l,A){const T=`结算于 ${an(l.resolvedAt,A)}`;if(l.receiptExpected===!1&&l.endedBy==="abandoned")return l.late===!0?{text:"已移出(免回执) · 回执迟到",tone:"warn",hint:`${T};免回执消息本机移出后对方回执才到,结局不改写`}:{text:"已移出(免回执)",tone:"muted",hint:`${T};免回执消息,本机移出台账,不是失败`};if(l.endedBy==="abandoned"||l.endedBy==="cancelled"){const pe=l.endedBy==="cancelled"?"撤回":"放弃";return l.late===!0?{text:`已${pe} · 回执迟到`,tone:"warn",hint:`${T};本机${pe}之后对方回执才到,结局不改写`}:{text:`已${pe}`,tone:"muted",hint:`${T};本机${pe},未等到回执`}}if(l.endedBy==="echo")return{text:"已结算 · 内容回显",tone:"ok",hint:`${T};对方回了内容但未带正式回执,按内容回显结算`};if(l.endedBy===void 0&&l.outcome==="abandoned")return{text:"已放弃(本机或对方)",tone:"muted",hint:`${T};本机放弃或撤回,或对方回执报告放弃`};const V=l.summary!==void 0&&l.summary!==""?` · ${l.summary}`:"";if(l.outcome==="abandoned")return{text:"已回执 · 对方放弃",tone:"warn",hint:`${T};对方回执报告放弃${V}`};const W=pn.find(pe=>pe.key===l.outcome),he=(W==null?void 0:W.tone)==="completed"?"ok":(W==null?void 0:W.tone)==="failed"?"danger":(W==null?void 0:W.tone)==="rejected"?"warn":"muted";return l.outcome==="unclassified"?{text:"已回执",tone:"ok",hint:`${T};回执未带结论${V}`}:{text:`已回执 · ${(W==null?void 0:W.label)??l.outcome}`,tone:he,hint:`${T}${V}`}}function ct(l,A,T){const V=je(A).find(pe=>pe.taskId===l);if(V!==void 0)return at(V);const W=He(A).find(pe=>pe.taskId===l);if(W!==void 0)return Xe(W,T);const he=((n==null?void 0:n.archived)??[]).find(pe=>pe.taskId===l&&pe.team===A);return he!==void 0?Ge(he,T):f.has(l)?{text:"已离开台账",tone:"muted",hint:"已结算、放弃或撤回之一;主机未给出这条的结局(旧主机,或已超出最近 64 条归档)"}:{text:"已派发",tone:"muted",hint:"异步送达;回执到达后进台账"}}function bt(l){const A=e.now(),T=d.get(l)??[],V=new Set(T.map(q=>q.taskId).filter(q=>q!==void 0)),W=q=>q!==void 0&&q!==""?q:"(无摘要)",he=He(l).filter(q=>!V.has(q.taskId)).map(q=>({at:q.startedAt,side:q.direction==="inbound"?"theirs":"mine",text:W(q.brief),status:Xe(q,A),taskId:q.taskId})),pe=je(l).filter(q=>!V.has(q.taskId)).map(q=>{var Je;const Pe=q.direction??y.get(q.taskId)??(((Je=q.peer)==null?void 0:Je.startsWith("local:"))===!0?"inbound":void 0);return{at:q.startedAt,side:Pe==="inbound"?"theirs":Pe==="outbound"?"mine":"system",text:W(q.brief),status:at(q),taskId:q.taskId}}),ye=T.map(q=>({at:q.at,side:"mine",text:q.text,status:q.state==="sending"?{text:"发送中…",tone:"muted"}:q.state==="failed"?{text:`失败:${q.error??"未知原因"}`,tone:"danger"}:q.taskId!==void 0?ct(q.taskId,l,A):{text:"已派发",tone:"muted"},taskId:q.taskId}));return[...he,...pe,...ye].sort((q,Pe)=>q.at-Pe.at)}function Ke(l=!1){const A=t,T=A!==null?cn(A):void 0,V=T!==void 0?bt(T):[],W=JSON.stringify([T??"",...V.map(ye=>[ye.taskId??"",ye.side,ye.text,ye.status.text])]);if(!l&&W===Be)return;Be=W;const he=Re();if(O.replaceChildren(),V.length===0)return;const pe=ve("div","wb-chat-divider");pe.textContent="台账往来 · 异步送达,回执进台账",O.appendChild(pe);for(const ye of V){const q=ye.side==="mine"?"wb-msg wb-msg-user wb-msg-out":ye.side==="theirs"?"wb-msg wb-msg-assistant wb-msg-in":"wb-msg wb-msg-ledger",Pe=ve("div",q);Pe.appendChild(ve("span","wb-msg-who")).textContent=ye.side==="mine"?"我":ye.side==="theirs"?"对方":"台账记录",Pe.appendChild(ve("div","wb-msg-text")).textContent=ye.text;const Je=ve("div","wb-msg-meta");ye.taskId!==void 0&&(Je.appendChild(ve("span","wb-msg-task")).textContent=ye.taskId);const Ne=ve("span",`wb-msg-status is-${ye.status.tone}`);Ne.textContent=ye.status.text,ye.status.hint!==void 0&&(Ne.title=ye.status.hint),Je.appendChild(Ne),Pe.appendChild(Je),O.appendChild(Pe)}he&&Se()}function Ue(l){const A=l.text.value.length;l.note.classList.remove("is-error"),l.note.textContent=A>Lt*.9?`${A}/${Lt}`:"Enter 发送 · Shift+Enter 换行",A>Lt&&l.note.classList.add("is-error"),l.submit.disabled=l.text.value.trim()===""||A>Lt}function gt(l){l.style.height="auto",l.style.height=`${Math.min(l.scrollHeight,160)}px`}function ft(l){const A=ve("form","wb-dispatch-form wb-chat-composer"),T=document.createElement("textarea");T.className="wb-dispatch-text",T.rows=1,T.placeholder="发一句话任务给这个节点…",T.setAttribute("aria-label","发送消息");const V=ve("button","wb-dispatch-submit");V.type="submit",V.textContent="发送",V.setAttribute("aria-label","发送");const W=ve("div","wb-dispatch-note");W.setAttribute("aria-live","polite");const he=ve("div","wb-chat-composer-row");he.append(T,V),A.append(he,W);const pe={team:l,form:A,text:T,note:W,submit:V};return T.addEventListener("input",()=>{gt(T),Ue(pe)}),T.addEventListener("keydown",ye=>{ye.key!=="Enter"||ye.shiftKey||ye.ctrlKey||ye.altKey||ye.metaKey||ye.isComposing||(ye.preventDefault(),A.requestSubmit())}),A.addEventListener("submit",ye=>{ye.preventDefault();const q=T.value.trim();if(q===""||q.length>Lt||e.dispatchQuick===void 0)return;const Pe={text:q,at:e.now(),state:"sending"},Je=d.get(l)??[];Je.push(Pe),d.set(l,Je),T.value="",gt(T),Ue(pe),T.focus({preventScroll:!0}),Ke(),Se(),e.dispatchQuick(l,q).then(Ne=>Ne,Ne=>({ok:!1,error:Ne instanceof Error?Ne.message:String(Ne)})).then(Ne=>{Ne.ok===!0?(Pe.state="sent",Pe.taskId=Ne.task_id,W.classList.remove("is-error"),W.textContent=`已派发${Ne.task_id!==void 0?` · ${Ne.task_id}`:""} · 回执将入台账`):(Pe.state="failed",Pe.error=Ne.error??"未知原因",T.value===""&&(T.value=q,gt(T)),W.classList.add("is-error"),W.textContent=`失败:${Pe.error}`,V.disabled=T.value.trim()===""),t!==null&&cn(t)===l&&Ke()})}),Ue(pe),pe}function ke(){const l=t;if(B.replaceChildren(),l===null)return;const A=cn(l);if(A!==void 0&&e.dispatchQuick!==void 0){let V=m.get(A);V===void 0&&(V=ft(A),m.set(A,V)),B.appendChild(V.form),s&&(s=!1,V.text.focus({preventScroll:!0}));return}s=!1;const T=ve("div","wb-chat-readonly");T.textContent=l.kind==="log"?"只读日志:此会话不在网络目录,不能从这里派发。":l.kind==="peer"?"对端主机:选择会话阅读;要派发请打开它的远端会话节点。":"此节点没有可派发的路由。",B.appendChild(T)}function Fe(){Me(),z(),be(),ke()}function tt(l){const A=t!==null&&Ln(t)===Ln(l);t=l,A||(s=!0),Fe(),k.classList.add("is-open")}function vt(){t=null,k.classList.remove("is-open")}function lt(l){n=l;for(const T of(l==null?void 0:l.tasks)??[])f.add(T.taskId),y.set(T.taskId,T.direction==="inbound"?"inbound":"outbound");const A=t;if(A!==null){if(A.kind==="session"&&l!==null){const T=(l.sessions??[]).find(V=>V.id===A.id);T!==void 0&&(A.title=st(T),A.live=T.live)}Me(),Ke()}}return{root:k,open:tt,close:vt,isOpen:()=>t!==null,update:lt}}const so="dsh-a2a.rail.tab";function Po(){try{return window.localStorage.getItem(so)}catch{return null}}function Ro(e){try{window.localStorage.setItem(so,e)}catch{}}function Do(e,t={}){var se;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 N of e){const x=document.createElement("button");x.type="button",x.className="wb-tab",x.id=`wb-tab-${N.key}`,x.dataset.sec=N.key,x.setAttribute("role","tab"),x.setAttribute("aria-controls",`wb-panel-${N.key}`);const M=document.createElement("span");M.className="wb-tab-label",M.textContent=N.label;const C=document.createElement("span");C.className="wb-tab-badge",x.append(M,C),x.addEventListener("click",()=>E(N.key)),s.appendChild(x);const Q=document.createElement("section");Q.className="wb-tabpanel",Q.id=`wb-panel-${N.key}`,Q.dataset.sec=N.key,Q.setAttribute("role","tabpanel"),Q.setAttribute("aria-labelledby",x.id),Q.tabIndex=-1,o.appendChild(Q),i.set(N.key,x),r.set(N.key,Q),c.set(N.key,C)}const f=()=>e.map(N=>N.key).filter(N=>!d.has(N)),y=Po();let m=((se=e.find(N=>N.key===y))==null?void 0:se.key)??e[0].key;s.addEventListener("keydown",N=>{const x=f(),M=x.indexOf(m);let C;N.key==="ArrowRight"?C=x[(M+1)%x.length]:N.key==="ArrowLeft"?C=x[(M-1+x.length)%x.length]:N.key==="Home"?C=x[0]:N.key==="End"&&(C=x[x.length-1]),C!==void 0&&(N.preventDefault(),E(C,{focus:!0}))});function k(){for(const N of e){const x=N.key===m,M=i.get(N.key);M.setAttribute("aria-selected",String(x)),M.tabIndex=x?0:-1,M.classList.toggle("is-active",x),M.hidden=d.has(N.key),r.get(N.key).hidden=!x}}function E(N,x={}){var C;if(d.has(N))return;const M=N!==m;m=N,Ro(N),k(),x.focus===!0&&i.get(N).focus(),M&&((C=t.onChange)==null||C.call(t,N))}function G(N,x,M){const C=c.get(N);C.textContent=x,C.className=`wb-tab-badge${M!==void 0?` is-${M}`:""}`}function fe(N,x){x?d.add(N):d.delete(N),d.has(m)&&(m=f()[0]??e[0].key),k()}return k(),{root:n,panel:N=>r.get(N),select:E,selected:()=>m,setBadge:G,setHidden:fe}}const jo=[{key:"all",label:"全部",hint:"不过滤:目录全部条目"},{key:"local",label:"本机",hint:"本机会话节点(现场 + 冷启动)"},{key:"canvas",label:"队",hint:"画布队(人类手工分配的组队)"},{key:"remote",label:"远端",hint:"远端会话队(来自对端卡片)"},{key:"logs",label:"日志",hint:"本机日志:不在网络目录里的会话档案"}];function Ze(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 Bo(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 In(e){return e>=1e6?`${(e/1e6).toFixed(1)} MB`:e>=1e3?`${Math.round(e/1e3)} KB`:`${e} B`}function Ho(e,t){const n=new Date(t);n.setHours(0,0,0,0);const s=n.getTime();return e>=s?"今天":e>=s-864e5?"昨天":"更早"}function Yo(e,t){var M,C,Q;e.replaceChildren();const{state:n,search:s,filter:o}=t,i=s!==""||o!=="all",r=(b,h)=>(o==="all"||o===b)&&(s===""||h.includes(s)),c=(b,h,S)=>{const u=Ze("div","wb-dir-group"),O=Ze("div","wb-dir-head");return O.appendChild(Ze("span","wb-dir-head-label")).textContent=`${b} · ${h}`,S!==void 0&&(O.appendChild(Ze("span","wb-dir-head-note")).textContent=S),u.appendChild(O),e.appendChild(u),u},d=(b,h,S,u,O,B,X)=>{const ge=Ze("button","wb-item");ge.type="button",ge.appendChild(Ze("span",`wb-dot ${h}`)).textContent=S;const Me=Ze("span","wb-item-text");return Me.appendChild(Ze("span","wb-item-label")).textContent=u,O!==""&&(Me.appendChild(Ze("span","wb-item-sub")).textContent=O),ge.appendChild(Me),X!==void 0&&(ge.title=X),ge.addEventListener("click",B),b.appendChild(ge),ge},f=(b,h)=>{if(h===void 0||h.length===0)return;const S=Ze("span","wb-item-badge"),u=h.map(O=>O.slice(O.lastIndexOf("/")+1));S.textContent=`▤ ${u.slice(0,2).join(" ")}${u.length>2?` +${u.length-2}`:""}`,S.title=`画布队:${h.join(" · ")}`,b.appendChild(S)},y=(n.sessions??[]).filter(b=>r("local",Bt(st(b),b.team,b.label,b.id,b.canvasTeams))),m=y.filter(b=>b.live===!0),k=y.filter(b=>b.live!==!0);if(y.length>0){const b=c("本机会话",y.length,k.length>0?`${m.length} 在线 · ${k.length} 冷`:void 0);for(const h of[...m,...k]){const S=h.live===!0,u=h.nodePromptMissing===!0,O=d(b,S?"wb-dot-live":"wb-dot-cold",S?"●":"○",st(h),S?h.team:`冷 · ${h.team}`,()=>t.openChat({kind:"session",id:h.id,title:st(h),sub:h.team,team:h.team,live:h.live}),h.id);if(u){O.classList.add("is-node-prompt-missing");const B=Ze("span","wb-node-warning");B.textContent="本会话的组装不含节点段",(M=O.querySelector(".wb-item-text"))==null||M.appendChild(B)}f(O,h.canvasTeams)}}const E=(((C=n.canvas)==null?void 0:C.teams)??[]).filter(b=>r("canvas",Bt(b.name,b.team,b.members.map(h=>h.team??h.id))));if(E.length>0){const b=c("画布队",E.length);for(const h of E){const S=h.members.filter(u=>u.remote===!0).length;d(b,"wb-dot-canvas","▤",h.name,`${h.members.length} 成员${S>0?` · ${S} 远端`:""}`,()=>t.selectCanvas(h),h.team)}}const G=(n.remote??[]).filter(b=>r("remote",Bt(st(b),b.team,b.origin,b.workspace,b.canvasTeams)));if(G.length>0){const b=c("远端节点",G.length);for(const h of G){const S=d(b,"wb-dot-remote","◇",st(h),h.origin!==void 0&&h.origin!==""?h.origin:h.team,()=>t.openChat({kind:"remote",team:h.team,title:st(h),sub:h.team,row:h}),h.team);if(h.unreachable===!0){S.classList.add("is-unreachable");const u=Ze("span","wb-unreachable-note");u.textContent="对端未应答(显示的是最后已知状态)",(Q=S.querySelector(".wb-item-text"))==null||Q.appendChild(u)}f(S,h.canvasTeams)}}const fe=new Set((n.sessions??[]).map(b=>b.id)),se=t.logs.filter(b=>!fe.has(b.id)&&r("logs",Bt(b.id,t.titles.get(b.id))));if(se.length>0){const b=t.logTotal!==void 0&&t.logTotal>t.logs.length,h=c("本机日志",se.length,b?`显示 ${t.logs.length} / 共 ${t.logTotal}`:void 0);let S="";for(const u of[...se].sort((O,B)=>B.mtimeMs-O.mtimeMs)){const O=Ho(u.mtimeMs,t.now);O!==S&&(S=O,h.appendChild(Ze("div","wb-dir-day")).textContent=O);const B=t.titles.get(u.id),X=d(h,"wb-dot-log","❐",B??`会话 …${u.id.slice(-12)}`,`${Bo(u.mtimeMs,t.now)} · ${In(u.sizeBytes)}`,()=>t.openChat({kind:"log",id:u.id,title:B??`…${u.id.slice(-12)}`,sub:"本机日志"}),`${u.id}
|
|
3
|
+
${new Date(u.mtimeMs).toLocaleString()} · ${In(u.sizeBytes)}`);B===void 0&&X.classList.add("is-untitled")}}y.length+E.length+G.length+se.length===0&&(e.appendChild(Ze("div","wb-dir-empty")).textContent=i?"无匹配条目":"目录为空");const N=n.sessions??[];return`${N.filter(b=>b.live===!0).length}/${N.length}`}const io="dsh-a2a.logtitles",Wo=300,Tn=60;function Xo(){try{const e=window.localStorage.getItem(io),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 Ko(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>Tn?`${o.slice(0,Tn-1)}…`:o;if(e.get(t)===i)return!1;for(e.delete(t),e.set(t,i);e.size>Wo;)e.delete(e.keys().next().value);try{window.localStorage.setItem(io,JSON.stringify(Object.fromEntries(e)))}catch{}return!0}function mt(e){return e.name??e.team??e.label??""}function It(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 I(e,t){const n=document.createElement(e);return t!==void 0&&(n.className=t),n}function _n(e,t,n){const s=I("div","wb-kv");s.appendChild(I("span","wb-kv-k")).textContent=t,s.appendChild(I("span","wb-kv-v")).textContent=n,e.appendChild(s)}function Uo(e){try{return new URL(e).host}catch{return e}}const zo=[{key:"directory",label:"目录"},{key:"hosts",label:"主机"},{key:"ledger",label:"台账"},{key:"activity",label:"活动"},{key:"plan",label:"规划"}];function qo(e){const t=e.board;let n="data",s,o=null,i="",r="all",c=null,d=null,f=[],y;const m=Xo();let k=!1;const E=I("div","wb");E.setAttribute("data-testid","wb-root");const G=I("header","wb-header"),fe=I("button","wb-icon-btn wb-menu");fe.type="button",fe.dataset.testid="wb-menu",fe.setAttribute("aria-label","打开目录抽屉"),fe.textContent="☰",fe.addEventListener("click",()=>E.classList.toggle("is-rail-open")),G.appendChild(fe);const se=I("div","wb-title");se.appendChild(I("span","wb-title-main")).textContent="A2A 工作台";const N=I("span","wb-badge");se.appendChild(N),G.appendChild(se);const x=I("button","wb-icon-btn wb-owner-btn");x.type="button",x.dataset.testid="wb-owner-btn",x.setAttribute("aria-label","主人设置(三键面板)"),x.title="主人设置:入网白名单 / 可见性 / 发布",x.textContent="⚙",x.addEventListener("click",()=>{lt=!lt,A()}),G.appendChild(x);const M=I("div","wb-header-stats");G.appendChild(M);const C=I("button","wb-icon-btn wb-rail-toggle");C.type="button",C.dataset.testid="wb-rail-toggle",C.setAttribute("aria-label","折叠/展开侧栏"),C.textContent="◧",C.addEventListener("click",()=>{E.classList.toggle("is-rail-collapsed"),n==="canvas"&&t!==void 0&&t.activate()}),G.appendChild(C);const Q=I("div","wb-body"),b=Do(zo),h=b.root,S=I("div","wb-directory"),u=I("div","wb-dir-tools"),O=document.createElement("input");O.className="wb-search",O.type="search",O.placeholder="搜索:名称 / 队 / 会话 / 节点",O.setAttribute("aria-label","统一搜索目录"),O.addEventListener("input",()=>{i=O.value.trim().toLowerCase(),Xe()}),u.appendChild(O);const B=I("div","wb-filters");for(const $ of jo){const w=I("button","wb-filter");w.type="button",w.textContent=$.label,w.dataset.filter=$.key,w.title=$.hint,w.addEventListener("click",()=>{r=$.key,Xe()}),B.appendChild(w)}u.appendChild(B),b.panel("directory").appendChild(u),b.panel("directory").appendChild(S);const X=I("section","wb-pane"),ge=I("section","wb-pane"),Me=I("section","wb-pane"),P=I("section","wb-pane"),z=[["ledger",X],["activity",ge],["plan",Me],["hosts",P]],ae=I("main","wb-stage"),Re=I("section","wb-stage-board");t!==void 0&&(Re.appendChild(t.root),ae.appendChild(Re));const Se=I("div","wb-data"),K=I("aside","wb-inspector"),ie=I("div","wb-inspector-head");ie.appendChild(I("span","wb-inspector-title")).textContent="详情";const U=I("button","wb-icon-btn");U.type="button",U.setAttribute("aria-label","关闭详情"),U.textContent="✕",U.addEventListener("click",()=>at(void 0)),ie.appendChild(U),K.appendChild(ie);const re=I("div","wb-inspector-body");K.appendChild(re);const be=Fo({now:e.now,sessionLog:e.sessionLog,remoteSessionLog:e.remoteSessionLog,dispatchQuick:e.dispatchQuick,onTranscript:($,w)=>{$.kind!=="log"&&$.kind!=="session"||Ko(m,$.id,w)&&Xe()}});ae.appendChild(Se),Q.appendChild(h),Q.appendChild(ae),Q.appendChild(K),Q.appendChild(be.root),E.appendChild(G),E.appendChild(Q);function He($){for(const[w,j]of z){const L=$==="canvas"?b.panel(w):Se;b.setHidden(w,$!=="canvas"),j.parentElement!==L&&L.appendChild(j)}}function je(){const w=t!==void 0&&t.available()?"canvas":"data";E.dataset.mode=w,Re.classList.toggle("is-hidden",w!=="canvas"),Se.classList.toggle("is-hidden",w==="canvas"),He(w),w!==n&&(t!==void 0&&(w==="canvas"?t.activate():t.deactivate()),n=w)}function Be($){for(;$.firstChild!==null;)$.removeChild($.firstChild);return $}function at($){s=$,(($==null?void 0:$.kind)!=="canvas"||(c==null?void 0:c.name)!==$.row.name)&&(c=null),($==null?void 0:$.kind)!=="canvas"&&(d=null),V(),E.classList.remove("is-rail-open")}function Xe(){for(let w=0;w<B.children.length;w++){const j=B.children[w];j.classList.toggle("is-active",j.dataset.filter===r)}if(o===null){S.replaceChildren(I("div","wb-muted")),S.firstElementChild.textContent="载入中…",b.setBadge("directory","");return}const $=Yo(S,{state:o,logs:f,logTotal:y,titles:m,search:i,filter:r,now:e.now(),openChat:pe,selectCanvas:w=>at({kind:"canvas",row:w})});b.setBadge("directory",$)}function Ge(){const $=Be(P);if(o===null){b.setBadge("hosts","");return}const w=e.now(),j=[...o.peers??[]].sort((L,D)=>{const _=te=>te.link==="linked"?0:1;return _(L)-_(D)||(D.score??0)-(L.score??0)});if(b.setBadge("hosts",j.length>0?`${j.filter(L=>L.link==="linked").length}/${j.length}`:""),j.length===0){$.appendChild(I("div","wb-nodelist-empty")).textContent="暂无 tracked peer——配 peers 种子或等 referral 到达";return}for(const L of j){const D=Uo(L.url),_=I("div","wb-host-row"),te=I("span","wb-host-lamp"),de=L.lastContactAt,ee=de===void 0?void 0:w-de,we=L.lastContactOk;ee===void 0?te.classList.add("is-unknown"):we===!1&&ee<=5*6e4?te.classList.add("is-fail"):ee<=6e4?te.classList.add("is-live"):ee<=5*6e4?te.classList.add("is-warm"):te.classList.add("is-cold"),te.title=de===void 0?"尚无接触记录":`最近接触 ${It(de,w)}${we===!1?"(失败)":we===!0?"(成功)":""}`,_.appendChild(te),_.appendChild(I("span","wb-host-name")).textContent=L.name!==void 0&&L.name!==""?L.name:D;const Te=I("span",`wb-host-badge ${L.link==="linked"?"is-linked":"is-stranger"}`);Te.textContent=`${L.link==="linked"?"linked":"stranger"} ${L.verified===!0?"✓":"✗"}`,Te.title=L.link==="linked"?`已建立运营者链接(互种或 canvas 引用);${L.verified===!0?"验签有效":"尚未持有验签通过的卡片"}`:"无运营者关系(验签 ≠ 关系)",_.appendChild(Te),L.version!==void 0&&L.version!==""&&(_.appendChild(I("span","wb-host-ver")).textContent=L.version),_.appendChild(I("span","wb-host-url mono")).textContent=D,_.setAttribute("role","button"),_.tabIndex=0,_.title=`${L.url} · score ${String(L.score??0)}`;const ne=()=>{pe({kind:"peer",id:`peer-${D}`,title:L.name!==void 0&&L.name!==""?L.name:D,sub:D,url:L.url})};_.addEventListener("click",ne),_.addEventListener("keydown",_e=>{(_e.key==="Enter"||_e.key===" ")&&(_e.preventDefault(),ne())}),$.appendChild(_)}}function ct(){if(o===null){X.replaceChildren(),b.setBadge("ledger","");return}const $=o,w=L=>{const D=($.sessions??[]).find(te=>te.team===L);if(D!==void 0)return{kind:"session",id:D.id,title:mt(D),sub:D.team,team:D.team,live:D.live};const _=($.remote??[]).find(te=>te.team===L);if(_!==void 0)return{kind:"remote",team:_.team,title:mt(_),sub:_.team,row:_}},j=To(X,{state:$,now:e.now(),abandon:(L,D)=>e.abandon(L,D),canOpenTeam:L=>w(L)!==void 0,openTeam:L=>{const D=w(L);return D===void 0?!1:(pe(D),!0)}});b.setBadge("ledger",j.badge,j.tone)}function bt($,w,j){Kt($.appendChild(I("span","wb-row-team")),w,j)}function Ke(){var te;const $=Be(ge);if(o===null)return;const w=e.now(),j=o.inFlight??[];b.setBadge("activity",j.length>0?String(j.length):"",j.length>0?"accent":void 0);const L=I("div","wb-pane-head");if(L.textContent=`在途 ${j.length} · 活动 ${((te=o.activity)==null?void 0:te.length)??0}`,$.appendChild(L),j.length>0){const de=I("div","wb-pane-subhead");de.textContent="在途路由",$.appendChild(de);for(const ee of j){const we=I("div","wb-row");we.appendChild(I("span","wb-row-dir")).textContent="→",bt(we,o,ee.team),we.appendChild(I("span","wb-row-meta")).textContent=`${ee.peer} · ${It(ee.startedAt,w)}`,$.appendChild(we)}}const D=I("div","wb-pane-subhead");D.textContent="活动环(最新在前)",$.appendChild(D);const _=o.activity??[];if(_.length===0){$.appendChild(I("div","wb-muted")).textContent="暂无活动";return}for(const de of _){const ee=I("div","wb-row"),we=I("span","wb-row-dir");we.textContent=de.dir==="out"?"→":"←",de.ok!==!0&&we.classList.add("is-fail"),ee.appendChild(we),bt(ee,o,de.team),ee.appendChild(I("span","wb-row-meta")).textContent=`${de.peer} · ${It(de.ts,w)}`,ee.appendChild(I("span","wb-row-badges")).textContent=de.ok===!0?"":"失败",$.appendChild(ee)}}function Ue($){var te,de;const w=e.now(),j=[],L=fn($,w);L.deadLetters.length>0&&j.push({severity:"high",text:`清账 ${L.deadLetters.length} 条死信(目标早已离开或死信化,无回执可期)`});for(const ee of L.stale){const we=ee.brief===void 0||ee.brief===""?"":`「${ee.brief}」`;j.push({severity:"normal",text:`催办 ${ee.taskId} → ${Ao($,ee.team)}(等待 ${It(ee.startedAt,w)} 无回执)${we}`,brief:`a2a_route 催收回执:task ${ee.taskId}(team ${ee.team})${we===""?"":`原任务「${ee.brief}」`}已派发 ${It(ee.startedAt,w)},请回报结果或回执。`})}const D=($.sessions??[]).filter(ee=>ee.live!==!0).map(ee=>mt(ee));if(D.length>0){const ee=D.slice(0,3).join("、")+(D.length>3?` 等 ${D.length} 个`:"");j.push({severity:"normal",text:`冷会话 ${D.length} 个(${ee}):在 GUI 打开即可唤醒加入面`})}for(const ee of((te=$.reconcile)==null?void 0:te.rows)??[])if(ee.needsRepair===!0){const we=($.sessions??[]).find(ne=>ne.id===ee.id),Te=we!==void 0?`${mt(we)}(${ee.id})`:ee.id;j.push({severity:"high",text:`reconcile 需修复:${Te} ${ee.error}`})}const _=((de=$.idempotency)==null?void 0:de.conflicts)??0;return _>0&&j.push({severity:"high",text:`幂等冲突 ${_} 例:人工核查 UNIQUE-ization 流量`}),j}function gt(){const $=Be(Me);if(o===null)return;const w=Ue(o);b.setBadge("plan",w.length>0?String(w.length):"",w.some(D=>D.severity==="high")?"danger":void 0);const j=I("div","wb-pane-head");j.textContent=w.length===0?"网络健康——无待办行动":`待办行动 ${w.length}`,$.appendChild(j);for(const D of w){const _=I("div",`wb-action${D.severity==="high"?" wb-action-high":""}`);if(_.appendChild(I("span","wb-action-text")).textContent=D.text,D.brief!==void 0){const te=I("button","wb-btn");te.type="button",te.textContent="复制催办",te.addEventListener("click",()=>e.copy(D.brief??"")),_.appendChild(te)}$.appendChild(_)}const L=I("div","wb-pane-subhead");L.textContent="派单起草(复制后在任一会话粘贴执行)",$.appendChild(L),$.appendChild(ft)}const ft=I("div","wb-draft"),ke=document.createElement("select");ke.className="wb-select";const Fe=document.createElement("textarea");Fe.className="wb-textarea",Fe.rows=3,Fe.placeholder="任务正文:目标、验收、期限…";const tt=I("button","wb-btn wb-btn-primary");tt.type="button",tt.textContent="复制任务书",tt.addEventListener("click",()=>{const $=ke.value,w=Fe.value.trim();$===""||w===""||e.copy(`a2a_route 派单 → ${$}:
|
|
5
|
+
${w}`)}),ft.appendChild(ke),ft.appendChild(Fe),ft.appendChild(tt);function vt(){var D;const $=ke.value;Be(ke);const w=document.createElement("option");if(w.value="",w.textContent="选择目标队…",ke.appendChild(w),o===null)return;const j=o,L=new Map;for(const _ of j.sessions??[])_.team!==void 0&&_.team!==""&&L.set(_.team,`${mt(_)}(会话队)`);for(const _ of((D=j.canvas)==null?void 0:D.teams)??[])L.set(_.team,`${_.name}(canvas 队)`);for(const _ of j.remote??[])L.set(_.team,`${mt(_)}(远端)`);for(const[_,te]of L){const de=document.createElement("option");de.value=_,de.textContent=`${te} · ${_}`,ke.appendChild(de)}$!==""&&L.has($)&&(ke.value=$)}let lt=!1,l=null;function A(){var $;V(),lt&&(($=e.ownerSettingsRead)==null||$.call(e).then(w=>{if(lt){if(w.ok!==!0){l=null,V();return}l={teamJoinAllowlist:w.teamJoinAllowlist??[],teamScopeInfo:w.teamScopeInfo!==!1,announce:w.announce===!0,announceRestartPending:w.announceRestartPending===!0},V()}}))}function T($){const w=I("div","wb-card"),j=I("div","wb-inspector-head");j.appendChild(I("span","wb-inspector-title")).textContent="主人设置";const L=I("button","wb-icon-btn");if(L.type="button",L.setAttribute("aria-label","关闭主人设置"),L.textContent="✕",L.addEventListener("click",()=>{lt=!1,V()}),j.appendChild(L),w.appendChild(j),e.ownerSettingsRead===void 0){const xe=I("div","wb-hint");xe.textContent="此宿主未提供主人设置面(旧版本)——升级后可用。",w.appendChild(xe),$.appendChild(w);return}if(l===null){const xe=I("div","wb-hint");xe.textContent="读取中…",w.appendChild(xe),$.appendChild(w);return}const D=l,_=I("div","wb-side-head");_.textContent="入网白名单(精确团队名)",w.appendChild(_);for(const xe of D.teamJoinAllowlist){const ot=I("div","wb-member-row");ot.appendChild(I("span","wb-member-label")).textContent=xe;const yt=I("button","wb-member-remove");yt.type="button",yt.textContent="移除",yt.addEventListener("click",()=>{var St;(St=e.ownerSettingsWrite)==null||St.call(e,{teamJoinAllowlist:D.teamJoinAllowlist.filter(sn=>sn!==xe)}).then(()=>A())}),ot.appendChild(yt),w.appendChild(ot)}const te=I("div","wb-member-add"),de=I("input","wb-member-manual");de.type="text",de.placeholder="dsh/团队名(精确,无通配)",de.setAttribute("aria-label","新增白名单团队名");const ee=I("button","wb-member-submit");ee.type="button",ee.textContent="加入";const we=()=>{var ot;const xe=de.value.trim();xe===""||D.teamJoinAllowlist.includes(xe)||(ot=e.ownerSettingsWrite)==null||ot.call(e,{teamJoinAllowlist:[...D.teamJoinAllowlist,xe]}).then(()=>A())};ee.addEventListener("click",we),de.addEventListener("keydown",xe=>{xe.key==="Enter"&&we()}),te.append(de,ee),w.appendChild(te);const Te=I("div","wb-side-head");Te.textContent="目录可见性(teamScopeInfo)",w.appendChild(Te);const ne=I("div","wb-member-row"),_e=I("button","wb-member-submit");_e.type="button",_e.textContent=D.teamScopeInfo?"已开:仅显示已加入团队(点击放开为全舰队可见)":"已关:全舰队可见(点击收窄为已加入团队)",_e.addEventListener("click",()=>{var xe;(xe=e.ownerSettingsWrite)==null||xe.call(e,{teamScopeInfo:!D.teamScopeInfo}).then(()=>A())}),ne.appendChild(_e),w.appendChild(ne);const ze=I("div","wb-hint");ze.textContent="精度说明:teamScopeInfo 只管「目录显示范围」。关上它不会解锁任何通信准入——会话入网(S3)与目标级路由(F5)规则原样生效。",w.appendChild(ze);const Ve=I("div","wb-side-head");Ve.textContent="节点发布(announce)",w.appendChild(Ve);const dt=I("div","wb-member-row"),Ye=I("button","wb-member-submit");if(Ye.type="button",Ye.textContent=D.announce?"已开:本节点发布签名卡(点击关闭)":"已关:本节点不发布(点击开启——重启宿主后生效)",Ye.addEventListener("click",()=>{var xe;(xe=e.ownerSettingsWrite)==null||xe.call(e,{announce:!D.announce}).then(()=>A())}),dt.appendChild(Ye),w.appendChild(dt),D.announceRestartPending){const xe=I("div","wb-hint");xe.textContent="有 announce 变更待生效:重启宿主后按新配置发布。",w.appendChild(xe)}$.appendChild(w)}function V(){var L;const $=Be(re);if(lt){K.classList.add("is-open"),T($);return}if(K.classList.toggle("is-open",s!==void 0),s===void 0)return;const w=s,j=I("div","wb-card");if(w.kind==="canvas"){const D=(((L=o==null?void 0:o.canvas)==null?void 0:L.teams)??[]).find(ne=>ne.name===w.row.name)??w.row;_n(j,"Canvas 队",D.name),_n(j,"路由队",D.team);const _=I("div","wb-side-head");if(_.textContent=`成员 · ${D.members.length}`,j.appendChild(_),D.members.length===0){const ne=I("div","wb-muted");ne.textContent="空队——用下方表单添加成员",j.appendChild(ne)}for(const ne of D.members){const _e=I("div","wb-member-row"),ze=ne.remote===!0?"◇ 远端":ne.live===!0?"● 现场":ne.joined===!0?"○ 冷启":"· 未入网";_e.appendChild(I("span","wb-member-dot")).textContent=ze;const Ve=I("span","wb-member-label"),dt=((o==null?void 0:o.sessions)??[]).find(xe=>xe.id===ne.id);Ve.textContent=ne.remote===!0?ne.id:dt!==void 0?mt(dt):ne.id,Ve.title=ne.team??ne.id,_e.appendChild(Ve);const Ye=I("button","wb-member-remove");Ye.type="button",Ye.textContent="移除",Ye.addEventListener("click",async()=>{Ye.disabled=!0,await e.canvasOp("remove-member",D.name,ne.id)||(Ye.disabled=!1)}),_e.appendChild(Ye),j.appendChild(_e)}if((c==null?void 0:c.name)!==D.name){const ne=I("form","wb-member-add"),_e=document.createElement("select");_e.className="wb-member-pick",_e.setAttribute("aria-label","选择成员");const ze=document.createElement("input");ze.type="text",ze.className="wb-member-manual",ze.placeholder="或输入远端句柄 zone/id8",ze.setAttribute("aria-label","远端成员句柄");const Ve=I("button","wb-member-submit");Ve.type="submit",Ve.textContent="添加",ne.appendChild(_e),ne.appendChild(ze),ne.appendChild(Ve),ne.addEventListener("submit",async dt=>{dt.preventDefault();const Ye=ze.value.trim(),xe=Ye!==""?Ye:_e.value;if(xe==="")return;Ve.disabled=!0;const ot=await e.canvasOp("add-member",D.name,xe);Ve.disabled=!1,ot&&(ze.value="")}),c={name:D.name,form:ne,pick:_e,manual:ze}}const te=c.pick,de=te.value;Be(te),te.appendChild(new Option("本机会话(现场/冷启动)…","",!0,!0));const ee=new Set(D.members.map(ne=>ne.id));for(const ne of(o==null?void 0:o.sessions)??[])ee.has(ne.id)||te.appendChild(new Option(`${mt(ne)} — 本机`,ne.id));let we=!1;for(const ne of(o==null?void 0:o.remote)??[])ne.team.includes("/")&&(ee.has(ne.team)||(we||(te.appendChild(new Option("远端会话队(目录卡片)…","",!0,!1)),we=!0),te.appendChild(new Option(`${mt(ne)} — 远端`,ne.team))));we||te.appendChild(new Option("(暂无可拉入的远端会话队——见下方说明)","",!0,!1)),de!==""&&Array.from(te.options).some(ne=>ne.value===de)&&(te.value=de),j.appendChild(c.form);const Te=I("div","wb-hint");Te.textContent="成员由人类在此手工分配(agent 不可自组队)。远端成员走对端目录路由,不做本机冷唤醒;地址由目录在派发时重解析。远端下拉只列 zone/id8 会话句柄——若为空,说明目录里还没有已链接对端的会话队(未链接的对端只给最小卡);此时可在输入框手输句柄(如 dsh/xxxxxxxx)先把人拉进来,句柄本身即链接手势。",j.appendChild(Te),e.dispatchQuick!==void 0&&j.appendChild(he(D.team))}$.appendChild(j)}function W($){const w=I("form","wb-dispatch-form"),j=document.createElement("textarea");j.className="wb-dispatch-text",j.placeholder="一句话任务…(≤4000 字符,异步送达,回执进台账)",j.setAttribute("aria-label","快派消息");const L=I("button","wb-dispatch-submit");L.type="submit",L.textContent="发送";const D=I("div","wb-dispatch-note");return w.appendChild(j),w.appendChild(L),w.appendChild(D),j.addEventListener("keydown",_=>{_.key!=="Enter"||_.shiftKey||_.ctrlKey||_.altKey||_.metaKey||_.isComposing||(_.preventDefault(),L.disabled||w.requestSubmit())}),w.addEventListener("submit",async _=>{var ee;_.preventDefault();const te=j.value.trim();if(te===""||L.disabled)return;L.disabled=!0,D.textContent="派发中…";let de;try{de=await(((ee=e.dispatchQuick)==null?void 0:ee.call(e,$,te))??Promise.resolve({ok:!1,error:"dispatch unavailable"}))}catch(we){de={ok:!1,error:we instanceof Error?we.message:String(we)}}L.disabled=!1,de.ok===!0&&(j.value=""),j.focus({preventScroll:!0}),D.textContent=de.ok===!0?`已派发${de.task_id!==void 0?` · ${de.task_id}`:""} · 回执将入台账(待回执)`:`失败:${de.error??"未知原因"}`}),{form:w,text:j,note:D}}function he($){const w=I("div","wb-dispatch"),j=I("div","wb-side-head");return j.textContent="快派",w.appendChild(j),(d==null?void 0:d.team)!==$&&(d={team:$,...W($)}),w.appendChild(d.form),w}function pe($){be.open($),E.classList.remove("is-rail-open")}function ye($){if(o===null)return;const w=(o.sessions??[]).find(L=>L.id===$);if(w!==void 0){pe({kind:"session",id:$,title:mt(w),sub:w.team,team:w.team,live:w.live});return}if($.startsWith("peer-")){const L=$.slice(5),D=(o.peers??[]).find(_=>_.url.includes(L));pe({kind:"peer",id:$,title:D!==void 0?D.url:L,sub:L,url:D==null?void 0:D.url});return}f.find(L=>L.id===$)!==void 0&&pe({kind:"log",id:$,title:`…${$.slice(-12)}`,sub:"档案"})}function q(){var ee,we;N.textContent=(o==null?void 0:o.version)!==void 0?`v${o.version}`:"",N.hidden=(o==null?void 0:o.version)===void 0;const $=Be(M);if(o===null)return;const w=[],j=fn(o,e.now()),L=j.deadLetters.length;L>0&&w.push({text:`死信 ${L}`,tone:"danger",title:"超过 24h TTL 仍未结算的任务(unconsumed),需在台账清账",tab:"ledger",group:"死信"});const D=j.stale.length;D>0&&w.push({text:`陈旧 ${D}`,tone:"warn",title:"我方派发、要回执、已等待 ≥1h 仍未回执(可催办;免回执行不算)",tab:"ledger",group:"陈旧"});const _=j.owedOverdue.length;_>0&&w.push({text:`欠回执 ${_}`,tone:"warn",title:"对方投递给本机、已等待本机回执超过 1 小时",tab:"ledger",group:"待本机回执"});const te=((ee=o.idempotency)==null?void 0:ee.conflicts)??0;te>0&&w.push({text:`幂等冲突 ${te}`,tone:"danger",title:"同一幂等键对应了不同载荷,需人工核查",tab:"ledger",group:"取证"});const de=(((we=o.reconcile)==null?void 0:we.rows)??[]).filter(Te=>Te.needsRepair===!0).length;if(de>0&&w.push({text:`需修复 ${de}`,tone:"danger",title:"reconcile 无法自动恢复的会话,见行动计划",tab:"plan"}),w.length===0){$.appendChild(I("span","wb-header-ok")).textContent="● 无异常";return}for(const Te of w){const ne=I("button",`wb-alert wb-alert-${Te.tone}`);ne.type="button",ne.textContent=Te.text,ne.title=`${Te.title}(点击查看)`,ne.addEventListener("click",()=>Pe(Te.tab,Te.group)),$.appendChild(ne)}}function Pe($,w){var D;const j=z.find(([_])=>_===$)[1];n==="canvas"&&(E.classList.add("is-rail-open"),b.select($,{focus:!1}));const L=w===void 0?j:w==="取证"?j.querySelector("details.wb-led-forensics"):Array.from(j.querySelectorAll(".wb-led-group")).find(_=>_.dataset.group===w)??null;L!==null&&(L instanceof HTMLDetailsElement&&(L.open=!0),(D=L.scrollIntoView)==null||D.call(L,{block:"start",behavior:"smooth"}))}function Je($){o=$,e.sessionLogList!==void 0&&!k&&(k=!0,e.sessionLogList().then(w=>{f=w.ok&&w.sessions!==void 0?w.sessions:[],y=w.ok?w.count:void 0}).catch(()=>{}).finally(()=>{k=!1,Xe()})),q(),Xe(),vt(),Ge(),ct(),be.update($),Ke(),gt(),V(),je()}function Ne($){if($==="board"){je();return}b.select($)}return Je(null),{root:E,update:Je,mode:()=>n,selectTab:Ne,openNodeChat:ye}}const pt=1e6,yn=.25,wn=3,ro=256,ao=96;function Mt(e){const t=typeof e=="number"?e:Number.NaN;if(Number.isFinite(t))return Math.max(-pt,Math.min(pt,Math.round(t)))}function co(e){if(e===null||typeof e!="object")return;const t=e,n=Mt(t.x),s=Mt(t.y);return n===void 0||s===void 0?void 0:{x:n,y:s}}function Jo(e){const t=co(e);if(t===void 0)return;const n=e,s=Mt(n.w),o=Mt(n.h);if(!(s===void 0||o===void 0||s<=0||o<=0))return{...t,w:Math.min(s,pt),h:Math.min(o,pt)}}const lo=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=Mt(s.x),i=Mt(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(yn,Math.min(wn,c)),f={};if(t.nodes!==null&&typeof t.nodes=="object")for(const[m,k]of Object.entries(t.nodes)){if(typeof m!="string"||m===""||m.length>128)continue;const E=co(k);if(E!==void 0&&(f[m]=E),Object.keys(f).length>=ro)break}const y={};if(t.frames!==null&&typeof t.frames=="object")for(const[m,k]of Object.entries(t.frames)){if(!lo(m))continue;const E=Jo(k);if(E!==void 0&&(y[m]=E),Object.keys(y).length>=ao)break}return{version:1,viewport:{x:o,y:i,scale:d},nodes:f,frames:y}}function Vo(e,t,n){const s=r=>Math.max(-pt,Math.min(pt,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>=ro))break;const i={};for(const[r,c]of n){if(!lo(r))continue;const d=s(c.w),f=s(c.h);if(!(d<=0||f<=0)&&(i[r]={x:s(c.x),y:s(c.y),w:Math.min(d,pt),h:Math.min(f,pt)},Object.keys(i).length>=ao))break}return{version:1,viewport:{x:s(e.x),y:s(e.y),scale:Math.max(yn,Math.min(wn,e.scale))},nodes:o,frames:i}}function uo(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 De=172,Oe=56,Ct=[150,290,430],nt=16;function Go(e){const t=uo(e),n=Math.floor(t/nt)%Ct.length,o=t%nt/nt*Math.PI*2+n*(Math.PI/nt),i=Ct[n];return{x:Math.round(Math.cos(o)*i),y:Math.round(Math.sin(o)*i*.6)}}function fo(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 On=64,Fn=24,Pn=20,Qo=4,Rn=24,Dn=44,Zo=24;function es(e,t,n=Number.POSITIVE_INFINITY){const s=new Set(t),o=fo(e),i=e.map(m=>[...new Set(m.members.map(k=>k.id))].filter(k=>s.has(k)&&o.get(k)===m.name));i.push(t.filter(m=>!o.has(m)));const r=new Map;let c=0,d=0,f=0,y=0;for(const m of i){if(m.length===0)continue;const k=Math.min(3,Math.max(m.length>1?2:1,Math.ceil(Math.sqrt(m.length)))),E=Math.ceil(m.length/k),G=Math.max(260,k*De+(k-1)*Fn+Rn*2),fe=Math.max(160,E*Oe+(E-1)*Pn+Dn+Zo);y>0&&(y%Qo===0||c+G>n)&&(c=0,d+=f+On,f=0),m.forEach((se,N)=>{const x=N%k,M=Math.floor(N/k);r.set(se,{x:c+Rn+De/2+x*(De+Fn),y:d+Dn+Oe/2+M*(Oe+Pn)})}),c+=G+On,f=Math.max(f,fe),y+=1}return r}const Ht=12;function po(e,t){const n=d=>t.every(f=>Math.abs(f.x-d.x)>=De+Ht||Math.abs(f.y-d.y)>=Oe+Ht),s=Go(e);if(n(s))return s;const o=uo(e),i=nt*Ct.length,r=Math.floor(o/nt)%Ct.length*nt+o%nt;for(let d=1;d<i;d++){const f=(r+d)%i,y=Math.floor(f/nt),m=f%nt/nt*Math.PI*2+y*(Math.PI/nt),k=Ct[y],E={x:Math.round(Math.cos(m)*k),y:Math.round(Math.sin(m)*k*.6)};if(n(E))return E}const c=Ct[Ct.length-1];for(let d=0;;d++)for(let f=0;f<6;f++){const y={x:Math.round(-c+f*(De+Ht)),y:Math.round(c*.6+Oe*2+d*(Oe+Ht))};if(n(y))return y}}function rt(e){return{x:e.x-De/2,y:e.y-Oe/2,w:De,h:Oe}}function xn(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 y of e)t=Math.min(t,y.x),n=Math.min(n,y.y),s=Math.max(s,y.x+y.w),o=Math.max(o,y.y+y.h);const i=24,r=44,c=24,d=Math.max(260,Math.round(s-t+i*2)),f=Math.max(160,Math.round(o-n+r+c));return{x:Math.round(t-i),y:Math.round(n-r),w:d,h:f}}class Cn{constructor(){Et(this,"revisionCounter",0);Et(this,"nodes",new Map);Et(this,"frames",new Map);Et(this,"selection",new Set);Et(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=rt(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(rt(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 Cn,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 f=po(i.id,[...n.nodes.values()]);c=f.x,d=f.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 f=n.nodes.get(d.id);f!==void 0&&c.push(rt(f))}c.length>0&&n.frames.set(i.name,xn(c))}return n.viewport=s!==void 0?{...s.viewport}:{x:0,y:0,scale:1},n}}const ts=24,ho=-13,ns=ho+ts;function os(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+ns;for(const f of i.members){const y=n.get(f.id);if(y===void 0)continue;const m=o.has(f.id);o.add(f.id),s.push({x1:c,y1:d,x2:y.x,y2:y.y-Oe/2,dashed:m,team:i.name,id:f.id})}}return s}function ss(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 os(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 is(e){return`peer-${it(e).replace(/[^A-Za-z0-9.:\[\]-]/g,"-")}`}function it(e){try{return new URL(e).host}catch{return e}}function rs(e){const t=new Map;for(const n of e){const s=n.via!==void 0&&n.via!==""?it(n.via):"",o=t.get(s)??[];o.push(n),t.set(s,o)}return t}const as=140,cs=200,ls=90,ds=20,Yt=60;function ms(e,t){const n=t!==null?t.maxX+as:cs,s=t!==null?t.minY:0;return e.map((o,i)=>({url:o.url,score:o.score,x:n,y:s+i*ls}))}function us(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(y=>{try{return new URL(y.url).host===r.peer}catch{return!1}});if(d===void 0)continue;const f=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} · ${f}s`+(r.count>1?` ×${r.count}`:"")})}return i}function fs(e,t){const n=t!==null?{x:t.maxX+ds,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 ps(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-Yt),s=Math.min(s,r.y-Yt),o=Math.max(o,r.x+Yt),i=Math.max(i,r.y+Yt);return{minX:n,minY:s,maxX:o,maxY:i}}const hs=11;function bs(e,t){let n=[],s=[],o=[];function i(c){for(const y of n)y.remove();n=[];const d=t.allNodes().filter(y=>y.remote===!0).map(y=>({url:y.peerUrl??y.id.slice(5),score:y.score,x:y.x,y:y.y}));s=d;const f=t.contentBounds();if(f!==null){const y=new Map;for(const[m,k]of t.allFrames())y.set(m,{name:m,x:k.x+k.w/2,y:k.y+hs});for(const m of us(o,y,d,c))n.push(...r(m,"e-activity",m.label));for(const m of fs(d,f))n.push(...r(m,"e-federal",m.label))}}function r(c,d,f){const y=document.createElementNS("http://www.w3.org/2000/svg","line");y.setAttribute("class",d),y.setAttribute("x1",String(c.x1)),y.setAttribute("y1",String(c.y1)),y.setAttribute("x2",String(c.x2)),y.setAttribute("y2",String(c.y2)),e.appendChild(y);const m=[y];if(f!==""){const k=document.createElementNS("http://www.w3.org/2000/svg","text");k.setAttribute("class","edge-label mono"),k.setAttribute("x",String((c.x1+c.x2)/2+14)),k.setAttribute("y",String((c.y1+c.y2)/2+18)),k.textContent=f,e.appendChild(k),m.push(k)}return m}return{render:i,flyTo(c){return c(),s},placements:()=>s,setInFlight:c=>{o=c}}}function gs(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 vs(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 Vt(e){return Math.max(yn,Math.min(wn,e))}function $t(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:Vt(t)}}function ut(e,t,n){return{x:e.x+t/e.scale,y:e.y+n/e.scale}}function ln(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=Vt(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 ys=680,ws=.8,xs=.6,Hn=16;function kn(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<ys?ws:xs;if(r<d){const y=Vt(Math.min(s,d));return{x:e.minX-Hn/y,y:e.minY-Hn/y,scale:y}}const f=Vt(c);return{x:(e.minX+e.maxX)/2-t/(2*f),y:(e.minY+e.maxY)/2-n/(2*f),scale:f}}function Cs(e){return`translate(${-e.x*e.scale}px, ${-e.y*e.scale}px) scale(${e.scale})`}function Yn(e,t){let n=e===null?null:{...e,minY:e.minY+ho};for(const s of t){if(s.remote!==!0)continue;const o=rt(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 Wn(e,t,n,s){const o=s>0&&s<n/2?s:0,i=kn(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 Pt(e){return e.type==="join-network"||e.type==="leave-network"?"$network":e.type==="create-team"||e.type==="remove-team"?e.name:e.team}function ks(e,t){if(t.type==="create-team"){const o=t.ids.map(i=>e.getNode(i)).filter(i=>i!==void 0).map(i=>rt(i));return o.length>0&&e.setFrame(t.name,xn(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 Kn(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(Pt(t))!==void 0)return o;const r={...o.frames};return delete r[Pt(t)],{...o,frames:r}}function hn(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 Es(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 dn(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 Un=[9133302,3900150,1357990,16096779,15485081,8702998];function $s(e){let t=0;for(let c=0;c<e.length;c++)t=(t*31+e.charCodeAt(c)&268435455)>>>0;const n=Un[t%Un.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 Gt="roster:",bo=e=>e.startsWith(Gt)?e.slice(Gt.length):void 0,_t=e=>Gt+e,Qt=e=>{const t=bo(e);return t===void 0?e:`网络队 · roster · ${t}`};function Ns(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(Gt)||s.includes("*")?[]:[{name:_t(s),team:n.team,kind:"roster",members:n.members.filter(o=>typeof o=="string"&&o!=="").map(o=>({id:o}))}]})}function Ms(e){const{root:t,netBtn:n,signal:s,model:o}=e,i=b=>e.isRoster(b)?Qt(b):b;function r(){return o.selectedIds().map(b=>{var h;return{id:b,y:((h=o.getNode(b))==null?void 0:h.y)??0}}).sort((b,h)=>b.y-h.y).map(b=>b.id)}function c(){if(d!==null)return;const b=r().filter(h=>{const S=o.getNode(h);return S===void 0?!1:S.remote!==!0||S.remoteHandle!==void 0&&S.remoteHandle!==""});if(b.length<2){e.notice("info","框选至少 2 个会话节点");return}f(b)}let d=null;function f(b){const h=document.createElement("div");h.className="p-dialog";const S=document.createElement("div");S.className="p-dialog-panel",S.setAttribute("role","dialog"),S.setAttribute("aria-modal","true"),S.setAttribute("aria-labelledby","p-dialog-title");const u=document.createElement("div");u.id="p-dialog-title",u.className="p-dialog-title",u.textContent=`组建团队(${b.length} 个节点,自上而下即优先级)`;const O=document.createElement("select");O.className="p-dialog-kind",O.setAttribute("aria-label","团队类型");for(const[K,ie]of[["canvas","canvas 队"],["roster","roster 网络队"]]){const U=document.createElement("option");U.value=K,U.textContent=ie,O.appendChild(U)}const B=document.createElement("input");B.className="p-dialog-input",B.maxLength=40,B.setAttribute("aria-label","团队名");const X=document.createElement("div");X.className="p-dialog-err",X.setAttribute("aria-live","polite");const ge=document.createElement("div");ge.className="p-dialog-row";const Me=document.createElement("button");Me.type="button",Me.textContent="组建";const P=document.createElement("button");P.type="button",P.textContent="取消",ge.append(Me,P),S.append(u,O,B,X,ge),h.appendChild(S),t.appendChild(h);const z=document.activeElement,ae=()=>{h.remove(),d=null,z==null||z.focus()},Re=()=>{const K=B.value.trim();return K===""||K.length>40||K.includes("/")||K.startsWith("roster:")||O.value==="roster"&&K.includes("*")||/^\d+$/.test(K)?"队名需 1..40 字,不含“/”、通配符或保留前缀,不为纯数字":O.value==="roster"&&o.getFrame(K)!==void 0?"同名 canvas 队已存在,不能创建 roster 队":O.value==="roster"&&o.getFrame(_t(K))!==void 0&&!e.isRoster(_t(K))?"roster 框名已被 canvas 或镜像队占用":O.value==="canvas"&&o.getFrame(_t(K))!==void 0?"同名 roster 队已存在,不能创建 canvas 队":O.value==="roster"&&b.some(ie=>{var U;return((U=o.getNode(ie))==null?void 0:U.remote)===!0||!e.joined(ie)})?"roster 仅接受本机已入网的会话":null},Se=()=>{const K=Re();if(K!==null){X.textContent=K,B.focus();return}const ie=O.value==="roster"?_t(B.value.trim()):B.value.trim();if(ae(),o.getFrame(ie)!==void 0){e.notice("info",`已加入现有团队「${O.value==="roster"?Qt(ie):ie}」`),e.emit({type:"add-member",team:ie,ids:b});return}e.emit({type:"create-team",name:ie,ids:b,created:!0,...O.value==="roster"?{roster:!0}:{}})};Me.addEventListener("click",Se),P.addEventListener("click",ae),B.addEventListener("keydown",K=>{const ie=K;ie.key==="Enter"&&(ie.preventDefault(),Se()),ie.key==="Escape"&&(ie.preventDefault(),ae())}),h.addEventListener("keydown",K=>{const ie=K;if(ie.key==="Escape"){ie.preventDefault(),ie.stopPropagation(),ae();return}if(ie.key!=="Tab")return;ie.preventDefault();const U=Array.from(S.querySelectorAll("input, select, button")),re=U.indexOf(document.activeElement),be=ie.shiftKey?U[(re-1+U.length)%U.length]:U[(re+1)%U.length];be==null||be.focus()},s),d={wrap:h,restoreFocus:z},B.focus()}let y=null,m="root",k=null,E=null,G=[];function fe(){E==null||E.remove(),E=null}function se(){var S;if(E!==null){fe();return}if(G.length===0)return;const b=document.createElement("div");b.className="p-menu p-netmenu",b.setAttribute("role","menu"),b.setAttribute("aria-label","未入网会话");for(const u of G)b.appendChild(x(`${u.name!==void 0&&u.name!==""?u.name:u.label} — 入网`,!0,()=>{fe(),e.emit({type:"join-network",id:u.id})}));E=b,t.appendChild(b);const h=n.getBoundingClientRect();b.style.left=`${String(Math.min(h.left,window.innerWidth-220))}px`,b.style.top=`${String(Math.max(8,h.top-(G.length*30+10)))}px`,b.addEventListener("keydown",u=>{u.key==="Escape"&&(u.stopPropagation(),fe(),n.focus())}),(S=b.querySelector("button"))==null||S.focus(),document.addEventListener("pointerdown",u=>{if(E===null)return;const O=u.target;O!==null&&(O.closest(".p-netmenu")!==null||O===n||n.contains(O))||fe()},s)}function N(){y==null||y.remove(),y=null,m="root",k!==null&&k.isConnected?k.focus():t.focus(),k=null}function x(b,h,S){const u=document.createElement("button");return u.type="button",u.setAttribute("role","menuitem"),u.textContent=b,h?u.addEventListener("click",()=>{N(),S()}):(u.disabled=!0,u.setAttribute("aria-disabled","true")),u}function M(b,h,S,u="root",O){var Me,P,z,ae,Re,Se,K;O!==void 0&&(k=O),k===null&&(k=e.anchorFor(S)),y==null||y.remove(),m=u;const B=document.createElement("div");B.className="p-menu",B.setAttribute("role","menu"),B.setAttribute("aria-label","团队操作");let X=[];if(S.kind==="frame")X=[x(`解散团队「${i(S.name)}」`,!0,()=>e.emit({type:"remove-team",name:S.name}))];else{const ie=S.id;if(u==="root"){const U=x("组成团队…",o.selectedIds().length>=2,()=>f(r()));U.title="先框选或 Shift 加选至少 2 个节点",X.push(U),e.teams().length>0&&(X.push(x("加入团队 ▸",!0,()=>M(b,h,S,"join"))),(((Me=o.getNode(ie))==null?void 0:Me.memberships.map(be=>be.team))??[]).length>0&&(X.push(x("置顶路由 ▸",!0,()=>M(b,h,S,"promote"))),X.push(x("离队 ▸",!0,()=>M(b,h,S,"leave"))))),((P=o.getNode(ie))==null?void 0:P.remote)!==!0&&X.push(x("退网",!0,()=>e.emit({type:"leave-network",id:ie})))}else{X.push(x("‹ 返回",!0,()=>M(b,h,S,"root")));for(const U of e.teams())if(u==="join"){const re=((z=o.getNode(ie))==null?void 0:z.memberships.some(je=>je.team===U.name))??!0,be=!e.isRoster(U.name)||e.joined(ie)&&((ae=o.getNode(ie))==null?void 0:ae.remote)!==!0,He=x(re?`${i(U.name)}(已加入)`:i(U.name),!re&&be,()=>e.emit({type:"add-member",team:U.name,ids:[ie]}));be||(He.title="roster 只接受本机已入网会话"),X.push(He)}else if(u==="leave"){const re=((Re=o.getNode(ie))==null?void 0:Re.memberships.some(be=>be.team===U.name))??!1;X.push(x(i(U.name),re,()=>e.emit({type:"remove-member",team:U.name,ids:[ie]})))}else{const re=((Se=o.getNode(ie))==null?void 0:Se.memberships.some(be=>be.team===U.name))??!1;if(e.isRoster(U.name))continue;X.push(x(i(U.name),re,()=>{const be=o.teamMemberIds(U.name),He=[ie,...be.filter(je=>je!==ie)];e.emit({type:"reorder",team:U.name,ops:hn(be,He)})}))}}}B.append(...X),B.style.left=`${Math.min(b,window.innerWidth-200)}px`;const ge=X.length*30+8;B.style.top=`${Math.max(8,Math.min(h,window.innerHeight-ge-8))}px`,B.addEventListener("keydown",ie=>{var He,je,Be,at;const U=ie,re=Array.from(B.querySelectorAll("[role=menuitem]")),be=re.indexOf(document.activeElement);U.key==="ArrowDown"?(U.preventDefault(),(He=re[(be+1+re.length)%re.length])==null||He.focus()):U.key==="ArrowUp"?(U.preventDefault(),(je=re[(be-1+re.length)%re.length])==null||je.focus()):U.key==="Home"?(U.preventDefault(),(Be=re[0])==null||Be.focus()):U.key==="End"?(U.preventDefault(),(at=re[re.length-1])==null||at.focus()):U.key==="Escape"&&(U.preventDefault(),U.stopPropagation(),m!=="root"?M(b,h,S,"root"):N())}),t.appendChild(B),y=B,(K=X[0])==null||K.focus()}function C(b,h,S){if(d!==null)return;const u=(S==null?void 0:S.closest(".p-node"))??null;if(u!==null){const X=o.getNode(u.dataset.id??"");if((X==null?void 0:X.remote)===!0&&(X.remoteHandle===void 0||X.remoteHandle===""))return}const O=u,B=(S==null?void 0:S.closest(".p-frame-head"))??null;if(O!==null){const X=O.dataset.id??"";o.isSelected(X)||o.setSelection([X]),k=O,M(b,h,{kind:"node",id:X})}else B!==null&&(k=B,M(b,h,{kind:"frame",name:B.dataset.frame??""}))}function Q(b){G=b,n.textContent=`未入网${G.length>0?`(${String(G.length)})`:""}`,n.disabled=G.length===0,n.setAttribute("aria-disabled",String(G.length===0)),G.length===0&&fe()}return{menuItem:x,isMenuOpen:()=>y!==null,isDialogOpen:()=>d!==null,closeMenu:N,openMenu:M,contextMenuAt:C,openNameDialog:f,startCreateFromSelection:c,toggleNetMenu:se,setUnjoined:Q}}function Ss(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 As(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 Ls(e,t=1200){e!==void 0&&(e.classList.add("pulse"),setTimeout(()=>e.classList.remove("pulse"),t))}function Is(e){return t=>{const n=e.model.getNode(t);if(n===void 0)return;const s=e.viewSize();e.setVp(kn({minX:n.x,minY:n.y,maxX:n.x+De,maxY:n.y+Oe},s.w,s.h,1)),e.applyViewport(),e.markDirty(),Ls(e.cardEl(t))}}function Ts(e,t,n,s){const o=_s({onPick:s});return e.appendChild(o.root),{...o,refresh:()=>o.setIndex(As(t,n))}}function _s(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((m,k)=>{const E=document.createElement("div");E.className="p-search-hit"+(k===r?" active":""),E.dataset.id=m.id,E.textContent=m.name===m.team?m.name:`${m.name} · ${m.team}`,E.addEventListener("mousedown",G=>{G.preventDefault(),e.onPick(m.id),f()}),s.appendChild(E)}),s.style.display="block"},f=()=>{n.value="",i=[],c()},y=()=>{i=Ss(o,n.value),r=0,d()};return n.addEventListener("input",y),n.addEventListener("keydown",m=>{if(m.key==="Escape"){f(),n.blur(),m.stopPropagation();return}if(m.key==="ArrowDown"||m.key==="ArrowUp"){if(i.length===0)return;m.preventDefault(),r=(r+(m.key==="ArrowDown"?1:i.length-1))%i.length,d();return}m.key==="Enter"&&i.length>0&&(m.preventDefault(),e.onPick(i[r].id),f())}),t.append(n,s),{root:t,setIndex(m){o=m,n.value!==""&&y()},focus(){n.focus(),n.select()},clear(){f()}}}const Wt=28,zn=16,qn=14,Jn=48,Os=4,Fs=180,Ps=90,Rs=1600;function Ds(e){const t=e.wrapWidth??Rs,n=e.frames.map(d=>{const f=Math.max(d.soleIds.length,1),y=Math.min(Os,Math.max(1,Math.ceil(Math.sqrt(f)))),m=Math.ceil(f/y),k=Math.max(Fs,Wt*2+y*De+(y-1)*zn),E=Math.max(Ps,Wt*2+m*Oe+(m-1)*qn);return{name:d.name,w:k,h:E,rows:m,perRow:y,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+Jn,c=0);const f={x:i,y:r,w:d.w,h:d.h};s.push({name:d.name,rect:f});const y=f.x+Wt+De/2;let m=f.y+Wt+Oe/2;d.soleIds.forEach((k,E)=>{const G=E%d.perRow;E>0&&G===0&&(m+=Oe+qn),o.push({id:k,x:y+G*(De+zn),y:m})}),i+=d.w+Jn,c=Math.max(c,d.h)}return{frames:s,seats:o}}function js(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=Ds({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 Bs(e,t){if(e===void 0)return;const n=it(e);return{text:t?`同步中… · ${n}`:`镜像 · ${n}`,title:t?`已把改动交给属主 ${n},等待它确认`:`这个团队属于 ${n},这里显示的是它的镜像;拖入或移出成员会经中继交给 ${n} 执行`,syncing:t}}const Hs=1e4;function Ys(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>Hs)&&n.delete(i)}}}const kt=24,Ws=200,Ut=(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 Xs(e,t){const n=t.x+t.w+kt-e.x,s=t.x-kt-(e.x+e.w),o=t.y+t.h+kt-e.y,i=t.y-kt-(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 Ks(e,t,n,s){const o=e.beginFrameDrag(t);o!==void 0&&e.applyFrameDrag(o,n,s)}function Us(e,t,n){let s=!1;for(let o=0;o<Ws;o++){const i=e.allFrames();let r;for(let N=0;N<i.length&&r===void 0;N++)for(let x=N+1;x<i.length;x++){const[M,C]=i[N],[Q,b]=i[x];if(!(t.has(M)&&t.has(Q))&&Ut(C,b)){r=[M,C,Q,b];break}}if(r===void 0)return s;const[c,d,f,y]=r,m=N=>t.has(N)?2:N===n?1:0,[k,E,G]=m(c)<m(f)?[c,d,y]:[f,y,d],{dx:fe,dy:se}=Xs(E,G);Ks(e,k,fe,se),s=!0}return s}const ht=28,zt=16,Zt=14;function zs(e){const t=[];for(let n=e.y+ht;n+Oe<=e.y+e.h-ht;n+=Oe+Zt)for(let s=e.x+ht;s+De<=e.x+e.w-ht;s+=De+zt)t.push({x:s+De/2,y:n+Oe/2});return t}function qs(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(se=>se.team)),r=n.find(([se,N])=>!i.has(se)&&Ut(rt(o),N));if(r===void 0)continue;const c=r[1],d=se=>{const N=rt(se);return n.every(([x,M])=>i.has(x)||!Ut(N,M))&&e.allNodes().every(x=>x.id===o.id||!Ut(N,rt(x)))},y=o.memberships.map(se=>s.get(se.team)).filter(se=>se!==void 0).flatMap(zs).find(d),m={x:c.x+c.w+kt+De/2,y:o.y},k={x:o.x,y:c.y+c.h+kt+Oe/2},E=Math.max(...n.map(([,se])=>se.x+se.w))+kt+De/2,G=Array.from({length:2*e.allNodes().length+1},(se,N)=>({x:E,y:c.y+Oe/2+N*(Oe+Zt)})),fe=y??[m,k,...G].find(d)??G[G.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=Us(e,t,n),o=qs(e);return s||o}function Js(e){for(const[t,n]of e.allFrames()){const s=e.teamMemberIds(t).map(f=>e.getNode(f)).filter(f=>f!==void 0).filter(f=>f.memberships.length===1);if(s.length===0)continue;const o=Math.max(1,Math.floor((n.w-2*ht+zt)/(De+zt))),i=Math.ceil(s.length/o),r=ht*2+i*Oe+(i-1)*Zt;r>n.h&&e.setFrame(t,{...n,h:Math.min(r,n.h+400)});const c=n.x+ht+De/2;let d=n.y+ht+Oe/2;s.forEach((f,y)=>{const m=y%o;y>0&&m===0&&(d+=Oe+Zt);const k=c+m*(De+zt);e.dragNodes([f.id],k-f.x,d-f.y)})}}const Vs=30;function Gs(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>Vs&&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 Qs(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 f(){d(),i==null||i.remove(),i=null}function y(){if(i!==null){f();return}const x=document.createElement("div");x.className="p-menu p-nodelist",x.setAttribute("role","dialog"),x.setAttribute("aria-label","节点清单"),i=x,t.appendChild(x);const M=n.getBoundingClientRect();x.style.left=`${String(Math.min(M.left,window.innerWidth-340))}px`,x.style.top=`${String(Math.max(8,M.top-320))}px`,x.addEventListener("keydown",C=>{C.key==="Escape"&&(C.stopPropagation(),f(),n.focus())}),m()}function m(){var S;const x=i;if(x===null)return;d(),x.textContent="";const M=document.createElement("div");M.className="p-nodelist-head";const C=document.createElement("span");C.className="p-nodelist-title",C.textContent="节点";const Q=document.createElement("select");Q.className="p-nodesel",Q.setAttribute("aria-label","选择 host 或对等节点");const b=document.createElement("option");b.value="",b.textContent="本机",Q.appendChild(b);for(const[u,O]of e.facts().remoteTeams){if(u==="")continue;const B=document.createElement("option");B.value=u,B.textContent=((S=O[0])==null?void 0:S.origin)!==void 0&&O[0].origin!==""?`${O[0].origin}(${u})`:u,Q.appendChild(B)}r!==""&&!e.facts().remoteTeams.has(r)&&(r=""),Q.value=r,Q.addEventListener("change",()=>{r=Q.value,m()}),M.append(C,Q);const h=document.createElement("div");h.className="p-nodelist-body",x.append(M,h),r===""?se(h):N(h,e.facts().remoteTeams.get(r)??[])}function k(x,M){const C=document.createElement("span");return C.className="p-nodedot"+(M!==!0?" off":x===!1?" cold":""),C}function E(x,M){const C=document.createElement("button");return C.type="button",C.className="p-listbtn",C.textContent=x,C.addEventListener("click",Q=>{Q.stopPropagation(),M()}),C}function G(x,M){const C=document.createElement("div");if(C.className="p-nodelist-group",C.textContent=x,M!==void 0){const Q=document.createElement("span");Q.className="p-nodelist-note",Q.textContent=M,C.appendChild(Q)}return C}function fe(x,M){var b,h;d();const C=document.createElement("div");C.className="p-menu",C.setAttribute("role","menu"),C.setAttribute("aria-label","加入团队");for(const S of e.facts().teams){const u=((b=o.getNode(M))==null?void 0:b.memberships.some(O=>O.team===S.name))??!1;C.appendChild(e.menuItem(u?`${S.name}(已加入)`:S.name,!u,()=>{f(),e.emit({type:"add-member",team:S.name,ids:[M]})}))}C.appendChild(e.menuItem("新团队…",!0,()=>{f(),e.openNameDialog([M])})),c=C,t.appendChild(C);const Q=x.getBoundingClientRect();C.style.left=`${String(Math.min(Q.right+4,window.innerWidth-180))}px`,C.style.top=`${String(Math.max(8,Q.top-60))}px`,C.addEventListener("keydown",S=>{S.key==="Escape"&&(S.stopPropagation(),d(),x.focus())}),(h=C.querySelector("button"))==null||h.focus()}function se(x){var h,S;const M=new Set(e.facts().canvasMemberIds);for(const u of e.facts().sessions)u.teams!==void 0&&u.teams.length>0&&M.add(u.id);const C=e.facts().sessions.filter(u=>u.joined===!0&&!M.has(u.id)),Q=e.facts().sessions.filter(u=>u.joined!==!0),b=e.facts().sessions.filter(u=>u.joined===!0&&M.has(u.id));x.appendChild(G(`未组队 (${String(C.length)})`,"无网络能力"));for(const u of C){const O=document.createElement("div");O.className="p-noderow";const B=document.createElement("span");B.className="p-nodename",B.textContent=u.name!==void 0&&u.name!==""?u.name:u.label,B.title=u.team;const X=document.createElement("span");X.className="p-nonet",X.textContent="无网络能力";const ge=E("入队▸",()=>fe(ge,u.id));O.append(k(u.live,!0),B,X,ge,E("退网",()=>{f(),e.emit({type:"leave-network",id:u.id})})),x.appendChild(O)}x.appendChild(G(`未入网 (${String(Q.length)})`));for(const u of Q){const O=document.createElement("div");O.className="p-noderow";const B=document.createElement("span");B.className="p-nodename",B.textContent=u.name!==void 0&&u.name!==""?u.name:u.label,B.title=u.id,O.append(k(u.live,!1),B,E("入网",()=>{f(),e.emit({type:"join-network",id:u.id})})),x.appendChild(O)}x.appendChild(G(`已组队 (${String(b.length)})`,"画布展示"));for(const u of b){const O=document.createElement("div");O.className="p-noderow";const B=document.createElement("span");B.className="p-nodename",B.textContent=u.name!==void 0&&u.name!==""?u.name:u.label,B.title=u.team;const X=((h=o.getNode(u.id))==null?void 0:h.memberships.length)??0,ge=((S=u.teams)==null?void 0:S.length)??0,Me=document.createElement("span");Me.className="p-teamcount",Me.textContent=`队×${String(Math.max(X,0)+ge)}`,O.append(k(u.live,!0),B,Me,E("定位",()=>{e.locate(u.id)})),x.appendChild(O)}if(e.facts().sessions.length===0){const u=document.createElement("div");u.className="p-nodelist-empty",u.textContent="无会话节点",x.appendChild(u)}}function N(x,M){var b;const C=M.filter(h=>h.teams===void 0||h.teams.length===0),Q=M.filter(h=>h.teams!==void 0&&h.teams.length>0);x.appendChild(G(`未组队 (${String(C.length)})`,"无网络能力 · 只读"));for(const h of C){const S=document.createElement("div");S.className="p-noderow";const u=document.createElement("span");u.className="p-nodename",u.textContent=h.name!==void 0&&h.name!==""?h.name:h.team,u.title=h.team;const O=document.createElement("span");O.className="p-nonet",O.textContent="无网络能力",S.append(k(!0,!0),u,O),x.appendChild(S)}x.appendChild(G(`已组队 (${String(Q.length)})`,"只读"));for(const h of Q){const S=document.createElement("div");S.className="p-noderow";const u=document.createElement("span");u.className="p-nodename",u.textContent=h.name!==void 0&&h.name!==""?h.name:h.team,u.title=h.team;const O=document.createElement("span");O.className="p-teamcount",O.textContent=`队×${String(((b=h.teams)==null?void 0:b.length)??0)}`,S.append(k(!0,!0),u,O),x.appendChild(S)}if(M.length===0){const h=document.createElement("div");h.className="p-nodelist-empty",h.textContent="该节点未发布会话",x.appendChild(h)}}return document.addEventListener("pointerdown",x=>{if(i===null)return;const M=x.target;if(M===null){f();return}M.closest(".p-nodelist")!==null||M.closest(".p-menu")!==null||M===n||n.contains(M)||f()},s),{toggle:y,close:f,refresh:()=>{i!==null&&m()}}}function Zs(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 ei(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 ti(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),f=t.length===1&&t[0].name!==void 0&&t[0].name!==""?t[0].name:void 0,y=ei(t,n);return f!==void 0?{title:f,sub:`${d} · ${y}`,tip:`${f}
|
|
6
|
+
${d}
|
|
7
|
+
${y}`}:{title:d,sub:y,tip:`${d}
|
|
8
|
+
${y}`}}const s=st(e),o=e.team+(e.name!==void 0&&e.name!==""?" · "+e.name:""),i=Zs(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}}const Vn="dsh-a2a.board.legend";function ni(){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(Vn)==="open"}catch{}return e.addEventListener("toggle",()=>{try{window.localStorage.setItem(Vn,e.open?"open":"closed")}catch{}}),e}const qt="对端未应答(显示的是最后已知状态)";function Gn(e){const t=new Set;for(const s of e.remoteTeams??[])s.unreachable===!0&&s.via&&t.add(it(s.via));for(const s of e.peerOrg??[])s.unreachable===!0&&t.add(it(s.url));const n=new Set;for(const s of e.remoteTeams??[])s.via&&t.has(it(s.via))&&n.add(`member-${s.team.replace(/[^a-z0-9-]/gi,"-")}`);return{hosts:t,members:n}}function oi(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=qt,e.appendChild(s)}else t||n==null||n.remove()}function si(e){return e<680?"narrow":e<1024?"medium":"wide"}function ii(e){const t=new Cn;let n,s={...t.viewport},o={kind:"none"},i=!1,r=-1,c=!0,d=!1;const f=Gs(t);let y,m=!1;const k=()=>si(globalThis.innerWidth||Ge),E=()=>{var a;(a=e.viewportStore)==null||a.set(k(),s),e.onDirty()},G=e.now??Date.now,fe=new AbortController,se=[];let N=null,x=!1;const M={signal:fe.signal},C=document.createElement("section");C.id="dsh-plan",C.setAttribute("role","tabpanel"),C.setAttribute("aria-label","A2A 规划画布"),C.tabIndex=0,C.style.display="none";const Q=document.createElement("div");Q.className="p-grid";const b=document.createElement("div");b.className="p-world";const h=document.createElementNS("http://www.w3.org/2000/svg","svg");h.setAttribute("class","p-edges");const S=document.createElement("div");S.className="p-layer p-frames";let u;const O=a=>{var p,g;u!==void 0&&((p=Fe.get(u))==null||p.classList.remove("selected")),u=a,a!==void 0&&((g=Fe.get(a))==null||g.classList.add("selected"))},B=document.createElement("div");B.className="p-layer p-nodes",B.setAttribute("role","listbox"),B.setAttribute("aria-multiselectable","true"),B.setAttribute("aria-label","会话节点"),b.append(h,S,B);const X=document.createElement("div");X.className="p-marquee";const ge=document.createElement("div");ge.className="p-toolbar";const Me=document.createElement("span");Me.className="p-zoom mono",Me.textContent="100%";const P=(a,p,g)=>{const R=document.createElement("button");return R.type="button",R.textContent=a,R.title=p,R.addEventListener("click",g,M),R},z=()=>{const a=document.createElement("span");return a.className="p-sep",a.setAttribute("role","separator"),a.setAttribute("aria-orientation","vertical"),a};ge.append(P("适配","适配视图(快捷键 0)",()=>yt()),P("-","缩小",()=>xe(1/1.2)),Me,P("+","放大",()=>xe(1.2)),z(),P("建队","组成团队(G):先框选至少 2 个节点",()=>_.startCreateFromSelection()),P("整理成员","每队框内仅属一队的成员自动排齐(多队成员不动)",()=>gt()),P("一键重排","全板队框+成员重排:框尺寸随内容自适应、框位行流式平铺(远端队框与多归属成员不动)",()=>ft()),P("撤销","撤销上一次布局改动:拖动、缩放、整理、重排、载入时避让(Ctrl+Z;入队离队不撤销)",()=>ot()));const ae=P("未入网","未入网会话(点击选择入网)",()=>_.toggleNetMenu());ae.className="p-netbtn",ae.setAttribute("aria-haspopup","menu"),ge.append(z(),ae);const Re=Ts(ge,t,st,a=>pe(a)),Se=P("节点","节点清单:本机与对等节点(未组队/未入网在此管理)",()=>ee.toggle());Se.className="p-nodebtn",Se.setAttribute("aria-haspopup","dialog"),ge.appendChild(Se);const K=document.createElement("span");K.setAttribute("aria-live","polite"),K.className="p-lamp";const ie=document.createElement("i"),U=document.createElement("span");U.textContent="布局",K.append(ie,U),K.addEventListener("click",()=>{K.classList.contains("error")&&e.onLampClick()},M),K.addEventListener("keydown",a=>{const p=a;(p.key==="Enter"||p.key===" ")&&K.classList.contains("error")&&(p.preventDefault(),e.onLampClick())},M),ge.appendChild(K);const re=document.createElement("div");re.className="p-status";const be=document.createElement("span"),He=document.createElement("span"),je=document.createElement("span");je.className="mut";const Be=document.createElement("span");Be.className="mut",re.append(be,He,je,Be),re.tabIndex=0,re.setAttribute("role","button"),re.setAttribute("aria-label","定位在途路由与联邦对端"),re.title="定位在途与联邦(回车)",re.addEventListener("click",()=>he(),M),re.addEventListener("keydown",a=>{const p=a;(p.key==="Enter"||p.key===" ")&&(p.preventDefault(),he())},M);const at=ni(),Xe=document.createElement("div");Xe.className="p-notice-stack",Xe.setAttribute("role","log"),Xe.setAttribute("aria-live","polite"),C.append(Q,b,X,ge,re,at,Xe);let Ge=0,ct=0;const bt=()=>e.viewSize?e.viewSize():{w:C.clientWidth,h:C.clientHeight},Ke=()=>{const a=bt();Ge=a.w,ct=a.h};function Ue(){b.style.transform=Cs(s);const a=24*s.scale;Q.style.backgroundSize=`${a}px ${a}px`,Q.style.backgroundPosition=`${-s.x*s.scale}px ${-s.y*s.scale}px`,Me.textContent=`${Math.round(s.scale*100)}%`}function gt(){const a=f.capture();Js(t),Xt(t,new Set(Ne.keys())),f.commit(a),E(),ke()}function ft(){const a=f.capture();js(t,new Set(Ne.keys()))&&(Xt(t,new Set(Ne.keys())),f.commit(a),E(),ke())}function ke(){Ue(),t.revision!==r&&(r=t.revision,vt(),lt(),ss(h,t)),W()}const Fe=new Map,tt=new Map;function vt(){var p;const a=new Set;for(const[g,R]of t.allFrames()){a.add(g);let F=Fe.get(g);if(F===void 0){F=document.createElement("div"),F.className="p-frame",F.dataset.name=g;const Ce=document.createElement("div");Ce.className="p-frame-head",Ce.dataset.frame=g,Ce.tabIndex=0,Ce.setAttribute("role","button"),Ce.setAttribute("aria-haspopup","menu"),Ce.setAttribute("aria-label",`团队框 ${g}(拖动整组,回车菜单)`);const qe=document.createElement("span");qe.className="ttl";const Qe=document.createElement("span");Qe.className="cnt mono";const wt=document.createElement("span");wt.className="route mono",Ce.append(qe,Qe,wt),F.appendChild(Ce);for(const At of["n","s","e","w","ne","nw","se","sw"]){const xt=document.createElement("div");xt.className=`p-frame-handle p-h-${At}`,xt.dataset.frame=g,xt.dataset.dir=At,F.appendChild(xt)}S.appendChild(F),Fe.set(g,F)}const ce=$s(g);F.style.setProperty("--frame-line",ce.line),F.style.setProperty("--frame-bg",ce.bg),F.style.left=`${R.x}px`,F.style.top=`${R.y}px`,F.style.width=`${R.w}px`,F.style.height=`${R.h}px`;const H=F.querySelector(".ttl"),Y=F.querySelector(".cnt"),J=F.querySelector(".route"),le=$.has(g),Le=le?Qt(g):g;H.textContent!==Le&&(H.textContent=Le),F.classList.toggle("is-roster",le);let Ee=0,me=0;for(const Ce of t.allNodes())Ce.memberships.find(Qe=>Qe.team===g)!==void 0&&(Ee+=1,Ce.memberships.length>1&&(me+=1));const v=`${Ee} 成员`+(me>0?` +${me} 跨队`:"");Y.textContent!==v&&(Y.textContent=v);const Z=Bs(Ne.get(g),q.has(g)),oe=Z!==void 0&&w.hosts.has(it(Ne.get(g))),Ie=(Z==null?void 0:Z.text)??((p=Rt.find(Ce=>Ce.name===g))==null?void 0:p.team)??g;J.textContent!==Ie&&(J.textContent=Ie),J.title=`${(Z==null?void 0:Z.title)??""}${oe?` · ${qt}`:""}`,oi(F,oe),F.classList.toggle("is-mirror",Z!==void 0),F.classList.toggle("is-syncing",(Z==null?void 0:Z.syncing)===!0);const Ae=`团队框 ${g}${Z!==void 0?`(${Z.text})`:""}${oe?`(${qt})`:""}(拖动整组,回车菜单)`,ue=F.querySelector(".p-frame-head");ue.getAttribute("aria-label")!==Ae&&ue.setAttribute("aria-label",Ae)}for(const[g,R]of[...Fe])a.has(g)||(R.remove(),Fe.delete(g))}function lt(){const a=new Set;for(const p of t.allNodes()){a.add(p.id);let g=tt.get(p.id);if(g===void 0){g=document.createElement("div"),g.className="p-node",g.dataset.id=p.id,g.tabIndex=0;const me=document.createElement("div");me.className="nm";const v=document.createElement("span");v.className="dot";const Z=document.createElement("span");Z.className="nm-text",me.append(v,Z);const oe=document.createElement("div");oe.className="sub mono";const Ie=document.createElement("span");Ie.className="prio mono",g.append(me,oe,Ie),B.appendChild(g),tt.set(p.id,g)}const R=rt(p);g.style.left=`${R.x}px`,g.style.top=`${R.y}px`,g.classList.toggle("cold",!p.live),g.classList.toggle("remote",p.remote===!0),g.classList.toggle("selected",t.isSelected(p.id)),g.setAttribute("aria-selected",String(t.isSelected(p.id)));const F=p.id.slice(5),ce=ti(p,p.remote===!0?A.get(F)??[]:[],T.get(F)),H=p.remote===!0&&(p.id.startsWith("member-")?w.members.has(p.id):w.hosts.has(F));g.classList.toggle("is-unreachable",H);const Y=g.querySelector(".nm-text");Y.textContent!==ce.title&&(Y.textContent=ce.title);const J=g.querySelector(".sub"),le=H?`未应答 · ${ce.sub}`:ce.sub;J.textContent!==le&&(J.textContent=le);const Le=H?`${ce.tip} · ${qt}`:ce.tip;g.title!==Le&&(g.title=Le);const Ee=g.querySelector(".prio");if(p.remote===!0){const me=V.get(F),v=(me==null?void 0:me.link)==="linked"?"lnk-linked":(me==null?void 0:me.link)==="stranger"?"lnk-stranger":"";Ee.className!==`prio mono ${v}`.trim()&&(Ee.className=`prio mono ${v}`.trim());const Z=me===void 0?"":me.verified===!0?"✓":"✗",oe=((me==null?void 0:me.link)??"peer")+Z;Ee.textContent!==oe&&(Ee.textContent=oe)}else{Ee.className!=="prio mono"&&(Ee.className="prio mono");const me=p.memberships[0]!==void 0?`P${p.memberships[0].index}`:"";Ee.textContent!==me&&(Ee.textContent=me)}}for(const[p,g]of[...tt])a.has(p)||(g.remove(),tt.delete(p));Re.refresh()}const l=bs(h,t);let A=new Map;const T=new Map,V=new Map;function W(){l.render(G())}function he(){s=kn(ps(t.contentBounds(),l.placements()),C.clientWidth||Ge,C.clientHeight||ct),Ue(),E()}const pe=Is({model:t,viewSize:bt,setVp:a=>{s=a},applyViewport:Ue,markDirty:E,cardEl:a=>tt.get(a)});function ye(a){var R;const p=a.sessions.filter(F=>F.live!==!1).length,g=(F,ce,H)=>{const Y=document.createElement("b");Y.className=ce,Y.textContent=H,F.replaceChildren(Y)};g(be,"ok",`● ${p} live`),g(He,"warn",`● ${a.sessions.length-p} cold`),je.textContent=`${((R=a.inFlight)==null?void 0:R.length)??0} inFlight`,Be.className="mut",Be.textContent=`${a.teams.length} 队 · ${a.peerCount} peer`}const q=new Map,Pe=a=>{q.set(a,(q.get(a)??0)+1),r=-1},Je=a=>{r=-1;const p=(q.get(a)??0)-1;p<=0?q.delete(a):q.set(a,p)};let Ne=new Map,$=new Set,w=Gn({});const j=Ys(e.now);function L(a){const p=a.type==="create-team"&&a.roster===!0||$.has(Pt(a));if(p&&a.type==="remove-team"&&!window.confirm(`解散网络队「${Qt(a.name)}」并撤回成员与白名单?`))return;if(p&&a.type==="reorder"){D("error","roster 队不支持置顶路由");return}if(p&&(a.type==="create-team"||a.type==="add-member")&&a.ids.some(H=>{var Y;return((Y=t.getNode(H))==null?void 0:Y.remote)===!0||!te.some(J=>J.id===H&&J.joined===!0)})){D("error","roster 只接受本机已入网会话,远端或未入网成员未写入");return}function g(H){const Y=J=>{var Le;const le=[];for(const Ee of J){if(!Ee.startsWith("peer-")&&!Ee.startsWith("member-")){le.push(Ee);continue}const me=(Le=t.getNode(Ee))==null?void 0:Le.remoteHandle;me!==void 0&&me!==""&&le.push(me)}return le};if(H.type==="add-member"||H.type==="remove-member"||H.type==="create-team"){const J=Y(H.ids),le=H.type!=="create-team"?Ne.get(H.team):void 0;return J.length>0||le!==void 0?{...H,ids:J,...le!==void 0?{fleetPeer:le}:{}}:H}return H.type==="remove-team"&&Ne.has(H.name)?j.fork(H,Ne.get(H.name)):H}if(a.type==="add-member"||a.type==="remove-member"||a.type==="reorder"||a.type==="create-team"){const H=a.type==="reorder"?a.ops.map(Y=>Y.id):[...a.ids];for(const Y of H){if(Y===""||Y.startsWith("peer-")||Y.startsWith("member-")||t.getNode(Y)!==void 0)continue;const J=te.find(Ee=>Ee.id===Y);if(J===void 0)continue;const le=n==null?void 0:n.nodes[Y],Le=le!==void 0?{x:le.x,y:le.y}:$n(Y);t.upsertNode({id:Y,x:Le.x,y:Le.y,label:J.label,team:J.team,name:J.name,description:J.description,live:J.live!==!1,memberships:[],...J.teams!==void 0&&J.teams.length>0?{teams:J.teams}:{}})}}p&&a.type==="create-team"&&$.add(a.name);const R=ks(t,a),F=Pt(a);Pe(F),ke();const ce=g(p?{...a,roster:!0}:a);e.onCanvasAction(ce).then(H=>{Je(F),!H&&a.type==="create-team"&&p&&$.delete(F),n=Kn(t,a,H,R,n),E(),j.settled(ce,H),ke()},()=>{Je(F),a.type==="create-team"&&p&&$.delete(F),n=Kn(t,a,!1,R,n),E(),j.settled(ce,!1),D("error","操作通道异常,已回滚"),ke()})}function D(a,p){var R;for(;Xe.childElementCount>=3;)(R=Xe.firstElementChild)==null||R.remove();const g=document.createElement("div");g.className="p-notice"+(a==="error"?" error":""),g.setAttribute("role",a==="error"?"alert":"status"),g.textContent=p,Xe.appendChild(g),se.push(setTimeout(()=>g.remove(),4e3))}const _=Ms({root:C,netBtn:ae,signal:M,model:t,teams:()=>Rt,joined:a=>te.some(p=>p.id===a&&p.joined===!0),isRoster:a=>$.has(a),anchorFor:a=>(a.kind==="node"?tt.get(a.id):Fe.get(a.name))??null,emit:L,notice:D});let te=[],de=new Set;const ee=Qs({root:C,trigger:Se,signal:M,model:t,facts:()=>({sessions:te,canvasMemberIds:de,remoteTeams:A,teams:Rt}),menuItem:_.menuItem,emit:L,openNameDialog:_.openNameDialog,locate:we});function we(a){var R;const p=t.getNode(a);if(p===void 0)return;ee.close();const g=((R=e.viewSize)==null?void 0:R.call(e))??{w:C.clientWidth>0?C.clientWidth:800,h:C.clientHeight>0?C.clientHeight:600};s=$t({scale:s.scale,x:p.x-g.w/(2*s.scale),y:p.y-g.h/(2*s.scale)}),Ue(),r=-1,ke()}function Te(a){const p=C.getBoundingClientRect();return{x:a.clientX-p.left,y:a.clientY-p.top}}function ne(a,p){var H;const g=Te(p),R=ut(s,g.x,g.y),F=dn(new Map(t.allFrames()),R),ce=a.ids.filter(Y=>{const J=t.getNode(Y);return J===void 0?!1:J.remote!==!0?!0:J.remoteHandle!==void 0&&J.remoteHandle!==""});if(F!==void 0){const Y=ce.filter(J=>{var le;return!((le=t.getNode(J))!=null&&le.memberships.some(Le=>Le.team===F))});if(Y.length>0){L({type:"add-member",team:F,ids:Y});return}if(a.ids.length===1&&((H=t.getNode(a.clicked))==null?void 0:H.remote)!==!0){const J=t.teamMemberIds(F),le=Es(t,F);le.join("\0")!==J.join("\0")&&L({type:"reorder",team:F,ops:hn(J,le)})}}if(a.rosterOrigin!==void 0&&F!==a.rosterOrigin){const Y=a.ids.filter(J=>t.teamMemberIds(a.rosterOrigin).includes(J));Y.length>0&&L({type:"remove-member",team:a.rosterOrigin,ids:Y})}}function _e(a){if(Ge===0&&Ke(),_.isDialogOpen()){a.preventDefault();return}const p=a.target;if(_.isMenuOpen()){if(p!==null&&p.closest(".p-menu")!==null)return;_.closeMenu(),a.preventDefault();return}if(p!==null&&p.closest("button, input, textarea, select, .p-toolbar, .p-search, .p-lamp, .p-status, .p-legend")!==null)return;y=f.capture();const g=Te(a);if(a.button===2){N={x:g.x,y:g.y,target:a.target,moved:!1},a.preventDefault();try{C.setPointerCapture(a.pointerId??0)}catch{}return}const R=p!==null?p.closest(".p-node"):null,F=p!==null?p.closest(".p-frame-head"):null;if((R!==null||F!==null)&&a.button===1){o={kind:"pan",last:g,moved:!1},a.preventDefault();try{C.setPointerCapture(a.pointerId??0)}catch{}return}const ce=p!==null?p.closest(".p-frame-handle"):null;if(u!==void 0){const H=Fe.get(u),Y=p!==null&&H!==void 0&&(H.contains(p)||H===p),J=F!==null&&F.dataset.frame===u;!Y&&!J&&O(void 0)}if(ce!==null&&a.button===0){const H=ce.dataset.frame??"";O(H);const Y=t.getFrame(H);if(Y===void 0)return;o={kind:"frame-resize",name:H,dir:ce.dataset.dir??"se",startRect:{...Y},origin:ut(s,g.x,g.y),moved:!1},a.preventDefault();try{C.setPointerCapture(a.pointerId??0)}catch{}return}if(R!==null){if(a.button!==0)return;const H=R.dataset.id??"",Y=t.isSelected(H);!Y&&!a.shiftKey&&t.setSelection([H]);const J=a.shiftKey||Y?t.isSelected(H)?t.selectedIds():[...t.selectedIds(),H]:[H],le=dn(new Map(t.allFrames()),ut(s,g.x,g.y));o={kind:"node",clicked:H,ids:J,...le&&$.has(le)&&t.teamMemberIds(le).includes(H)?{rosterOrigin:le}:{},last:ut(s,g.x,g.y),moved:!1,el:R},R.classList.add("dragging")}else if(F!==null){if(a.button!==0)return;const H=F.dataset.frame??"";O(H);const Y=t.beginFrameDrag(H);if(Y===void 0)return;o={kind:"frame",name:H,snap:Y,origin:ut(s,g.x,g.y),moved:!1}}else if(a.button===1||a.button===0&&i)o={kind:"pan",last:g,moved:!1};else if(a.button===0)o={kind:"marquee",origin:g,last:g,additive:a.shiftKey},X.style.display="block",X.style.left=`${g.x}px`,X.style.top=`${g.y}px`,X.style.width="0px",X.style.height="0px";else return;a.preventDefault();try{C.setPointerCapture(a.pointerId??0)}catch{}}function ze(a){const p=Te(a);if(N!==null){const g=p.x-N.x,R=p.y-N.y;Math.hypot(g,R)>4&&(N.moved=!0,s=$t(ln(s,-g,-R)),N.x=p.x,N.y=p.y,Ue());return}if(o.kind==="node"){const g=ut(s,p.x,p.y),R=g.x-o.last.x,F=g.y-o.last.y;if(R===0&&F===0)return;o.moved=!0,o.last=g,t.dragNodes(o.ids,R,F);const ce=dn(new Map(t.allFrames()),g),H=o.ids.filter(J=>{const le=t.getNode(J);return le===void 0?!1:le.remote!==!0||le.remoteHandle!==void 0&&le.remoteHandle!==""}),Y=ce!==void 0&&H.length>0;for(const[J,le]of Fe)le.classList.toggle("drop-target",Y&&J===ce);ke()}else if(o.kind==="frame"){const g=ut(s,p.x,p.y),R=g.x-o.origin.x,F=g.y-o.origin.y;if(!o.moved&&R===0&&F===0)return;o.moved=!0,t.applyFrameDrag(o.snap,R,F),ke()}else if(o.kind==="frame-resize"){const g=ut(s,p.x,p.y),R=g.x-o.origin.x,F=g.y-o.origin.y;if(!o.moved&&R===0&&F===0)return;o.moved=!0;const ce=220,H=120,Y={...o.startRect};let{x:J,y:le,w:Le,h:Ee}=Y;o.dir.includes("e")&&(Le=Math.max(ce,Y.w+R)),o.dir.includes("s")&&(Ee=Math.max(H,Y.h+F)),o.dir.includes("w")&&(Le=Math.max(ce,Y.w-R),J=Y.x+(Y.w-Le)),o.dir.includes("n")&&(Ee=Math.max(H,Y.h-F),le=Y.y+(Y.h-Ee)),t.setFrame(o.name,{x:Math.round(J),y:Math.round(le),w:Math.round(Le),h:Math.round(Ee)}),ke()}else if(o.kind==="pan")s=ln(s,p.x-o.last.x,p.y-o.last.y),o.last=p,o.moved=!0,Ue();else if(o.kind==="marquee"){const g=Math.min(o.origin.x,p.x),R=Math.min(o.origin.y,p.y);X.style.left=`${g}px`,X.style.top=`${R}px`,X.style.width=`${Math.abs(p.x-o.origin.x)}px`,X.style.height=`${Math.abs(p.y-o.origin.y)}px`,o.last=p}}function Ve(a){var p,g;if(N!==null){const R=N.moved,F=N.target,ce=N.x,H=N.y;N=null,R?(x=!0,E()):F!==null&&_.contextMenuAt(ce,H,F);return}if(o.kind==="node"){const R=o.clicked;if(o.moved)ne(o,a),E();else if(a.shiftKey){const F=t.selectedIds();t.setSelection(F.includes(R)?F.filter(ce=>ce!==R):[...F,R])}else t.setSelection([R]),(p=e.onNodePick)==null||p.call(e,R);for(const F of Fe.values())F.classList.remove("drop-target");(g=o.el)==null||g.classList.remove("dragging"),ke()}else if(o.kind==="frame"||o.kind==="frame-resize")o.moved&&(Xt(t,new Set(Ne.keys()),o.name),E(),ke());else if(o.kind==="pan")o.moved&&E();else if(o.kind==="marquee"){const R=o.last,F=ut(s,Math.min(o.origin.x,R.x),Math.min(o.origin.y,R.y)),ce=ut(s,Math.max(o.origin.x,R.x),Math.max(o.origin.y,R.y));t.marqueeSelect({x:F.x,y:F.y,w:ce.x-F.x,h:ce.y-F.y},o.additive),X.style.display="none",ke()}o={kind:"none"},y!==void 0&&(f.commit(y),y=void 0);try{C.releasePointerCapture(a.pointerId??0)}catch{}}function dt(a){var g;for(const R of Fe.values())R.classList.remove("drop-target");o.kind==="node"&&((g=o.el)==null||g.classList.remove("dragging"));const p=o.kind==="pan"&&o.moved||(N==null?void 0:N.moved)===!0;X.style.display="none",N=null,o={kind:"none"},y!==void 0&&f.revert(y)&&ke(),p&&E(),y=void 0;try{C.releasePointerCapture(a.pointerId??0)}catch{}}function Ye(a){_.isMenuOpen()&&_.closeMenu();const p=Te(a);if(a.shiftKey&&!a.ctrlKey){const g=a.deltaMode===1?16:1;s=$t(ln(s,(a.deltaX??0)*g,(a.deltaY??0)*g))}else{const g=a.deltaMode===1?16:1,R=Math.exp(-((a.deltaY??0)*g)*.0015);s=Bn(s,R,p.x,p.y)}a.preventDefault(),Ue(),E()}function xe(a){Ke(),s=Bn(s,a,Ge/2,ct/2),Ue(),E()}function ot(){f.undo()?(E(),ke()):D("info","没有可撤销的布局改动")}function yt(){Ke(),s=Wn(Yn(t.contentBounds(),t.allNodes()),Ge,ct,Xn(ge,re)),Ue(),E()}function St(a){var ce,H,Y,J,le,Le,Ee;if(_.isDialogOpen()||((H=(ce=a.target)==null?void 0:ce.closest)==null?void 0:H.call(ce,".p-search"))!==null)return;if((a.ctrlKey||a.metaKey)&&a.key.toLowerCase()==="k"){a.preventDefault(),Re.focus();return}if((a.ctrlKey||a.metaKey)&&!a.shiftKey&&a.key.toLowerCase()==="z"){a.preventDefault(),ot();return}if(a.ctrlKey||a.metaKey)return;if(_.isMenuOpen()){a.key==="Escape"&&(_.closeMenu(),a.preventDefault());return}if(a.key===" "&&a.target===C){i=!0,a.preventDefault();return}const p=((J=(Y=a.target)==null?void 0:Y.closest)==null?void 0:J.call(Y,".p-frame-head"))??null;if((a.key==="Enter"||a.key===" ")&&p!==null){a.preventDefault();const me=p.getBoundingClientRect();_.contextMenuAt(me.left+me.width/2,me.top+me.height/2,p);return}if(a.key===" "&&((Le=(le=a.target)==null?void 0:le.classList)!=null&&Le.contains("p-node"))){const v=a.target.dataset.id??"",Z=t.selectedIds();t.setSelection(Z.includes(v)?Z.filter(oe=>oe!==v):[...Z,v]),ke(),a.preventDefault();return}if(a.key==="F10"&&a.shiftKey||a.key==="ContextMenu"){a.preventDefault();const me=document.activeElement??null,v=((Ee=me==null?void 0:me.getBoundingClientRect)==null?void 0:Ee.call(me))??{left:0,top:0,width:0,height:0};_.contextMenuAt(v.left+v.width/2,v.top+v.height/2,me);return}if(a.key==="Delete"||a.key==="Backspace"){a.preventDefault(),sn();return}if(a.altKey&&(a.key==="ArrowUp"||a.key==="ArrowDown")){a.preventDefault(),vo(a.key==="ArrowUp");return}if(a.key==="g"||a.key==="G"){_.startCreateFromSelection();return}if(a.key==="0"){yt();return}if(a.key==="="||a.key==="+"){xe(1.2);return}if(a.key==="-"){xe(1/1.2);return}if(a.key==="Escape"){if(_.isMenuOpen()){_.closeMenu(),ke();return}t.setSelection([]),ke();return}const g=a.shiftKey?40:8,F={ArrowLeft:[-g,0],ArrowRight:[g,0],ArrowUp:[0,-g],ArrowDown:[0,g]}[a.key];if(F!==void 0){a.preventDefault();const me=t.selectedIds();if(me.length>0){const v=f.capture();t.nudge(me,F[0],F[1]),f.commit(v),ke(),E()}}}function sn(){var R,F,ce;const a=document.activeElement,p=((R=a==null?void 0:a.closest)==null?void 0:R.call(a,".p-frame-head"))??null,g=((F=a==null?void 0:a.closest)==null?void 0:F.call(a,".p-node"))??null;if(p!==null){L({type:"remove-team",name:p.dataset.frame??""});return}if(g!==null){const H=g.dataset.id??"",Y=((ce=t.getNode(H))==null?void 0:ce.memberships.map(J=>J.team))??[];if(Y.length===0){D("info","该节点未加入任何团队");return}if(Y.length===1){L({type:"remove-member",team:Y[0],ids:[H]});return}_.openMenu(window.innerWidth/2,window.innerHeight/2,{kind:"node",id:H},"leave",g);return}D("info","焦点不在节点或团队框上")}function vo(a){var Le,Ee;const p=document.activeElement,g=((Le=p==null?void 0:p.closest)==null?void 0:Le.call(p,".p-node"))??null;if(g===null)return;const R=g.dataset.id??"",F=((Ee=t.getNode(R))==null?void 0:Ee.memberships)??[];if(F.length!==1)return;const ce=F[0].team,H=t.teamMemberIds(ce),Y=H.indexOf(R),J=a?Math.max(0,Y-1):Math.min(H.length-1,Y+1);if(J===Y)return;const le=[...H];le.splice(Y,1),le.splice(J,0,R),L({type:"reorder",team:ce,ops:hn(H,le)})}function En(a){a.key===" "&&(i=!1)}C.addEventListener("pointerdown",a=>_e(a),M),C.addEventListener("pointermove",a=>ze(a),M),C.addEventListener("pointerup",a=>Ve(a),M),C.addEventListener("pointercancel",a=>dt(a),M),C.addEventListener("wheel",a=>Ye(a),{...M,passive:!1}),C.addEventListener("keydown",a=>St(a),M),C.addEventListener("keyup",a=>En(a),M),C.addEventListener("contextmenu",a=>{var g,R;const p=a;if(((R=(g=p.target)==null?void 0:g.closest)==null?void 0:R.call(g,"input, textarea, .p-search"))==null){if(p.preventDefault(),x){x=!1;return}_.contextMenuAt(p.clientX,p.clientY,p.target)}},M);let Rt=[];function yo(a){var me;Rt=a.teams,$=new Set([...a.teams.filter(v=>v.kind==="roster").map(v=>v.name),...[...$].filter(v=>q.has(v))]),a.peers,l.setInFlight(a.inFlight??[]),te=a.sessions,_.setUnjoined(a.sessions.filter(v=>v.joined!==!0&&!v.id.startsWith("peer-")));const p=new Map;for(const v of a.teams)for(let Z=0;Z<v.members.length;Z++){const oe=v.members[Z].id,Ie=p.get(oe)??[];Ie.push({team:v.name,index:Z}),p.set(oe,Ie)}de=new Set(p.keys());const g=new Set,R=v=>{const Z=p.get(v)??[];if(q.size===0)return Z;const oe=Z.filter(Ae=>!q.has(Ae.team)),Ie=[];for(const[Ae]of q){const Ce=t.teamMemberIds(Ae).indexOf(v);Ce>=0&&Ie.push({team:Ae,index:Ce})}return[...oe,...Ie]};let F;if(n===void 0&&!t.allNodes().some(v=>v.remote!==!0)){const v=a.sessions.filter(Z=>{var oe;return Z.joined===!0&&(R(Z.id).length>0||(((oe=Z.teams)==null?void 0:oe.length)??0)>0)}).map(Z=>Z.id);Ke(),F=es(a.teams,v,Ge>0?Ge:void 0)}for(const v of a.sessions){if(v.joined!==!0)continue;const Z=R(v.id);if(!(Z.length===0&&(v.teams===void 0||v.teams.length===0)))if(g.add(v.id),t.getNode(v.id)!==void 0)t.upsertNode({id:v.id,x:t.getNode(v.id).x,y:t.getNode(v.id).y,label:v.label,team:v.team,name:v.name,description:v.description,live:v.live!==!1,memberships:Z,...v.teams!==void 0&&v.teams.length>0?{teams:v.teams}:{}});else{const oe=n==null?void 0:n.nodes[v.id];let Ie,Ae;if(oe!==void 0)Ie=oe.x,Ae=oe.y;else{const ue=(F==null?void 0:F.get(v.id))??$n(v.id);Ie=ue.x,Ae=ue.y}t.upsertNode({id:v.id,x:Ie,y:Ae,label:v.label,team:v.team,name:v.name,description:v.description,live:v.live!==!1,memberships:Z,...v.teams!==void 0&&v.teams.length>0?{teams:v.teams}:{}})}}for(const v of t.nodeIds())!g.has(v)&&!v.startsWith("peer-")&&!v.startsWith("member-")&&t.removeNode(v);const ce=new Set;A=rs(a.remoteTeams??[]),w=Gn(a),T.clear();for(const v of a.peers??[])T.set(it(v.url),v.score),V.set(it(v.url),{link:v.link,verified:v.verified});if(a.peers!==void 0){const v=t.contentBounds(),Z=ms(a.peers,v);a.peers.forEach((oe,Ie)=>{var At,xt,Nn,Mn;const Ae=is(oe.url);ce.add(Ae);const ue=n==null?void 0:n.nodes[Ae],Ce=t.getNode(Ae),qe=Ce!==void 0?{x:Ce.x,y:Ce.y}:ue!==void 0?{x:ue.x,y:ue.y}:{x:((At=Z[Ie])==null?void 0:At.x)??200,y:((xt=Z[Ie])==null?void 0:xt.y)??0},Qe=it(oe.url),wt=(Mn=(Nn=A.get(Qe))==null?void 0:Nn[0])==null?void 0:Mn.team;t.upsertNode({id:Ae,x:qe.x,y:qe.y,label:oe.url,team:"",name:oe.url,peerUrl:oe.url,remoteHandle:wt,live:!0,remote:!0,memberships:[]}),t.upsertScore(Ae,oe.score)})}for(const v of t.nodeIds())v.startsWith("peer-")&&!ce.has(v)&&t.removeNode(v);const H=new Set;for(const[v,Z]of A){const oe=t.allNodes().find(ue=>ue.remote===!0&&it(ue.peerUrl??"")===v&&!ue.id.startsWith("member-")),Ie=((oe==null?void 0:oe.x)??400)+190;let Ae=(oe==null?void 0:oe.y)??0;for(const ue of Z){if(!ue.team.includes("/"))continue;const Ce=`member-${ue.team.replace(/[^a-z0-9-]/gi,"-")}`;if(H.has(Ce))continue;H.add(Ce);const qe=n==null?void 0:n.nodes[Ce],Qe=t.getNode(Ce),wt=Qe!==void 0?{x:Qe.x,y:Qe.y}:qe!==void 0?{x:qe.x,y:qe.y}:{x:Ie,y:Ae};Ae+=92,t.upsertNode({id:Ce,x:wt.x,y:wt.y,label:ue.team,team:ue.team,name:ue.name!==void 0&&ue.name!==""?ue.name:ue.team,remoteHandle:ue.team,live:!0,remote:!0,memberships:[]})}}for(const v of t.nodeIds())v.startsWith("member-")&&!H.has(v)&&t.removeNode(v);const Y=new Map;for(const v of t.allNodes())v.remote!==!0||v.remoteHandle===void 0||v.remoteHandle===""||(!Y.has(v.remoteHandle)||v.id.startsWith("member-"))&&Y.set(v.remoteHandle,v.id);for(const v of a.teams){if(q.has(v.name))continue;const Z=[];for(const Ae of v.members){const ue=Y.get(Ae.id)??Ae.id;t.getNode(ue)!==void 0&&Z.push(ue)}const oe=[...t.teamMemberIds(v.name)].sort().join("|"),Ie=[...Z].sort().join("|");oe!==Ie&&t.setTeamMembers(v.name,Z)}const J=new Map,le=Ne;if(Ne=J,a.peerOrg!==void 0){let v=0;const Z=new Set(a.teams.map(oe=>oe.name));j.sweep(a.peerOrg);for(const oe of a.peerOrg){const Ie=new Set((a.remoteTeams??[]).map(ue=>ue.team)),Ae=gs(a.sessions,Ie);for(const ue of oe.org){if(ue.name===""||Z.has(ue.name)||j.hides(ue.name,oe.url))continue;const Ce=ue.members.map(Qe=>vs(Qe,Ae,a.remoteTeams,oe.url)).filter(Qe=>t.getNode(Qe)!==void 0),qe=(me=n==null?void 0:n.frames)==null?void 0:me[ue.name];t.getFrame(ue.name)===void 0&&t.setFrame(ue.name,qe!==void 0?{x:qe.x,y:qe.y,w:qe.w,h:qe.h}:{x:200+v%4*280,y:940+Math.floor(v/4)*160,w:250,h:130}),t.setTeamMembers(ue.name,Ce),J.set(ue.name,oe.url),v+=1}}}for(const[v,Z]of le)J.has(v)||t.removeFrame(v);const Le=new Map;for(const v of t.allNodes())v.remote===!0&&v.remoteHandle!==void 0&&v.remoteHandle!==""&&Le.set(v.remoteHandle,v.id);const Ee=fo(a.teams);for(const v of a.teams){if(t.getFrame(v.name)!==void 0||q.has(v.name))continue;const Z=n==null?void 0:n.frames[v.name];if(Z!==void 0){t.setFrame(v.name,{...Z});continue}const oe=[],Ie=[];for(const ue of v.members){const Ce=t.getNode(Le.get(ue.id)??ue.id);Ce!==void 0&&(Ie.push(rt(Ce)),Ee.get(Ce.id)===v.name&&oe.push(rt(Ce)))}const Ae=oe.length>0?oe:Ie;Ae.length>0&&t.setFrame(v.name,xn(Ae))}for(const[v]of t.allFrames())q.has(v)||!a.teams.some(Z=>Z.name===v)&&!J.has(v)&&t.removeFrame(v);if(ee.refresh(),ye(a),!d&&o.kind==="none"&&t.nodeIds().length>0){d=!0;const v=f.capture();Xt(t,new Set(Ne.keys())),f.commit(v)}c&&o.kind==="none"&&t.nodeIds().length>0&&(Ke(),Ge>0&&ct>0&&(c=!1,s=Wn(Yn(t.contentBounds(),t.allNodes()),Ge,ct,Xn(ge,re)))),ke()}function $n(a){return po(a,t.allNodes().filter(p=>p.remote!==!0))}function wo(a){const p=mo(a);if(p===void 0)return;n=p;const g=e.viewportStore;if(g===void 0)c=!1,o.kind==="none"&&(s=$t({...p.viewport}));else if(!m&&o.kind==="none"){m=!0;const R=g.get(k());R!=null&&Number.isFinite(R.x)&&Number.isFinite(R.y)&&Number.isFinite(R.scale)?(s=$t({x:R.x,y:R.y,scale:R.scale}),c=!1):k()==="wide"&&(s=$t({...p.viewport}),c=!1)}r=-1,ke()}function xo(){return Vo(s,t.positions(),t.frameRects())}function Co(a,p){K.classList.remove("pending","saved","error"),a==="pending"&&K.classList.add("pending"),a==="saved"&&K.classList.add("saved"),a==="error"&&K.classList.add("error"),a==="error"?(K.tabIndex=0,K.setAttribute("role","button"),K.setAttribute("aria-label","布局保存失败,按回车重试")):(K.removeAttribute("tabindex"),K.removeAttribute("role"),K.removeAttribute("aria-label"));const g=a==="pending"?"布局待保存…":a==="saved"?`布局已保存 ${p??""}`.trimEnd():a==="error"?"保存失败 · 回车重试":"布局";U.textContent=g}function ko(){C.style.display="block",Ke(),Ue(),C.focus()}function Eo(){C.style.display="none"}function $o(){fe.abort();for(const a of se)clearTimeout(a)}return{root:C,reconcile:yo,activate:ko,deactivate:Eo,adoptExternalLayout:wo,snapshotDoc:xo,setLamp:Co,notice:D,destroy:$o,seam:{pointerDown:_e,pointerMove:ze,pointerUp:Ve,pointerCancel:dt,wheel:Ye,key:St,keyUp:En,contextMenu(a){a.preventDefault(),_.contextMenuAt(a.clientX,a.clientY,a.target)}}}}const ri=800;function ai(e){let t,n=!1,s=!1,o=!1,i="idle";function r(y){y!==i&&(i=y,e.onLamp(y))}function c(){t!==void 0&&(t(),t=void 0)}function d(){c(),t=e.schedule(()=>{t=void 0,f(!1)},ri)}async function f(y){if(n){s=!0;return}n=!0,c();const m=e.snapshot();let k;try{k=JSON.stringify(m)}catch{n=!1,r("error"),e.onHttpError("layout document is not JSON-serializable");return}try{const E=await e.send(m,{keepalive:y});if(E===null||typeof E!="object"||E.ok!==!0){r("error");const G=E!==null&&typeof E=="object"&&typeof E.error=="string"?E.error:"layout save refused";e.onHttpError(`layout save: ${G}`)}else JSON.stringify(e.snapshot())===k&&(e.onAdopt(E.layout),r("saved"))}catch(E){r("error"),e.onHttpError(`layout save unreachable: ${String((E==null?void 0:E.message)??E).slice(0,80)}`)}if(n=!1,i==="error"){o=!1;return}if(o){o=!1,f(!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"),f(!1))},flush(){if(n){o=!0,s=!0;return}c(),f(!0)},isBusy(){return n},dispose(){c()}}}function Qn(e){return e!=null&&typeof e.error=="string"?e.error:void 0}function ci(e){const t=new Map;let n=0;function s(r,c){n+=1;const d=t.get(r)??Promise.resolve(),f=async()=>{try{return await c()}finally{n-=1}},y=d.then(f,f);return t.set(r,y.then(()=>{},()=>{})),y}async function o(r){var fe,se,N,x;let c;try{c=await e.send(r)}catch(M){const C=String((M==null?void 0:M.message)??M).slice(0,80);return e.onNotice("error",`画布不可达:${C}`),!1}if(c.status>=400)return e.onNotice("error",Qn(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"?Qn(c.body):void 0;if(d!==void 0)return e.onNotice("error",d),!1;const f=String(r.name??""),y=String(r.id??""),m=(se=c.body)==null?void 0:se.members,k=(N=c.body)==null?void 0:N.teams,E=Array.isArray(m)&&m.every(M=>typeof M=="string"),G=Array.isArray(k)&&k.every(M=>typeof M=="string");return((x=c.body)==null?void 0:x.ok)===!1&&(r.action==="add-member"&&E&&m.includes(y)||r.action==="remove-member"&&E&&!m.includes(y)||r.action==="remove"&&G&&!k.includes(f))?!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 f=d.op==="remove"?{action:"remove-member",name:r,id:d.id}:{action:"add-member",name:r,id:d.id};if(!await o(f))return!1}return!0})},removeTeam(r){return s(r,()=>o({action:"remove",name:r}))},hasPending(){return n>0}}}const go=document.getElementById("app"),li=(()=>{try{return window.sessionStorage.getItem("dsh_a2a_key")??""}catch{return""}})(),bn=window.__DSH_A2A_KEY__??li,We=(e,t={})=>fetch(e,{...t,headers:{...t.headers??{},...bn!==""?{"X-API-Key":bn}:{}}});bn===""&&We("/__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 Ot=document.createElement("div");Ot.className="nexus-fault";go.appendChild(Ot);const{fault:gn,clear:di}=So({show(e){Ot.textContent=e,Ot.style.display="block"},hide(){Ot.style.display="none"}},e=>console.error(e));let Jt;const Zn="dsh-a2a.viewport.",mi={get(e){try{const t=window.localStorage.getItem(Zn+e);return t===null?void 0:JSON.parse(t)}catch{return}},set(e,t){try{window.localStorage.setItem(Zn+e,JSON.stringify({x:t.x,y:t.y,scale:t.scale}))}catch{}}},et=ii({viewportStore:mi,onDirty:()=>en.markDirty(),onLampClick:()=>en.retry(),onNodePick:e=>{Jt==null||Jt(e)},onCanvasAction:async e=>{const t=await fi(e);return on(),t}}),en=ai({snapshot:()=>et.snapshotDoc(),send:(e,t)=>We("/__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=>{vn=e;const t=new Date,n=String(t.getHours()).padStart(2,"0")+":"+String(t.getMinutes()).padStart(2,"0");et.setLamp(e,n)},onAdopt:e=>{et.adoptExternalLayout(e)},onHttpError:e=>gn(e)});window.addEventListener("pagehide",()=>en.flush());const Tt=ci({send:async e=>{const t=await We("/__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)=>et.notice(e,t)});async function eo(e,t,n,s){const o=await We("/__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&&et.notice("info",`属主那边已没有「${n}」,无需解散`),(i==null?void 0:i.ok)===!0?!0:(et.notice("error",`跨主机团队操作失败:${String((i==null?void 0:i.error)??"对端无响应")}`),!1)}async function ui(e,t){const n=async s=>{const o=await We("/__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:(et.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 et.notice("error","roster 不支持该操作"),!1}function fi(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 eo(t,e.type,e.team,n))return!1;return!0})()}if(e.type==="remove-team"&&e.fleetPeer!==void 0)return eo(e.fleetPeer,"remove",e.name);if(e.roster===!0){const t=bo(Pt(e));return t!==void 0?ui(e,t):(et.notice("error","无效的 roster 框名"),Promise.resolve(!1))}switch(e.type){case"create-team":return Tt.createTeam(e.name,e.ids,e.created);case"add-member":return Tt.addMembers(e.team,e.ids);case"remove-member":return Tt.removeMembers(e.team,e.ids);case"remove-team":return Tt.removeTeam(e.name);case"reorder":return Tt.runRosterOps(e.team,e.ops);case"join-network":case"leave-network":return pi(e.type==="join-network"?"join":"leave",e.id)}}async function pi(e,t){const n=await We(`/__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 vn="idle",mn=new Set,to=0,tn=!1,no,un=!1;async function hi(){const e=await We("/__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 nn=qo({now:()=>Date.now(),async ownerSettingsRead(){try{return await(await We("/__dsh_a2a/owner-settings")).json()}catch{return{ok:!1,error:"unreachable"}}},async ownerSettingsWrite(e){try{return await(await We("/__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 We("/__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 canvasOp(e,t,n){try{const s=await We("/__dsh_a2a/canvas",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({action:e,name:t,id:n})}),o=await s.json().catch(()=>({}));return s.ok&&o.ok!==!1?!0:(console.warn(`canvas ${e} ${t}: ${o.error??`HTTP ${s.status}`}`),!1)}catch{return!1}},async dispatchQuick(e,t){try{const n=await We("/__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 We(`/__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 We("/__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 We(`/__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:et.root,activate:()=>et.activate(),deactivate:()=>et.deactivate(),available:()=>tn}});go.appendChild(nn.root);Jt=e=>{nn.openNodeChat(e)};if(new URLSearchParams(window.location.search).get("mode")==="plan"){const e=window.setInterval(()=>{tn&&(nn.selectTab("board"),window.clearInterval(e))},300);window.setTimeout(()=>window.clearInterval(e),3e4)}async function on(){var e,t;try{const n=await We("/__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()-to>=15e3){to=Date.now();try{const m=await We("/__dsh_a2a/nodes",{cache:"no-store"});if(!m.ok)throw new Error(`nodes ${m.status}`);const k=await m.json();mn=new Set((k.bindings??[]).filter(E=>E.mounted!==null&&E.effective!==null&&(E.effective.core===!1||E.effective.mutable===!1)).map(E=>E.session))}catch{mn.clear()}}const o={...s,sessions:(s.sessions??[]).map(m=>({...m,...mn.has(m.id)?{nodePromptMissing:!0}:{}}))};if(di(),tn=s.canvas!==void 0,nn.update(o),tn)try{const m=await hi(),k=JSON.stringify(m??null);k!==no&&(no=k,(vn==="idle"||vn==="saved")&&!en.isBusy()&&et.adoptExternalLayout(m)),un=!0}catch(m){if(!un){gn(`canvas layout 获取失败:${String(m)}`);return}}else un=!0;const i=(s.sessions??[]).map(m=>({...m,joined:m.joined===!0})),r=[...((e=s.canvas)==null?void 0:e.teams)??[],...Ns(((t=s.registry)==null?void 0:t.teams)??[],s.zone??"")],c=(s.peers??[]).filter(m=>m!==null&&typeof m=="object"&&typeof m.url=="string"),d=(s.inFlight??[]).filter(m=>m!==null&&typeof m=="object"&&typeof m.team=="string"&&typeof m.peer=="string"&&Number.isFinite(m.startedAt)),f=(s.remote??[]).filter(m=>m!==null&&typeof m=="object"&&typeof m.team=="string"&&typeof m.via=="string").map(m=>({team:m.team,name:m.name,via:m.via,workspace:m.workspace,...m.unreachable===!0?{unreachable:!0}:{},...typeof m.origin=="string"&&m.origin!==""?{origin:m.origin}:{},...Array.isArray(m.teams)&&m.teams.length>0?{teams:m.teams.filter(k=>typeof k=="string"&&k!=="")}:{}})),y=(s.peerOrg??[]).filter(m=>m!==null&&typeof m=="object").filter(m=>typeof m.url=="string"&&Array.isArray(m.org)).map(m=>({url:m.url,...m.unreachable===!0?{unreachable:!0}:{},org:m.org.filter(k=>k!==null&&typeof k=="object").filter(k=>typeof k.team=="string"&&k.team!=="").map(k=>({name:typeof k.name=="string"?k.name:"",team:k.team,members:Array.isArray(k.members)?k.members.filter(E=>typeof E=="string"):[]}))}));et.reconcile({sessions:i,teams:r,peerCount:c.length,peers:c,inFlight:d,remoteTeams:f,peerOrg:y})}catch(n){gn(`state 轮询失败:${String(n)}`)}}on();window.setInterval(()=>{document.hidden||on()},3e3);document.addEventListener("visibilitychange",()=>{document.hidden||on()});
|
|
@@ -18,8 +18,8 @@ html,body{margin:0;height:100%;background:var(--n-bg);color:var(--n-ink);
|
|
|
18
18
|
font-family:"Segoe UI",system-ui,sans-serif;}
|
|
19
19
|
#app{width:100%;height:100%;position:relative}
|
|
20
20
|
</style>
|
|
21
|
-
<script type="module" crossorigin src="./assets/index-
|
|
22
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
21
|
+
<script type="module" crossorigin src="./assets/index-Bbxnpf2p.js"></script>
|
|
22
|
+
<link rel="stylesheet" crossorigin href="./assets/index-BACVZe0j.css">
|
|
23
23
|
</head>
|
|
24
24
|
<body>
|
|
25
25
|
<div id="app"></div>
|