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

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 (72) hide show
  1. package/README.md +2 -1
  2. package/README_zh.md +2 -1
  3. package/assets/nexusDist/assets/index-CaA76j0F.js +9 -0
  4. package/assets/nexusDist/index.html +1 -1
  5. package/assets/stageDist/assets/index-Bj7S2pA1.css +1 -1
  6. package/assets/stageDist/assets/index-C-28k_o5.js +974 -974
  7. package/assets/stageDist/index.html +12 -12
  8. package/cli/a2a.mjs +24 -4
  9. package/lib/canvas-store.js +249 -17
  10. package/lib/client.js +62 -72
  11. package/lib/client.js.map +1 -1
  12. package/lib/config.js +1 -0
  13. package/lib/faces/admin.js +103 -63
  14. package/lib/faces/wire.js +3 -1
  15. package/lib/index.js +116 -22
  16. package/lib/origin-claim.js +4 -0
  17. package/lib/skill/SKILL.md +117 -117
  18. package/lib/skill/references/collaboration.md +428 -428
  19. package/lib/skill/references/discovery.md +78 -78
  20. package/lib/skill/references/intake.md +107 -107
  21. package/lib/skill/references/membership.md +73 -73
  22. package/lib/skill/references/pitfalls.md +51 -51
  23. package/lib/skill/references/router.md +96 -96
  24. package/lib/skill/references/routing.md +65 -65
  25. package/lib/types/canvas-store.d.ts +48 -1
  26. package/lib/types/config.d.ts +2 -0
  27. package/lib/types/faces/admin.d.ts +2 -0
  28. package/lib/types/origin-claim.d.ts +2 -0
  29. package/nexus-stage/package.json +21 -21
  30. package/nexus-stage/scripts/mockhost.py +261 -261
  31. package/nexus-stage/src/canvas-ops.ts +191 -191
  32. package/nexus-stage/src/canvas-wire.ts +164 -164
  33. package/nexus-stage/src/cli-home-picker.ts +42 -42
  34. package/nexus-stage/src/fault.ts +56 -56
  35. package/nexus-stage/src/federation-overlay.ts +103 -103
  36. package/nexus-stage/src/federation.ts +241 -241
  37. package/nexus-stage/src/layout-doc.ts +145 -145
  38. package/nexus-stage/src/main.ts +520 -513
  39. package/nexus-stage/src/planning-card-text.ts +73 -73
  40. package/nexus-stage/src/planning-card.ts +63 -63
  41. package/nexus-stage/src/planning-edges.ts +26 -26
  42. package/nexus-stage/src/planning-fit.ts +45 -45
  43. package/nexus-stage/src/planning-frame-hue.ts +13 -13
  44. package/nexus-stage/src/planning-legend.ts +39 -39
  45. package/nexus-stage/src/planning-member-handles.ts +61 -61
  46. package/nexus-stage/src/planning-menus.ts +422 -422
  47. package/nexus-stage/src/planning-mirror.ts +75 -75
  48. package/nexus-stage/src/planning-nodelist.ts +294 -294
  49. package/nexus-stage/src/planning-overlap.ts +159 -159
  50. package/nexus-stage/src/planning-reachability.ts +28 -28
  51. package/nexus-stage/src/planning-relayout.ts +121 -121
  52. package/nexus-stage/src/planning-roster.ts +15 -15
  53. package/nexus-stage/src/planning-search.ts +168 -168
  54. package/nexus-stage/src/planning-types.ts +115 -115
  55. package/nexus-stage/src/planning-undo.ts +68 -68
  56. package/nexus-stage/src/planning-view.ts +1499 -1499
  57. package/nexus-stage/src/planning.css +340 -340
  58. package/nexus-stage/src/seat-name-editor.ts +31 -31
  59. package/nexus-stage/src/session-drag.ts +64 -64
  60. package/nexus-stage/src/viewport.ts +106 -106
  61. package/nexus-stage/src/wb-chat.ts +684 -684
  62. package/nexus-stage/src/wb-directory.ts +237 -237
  63. package/nexus-stage/src/wb-ledger.ts +279 -279
  64. package/nexus-stage/src/wb-names.ts +43 -43
  65. package/nexus-stage/src/wb-rail.ts +147 -147
  66. package/nexus-stage/src/workbench.css +388 -388
  67. package/nexus-stage/src/workbench.ts +1294 -1272
  68. package/nexus-stage/src/world.ts +509 -509
  69. package/nexus-stage/tsconfig.json +24 -24
  70. package/nexus-stage/vite.config.ts +15 -15
  71. package/package.json +1 -1
  72. package/assets/nexusDist/assets/index-NkNSeIx6.js +0 -9
@@ -1,43 +1,43 @@
1
- /**
2
- * Readable names for routing team ids, shared by the activity and plan
3
- * panes and the 台账 tab (review 2026-10-27: rows read bare `dsh/1111…` ids;
4
- * the ledger kept doing so after #72 fixed the other two panes).
5
- * Names are attacker-shaped data: textContent only.
6
- * @module nexus-stage/wb-names
7
- */
8
- import type { StateBody } from './workbench'
9
- import { displayName } from './stage-name'
10
-
11
- /** The name behind a team id — a session, a remote node or a canvas team —
12
- * or undefined when none matches. An empty name counts as no match:
13
- * displayName's `??` keeps '', and a peer can publish one. `remote` marks a
14
- * name the PEER chose — it can collide with a local session's, so callers
15
- * must show where it is from. */
16
- export function teamName(state: StateBody, team: string): { name: string; remote: boolean } | undefined {
17
- const named = (name: string | undefined, remote: boolean) => name !== undefined && name.trim() !== '' ? { name, remote } : undefined
18
- const s = (state.sessions ?? []).find(r => r.team === team)
19
- if (s !== undefined) return named(displayName(s), false)
20
- const r = (state.remote ?? []).find(x => x.team === team)
21
- if (r !== undefined) return named(displayName(r), true)
22
- return named((state.canvas?.teams ?? []).find(t => t.team === team)?.name, false)
23
- }
24
-
25
- /** A name for plain text: a peer-published one says it is remote. */
26
- export function teamLabel(state: StateBody, team: string): string {
27
- const n = teamName(state, team)
28
- return n === undefined ? team : n.remote ? `${n.name}(远端)` : n.name
29
- }
30
-
31
- /** Fill `target` with `prefix` + the name (the id rides the tooltip; an
32
- * unknown team stays its id); a peer-published name gets a visible 远端 chip. */
33
- export function nameInto(target: HTMLElement, state: StateBody, team: string, prefix = ''): void {
34
- const n = teamName(state, team)
35
- target.textContent = `${prefix}${n?.name ?? team}`
36
- target.title = team
37
- if (n?.remote === true) {
38
- const chip = target.appendChild(document.createElement('span'))
39
- chip.className = 'wb-row-remote'
40
- chip.textContent = '远端'
41
- chip.title = '名字由对端自行发布'
42
- }
43
- }
1
+ /**
2
+ * Readable names for routing team ids, shared by the activity and plan
3
+ * panes and the 台账 tab (review 2026-10-27: rows read bare `dsh/1111…` ids;
4
+ * the ledger kept doing so after #72 fixed the other two panes).
5
+ * Names are attacker-shaped data: textContent only.
6
+ * @module nexus-stage/wb-names
7
+ */
8
+ import type { StateBody } from './workbench'
9
+ import { displayName } from './stage-name'
10
+
11
+ /** The name behind a team id — a session, a remote node or a canvas team —
12
+ * or undefined when none matches. An empty name counts as no match:
13
+ * displayName's `??` keeps '', and a peer can publish one. `remote` marks a
14
+ * name the PEER chose — it can collide with a local session's, so callers
15
+ * must show where it is from. */
16
+ export function teamName(state: StateBody, team: string): { name: string; remote: boolean } | undefined {
17
+ const named = (name: string | undefined, remote: boolean) => name !== undefined && name.trim() !== '' ? { name, remote } : undefined
18
+ const s = (state.sessions ?? []).find(r => r.team === team)
19
+ if (s !== undefined) return named(displayName(s), false)
20
+ const r = (state.remote ?? []).find(x => x.team === team)
21
+ if (r !== undefined) return named(displayName(r), true)
22
+ return named((state.canvas?.teams ?? []).find(t => t.team === team)?.name, false)
23
+ }
24
+
25
+ /** A name for plain text: a peer-published one says it is remote. */
26
+ export function teamLabel(state: StateBody, team: string): string {
27
+ const n = teamName(state, team)
28
+ return n === undefined ? team : n.remote ? `${n.name}(远端)` : n.name
29
+ }
30
+
31
+ /** Fill `target` with `prefix` + the name (the id rides the tooltip; an
32
+ * unknown team stays its id); a peer-published name gets a visible 远端 chip. */
33
+ export function nameInto(target: HTMLElement, state: StateBody, team: string, prefix = ''): void {
34
+ const n = teamName(state, team)
35
+ target.textContent = `${prefix}${n?.name ?? team}`
36
+ target.title = team
37
+ if (n?.remote === true) {
38
+ const chip = target.appendChild(document.createElement('span'))
39
+ chip.className = 'wb-row-remote'
40
+ chip.textContent = '远端'
41
+ chip.title = '名字由对端自行发布'
42
+ }
43
+ }
@@ -1,147 +1,147 @@
1
- /**
2
- * The workbench's left rail as tabs (2026-10-23 rewrite): one tab per pane
3
- * — 目录 · 主机 · 台账 · 活动 · 规划 — each panel full-height with its own
4
- * scroll, replacing the single accordion scroll where the host rail sat
5
- * last and the ledger pushed everything below the fold.
6
- *
7
- * WAI-ARIA tabs: role=tablist / tab / tabpanel, roving tabindex, ←/→ and
8
- * Home/End move between tabs and activate them. Badges carry each pane's
9
- * count, colored only when there is something to act on (danger / warn).
10
- * The selected tab is a per-viewer convenience kept in localStorage (every
11
- * access guarded; the rail works the same without it).
12
- * @module nexus-stage/wb-rail
13
- */
14
-
15
- export type RailTone = 'danger' | 'warn' | 'accent'
16
-
17
- export interface RailTabDef<K extends string> {
18
- readonly key: K
19
- readonly label: string
20
- }
21
-
22
- export interface RailTabs<K extends string> {
23
- readonly root: HTMLElement
24
- /** The panel a pane mounts into for tab `key`. */
25
- panel(key: K): HTMLElement
26
- select(key: K, opts?: { focus?: boolean }): void
27
- selected(): K
28
- setBadge(key: K, text: string, tone?: RailTone): void
29
- /** Hide a tab (data mode moves its pane to the stage); a hidden selected tab falls back to the first visible one. */
30
- setHidden(key: K, hidden: boolean): void
31
- }
32
-
33
- const STORE_KEY = 'dsh-a2a.rail.tab'
34
-
35
- function readStored(): string | null {
36
- try {
37
- return window.localStorage.getItem(STORE_KEY)
38
- } catch {
39
- return null
40
- }
41
- }
42
-
43
- function writeStored(key: string): void {
44
- try {
45
- window.localStorage.setItem(STORE_KEY, key)
46
- } catch { /* per-viewer convenience only */ }
47
- }
48
-
49
- export function createRailTabs<K extends string>(defs: ReadonlyArray<RailTabDef<K>>, opts: { onChange?(key: K): void } = {}): RailTabs<K> {
50
- const root = document.createElement('aside')
51
- root.className = 'wb-rail'
52
- const list = document.createElement('div')
53
- list.className = 'wb-tabs'
54
- list.setAttribute('role', 'tablist')
55
- list.setAttribute('aria-label', '工作台侧栏')
56
- const panels = document.createElement('div')
57
- panels.className = 'wb-tabpanels'
58
- root.append(list, panels)
59
-
60
- const tabs = new Map<K, HTMLButtonElement>()
61
- const panelEls = new Map<K, HTMLElement>()
62
- const badges = new Map<K, HTMLElement>()
63
- const hidden = new Set<K>()
64
- for (const def of defs) {
65
- const tab = document.createElement('button')
66
- tab.type = 'button'
67
- tab.className = 'wb-tab'
68
- tab.id = `wb-tab-${def.key}`
69
- tab.dataset.sec = def.key
70
- tab.setAttribute('role', 'tab')
71
- tab.setAttribute('aria-controls', `wb-panel-${def.key}`)
72
- const label = document.createElement('span')
73
- label.className = 'wb-tab-label'
74
- label.textContent = def.label
75
- const badge = document.createElement('span')
76
- badge.className = 'wb-tab-badge'
77
- tab.append(label, badge)
78
- tab.addEventListener('click', () => select(def.key))
79
- list.appendChild(tab)
80
- const panel = document.createElement('section')
81
- panel.className = 'wb-tabpanel'
82
- panel.id = `wb-panel-${def.key}`
83
- panel.dataset.sec = def.key
84
- panel.setAttribute('role', 'tabpanel')
85
- panel.setAttribute('aria-labelledby', tab.id)
86
- panel.tabIndex = -1
87
- panels.appendChild(panel)
88
- tabs.set(def.key, tab)
89
- panelEls.set(def.key, panel)
90
- badges.set(def.key, badge)
91
- }
92
-
93
- const visible = (): K[] => defs.map(d => d.key).filter(k => !hidden.has(k))
94
- const stored = readStored()
95
- let current: K = defs.find(d => d.key === stored)?.key ?? defs[0]!.key
96
-
97
- list.addEventListener('keydown', ev => {
98
- const keys = visible()
99
- const at = keys.indexOf(current)
100
- let next: K | undefined
101
- if (ev.key === 'ArrowRight') next = keys[(at + 1) % keys.length]
102
- else if (ev.key === 'ArrowLeft') next = keys[(at - 1 + keys.length) % keys.length]
103
- else if (ev.key === 'Home') next = keys[0]
104
- else if (ev.key === 'End') next = keys[keys.length - 1]
105
- if (next === undefined) return
106
- ev.preventDefault()
107
- select(next, { focus: true })
108
- })
109
-
110
- function paint(): void {
111
- for (const def of defs) {
112
- const on = def.key === current
113
- const tab = tabs.get(def.key)!
114
- tab.setAttribute('aria-selected', String(on))
115
- tab.tabIndex = on ? 0 : -1
116
- tab.classList.toggle('is-active', on)
117
- tab.hidden = hidden.has(def.key)
118
- panelEls.get(def.key)!.hidden = !on
119
- }
120
- }
121
-
122
- function select(key: K, o: { focus?: boolean } = {}): void {
123
- if (hidden.has(key)) return
124
- const changed = key !== current
125
- current = key
126
- writeStored(key)
127
- paint()
128
- if (o.focus === true) tabs.get(key)!.focus()
129
- if (changed) opts.onChange?.(key)
130
- }
131
-
132
- function setBadge(key: K, text: string, tone?: RailTone): void {
133
- const b = badges.get(key)!
134
- b.textContent = text
135
- b.className = `wb-tab-badge${tone !== undefined ? ` is-${tone}` : ''}`
136
- }
137
-
138
- function setHidden(key: K, h: boolean): void {
139
- if (h) hidden.add(key)
140
- else hidden.delete(key)
141
- if (hidden.has(current)) current = visible()[0] ?? defs[0]!.key
142
- paint()
143
- }
144
-
145
- paint()
146
- return { root, panel: (k) => panelEls.get(k)!, select, selected: () => current, setBadge, setHidden }
147
- }
1
+ /**
2
+ * The workbench's left rail as tabs (2026-10-23 rewrite): one tab per pane
3
+ * — 目录 · 主机 · 台账 · 活动 · 规划 — each panel full-height with its own
4
+ * scroll, replacing the single accordion scroll where the host rail sat
5
+ * last and the ledger pushed everything below the fold.
6
+ *
7
+ * WAI-ARIA tabs: role=tablist / tab / tabpanel, roving tabindex, ←/→ and
8
+ * Home/End move between tabs and activate them. Badges carry each pane's
9
+ * count, colored only when there is something to act on (danger / warn).
10
+ * The selected tab is a per-viewer convenience kept in localStorage (every
11
+ * access guarded; the rail works the same without it).
12
+ * @module nexus-stage/wb-rail
13
+ */
14
+
15
+ export type RailTone = 'danger' | 'warn' | 'accent'
16
+
17
+ export interface RailTabDef<K extends string> {
18
+ readonly key: K
19
+ readonly label: string
20
+ }
21
+
22
+ export interface RailTabs<K extends string> {
23
+ readonly root: HTMLElement
24
+ /** The panel a pane mounts into for tab `key`. */
25
+ panel(key: K): HTMLElement
26
+ select(key: K, opts?: { focus?: boolean }): void
27
+ selected(): K
28
+ setBadge(key: K, text: string, tone?: RailTone): void
29
+ /** Hide a tab (data mode moves its pane to the stage); a hidden selected tab falls back to the first visible one. */
30
+ setHidden(key: K, hidden: boolean): void
31
+ }
32
+
33
+ const STORE_KEY = 'dsh-a2a.rail.tab'
34
+
35
+ function readStored(): string | null {
36
+ try {
37
+ return window.localStorage.getItem(STORE_KEY)
38
+ } catch {
39
+ return null
40
+ }
41
+ }
42
+
43
+ function writeStored(key: string): void {
44
+ try {
45
+ window.localStorage.setItem(STORE_KEY, key)
46
+ } catch { /* per-viewer convenience only */ }
47
+ }
48
+
49
+ export function createRailTabs<K extends string>(defs: ReadonlyArray<RailTabDef<K>>, opts: { onChange?(key: K): void } = {}): RailTabs<K> {
50
+ const root = document.createElement('aside')
51
+ root.className = 'wb-rail'
52
+ const list = document.createElement('div')
53
+ list.className = 'wb-tabs'
54
+ list.setAttribute('role', 'tablist')
55
+ list.setAttribute('aria-label', '工作台侧栏')
56
+ const panels = document.createElement('div')
57
+ panels.className = 'wb-tabpanels'
58
+ root.append(list, panels)
59
+
60
+ const tabs = new Map<K, HTMLButtonElement>()
61
+ const panelEls = new Map<K, HTMLElement>()
62
+ const badges = new Map<K, HTMLElement>()
63
+ const hidden = new Set<K>()
64
+ for (const def of defs) {
65
+ const tab = document.createElement('button')
66
+ tab.type = 'button'
67
+ tab.className = 'wb-tab'
68
+ tab.id = `wb-tab-${def.key}`
69
+ tab.dataset.sec = def.key
70
+ tab.setAttribute('role', 'tab')
71
+ tab.setAttribute('aria-controls', `wb-panel-${def.key}`)
72
+ const label = document.createElement('span')
73
+ label.className = 'wb-tab-label'
74
+ label.textContent = def.label
75
+ const badge = document.createElement('span')
76
+ badge.className = 'wb-tab-badge'
77
+ tab.append(label, badge)
78
+ tab.addEventListener('click', () => select(def.key))
79
+ list.appendChild(tab)
80
+ const panel = document.createElement('section')
81
+ panel.className = 'wb-tabpanel'
82
+ panel.id = `wb-panel-${def.key}`
83
+ panel.dataset.sec = def.key
84
+ panel.setAttribute('role', 'tabpanel')
85
+ panel.setAttribute('aria-labelledby', tab.id)
86
+ panel.tabIndex = -1
87
+ panels.appendChild(panel)
88
+ tabs.set(def.key, tab)
89
+ panelEls.set(def.key, panel)
90
+ badges.set(def.key, badge)
91
+ }
92
+
93
+ const visible = (): K[] => defs.map(d => d.key).filter(k => !hidden.has(k))
94
+ const stored = readStored()
95
+ let current: K = defs.find(d => d.key === stored)?.key ?? defs[0]!.key
96
+
97
+ list.addEventListener('keydown', ev => {
98
+ const keys = visible()
99
+ const at = keys.indexOf(current)
100
+ let next: K | undefined
101
+ if (ev.key === 'ArrowRight') next = keys[(at + 1) % keys.length]
102
+ else if (ev.key === 'ArrowLeft') next = keys[(at - 1 + keys.length) % keys.length]
103
+ else if (ev.key === 'Home') next = keys[0]
104
+ else if (ev.key === 'End') next = keys[keys.length - 1]
105
+ if (next === undefined) return
106
+ ev.preventDefault()
107
+ select(next, { focus: true })
108
+ })
109
+
110
+ function paint(): void {
111
+ for (const def of defs) {
112
+ const on = def.key === current
113
+ const tab = tabs.get(def.key)!
114
+ tab.setAttribute('aria-selected', String(on))
115
+ tab.tabIndex = on ? 0 : -1
116
+ tab.classList.toggle('is-active', on)
117
+ tab.hidden = hidden.has(def.key)
118
+ panelEls.get(def.key)!.hidden = !on
119
+ }
120
+ }
121
+
122
+ function select(key: K, o: { focus?: boolean } = {}): void {
123
+ if (hidden.has(key)) return
124
+ const changed = key !== current
125
+ current = key
126
+ writeStored(key)
127
+ paint()
128
+ if (o.focus === true) tabs.get(key)!.focus()
129
+ if (changed) opts.onChange?.(key)
130
+ }
131
+
132
+ function setBadge(key: K, text: string, tone?: RailTone): void {
133
+ const b = badges.get(key)!
134
+ b.textContent = text
135
+ b.className = `wb-tab-badge${tone !== undefined ? ` is-${tone}` : ''}`
136
+ }
137
+
138
+ function setHidden(key: K, h: boolean): void {
139
+ if (h) hidden.add(key)
140
+ else hidden.delete(key)
141
+ if (hidden.has(current)) current = visible()[0] ?? defs[0]!.key
142
+ paint()
143
+ }
144
+
145
+ paint()
146
+ return { root, panel: (k) => panelEls.get(k)!, select, selected: () => current, setBadge, setHidden }
147
+ }