@nelsonlongxiang/dsh-open-a2a-net 0.5.15 → 0.6.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/README.md +243 -121
  2. package/README_zh.md +144 -84
  3. package/assets/nexusDist/assets/index-034h1cNc.js +3 -0
  4. package/assets/nexusDist/assets/index-PG9EieGX.css +1 -0
  5. package/assets/nexusDist/index.html +26 -0
  6. package/assets/stageDist/assets/index-Bj7S2pA1.css +1 -0
  7. package/assets/stageDist/assets/index-C-28k_o5.js +974 -0
  8. package/assets/stageDist/assets/interiors-CQGBjffT.png +0 -0
  9. package/assets/stageDist/assets/office-tileset-CHQT-uYL.png +0 -0
  10. package/assets/stageDist/index.html +13 -0
  11. package/lib/a2a-client.js +190 -13
  12. package/lib/canvas-store.js +218 -0
  13. package/lib/card.js +25 -0
  14. package/lib/client/A2aControl.js +45 -137
  15. package/lib/client/locales.js +16 -40
  16. package/lib/client.js +164 -467
  17. package/lib/client.js.map +1 -1
  18. package/lib/exposure-store.js +82 -0
  19. package/lib/group-store.js +6 -0
  20. package/lib/idempotency-store.js +291 -0
  21. package/lib/index.js +4446 -271
  22. package/lib/joined-store.js +11 -0
  23. package/lib/layout-store.js +155 -0
  24. package/lib/peer-store.js +98 -13
  25. package/lib/receipt-ladder.js +35 -0
  26. package/lib/receipt.js +102 -0
  27. package/lib/self-suppress.js +62 -0
  28. package/lib/session-transcript.js +150 -0
  29. package/lib/skill/SKILL.md +77 -0
  30. package/lib/skill/references/discovery.md +38 -0
  31. package/lib/skill/references/membership.md +50 -0
  32. package/lib/skill/references/pitfalls.md +42 -0
  33. package/lib/skill/references/routing.md +43 -0
  34. package/lib/skill-registration.js +52 -0
  35. package/lib/stage-mount.js +32 -0
  36. package/lib/task-ledger.js +540 -0
  37. package/lib/team-store.js +122 -0
  38. package/lib/teams-bridge.js +18 -0
  39. package/lib/transport-caps.js +31 -0
  40. package/lib/types/a2a-client.d.ts +72 -1
  41. package/lib/types/canvas-store.d.ts +102 -0
  42. package/lib/types/client/A2aControl.d.ts +18 -28
  43. package/lib/types/client/locales.d.ts +1 -1
  44. package/lib/types/exposure-store.d.ts +45 -0
  45. package/lib/types/group-store.d.ts +6 -0
  46. package/lib/types/idempotency-store.d.ts +164 -0
  47. package/lib/types/index.d.ts +211 -11
  48. package/lib/types/joined-store.d.ts +9 -0
  49. package/lib/types/layout-store.d.ts +63 -0
  50. package/lib/types/peer-store.d.ts +45 -2
  51. package/lib/types/receipt-ladder.d.ts +25 -0
  52. package/lib/types/receipt.d.ts +51 -0
  53. package/lib/types/self-suppress.d.ts +41 -0
  54. package/lib/types/session-transcript.d.ts +37 -0
  55. package/lib/types/skill-registration.d.ts +3 -0
  56. package/lib/types/stage-mount.d.ts +29 -0
  57. package/lib/types/task-ledger.d.ts +308 -0
  58. package/lib/types/team-store.d.ts +55 -0
  59. package/lib/types/teams-bridge.d.ts +112 -0
  60. package/lib/types/transport-caps.d.ts +29 -0
  61. package/lib/types/types.d.ts +43 -0
  62. package/nexus-stage/package-lock.json +2262 -0
  63. package/nexus-stage/package.json +21 -0
  64. package/nexus-stage/scripts/__pycache__/mockhost.cpython-312.pyc +0 -0
  65. package/nexus-stage/scripts/mockhost.py +253 -0
  66. package/nexus-stage/src/canvas-ops.ts +175 -0
  67. package/nexus-stage/src/canvas-wire.ts +156 -0
  68. package/nexus-stage/src/edges.ts +72 -0
  69. package/nexus-stage/src/fault.ts +56 -0
  70. package/nexus-stage/src/federation.ts +234 -0
  71. package/nexus-stage/src/layout-doc.ts +143 -0
  72. package/nexus-stage/src/layout-wire.ts +158 -0
  73. package/nexus-stage/src/main.ts +361 -0
  74. package/nexus-stage/src/planning-menus.ts +352 -0
  75. package/nexus-stage/src/planning-nodelist.ts +294 -0
  76. package/nexus-stage/src/planning-types.ts +111 -0
  77. package/nexus-stage/src/planning-view.ts +1313 -0
  78. package/nexus-stage/src/planning.css +280 -0
  79. package/nexus-stage/src/seat.ts +35 -0
  80. package/nexus-stage/src/stage-name.ts +13 -0
  81. package/nexus-stage/src/tokens.ts +32 -0
  82. package/nexus-stage/src/viewport.ts +83 -0
  83. package/nexus-stage/src/workbench.css +267 -0
  84. package/nexus-stage/src/workbench.ts +1530 -0
  85. package/nexus-stage/src/world.ts +509 -0
  86. package/nexus-stage/tsconfig.json +25 -0
  87. package/nexus-stage/vite.config.ts +16 -0
  88. package/package.json +218 -157
  89. package/lib/types/client.d.ts +0 -73
package/lib/client.js CHANGED
@@ -23,7 +23,7 @@ window.__ModuleLoader__.load({
23
23
  }
24
24
  //#endregion
25
25
  //#region \0dsh-css:D:\workspace\dsh-open-a2a-net\src\client\A2aControl.module.css.mjs
26
- const css = ".Q9Ky_q_wrap{max-width:100%;display:inline-flex;position:relative}.Q9Ky_q_trigger{align-items:center;gap:4px;display:inline-flex;position:relative}.Q9Ky_q_unreadBadge{text-align:center;color:#fff;background:var(--dsh-accent,#4c8bf5);border-radius:7px;min-width:14px;height:14px;padding:0 3px;font-size:9px;line-height:14px;animation:2s ease-in-out infinite Q9Ky_q_badgePulse;position:absolute;top:-6px;right:-8px}@keyframes Q9Ky_q_badgePulse{0%,to{box-shadow:0 0 #4c8bf573}50%{box-shadow:0 0 0 4px #4c8bf500}}@media (prefers-reduced-motion:reduce){.Q9Ky_q_unreadBadge{animation:none}}.Q9Ky_q_popover{z-index:1100;border:1px solid var(--dsh-border,#2a2a30);background:var(--dsh-surface-raised,#1c1c22);border-radius:10px;flex-direction:column;gap:8px;width:320px;max-width:calc(100vw - 16px);max-height:60vh;padding:12px;display:flex;position:fixed;overflow-y:auto;box-shadow:0 8px 24px #00000059}.Q9Ky_q_title{font-size:13px;font-weight:600}.Q9Ky_q_sectionTitle{border-top:1px solid var(--dsh-border,#2a2a30);text-transform:uppercase;letter-spacing:.04em;opacity:.65;margin-top:4px;padding-top:8px;font-size:11px;font-weight:600}.Q9Ky_q_empty{opacity:.7;font-size:12px}.Q9Ky_q_row{border:1px solid #0000;border-radius:8px;align-items:center;gap:10px;padding:8px;display:flex}.Q9Ky_q_joined{border-color:var(--dsh-border,#2a2a30)}.Q9Ky_q_facts{text-align:left;min-width:0;color:inherit;font:inherit;cursor:pointer;background:0 0;border:none;border-radius:6px;flex-direction:column;flex:1;gap:2px;padding:2px 4px;display:flex}.Q9Ky_q_facts:hover{background:var(--dsh-surface-hover,#ffffff0f)}.Q9Ky_q_nameRow{align-items:center;gap:6px;display:flex}.Q9Ky_q_stateDot{border-radius:50%;flex:none;width:7px;height:7px}.Q9Ky_q_stateDot.Q9Ky_q_live{background:var(--dsh-accent,#4c8bf5)}.Q9Ky_q_stateDot.Q9Ky_q_live.Q9Ky_q_joined{background:var(--dsh-success,#3fb96f)}.Q9Ky_q_stateDot.Q9Ky_q_cold{background:var(--dsh-warning,#d9a13c)}.Q9Ky_q_name{text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:500;overflow:hidden}.Q9Ky_q_description{opacity:.7;text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}.Q9Ky_q_team{opacity:.55;font-size:11px;font-family:var(--dsh-mono,monospace)}.Q9Ky_q_note{opacity:.6;font-size:11px}.Q9Ky_q_searchInput{box-sizing:border-box;border:1px solid var(--dsh-border,#2a2a30);background:var(--dsh-surface,#141419);width:100%;color:inherit;border-radius:6px;padding:5px 8px;font-size:12px}.Q9Ky_q_searchInput:focus{outline:1px solid var(--dsh-accent,#4c8bf5)}.Q9Ky_q_sessionGroup{flex-direction:column;gap:2px;display:flex}.Q9Ky_q_groupHead{color:inherit;font:inherit;opacity:.75;cursor:pointer;text-align:left;background:0 0;border:none;align-items:center;gap:6px;padding:4px 2px;font-size:11px;font-weight:600;display:flex}.Q9Ky_q_groupChevron{transition:transform .12s;display:inline-block}.Q9Ky_q_groupChevronClosed{transform:rotate(-90deg)}.Q9Ky_q_groupTag{text-overflow:ellipsis;white-space:nowrap;border:1px solid var(--dsh-border,#2a2a30);opacity:.8;border-radius:999px;flex:none;max-width:90px;padding:0 6px;font-size:10px;line-height:16px;overflow:hidden}.Q9Ky_q_groupButton{width:24px;height:24px;color:inherit;opacity:.55;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:6px;flex:none;font-size:12px;line-height:1}.Q9Ky_q_groupButton:hover{border-color:var(--dsh-border,#2a2a30);opacity:1}.Q9Ky_q_groupPicker{border:1px dashed var(--dsh-border,#2a2a30);border-radius:8px;flex-wrap:wrap;gap:6px;width:100%;padding:8px;display:flex;position:relative}.Q9Ky_q_groupOption{border:1px solid var(--dsh-border,#2a2a30);color:inherit;cursor:pointer;background:0 0;border-radius:999px;padding:2px 8px;font-size:11px}.Q9Ky_q_groupOptionActive{border-color:var(--dsh-accent,#4c8bf5);color:var(--dsh-accent,#4c8bf5)}.Q9Ky_q_groupNew{align-items:center;gap:6px;width:100%;margin-top:2px;display:flex}.Q9Ky_q_groupInput{border:1px solid var(--dsh-border,#2a2a30);background:var(--dsh-surface,#141419);min-width:0;color:inherit;border-radius:6px;flex:1;padding:4px 8px;font-size:12px}.Q9Ky_q_peerGrid{flex-wrap:wrap;gap:6px;display:flex}.Q9Ky_q_peerChip{border:1px solid var(--dsh-border,#2a2a30);border-radius:999px;align-items:center;gap:6px;padding:3px 8px;font-size:11px;display:inline-flex}.Q9Ky_q_peerHost{text-overflow:ellipsis;white-space:nowrap;max-width:160px;overflow:hidden}.Q9Ky_q_peerScore{font-family:var(--dsh-mono,monospace);opacity:.6}.Q9Ky_q_activityList{flex-direction:column;gap:2px;display:flex}.Q9Ky_q_activityRow{border-radius:4px;align-items:center;gap:8px;padding:2px 4px;font-size:11px;display:flex}.Q9Ky_q_activityRow[data-ok=false]{opacity:.55}.Q9Ky_q_activityDir{flex:none;font-weight:600}.Q9Ky_q_activityDir.Q9Ky_q_in{color:var(--dsh-success,#3fb96f)}.Q9Ky_q_activityDir.Q9Ky_q_out{color:var(--dsh-accent,#4c8bf5)}.Q9Ky_q_activityTeam{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-family:var(--dsh-mono,monospace);opacity:.8;flex:1;overflow:hidden}.Q9Ky_q_activityPeer{text-overflow:ellipsis;white-space:nowrap;opacity:.55;max-width:90px;overflow:hidden}.Q9Ky_q_activityTime{opacity:.5;font-family:var(--dsh-mono,monospace);flex:none}.Q9Ky_q_activityRow[data-jump=true]{cursor:pointer}.Q9Ky_q_activityRow[data-jump=true]:hover{background:var(--dsh-surface-hover,#ffffff0f)}.Q9Ky_q_fresh{animation:1.2s ease-out 3 Q9Ky_q_freshFlash}@keyframes Q9Ky_q_freshFlash{0%{background:#4c8bf538}to{background:0 0}}@media (prefers-reduced-motion:reduce){.Q9Ky_q_fresh{background:#4c8bf51f;animation:none}}.Q9Ky_q_inFlightList{flex-direction:column;gap:2px;margin-bottom:4px;display:flex}.Q9Ky_q_inFlightRow{border:1px dashed var(--dsh-border,#2a2a30);border-radius:4px;align-items:center;gap:8px;padding:3px 4px;font-size:11px;display:flex}.Q9Ky_q_inFlightPulse{background:var(--dsh-accent,#4c8bf5);border-radius:50%;flex:none;width:7px;height:7px;animation:1.1s ease-in-out infinite Q9Ky_q_flightPulse}@keyframes Q9Ky_q_flightPulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.5;transform:scale(.55)}}@media (prefers-reduced-motion:reduce){.Q9Ky_q_inFlightPulse{animation:none}}.Q9Ky_q_versionTag{color:var(--dsh-color-text-tertiary,#888);background:var(--dsh-color-bg-secondary,#8080801f);border-radius:999px;margin-left:auto;padding:1px 6px;font-size:10px;font-weight:500}.Q9Ky_q_inFlightStale{opacity:.55}.Q9Ky_q_inFlightStale .Q9Ky_q_inFlightPulse{opacity:.4;animation:none}";
26
+ const css = ".Q9Ky_q_wrap{max-width:100%;display:inline-flex;position:relative}.Q9Ky_q_trigger{align-items:center;gap:4px;display:inline-flex;position:relative}.Q9Ky_q_unreadBadge{text-align:center;color:#fff;background:var(--dsh-accent,#4c8bf5);border-radius:7px;min-width:14px;height:14px;padding:0 3px;font-size:9px;line-height:14px;animation:2s ease-in-out infinite Q9Ky_q_badgePulse;position:absolute;top:-6px;right:-8px}@keyframes Q9Ky_q_badgePulse{0%,to{box-shadow:0 0 #4c8bf573}50%{box-shadow:0 0 0 4px #4c8bf500}}@media (prefers-reduced-motion:reduce){.Q9Ky_q_unreadBadge{animation:none}}.Q9Ky_q_popover{z-index:1100;border:1px solid var(--dsh-border,#2a2a30);background:var(--dsh-surface-raised,#1c1c22);border-radius:10px;flex-direction:column;gap:8px;width:320px;max-width:calc(100vw - 16px);max-height:60vh;padding:12px;display:flex;position:fixed;overflow-y:auto;box-shadow:0 8px 24px #00000059}.Q9Ky_q_title{font-size:13px;font-weight:600}.Q9Ky_q_sectionTitle{border-top:1px solid var(--dsh-border,#2a2a30);text-transform:uppercase;letter-spacing:.04em;opacity:.65;margin-top:4px;padding-top:8px;font-size:11px;font-weight:600}.Q9Ky_q_stageRow{border-top:1px solid var(--dsh-border,#2a2a30);align-items:center;gap:8px;margin-top:4px;padding-top:8px;display:flex}.Q9Ky_q_stageTitle{text-transform:uppercase;letter-spacing:.04em;opacity:.65;font-size:11px;font-weight:600}.Q9Ky_q_stageLinks{gap:6px;display:flex}.Q9Ky_q_stageLink{border:1px solid var(--dsh-border,#2a2a30);color:inherit;border-radius:999px;align-items:center;padding:3px 8px;font-size:11px;text-decoration:none;display:inline-flex}.Q9Ky_q_stageLink:hover,.Q9Ky_q_stageLink:focus-visible{border-color:var(--dsh-accent,#4c8bf5)}.Q9Ky_q_empty{opacity:.7;font-size:12px}.Q9Ky_q_row{border:1px solid #0000;border-radius:8px;align-items:center;gap:10px;padding:8px;display:flex}.Q9Ky_q_joined{border-color:var(--dsh-border,#2a2a30)}.Q9Ky_q_facts{text-align:left;min-width:0;color:inherit;font:inherit;cursor:pointer;background:0 0;border:none;border-radius:6px;flex-direction:column;flex:1;gap:2px;padding:2px 4px;display:flex}.Q9Ky_q_facts:hover{background:var(--dsh-surface-hover,#ffffff0f)}.Q9Ky_q_nameRow{align-items:center;gap:6px;display:flex}.Q9Ky_q_stateDot{border-radius:50%;flex:none;width:7px;height:7px}.Q9Ky_q_stateDot.Q9Ky_q_live{background:var(--dsh-accent,#4c8bf5)}.Q9Ky_q_stateDot.Q9Ky_q_live.Q9Ky_q_joined{background:var(--dsh-success,#3fb96f)}.Q9Ky_q_stateDot.Q9Ky_q_cold{background:var(--dsh-warning,#d9a13c)}.Q9Ky_q_name{text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:500;overflow:hidden}.Q9Ky_q_description{opacity:.7;text-overflow:ellipsis;white-space:nowrap;font-size:12px;overflow:hidden}.Q9Ky_q_team{opacity:.55;font-size:11px;font-family:var(--dsh-mono,monospace)}.Q9Ky_q_note{opacity:.6;font-size:11px}.Q9Ky_q_searchInput{box-sizing:border-box;border:1px solid var(--dsh-border,#2a2a30);background:var(--dsh-surface,#141419);width:100%;color:inherit;border-radius:6px;padding:5px 8px;font-size:12px}.Q9Ky_q_searchInput:focus{outline:1px solid var(--dsh-accent,#4c8bf5)}.Q9Ky_q_sessionGroup{flex-direction:column;gap:2px;display:flex}.Q9Ky_q_groupHead{color:inherit;font:inherit;opacity:.75;cursor:pointer;text-align:left;background:0 0;border:none;align-items:center;gap:6px;padding:4px 2px;font-size:11px;font-weight:600;display:flex}.Q9Ky_q_groupChevron{transition:transform .12s;display:inline-block}.Q9Ky_q_groupChevronClosed{transform:rotate(-90deg)}.Q9Ky_q_groupTag{text-overflow:ellipsis;white-space:nowrap;border:1px solid var(--dsh-border,#2a2a30);opacity:.8;border-radius:999px;flex:none;max-width:90px;padding:0 6px;font-size:10px;line-height:16px;overflow:hidden}.Q9Ky_q_groupButton{width:24px;height:24px;color:inherit;opacity:.55;cursor:pointer;background:0 0;border:1px solid #0000;border-radius:6px;flex:none;font-size:12px;line-height:1}.Q9Ky_q_groupButton:hover{border-color:var(--dsh-border,#2a2a30);opacity:1}.Q9Ky_q_groupPicker{border:1px dashed var(--dsh-border,#2a2a30);border-radius:8px;flex-wrap:wrap;gap:6px;width:100%;padding:8px;display:flex;position:relative}.Q9Ky_q_groupOption{border:1px solid var(--dsh-border,#2a2a30);color:inherit;cursor:pointer;background:0 0;border-radius:999px;padding:2px 8px;font-size:11px}.Q9Ky_q_groupOptionActive{border-color:var(--dsh-accent,#4c8bf5);color:var(--dsh-accent,#4c8bf5)}.Q9Ky_q_groupNew{align-items:center;gap:6px;width:100%;margin-top:2px;display:flex}.Q9Ky_q_groupInput{border:1px solid var(--dsh-border,#2a2a30);background:var(--dsh-surface,#141419);min-width:0;color:inherit;border-radius:6px;flex:1;padding:4px 8px;font-size:12px}.Q9Ky_q_peerGrid{flex-wrap:wrap;gap:6px;display:flex}.Q9Ky_q_peerChip{border:1px solid var(--dsh-border,#2a2a30);border-radius:999px;align-items:center;gap:6px;padding:3px 8px;font-size:11px;display:inline-flex}.Q9Ky_q_peerHost{text-overflow:ellipsis;white-space:nowrap;max-width:160px;overflow:hidden}.Q9Ky_q_peerScore{font-family:var(--dsh-mono,monospace);opacity:.6}.Q9Ky_q_activityList{flex-direction:column;gap:2px;display:flex}.Q9Ky_q_activityRow{border-radius:4px;align-items:center;gap:8px;padding:2px 4px;font-size:11px;display:flex}.Q9Ky_q_activityRow[data-ok=false]{opacity:.55}.Q9Ky_q_activityDir{flex:none;font-weight:600}.Q9Ky_q_activityDir.Q9Ky_q_in{color:var(--dsh-success,#3fb96f)}.Q9Ky_q_activityDir.Q9Ky_q_out{color:var(--dsh-accent,#4c8bf5)}.Q9Ky_q_activityTeam{text-overflow:ellipsis;white-space:nowrap;min-width:0;font-family:var(--dsh-mono,monospace);opacity:.8;flex:1;overflow:hidden}.Q9Ky_q_activityPeer{text-overflow:ellipsis;white-space:nowrap;opacity:.55;max-width:90px;overflow:hidden}.Q9Ky_q_activityTime{opacity:.5;font-family:var(--dsh-mono,monospace);flex:none}.Q9Ky_q_activityRow[data-jump=true]{cursor:pointer}.Q9Ky_q_activityRow[data-jump=true]:hover{background:var(--dsh-surface-hover,#ffffff0f)}.Q9Ky_q_fresh{animation:1.2s ease-out 3 Q9Ky_q_freshFlash}@keyframes Q9Ky_q_freshFlash{0%{background:#4c8bf538}to{background:0 0}}@media (prefers-reduced-motion:reduce){.Q9Ky_q_fresh{background:#4c8bf51f;animation:none}}.Q9Ky_q_inFlightList{flex-direction:column;gap:2px;margin-bottom:4px;display:flex}.Q9Ky_q_inFlightRow{border:1px dashed var(--dsh-border,#2a2a30);border-radius:4px;align-items:center;gap:8px;padding:3px 4px;font-size:11px;display:flex}.Q9Ky_q_inFlightPulse{background:var(--dsh-accent,#4c8bf5);border-radius:50%;flex:none;width:7px;height:7px;animation:1.1s ease-in-out infinite Q9Ky_q_flightPulse}@keyframes Q9Ky_q_flightPulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.5;transform:scale(.55)}}@media (prefers-reduced-motion:reduce){.Q9Ky_q_inFlightPulse{animation:none}}.Q9Ky_q_versionTag{color:var(--dsh-color-text-tertiary,#888);background:var(--dsh-color-bg-secondary,#8080801f);border-radius:999px;margin-left:auto;padding:1px 6px;font-size:10px;font-weight:500}.Q9Ky_q_inFlightStale{opacity:.55}.Q9Ky_q_canvasCreate{align-items:center;gap:6px;margin-bottom:4px;display:flex}.Q9Ky_q_canvasCreate .Q9Ky_q_groupInput{flex:1;min-width:0}.Q9Ky_q_canvasChip{max-width:100%;color:var(--dsh-color-text-secondary,#aaa);background:var(--dsh-color-bg-secondary,#8080801f);border-radius:999px;align-items:center;gap:4px;margin:2px 4px 2px 0;padding:1px 6px;font-size:11px;display:inline-flex}.Q9Ky_q_canvasChip>span:not([class]){white-space:nowrap;text-overflow:ellipsis;min-width:0;overflow:hidden}.Q9Ky_q_canvasChipRemove{cursor:pointer;min-width:24px;min-height:24px;color:var(--dsh-color-text-tertiary,#888);background:0 0;border:none;padding:2px 5px;font-size:11px;line-height:1}.Q9Ky_q_canvasChipRemove:hover{color:var(--dsh-color-text-primary,#eee)}.Q9Ky_q_canvasChipRemove{transition:color .14s ease-out}@media (prefers-reduced-motion:reduce){.Q9Ky_q_canvasChipRemove{transition:none}}.Q9Ky_q_canvasChipRemove:focus-visible{outline:2px solid var(--dsh-color-primary,#4f8cff);outline-offset:1px;border-radius:4px}.Q9Ky_q_canvasActions{gap:6px;margin-top:4px;display:flex}.Q9Ky_q_inFlightStale .Q9Ky_q_inFlightPulse{opacity:.4;animation:none}.Q9Ky_q_failMark{color:#f87171;flex-shrink:0;font-size:11px}.Q9Ky_q_staleNote{color:var(--dsh-text-muted,#94a3b8b3);padding:4px 8px;font-size:11px}";
27
27
  const tagId = "@nelsonlongxiang/dsh-open-a2a-net/A2aControl.module.css";
28
28
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
29
29
  const tag = document.createElement("style");
@@ -40,10 +40,15 @@ window.__ModuleLoader__.load({
40
40
  "activityTeam": "Q9Ky_q_activityTeam",
41
41
  "activityTime": "Q9Ky_q_activityTime",
42
42
  "badgePulse": "Q9Ky_q_badgePulse",
43
+ "canvasActions": "Q9Ky_q_canvasActions",
44
+ "canvasChip": "Q9Ky_q_canvasChip",
45
+ "canvasChipRemove": "Q9Ky_q_canvasChipRemove",
46
+ "canvasCreate": "Q9Ky_q_canvasCreate",
43
47
  "cold": "Q9Ky_q_cold",
44
48
  "description": "Q9Ky_q_description",
45
49
  "empty": "Q9Ky_q_empty",
46
50
  "facts": "Q9Ky_q_facts",
51
+ "failMark": "Q9Ky_q_failMark",
47
52
  "flightPulse": "Q9Ky_q_flightPulse",
48
53
  "fresh": "Q9Ky_q_fresh",
49
54
  "freshFlash": "Q9Ky_q_freshFlash",
@@ -77,6 +82,11 @@ window.__ModuleLoader__.load({
77
82
  "searchInput": "Q9Ky_q_searchInput",
78
83
  "sectionTitle": "Q9Ky_q_sectionTitle",
79
84
  "sessionGroup": "Q9Ky_q_sessionGroup",
85
+ "stageLink": "Q9Ky_q_stageLink",
86
+ "stageLinks": "Q9Ky_q_stageLinks",
87
+ "stageRow": "Q9Ky_q_stageRow",
88
+ "stageTitle": "Q9Ky_q_stageTitle",
89
+ "staleNote": "Q9Ky_q_staleNote",
80
90
  "stateDot": "Q9Ky_q_stateDot",
81
91
  "team": "Q9Ky_q_team",
82
92
  "title": "Q9Ky_q_title",
@@ -88,15 +98,14 @@ window.__ModuleLoader__.load({
88
98
  //#endregion
89
99
  //#region lib/client/A2aControl.js
90
100
  /**
91
- * A2A network control: a footer action opening this host's network panel.
92
- * Probes the host's session-node state route at registration time (the seat
93
- * renders only on a host that serves it). The panel has three sections:
94
- * session nodes (live rows show title, recent-activity excerpt, and team with
95
- * a join/leave toggle and open the session on row click — the wake action on
96
- * cold rows opens the session through the standard flow), the peer fleet
97
- * (tracked URLs with quality scores), and the recent routing activity ring
98
- * (inbound and outbound outcomes). While open, the panel polls so listings
99
- * visibly follow each turn.
101
+ * A2A network control: a footer action opening this host's recent network
102
+ * activity feed. The feed is the panel's whole content — in-flight routes,
103
+ * owed receipts, and the routing activity ring. Session/team management
104
+ * lives in the planning view (design: docs/design/panel-activity-feed.md):
105
+ * the stage links row above the feed is the explicit navigation to it.
106
+ * Probes the host's state route at registration time (the seat renders only
107
+ * on a host that serves it). While open, the feed polls so it visibly
108
+ * follows each turn; the closed trigger's unread badge rides a slow poll.
100
109
  */
101
110
  /** Fetch the host's network state; undefined means the route is absent. */
102
111
  async function fetchState() {
@@ -106,11 +115,10 @@ window.__ModuleLoader__.load({
106
115
  if (body.nodes !== true || !Array.isArray(body.sessions)) return void 0;
107
116
  return {
108
117
  sessions: body.sessions,
109
- groups: Array.isArray(body.groups) ? body.groups : [],
110
- peers: Array.isArray(body.peers) ? body.peers : [],
111
118
  activity: Array.isArray(body.activity) ? body.activity : [],
112
119
  inFlight: Array.isArray(body.inFlight) ? body.inFlight : [],
113
- remote: Array.isArray(body.remote) ? body.remote : [],
120
+ tasks: Array.isArray(body.tasks) ? body.tasks : [],
121
+ ...typeof body.tasksStaleCount === "number" ? { tasksStaleCount: body.tasksStaleCount } : {},
114
122
  ...typeof body.version === "string" ? { version: body.version } : {}
115
123
  };
116
124
  }
@@ -122,155 +130,65 @@ window.__ModuleLoader__.load({
122
130
  if (minutes < 60) return `${String(minutes)}m`;
123
131
  return `${String(Math.round(minutes / 60))}h`;
124
132
  }
125
- /**
126
- * One session row: the facts block opens the session, the toggle joins or
127
- * leaves, and the tag button opens the group picker (assign / create /
128
- * clear).
129
- */
130
- function SessionRow({ row, t, listById, openSession, busy, onToggle, pickerFor, setPickerFor, groups, newGroupName, setNewGroupName, onAssign }) {
131
- const cold = row.live === false;
132
- const name = cold ? listById[row.id]?.displayTitle ?? row.label : row.name ?? row.label;
133
- const description = cold ? t("a2a.cold") : row.description ?? "";
134
- const pickerOpen = pickerFor === row.id;
133
+ /** One feed row: direction glyph (aria-labelled), team, peer host, age, fail mark. */
134
+ function FeedRow({ dir, team, peer, ts, ok, target, openSession, t }) {
135
+ const fresh = Date.now() - ts < 5e3;
135
136
  return (0, react_jsx_runtime.jsxs)("div", {
136
- className: clsx(A2aControl_module_css_default.row, row.joined && A2aControl_module_css_default.joined),
137
+ className: clsx(A2aControl_module_css_default.activityRow, fresh && A2aControl_module_css_default.fresh),
138
+ "data-ok": ok === void 0 ? void 0 : String(ok),
139
+ "data-jump": target !== void 0,
140
+ title: target !== void 0 ? t("a2a.jump") : void 0,
141
+ onClick: () => {
142
+ if (target !== void 0) openSession(target.id);
143
+ },
144
+ role: target !== void 0 ? "button" : void 0,
137
145
  children: [
138
- (0, react_jsx_runtime.jsxs)("button", {
139
- type: "button",
140
- className: A2aControl_module_css_default.facts,
141
- title: cold ? t("a2a.wake") : name,
142
- onClick: () => {
143
- openSession(row.id);
144
- },
145
- children: [
146
- (0, react_jsx_runtime.jsxs)("span", {
147
- className: A2aControl_module_css_default.nameRow,
148
- children: [
149
- (0, react_jsx_runtime.jsx)("span", {
150
- className: clsx(A2aControl_module_css_default.stateDot, cold ? "cold" : "live", row.joined && "joined"),
151
- "aria-hidden": true
152
- }),
153
- (0, react_jsx_runtime.jsx)("span", {
154
- className: A2aControl_module_css_default.name,
155
- children: name
156
- }),
157
- row.group !== void 0 ? (0, react_jsx_runtime.jsx)("span", {
158
- className: A2aControl_module_css_default.groupTag,
159
- children: row.group
160
- }) : null
161
- ]
162
- }),
163
- (0, react_jsx_runtime.jsx)("span", {
164
- className: A2aControl_module_css_default.description,
165
- children: description
166
- }),
167
- (0, react_jsx_runtime.jsx)("span", {
168
- className: A2aControl_module_css_default.team,
169
- children: row.team
170
- })
171
- ]
146
+ (0, react_jsx_runtime.jsx)("span", {
147
+ className: clsx(A2aControl_module_css_default.activityDir, dir),
148
+ "aria-label": dir === "in" ? "inbound" : "outbound",
149
+ children: dir === "in" ? "←" : "→"
172
150
  }),
173
- (0, react_jsx_runtime.jsx)("button", {
174
- type: "button",
175
- className: A2aControl_module_css_default.groupButton,
176
- title: t("a2a.group"),
177
- "aria-label": t("a2a.group"),
178
- onClick: () => {
179
- setPickerFor(pickerOpen ? null : row.id);
180
- },
181
- children: "#"
151
+ (0, react_jsx_runtime.jsx)("span", {
152
+ className: A2aControl_module_css_default.activityTeam,
153
+ title: team,
154
+ children: team
182
155
  }),
183
- cold ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
184
- variant: "outline",
185
- size: "sm",
186
- disabled: busy === row.id,
187
- onClick: () => {
188
- onToggle(row);
189
- },
190
- children: t("a2a.leave")
191
- }) : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
192
- variant: row.joined ? "outline" : "primary",
193
- size: "sm",
194
- disabled: busy === row.id,
195
- onClick: () => {
196
- onToggle(row);
197
- },
198
- children: row.joined ? t("a2a.leave") : t("a2a.join")
156
+ (0, react_jsx_runtime.jsx)("span", {
157
+ className: A2aControl_module_css_default.activityPeer,
158
+ title: peer,
159
+ children: peer === "" || peer === "local" ? "" : peer.replace(/^https?:\/\//, "").replace(/\/.*$/, "")
199
160
  }),
200
- pickerOpen && (0, react_jsx_runtime.jsxs)("div", {
201
- className: A2aControl_module_css_default.groupPicker,
202
- children: [
203
- (0, react_jsx_runtime.jsx)("button", {
204
- type: "button",
205
- className: A2aControl_module_css_default.groupOption,
206
- onClick: () => {
207
- onAssign(row.id, "");
208
- },
209
- children: t("a2a.groupClear")
210
- }),
211
- groups.map((group) => (0, react_jsx_runtime.jsx)("button", {
212
- type: "button",
213
- className: clsx(A2aControl_module_css_default.groupOption, row.group === group && A2aControl_module_css_default.groupOptionActive),
214
- onClick: () => {
215
- onAssign(row.id, group);
216
- },
217
- children: group
218
- }, group)),
219
- (0, react_jsx_runtime.jsxs)("div", {
220
- className: A2aControl_module_css_default.groupNew,
221
- children: [(0, react_jsx_runtime.jsx)("input", {
222
- className: A2aControl_module_css_default.groupInput,
223
- value: newGroupName,
224
- placeholder: t("a2a.groupNew"),
225
- maxLength: 40,
226
- onChange: (event) => {
227
- setNewGroupName(event.target.value);
228
- },
229
- onKeyDown: (event) => {
230
- if (event.key === "Enter" && newGroupName.trim() !== "") onAssign(row.id, newGroupName.trim());
231
- }
232
- }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
233
- variant: "primary",
234
- size: "sm",
235
- disabled: newGroupName.trim() === "",
236
- onClick: () => {
237
- if (newGroupName.trim() !== "") onAssign(row.id, newGroupName.trim());
238
- },
239
- children: t("a2a.groupNewGo")
240
- })]
241
- })
242
- ]
161
+ ok === false ? (0, react_jsx_runtime.jsx)("span", {
162
+ className: A2aControl_module_css_default.failMark,
163
+ "aria-label": "failed",
164
+ children: "✕"
165
+ }) : null,
166
+ (0, react_jsx_runtime.jsx)("span", {
167
+ className: A2aControl_module_css_default.activityTime,
168
+ children: relativeTime(ts)
243
169
  })
244
170
  ]
245
171
  });
246
172
  }
247
173
  /**
248
- * Render the network toggle and its network panel.
174
+ * Render the network toggle and its activity feed.
249
175
  * @param props - composed slot props.
250
176
  * @returns the control element tree.
251
177
  */
252
- function A2aControl({ wide, t, useSessions, openSession }) {
178
+ function A2aControl({ wide, t, openSession }) {
253
179
  const [open, setOpen] = (0, react.useState)(false);
254
180
  const [state, setState] = (0, react.useState)({
255
181
  sessions: [],
256
- groups: [],
257
- peers: [],
258
182
  activity: [],
259
183
  inFlight: [],
260
- remote: []
184
+ tasks: []
261
185
  });
262
- const [busy, setBusy] = (0, react.useState)(null);
263
186
  const [seenActivity, setSeenActivity] = (0, react.useState)(0);
264
- const [search, setSearch] = (0, react.useState)("");
265
- const [pickerFor, setPickerFor] = (0, react.useState)(null);
266
- const [newGroupName, setNewGroupName] = (0, react.useState)("");
267
- const [collapsed, setCollapsed] = (0, react.useState)(/* @__PURE__ */ new Set());
268
187
  const stopped = (0, react.useRef)(false);
269
188
  (0, react.useEffect)(() => () => {
270
189
  stopped.current = true;
271
190
  }, []);
272
191
  const wrap = (0, react.useRef)(null);
273
- const listById = useSessions((state2) => state2.byId);
274
192
  const [anchor, setAnchor] = (0, react.useState)(null);
275
193
  const unread = Math.max(0, state.activity.filter((entry) => entry.dir === "in").length - seenActivity);
276
194
  const toggleOpen = () => {
@@ -318,47 +236,7 @@ window.__ModuleLoader__.load({
318
236
  document.removeEventListener("pointerdown", onPointerDown);
319
237
  };
320
238
  }, [open]);
321
- /** Join or leave one session, then refresh the listing. */
322
- const toggle = (row) => {
323
- setBusy(row.id);
324
- fetch(`/__dsh_a2a/${row.joined ? "leave" : "join"}`, {
325
- method: "POST",
326
- headers: { "Content-Type": "application/json" },
327
- body: JSON.stringify({ id: row.id })
328
- }).then(() => {
329
- refresh();
330
- }).catch(() => {}).finally(() => {
331
- if (!stopped.current) setBusy(null);
332
- });
333
- };
334
- /** Assign one session to a group ('' clears), then refresh. */
335
- const assign = (id, name) => {
336
- fetch("/__dsh_a2a/groups", {
337
- method: "POST",
338
- headers: { "Content-Type": "application/json" },
339
- body: JSON.stringify({
340
- action: "assign",
341
- id,
342
- name
343
- })
344
- }).then(() => {
345
- setPickerFor(null);
346
- setNewGroupName("");
347
- refresh();
348
- }).catch(() => {});
349
- };
350
- const { sessions, groups, peers, activity, inFlight, remote } = state;
351
- const needle = search.trim().toLowerCase();
352
- const matches = (row) => {
353
- if (needle === "") return true;
354
- return (row.live === false ? listById[row.id]?.displayTitle ?? row.label : row.name ?? row.label).toLowerCase().includes(needle) || row.team.toLowerCase().includes(needle) || (row.description ?? "").toLowerCase().includes(needle);
355
- };
356
- const visible = sessions.filter(matches);
357
- const ungrouped = visible.filter((row) => row.group === void 0);
358
- const grouped = groups.map((name) => ({
359
- name,
360
- rows: visible.filter((row) => row.group === name)
361
- })).filter((group) => group.rows.length > 0);
239
+ const { sessions, activity, inFlight, tasks } = state;
362
240
  return (0, react_jsx_runtime.jsxs)("div", {
363
241
  ref: wrap,
364
242
  className: clsx(A2aControl_module_css_default.wrap, wide ? A2aControl_module_css_default.wide : A2aControl_module_css_default.rail),
@@ -374,7 +252,7 @@ window.__ModuleLoader__.load({
374
252
  children: (0, react_jsx_runtime.jsxs)("span", {
375
253
  className: A2aControl_module_css_default.trigger,
376
254
  children: [
377
- (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconGlobeOutline14, {}),
255
+ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconGlobeOutlineRegular, {}),
378
256
  wide ? (0, react_jsx_runtime.jsx)("span", { children: t("a2a.label") }) : null,
379
257
  unread > 0 ? (0, react_jsx_runtime.jsx)("span", {
380
258
  className: A2aControl_module_css_default.unreadBadge,
@@ -400,258 +278,101 @@ window.__ModuleLoader__.load({
400
278
  children: ["v", state.version]
401
279
  }) : null]
402
280
  }),
403
- (0, react_jsx_runtime.jsx)("input", {
404
- className: A2aControl_module_css_default.searchInput,
405
- type: "search",
406
- value: search,
407
- placeholder: t("a2a.search"),
408
- "aria-label": t("a2a.search"),
409
- onChange: (event) => {
410
- setSearch(event.target.value);
411
- }
412
- }),
413
- sessions.length === 0 ? (0, react_jsx_runtime.jsx)("div", {
414
- className: A2aControl_module_css_default.empty,
415
- children: t("a2a.empty")
416
- }) : visible.length === 0 ? (0, react_jsx_runtime.jsx)("div", {
417
- className: A2aControl_module_css_default.empty,
418
- children: t("a2a.searchEmpty")
419
- }) : (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [ungrouped.length > 0 && (0, react_jsx_runtime.jsxs)("div", {
420
- className: A2aControl_module_css_default.sessionGroup,
421
- children: [(0, react_jsx_runtime.jsxs)("button", {
422
- type: "button",
423
- className: A2aControl_module_css_default.groupHead,
424
- onClick: () => {
425
- setCollapsed((current) => {
426
- const next = new Set(current);
427
- if (next.has("")) next.delete("");
428
- else next.add("");
429
- return next;
430
- });
431
- },
432
- children: [
433
- (0, react_jsx_runtime.jsx)("span", {
434
- className: clsx(A2aControl_module_css_default.groupChevron, collapsed.has("") && A2aControl_module_css_default.groupChevronClosed),
435
- "aria-hidden": true,
436
- children: "▾"
437
- }),
438
- t("a2a.groupDefault"),
439
- " · ",
440
- String(ungrouped.length)
441
- ]
442
- }), !collapsed.has("") && ungrouped.map((row) => (0, react_jsx_runtime.jsx)(SessionRow, {
443
- row,
444
- t,
445
- listById,
446
- openSession,
447
- busy,
448
- onToggle: toggle,
449
- pickerFor,
450
- setPickerFor,
451
- groups,
452
- newGroupName,
453
- setNewGroupName,
454
- onAssign: assign
455
- }, row.id))]
456
- }), grouped.map(({ name, rows }) => {
457
- const isCollapsed = collapsed.has(name);
458
- return (0, react_jsx_runtime.jsxs)("div", {
459
- className: A2aControl_module_css_default.sessionGroup,
460
- children: [(0, react_jsx_runtime.jsxs)("button", {
461
- type: "button",
462
- className: A2aControl_module_css_default.groupHead,
463
- onClick: () => {
464
- setCollapsed((current) => {
465
- const next = new Set(current);
466
- if (next.has(name)) next.delete(name);
467
- else next.add(name);
468
- return next;
469
- });
470
- },
471
- children: [
472
- (0, react_jsx_runtime.jsx)("span", {
473
- className: clsx(A2aControl_module_css_default.groupChevron, isCollapsed && A2aControl_module_css_default.groupChevronClosed),
474
- "aria-hidden": true,
475
- children: "▾"
476
- }),
477
- name,
478
- " · ",
479
- String(rows.length)
480
- ]
481
- }), !isCollapsed && rows.map((row) => (0, react_jsx_runtime.jsx)(SessionRow, {
482
- row,
483
- t,
484
- listById,
485
- openSession,
486
- busy,
487
- onToggle: toggle,
488
- pickerFor,
489
- setPickerFor,
490
- groups,
491
- newGroupName,
492
- setNewGroupName,
493
- onAssign: assign
494
- }, row.id))]
495
- }, name);
496
- })] }),
497
- (0, react_jsx_runtime.jsx)("div", {
498
- className: A2aControl_module_css_default.note,
499
- children: t("a2a.note")
281
+ (0, react_jsx_runtime.jsxs)("div", {
282
+ className: A2aControl_module_css_default.stageRow,
283
+ children: [(0, react_jsx_runtime.jsx)("span", {
284
+ className: A2aControl_module_css_default.stageTitle,
285
+ children: t("a2a.stageTitle")
286
+ }), (0, react_jsx_runtime.jsx)("span", {
287
+ className: A2aControl_module_css_default.stageLinks,
288
+ children: (0, react_jsx_runtime.jsx)("a", {
289
+ className: A2aControl_module_css_default.stageLink,
290
+ href: "/__dsh_a2a_nexus/",
291
+ target: "_blank",
292
+ rel: "noreferrer",
293
+ title: t("a2a.stageWorkbench"),
294
+ children: t("a2a.stageWorkbench")
295
+ })
296
+ })]
500
297
  }),
501
- (needle === "" ? remote : remote.filter((row) => row.team.toLowerCase().includes(needle) || row.name.toLowerCase().includes(needle) || (row.origin ?? "").toLowerCase().includes(needle) || (row.workspace ?? "").toLowerCase().includes(needle))).length > 0 && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("div", {
502
- className: A2aControl_module_css_default.sectionTitle,
503
- children: t("a2a.remote")
504
- }), Object.entries((needle === "" ? remote : remote.filter((row) => row.team.toLowerCase().includes(needle) || row.name.toLowerCase().includes(needle) || (row.origin ?? "").toLowerCase().includes(needle) || (row.workspace ?? "").toLowerCase().includes(needle))).reduce((byOrigin, row) => {
505
- const key = row.origin ?? "";
506
- byOrigin[key] = [...byOrigin[key] ?? [], row];
507
- return byOrigin;
508
- }, {})).map(([origin, rows]) => (0, react_jsx_runtime.jsxs)("div", {
509
- className: A2aControl_module_css_default.sessionGroup,
510
- children: [(0, react_jsx_runtime.jsxs)("button", {
511
- type: "button",
512
- className: A2aControl_module_css_default.groupHead,
513
- onClick: () => {
514
- setCollapsed((current) => {
515
- const next = new Set(current);
516
- if (next.has("remote:" + origin)) next.delete("remote:" + origin);
517
- else next.add("remote:" + origin);
518
- return next;
519
- });
520
- },
521
- children: [
522
- (0, react_jsx_runtime.jsx)("span", {
523
- className: clsx(A2aControl_module_css_default.groupChevron, collapsed.has("remote:" + origin) && A2aControl_module_css_default.groupChevronClosed),
524
- "aria-hidden": true,
525
- children: "▾"
526
- }),
527
- origin === "" ? t("a2a.remoteUnknownOrigin") : origin,
528
- " · ",
529
- String(rows.length)
530
- ]
531
- }), !collapsed.has("remote:" + origin) && rows.map((row) => (0, react_jsx_runtime.jsx)("div", {
532
- className: A2aControl_module_css_default.row,
533
- title: row.workspace ?? void 0,
534
- children: (0, react_jsx_runtime.jsxs)("div", {
535
- className: A2aControl_module_css_default.facts,
536
- children: [(0, react_jsx_runtime.jsxs)("span", {
537
- className: A2aControl_module_css_default.nameRow,
298
+ (0, react_jsx_runtime.jsxs)("div", {
299
+ "aria-live": "polite",
300
+ children: [
301
+ inFlight.length > 0 && (0, react_jsx_runtime.jsx)("div", {
302
+ className: A2aControl_module_css_default.inFlightList,
303
+ "aria-label": t("a2a.inFlight"),
304
+ children: inFlight.map((route) => (0, react_jsx_runtime.jsxs)("div", {
305
+ className: clsx(A2aControl_module_css_default.inFlightRow, Date.now() - route.startedAt > 12e4 && A2aControl_module_css_default.inFlightStale),
306
+ title: Date.now() - route.startedAt > 12e4 ? t("a2a.inFlightStale") : void 0,
307
+ children: [(0, react_jsx_runtime.jsx)("span", {
308
+ className: A2aControl_module_css_default.inFlightPulse,
309
+ "aria-hidden": true
310
+ }), (0, react_jsx_runtime.jsx)(FeedRow, {
311
+ dir: "out",
312
+ team: route.team,
313
+ peer: route.peer,
314
+ ts: route.startedAt,
315
+ openSession,
316
+ t
317
+ })]
318
+ }, `${route.team}-${String(route.startedAt)}`))
319
+ }),
320
+ (() => {
321
+ const settleableTasks = tasks.filter((task) => task.settleable !== false);
322
+ const staleCount = state.tasksStaleCount ?? tasks.length - settleableTasks.length;
323
+ if (settleableTasks.length === 0 && staleCount === 0) return null;
324
+ return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [settleableTasks.length > 0 && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("div", {
325
+ className: A2aControl_module_css_default.sectionTitle,
326
+ children: t("a2a.tasks")
327
+ }), (0, react_jsx_runtime.jsx)("div", {
328
+ className: A2aControl_module_css_default.inFlightList,
329
+ "aria-label": t("a2a.tasks"),
330
+ children: settleableTasks.map((task) => (0, react_jsx_runtime.jsx)("div", {
331
+ className: A2aControl_module_css_default.inFlightRow,
332
+ title: t("a2a.tasksNote"),
333
+ children: (0, react_jsx_runtime.jsx)(FeedRow, {
334
+ dir: "out",
335
+ team: task.team,
336
+ peer: task.peer,
337
+ ts: task.startedAt,
338
+ openSession,
339
+ t
340
+ })
341
+ }, task.taskId))
342
+ })] }), staleCount > 0 && (0, react_jsx_runtime.jsxs)("div", {
343
+ className: A2aControl_module_css_default.staleNote,
344
+ title: t("a2a.tasksNote"),
538
345
  children: [
539
- (0, react_jsx_runtime.jsx)("span", {
540
- className: A2aControl_module_css_default.stateDot,
541
- "data-peer": true,
542
- "aria-hidden": true
543
- }),
544
- (0, react_jsx_runtime.jsx)("span", {
545
- className: A2aControl_module_css_default.name,
546
- children: row.name === "" ? row.team : row.name
547
- }),
548
- row.workspace !== void 0 ? (0, react_jsx_runtime.jsx)("span", {
549
- className: A2aControl_module_css_default.groupTag,
550
- children: row.workspace
551
- }) : null
346
+ t("a2a.tasksStale"),
347
+ " · ",
348
+ String(staleCount)
552
349
  ]
553
- }), (0, react_jsx_runtime.jsx)("span", {
554
- className: A2aControl_module_css_default.team,
555
- children: row.team
556
- })]
557
- })
558
- }, row.team))]
559
- }, origin))] }),
560
- (0, react_jsx_runtime.jsx)("div", {
561
- className: A2aControl_module_css_default.sectionTitle,
562
- children: t("a2a.peers")
563
- }),
564
- peers.length === 0 ? (0, react_jsx_runtime.jsx)("div", {
565
- className: A2aControl_module_css_default.empty,
566
- children: t("a2a.peersEmpty")
567
- }) : (0, react_jsx_runtime.jsx)("div", {
568
- className: A2aControl_module_css_default.peerGrid,
569
- children: peers.map((peer) => (0, react_jsx_runtime.jsxs)("span", {
570
- className: A2aControl_module_css_default.peerChip,
571
- title: peer.url,
572
- children: [(0, react_jsx_runtime.jsx)("span", {
573
- className: A2aControl_module_css_default.peerHost,
574
- children: peer.url.replace(/^https?:\/\//, "").replace(/\/.*$/, "")
575
- }), typeof peer.score === "number" ? (0, react_jsx_runtime.jsx)("span", {
576
- className: A2aControl_module_css_default.peerScore,
577
- children: String(Math.round(peer.score))
578
- }) : null]
579
- }, peer.url))
580
- }),
581
- (0, react_jsx_runtime.jsx)("div", {
582
- className: A2aControl_module_css_default.sectionTitle,
583
- children: t("a2a.activity")
584
- }),
585
- inFlight.length > 0 && (0, react_jsx_runtime.jsx)("div", {
586
- className: A2aControl_module_css_default.inFlightList,
587
- "aria-label": t("a2a.inFlight"),
588
- children: inFlight.map((route) => (0, react_jsx_runtime.jsxs)("div", {
589
- className: clsx(A2aControl_module_css_default.inFlightRow, Date.now() - route.startedAt > 12e4 && A2aControl_module_css_default.inFlightStale),
590
- title: Date.now() - route.startedAt > 12e4 ? t("a2a.inFlightStale") : void 0,
591
- children: [
592
- (0, react_jsx_runtime.jsx)("span", {
593
- className: A2aControl_module_css_default.inFlightPulse,
594
- "aria-hidden": true
595
- }),
596
- (0, react_jsx_runtime.jsx)("span", {
597
- className: clsx(A2aControl_module_css_default.activityDir, "out"),
598
- children: "→"
599
- }),
600
- (0, react_jsx_runtime.jsx)("span", {
601
- className: A2aControl_module_css_default.activityTeam,
602
- title: route.team,
603
- children: route.team
604
- }),
605
- (0, react_jsx_runtime.jsx)("span", {
606
- className: A2aControl_module_css_default.activityPeer,
607
- children: route.peer === "local" ? "" : route.peer.replace(/^https?:\/\//, "").replace(/\/.*$/, "")
608
- }),
609
- (0, react_jsx_runtime.jsx)("span", {
610
- className: A2aControl_module_css_default.activityTime,
611
- children: relativeTime(route.startedAt)
350
+ })] });
351
+ })(),
352
+ (0, react_jsx_runtime.jsx)("div", {
353
+ className: A2aControl_module_css_default.sectionTitle,
354
+ children: t("a2a.activity")
355
+ }),
356
+ activity.length === 0 ? (0, react_jsx_runtime.jsx)("div", {
357
+ className: A2aControl_module_css_default.empty,
358
+ children: t("a2a.activityEmpty")
359
+ }) : (0, react_jsx_runtime.jsx)("div", {
360
+ className: A2aControl_module_css_default.activityList,
361
+ children: [...activity].reverse().slice(0, 10).map((entry, index) => {
362
+ const target = sessions.find((row) => row.team === entry.team);
363
+ return (0, react_jsx_runtime.jsx)(FeedRow, {
364
+ dir: entry.dir,
365
+ team: entry.team,
366
+ peer: entry.peer,
367
+ ts: entry.ts,
368
+ ok: entry.ok,
369
+ ...target !== void 0 ? { target } : {},
370
+ openSession,
371
+ t
372
+ }, `${String(entry.ts)}-${String(index)}`);
612
373
  })
613
- ]
614
- }, `${route.team}-${String(route.startedAt)}`))
615
- }),
616
- activity.length === 0 ? (0, react_jsx_runtime.jsx)("div", {
617
- className: A2aControl_module_css_default.empty,
618
- children: t("a2a.activityEmpty")
619
- }) : (0, react_jsx_runtime.jsx)("div", {
620
- className: A2aControl_module_css_default.activityList,
621
- children: [...activity].reverse().slice(0, 10).map((entry, index) => {
622
- const target = sessions.find((row) => row.team === entry.team);
623
- const fresh = Date.now() - entry.ts < 5e3;
624
- return (0, react_jsx_runtime.jsxs)("div", {
625
- className: clsx(A2aControl_module_css_default.activityRow, fresh && A2aControl_module_css_default.fresh),
626
- "data-ok": entry.ok,
627
- "data-jump": target !== void 0,
628
- title: target !== void 0 ? t("a2a.jump") : void 0,
629
- onClick: () => {
630
- if (target !== void 0) openSession(target.id);
631
- },
632
- role: target !== void 0 ? "button" : void 0,
633
- children: [
634
- (0, react_jsx_runtime.jsx)("span", {
635
- className: clsx(A2aControl_module_css_default.activityDir, entry.dir),
636
- children: entry.dir === "in" ? "←" : "→"
637
- }),
638
- (0, react_jsx_runtime.jsx)("span", {
639
- className: A2aControl_module_css_default.activityTeam,
640
- title: entry.team,
641
- children: entry.team
642
- }),
643
- (0, react_jsx_runtime.jsx)("span", {
644
- className: A2aControl_module_css_default.activityPeer,
645
- title: entry.peer,
646
- children: entry.peer === "" ? "" : entry.peer.replace(/^https?:\/\//, "").replace(/\/.*$/, "")
647
- }),
648
- (0, react_jsx_runtime.jsx)("span", {
649
- className: A2aControl_module_css_default.activityTime,
650
- children: relativeTime(entry.ts)
651
- })
652
- ]
653
- }, `${String(entry.ts)}-${String(index)}`);
654
- })
374
+ })
375
+ ]
655
376
  })
656
377
  ]
657
378
  }) : null]
@@ -663,56 +384,32 @@ window.__ModuleLoader__.load({
663
384
  /** Simplified Chinese dictionary. */
664
385
  const zh = {
665
386
  "a2a.label": "A2A 网络",
666
- "a2a.title": "A2A 网络面板",
667
- "a2a.empty": "没有可加入的会话",
668
- "a2a.join": "加入",
669
- "a2a.leave": "退出",
670
- "a2a.cold": "未加载(重启后待唤醒)",
671
- "a2a.wake": "唤醒",
672
- "a2a.note": "只有加入的会话才会被网络中的其他节点发现;点击会话行可跳转。",
673
- "a2a.remote": "远程节点(按 host 分组)",
674
- "a2a.remoteUnknownOrigin": "未知来源",
675
- "a2a.peers": "对等节点",
676
- "a2a.peersEmpty": "尚无已知对等节点(配 peers 种子入网)",
677
- "a2a.activity": "路由活动",
678
- "a2a.activityEmpty": "暂无路由记录",
387
+ "a2a.title": "A2A 网络动态",
388
+ "a2a.activity": "最近动态",
389
+ "a2a.activityEmpty": "暂无网络动态——加入网络即可开始协作",
679
390
  "a2a.inFlight": "进行中的路由",
680
391
  "a2a.inFlightStale": "等待回执超时(对端处理慢或回执丢失);180 秒后自动解除并按已送达处理",
392
+ "a2a.tasks": "欠回执的异步任务",
393
+ "a2a.tasksNote": "异步欠账分三段:未决(等回执)→ 死信(超期自动标注,目标恢复后仍可补回执结算)→ 归档(结算留痕不蒸发)",
394
+ "a2a.tasksStale": "对话式已送达未答(非欠账,24h 自动死信)",
681
395
  "a2a.jump": "点击跳转到该会话",
682
- "a2a.search": "搜索会话(名称 / team / 摘要)",
683
- "a2a.searchEmpty": "没有匹配的会话",
684
- "a2a.group": "设置分组",
685
- "a2a.groupDefault": "未分组",
686
- "a2a.groupClear": "清除分组",
687
- "a2a.groupNew": "新建分组…",
688
- "a2a.groupNewGo": "创建并归入"
396
+ "a2a.stageTitle": "A2A 工作台(目录 · 台账 · 活动 · 规划)",
397
+ "a2a.stageWorkbench": "打开工作台"
689
398
  };
690
399
  /** English dictionary. */
691
400
  const en = {
692
401
  "a2a.label": "A2A network",
693
- "a2a.title": "A2A network panel",
694
- "a2a.empty": "No joinable sessions",
695
- "a2a.join": "Join",
696
- "a2a.leave": "Leave",
697
- "a2a.cold": "not loaded (waiting to wake after a restart)",
698
- "a2a.wake": "Wake",
699
- "a2a.note": "Only joined sessions are discoverable by other nodes; click a row to open the session.",
700
- "a2a.remote": "Remote teams (by host)",
701
- "a2a.remoteUnknownOrigin": "Unknown origin",
702
- "a2a.peers": "Peers",
703
- "a2a.peersEmpty": "No known peers yet (set peers seeds to join the mesh)",
704
- "a2a.activity": "Routing activity",
705
- "a2a.activityEmpty": "No routes yet",
402
+ "a2a.title": "A2A network activity",
403
+ "a2a.activity": "Recent activity",
404
+ "a2a.activityEmpty": "No network activity yet — join sessions to the network to start collaborating",
706
405
  "a2a.inFlight": "Routes in flight",
707
406
  "a2a.inFlightStale": "Reply wait past 120s (slow or lost receipt); auto-releases as delivered at 180s",
407
+ "a2a.tasks": "Owed receipts",
408
+ "a2a.tasksNote": "Async debts in three tiers: pending (awaiting receipt) → dead-lettered (auto-flagged past the stale TTL; a revived target can still settle late) → archived (settled records kept for audit)",
409
+ "a2a.tasksStale": "Delivered conversationally, no formal receipt (not debt; auto-dead-letters at the TTL)",
708
410
  "a2a.jump": "Click to open this session",
709
- "a2a.search": "Search sessions (name / team / excerpt)",
710
- "a2a.searchEmpty": "No sessions match",
711
- "a2a.group": "Set group",
712
- "a2a.groupDefault": "Ungrouped",
713
- "a2a.groupClear": "Clear group",
714
- "a2a.groupNew": "New group…",
715
- "a2a.groupNewGo": "Create & assign"
411
+ "a2a.stageTitle": "A2A workbench (directory · ledger · activity · plan)",
412
+ "a2a.stageWorkbench": "Open workbench"
716
413
  };
717
414
  //#endregion
718
415
  //#region lib/client/index.js