@nelsonlongxiang/dsh-open-a2a-net 0.6.40 → 0.6.42

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 (76) hide show
  1. package/README.md +2 -1
  2. package/README_zh.md +2 -1
  3. package/assets/stageDist/assets/index-Bj7S2pA1.css +1 -1
  4. package/assets/stageDist/assets/index-C-28k_o5.js +974 -974
  5. package/assets/stageDist/index.html +12 -12
  6. package/lib/a2a-client.js +3 -2
  7. package/lib/client.js +64 -64
  8. package/lib/client.js.map +1 -1
  9. package/lib/config.js +1 -0
  10. package/lib/faces/files.js +2 -2
  11. package/lib/faces/session-log.js +3 -3
  12. package/lib/faces/wire.js +11 -16
  13. package/lib/index.js +102 -18
  14. package/lib/link-keys.js +29 -0
  15. package/lib/origin-claim.js +4 -0
  16. package/lib/skill/SKILL.md +117 -117
  17. package/lib/skill/references/collaboration.md +428 -428
  18. package/lib/skill/references/discovery.md +78 -78
  19. package/lib/skill/references/intake.md +107 -107
  20. package/lib/skill/references/membership.md +73 -73
  21. package/lib/skill/references/pitfalls.md +51 -51
  22. package/lib/skill/references/router.md +96 -96
  23. package/lib/skill/references/routing.md +65 -65
  24. package/lib/skill/references/setup.md +5 -1
  25. package/lib/tools/files.js +3 -1
  26. package/lib/types/a2a-client.d.ts +3 -1
  27. package/lib/types/config.d.ts +6 -0
  28. package/lib/types/faces/files.d.ts +2 -1
  29. package/lib/types/faces/session-log.d.ts +2 -0
  30. package/lib/types/faces/wire.d.ts +2 -1
  31. package/lib/types/link-keys.d.ts +13 -0
  32. package/lib/types/origin-claim.d.ts +2 -0
  33. package/lib/types/tools/files.d.ts +1 -1
  34. package/nexus-stage/package.json +21 -21
  35. package/nexus-stage/scripts/mockhost.py +261 -261
  36. package/nexus-stage/src/canvas-ops.ts +191 -191
  37. package/nexus-stage/src/canvas-wire.ts +164 -164
  38. package/nexus-stage/src/cli-home-picker.ts +42 -42
  39. package/nexus-stage/src/fault.ts +56 -56
  40. package/nexus-stage/src/federation-overlay.ts +103 -103
  41. package/nexus-stage/src/federation.ts +241 -241
  42. package/nexus-stage/src/layout-doc.ts +145 -145
  43. package/nexus-stage/src/main.ts +513 -513
  44. package/nexus-stage/src/planning-card-text.ts +73 -73
  45. package/nexus-stage/src/planning-card.ts +63 -63
  46. package/nexus-stage/src/planning-edges.ts +26 -26
  47. package/nexus-stage/src/planning-fit.ts +45 -45
  48. package/nexus-stage/src/planning-frame-hue.ts +13 -13
  49. package/nexus-stage/src/planning-legend.ts +39 -39
  50. package/nexus-stage/src/planning-member-handles.ts +61 -61
  51. package/nexus-stage/src/planning-menus.ts +422 -422
  52. package/nexus-stage/src/planning-mirror.ts +75 -75
  53. package/nexus-stage/src/planning-nodelist.ts +294 -294
  54. package/nexus-stage/src/planning-overlap.ts +159 -159
  55. package/nexus-stage/src/planning-reachability.ts +28 -28
  56. package/nexus-stage/src/planning-relayout.ts +121 -121
  57. package/nexus-stage/src/planning-roster.ts +15 -15
  58. package/nexus-stage/src/planning-search.ts +168 -168
  59. package/nexus-stage/src/planning-types.ts +115 -115
  60. package/nexus-stage/src/planning-undo.ts +68 -68
  61. package/nexus-stage/src/planning-view.ts +1499 -1499
  62. package/nexus-stage/src/planning.css +340 -340
  63. package/nexus-stage/src/seat-name-editor.ts +31 -31
  64. package/nexus-stage/src/session-drag.ts +64 -64
  65. package/nexus-stage/src/viewport.ts +106 -106
  66. package/nexus-stage/src/wb-chat.ts +684 -684
  67. package/nexus-stage/src/wb-directory.ts +237 -237
  68. package/nexus-stage/src/wb-ledger.ts +279 -279
  69. package/nexus-stage/src/wb-names.ts +43 -43
  70. package/nexus-stage/src/wb-rail.ts +147 -147
  71. package/nexus-stage/src/workbench.css +388 -388
  72. package/nexus-stage/src/workbench.ts +1272 -1272
  73. package/nexus-stage/src/world.ts +509 -509
  74. package/nexus-stage/tsconfig.json +24 -24
  75. package/nexus-stage/vite.config.ts +15 -15
  76. package/package.json +1 -1
@@ -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
+ }