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