@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.
- package/README.md +2 -1
- package/README_zh.md +2 -1
- package/assets/nexusDist/assets/index-CaA76j0F.js +9 -0
- package/assets/nexusDist/index.html +1 -1
- package/assets/stageDist/assets/index-Bj7S2pA1.css +1 -1
- package/assets/stageDist/assets/index-C-28k_o5.js +974 -974
- package/assets/stageDist/index.html +12 -12
- package/cli/a2a.mjs +24 -4
- package/lib/canvas-store.js +249 -17
- package/lib/client.js +62 -72
- package/lib/client.js.map +1 -1
- package/lib/config.js +1 -0
- package/lib/faces/admin.js +103 -63
- package/lib/faces/wire.js +3 -1
- package/lib/index.js +116 -22
- package/lib/origin-claim.js +4 -0
- package/lib/skill/SKILL.md +117 -117
- package/lib/skill/references/collaboration.md +428 -428
- package/lib/skill/references/discovery.md +78 -78
- package/lib/skill/references/intake.md +107 -107
- package/lib/skill/references/membership.md +73 -73
- package/lib/skill/references/pitfalls.md +51 -51
- package/lib/skill/references/router.md +96 -96
- package/lib/skill/references/routing.md +65 -65
- package/lib/types/canvas-store.d.ts +48 -1
- package/lib/types/config.d.ts +2 -0
- package/lib/types/faces/admin.d.ts +2 -0
- package/lib/types/origin-claim.d.ts +2 -0
- package/nexus-stage/package.json +21 -21
- package/nexus-stage/scripts/mockhost.py +261 -261
- package/nexus-stage/src/canvas-ops.ts +191 -191
- package/nexus-stage/src/canvas-wire.ts +164 -164
- package/nexus-stage/src/cli-home-picker.ts +42 -42
- package/nexus-stage/src/fault.ts +56 -56
- package/nexus-stage/src/federation-overlay.ts +103 -103
- package/nexus-stage/src/federation.ts +241 -241
- package/nexus-stage/src/layout-doc.ts +145 -145
- package/nexus-stage/src/main.ts +520 -513
- package/nexus-stage/src/planning-card-text.ts +73 -73
- package/nexus-stage/src/planning-card.ts +63 -63
- package/nexus-stage/src/planning-edges.ts +26 -26
- package/nexus-stage/src/planning-fit.ts +45 -45
- package/nexus-stage/src/planning-frame-hue.ts +13 -13
- package/nexus-stage/src/planning-legend.ts +39 -39
- package/nexus-stage/src/planning-member-handles.ts +61 -61
- package/nexus-stage/src/planning-menus.ts +422 -422
- package/nexus-stage/src/planning-mirror.ts +75 -75
- package/nexus-stage/src/planning-nodelist.ts +294 -294
- package/nexus-stage/src/planning-overlap.ts +159 -159
- package/nexus-stage/src/planning-reachability.ts +28 -28
- package/nexus-stage/src/planning-relayout.ts +121 -121
- package/nexus-stage/src/planning-roster.ts +15 -15
- package/nexus-stage/src/planning-search.ts +168 -168
- package/nexus-stage/src/planning-types.ts +115 -115
- package/nexus-stage/src/planning-undo.ts +68 -68
- package/nexus-stage/src/planning-view.ts +1499 -1499
- package/nexus-stage/src/planning.css +340 -340
- package/nexus-stage/src/seat-name-editor.ts +31 -31
- package/nexus-stage/src/session-drag.ts +64 -64
- package/nexus-stage/src/viewport.ts +106 -106
- package/nexus-stage/src/wb-chat.ts +684 -684
- package/nexus-stage/src/wb-directory.ts +237 -237
- package/nexus-stage/src/wb-ledger.ts +279 -279
- package/nexus-stage/src/wb-names.ts +43 -43
- package/nexus-stage/src/wb-rail.ts +147 -147
- package/nexus-stage/src/workbench.css +388 -388
- package/nexus-stage/src/workbench.ts +1294 -1272
- package/nexus-stage/src/world.ts +509 -509
- package/nexus-stage/tsconfig.json +24 -24
- package/nexus-stage/vite.config.ts +15 -15
- package/package.json +1 -1
- package/assets/nexusDist/assets/index-NkNSeIx6.js +0 -9
|
@@ -1,145 +1,145 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Client-side mirror of the host layout contract (src/layout-store.ts).
|
|
3
|
-
* The host module imports node:fs, so the stage cannot share its types -
|
|
4
|
-
* this file redeclares the v1 document shape and reimplements the exact
|
|
5
|
-
* clamp discipline. Parity is not optional: the save loop adopts the
|
|
6
|
-
* host's normalized response, and a mirror that clamped differently from
|
|
7
|
-
* the host would make every save look like an external edit and keep the
|
|
8
|
-
* save lamp pending forever. The clamp vectors in tests/planning-world.spec.ts
|
|
9
|
-
* pin both sides to the same answers.
|
|
10
|
-
*
|
|
11
|
-
* Zero dependencies, no DOM - unit-testable straight from the root suite.
|
|
12
|
-
* @module nexus-stage/layout-doc
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
/** One draggable point in world space. */
|
|
16
|
-
export interface LayoutPoint { readonly x: number; readonly y: number }
|
|
17
|
-
|
|
18
|
-
/** One team-frame rectangle in world space. */
|
|
19
|
-
export interface LayoutRect extends LayoutPoint { readonly w: number; readonly h: number }
|
|
20
|
-
|
|
21
|
-
/** The viewport transform (world point at the top-left corner, plus zoom). */
|
|
22
|
-
export interface LayoutViewport extends LayoutPoint { readonly scale: number }
|
|
23
|
-
|
|
24
|
-
/** The whole persisted document (v1). */
|
|
25
|
-
export interface LayoutDoc {
|
|
26
|
-
readonly version: 1
|
|
27
|
-
readonly viewport: LayoutViewport
|
|
28
|
-
readonly nodes: Readonly<Record<string, LayoutPoint>>
|
|
29
|
-
readonly frames: Readonly<Record<string, LayoutRect>>
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/** World-coordinate magnitude bound: values beyond are clamped, never trusted. */
|
|
33
|
-
export const COORD_LIMIT = 1_000_000
|
|
34
|
-
/** Zoom bounds, matching the page's wheel clamps. */
|
|
35
|
-
export const SCALE_MIN = 0.25
|
|
36
|
-
export const SCALE_MAX = 3
|
|
37
|
-
/** Document shape caps: a layout taxonomy, not a database. */
|
|
38
|
-
export const LAYOUT_NODE_CAP = 256
|
|
39
|
-
export const LAYOUT_FRAME_CAP = 96
|
|
40
|
-
|
|
41
|
-
function clampCoord(v: unknown): number | undefined {
|
|
42
|
-
const n = typeof v === 'number' ? v : Number.NaN
|
|
43
|
-
if (!Number.isFinite(n)) return undefined
|
|
44
|
-
return Math.max(-COORD_LIMIT, Math.min(COORD_LIMIT, Math.round(n)))
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function clampPoint(raw: unknown): LayoutPoint | undefined {
|
|
48
|
-
if (raw === null || typeof raw !== 'object') return undefined
|
|
49
|
-
const rec = raw as Record<string, unknown>
|
|
50
|
-
const x = clampCoord(rec.x)
|
|
51
|
-
const y = clampCoord(rec.y)
|
|
52
|
-
return x === undefined || y === undefined ? undefined : { x, y }
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function clampRect(raw: unknown): LayoutRect | undefined {
|
|
56
|
-
const point = clampPoint(raw)
|
|
57
|
-
if (point === undefined) return undefined
|
|
58
|
-
const rec = raw as Record<string, unknown>
|
|
59
|
-
const w = clampCoord(rec.w)
|
|
60
|
-
const h = clampCoord(rec.h)
|
|
61
|
-
if (w === undefined || h === undefined || w <= 0 || h <= 0) return undefined
|
|
62
|
-
return { ...point, w: Math.min(w, COORD_LIMIT), h: Math.min(h, COORD_LIMIT) }
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Normalize an untrusted layout document exactly as the host does:
|
|
67
|
-
* version!==1 rejects the whole doc; non-finite coordinates drop the
|
|
68
|
-
* point; coordinates round and clamp to ±COORD_LIMIT; scale clamps to
|
|
69
|
-
* [SCALE_MIN, SCALE_MAX]; node keys cap at 128 chars; canvas frame names cap at 40,
|
|
70
|
-
* roster:<name> reserves seven extra characters; rects need w>0 and h>0; caps are
|
|
71
|
-
* first-wins in insertion order - entries beyond are silently dropped,
|
|
72
|
-
* never refused (an overflow renders, it just does not persist).
|
|
73
|
-
*/
|
|
74
|
-
const validFrame = (name: string): boolean => name !== '' && !name.includes('/') && (name.startsWith('roster:') ? name.length > 7 && name.length <= 47 : name.length <= 40)
|
|
75
|
-
|
|
76
|
-
export function clampDoc(raw: unknown): LayoutDoc | undefined {
|
|
77
|
-
if (raw === null || typeof raw !== 'object') return undefined
|
|
78
|
-
const rec = raw as Record<string, unknown>
|
|
79
|
-
if (rec.version !== 1) return undefined
|
|
80
|
-
const vpRaw = rec.viewport
|
|
81
|
-
if (vpRaw === null || typeof vpRaw !== 'object') return undefined
|
|
82
|
-
const vp = vpRaw as Record<string, unknown>
|
|
83
|
-
const vx = clampCoord(vp.x)
|
|
84
|
-
const vy = clampCoord(vp.y)
|
|
85
|
-
const vsRaw = vp.scale
|
|
86
|
-
const vsNum = typeof vsRaw === 'number' ? vsRaw : Number.NaN
|
|
87
|
-
if (vx === undefined || vy === undefined || !Number.isFinite(vsNum)) return undefined
|
|
88
|
-
const scale = Math.max(SCALE_MIN, Math.min(SCALE_MAX, vsNum))
|
|
89
|
-
const nodes: Record<string, LayoutPoint> = {}
|
|
90
|
-
if (rec.nodes !== null && typeof rec.nodes === 'object') {
|
|
91
|
-
for (const [id, point] of Object.entries(rec.nodes as Record<string, unknown>)) {
|
|
92
|
-
if (typeof id !== 'string' || id === '' || id.length > 128) continue
|
|
93
|
-
const p = clampPoint(point)
|
|
94
|
-
if (p !== undefined) nodes[id] = p
|
|
95
|
-
if (Object.keys(nodes).length >= LAYOUT_NODE_CAP) break
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
const frames: Record<string, LayoutRect> = {}
|
|
99
|
-
if (rec.frames !== null && typeof rec.frames === 'object') {
|
|
100
|
-
for (const [name, rect] of Object.entries(rec.frames as Record<string, unknown>)) {
|
|
101
|
-
if (!validFrame(name)) continue
|
|
102
|
-
const r = clampRect(rect)
|
|
103
|
-
if (r !== undefined) frames[name] = r
|
|
104
|
-
if (Object.keys(frames).length >= LAYOUT_FRAME_CAP) break
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
return { version: 1, viewport: { x: vx, y: vy, scale }, nodes, frames }
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* Build a save payload from trusted in-memory state. Pre-clamps with the
|
|
112
|
-
* same mirror discipline and truncates in roster insertion order, so the
|
|
113
|
-
* document we send is already the document the host will normalize to -
|
|
114
|
-
* the save response is then a fixpoint of our payload, which the save
|
|
115
|
-
* loop relies on to tell "our own save echoed back" from "someone else
|
|
116
|
-
* edited while the request was in flight".
|
|
117
|
-
*/
|
|
118
|
-
export function buildLayoutDoc(
|
|
119
|
-
viewport: LayoutViewport,
|
|
120
|
-
nodes: ReadonlyMap<string, LayoutPoint>,
|
|
121
|
-
frames: ReadonlyMap<string, LayoutRect>,
|
|
122
|
-
): LayoutDoc {
|
|
123
|
-
const clamp = (n: number): number => Math.max(-COORD_LIMIT, Math.min(COORD_LIMIT, Math.round(n)))
|
|
124
|
-
const docNodes: Record<string, LayoutPoint> = {}
|
|
125
|
-
for (const [id, p] of nodes) {
|
|
126
|
-
if (typeof id !== 'string' || id === '' || id.length > 128) continue
|
|
127
|
-
docNodes[id] = { x: clamp(p.x), y: clamp(p.y) }
|
|
128
|
-
if (Object.keys(docNodes).length >= LAYOUT_NODE_CAP) break
|
|
129
|
-
}
|
|
130
|
-
const docFrames: Record<string, LayoutRect> = {}
|
|
131
|
-
for (const [name, r] of frames) {
|
|
132
|
-
if (!validFrame(name)) continue
|
|
133
|
-
const w = clamp(r.w)
|
|
134
|
-
const h = clamp(r.h)
|
|
135
|
-
if (w <= 0 || h <= 0) continue
|
|
136
|
-
docFrames[name] = { x: clamp(r.x), y: clamp(r.y), w: Math.min(w, COORD_LIMIT), h: Math.min(h, COORD_LIMIT) }
|
|
137
|
-
if (Object.keys(docFrames).length >= LAYOUT_FRAME_CAP) break
|
|
138
|
-
}
|
|
139
|
-
return {
|
|
140
|
-
version: 1,
|
|
141
|
-
viewport: { x: clamp(viewport.x), y: clamp(viewport.y), scale: Math.max(SCALE_MIN, Math.min(SCALE_MAX, viewport.scale)) },
|
|
142
|
-
nodes: docNodes,
|
|
143
|
-
frames: docFrames,
|
|
144
|
-
}
|
|
145
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Client-side mirror of the host layout contract (src/layout-store.ts).
|
|
3
|
+
* The host module imports node:fs, so the stage cannot share its types -
|
|
4
|
+
* this file redeclares the v1 document shape and reimplements the exact
|
|
5
|
+
* clamp discipline. Parity is not optional: the save loop adopts the
|
|
6
|
+
* host's normalized response, and a mirror that clamped differently from
|
|
7
|
+
* the host would make every save look like an external edit and keep the
|
|
8
|
+
* save lamp pending forever. The clamp vectors in tests/planning-world.spec.ts
|
|
9
|
+
* pin both sides to the same answers.
|
|
10
|
+
*
|
|
11
|
+
* Zero dependencies, no DOM - unit-testable straight from the root suite.
|
|
12
|
+
* @module nexus-stage/layout-doc
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/** One draggable point in world space. */
|
|
16
|
+
export interface LayoutPoint { readonly x: number; readonly y: number }
|
|
17
|
+
|
|
18
|
+
/** One team-frame rectangle in world space. */
|
|
19
|
+
export interface LayoutRect extends LayoutPoint { readonly w: number; readonly h: number }
|
|
20
|
+
|
|
21
|
+
/** The viewport transform (world point at the top-left corner, plus zoom). */
|
|
22
|
+
export interface LayoutViewport extends LayoutPoint { readonly scale: number }
|
|
23
|
+
|
|
24
|
+
/** The whole persisted document (v1). */
|
|
25
|
+
export interface LayoutDoc {
|
|
26
|
+
readonly version: 1
|
|
27
|
+
readonly viewport: LayoutViewport
|
|
28
|
+
readonly nodes: Readonly<Record<string, LayoutPoint>>
|
|
29
|
+
readonly frames: Readonly<Record<string, LayoutRect>>
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** World-coordinate magnitude bound: values beyond are clamped, never trusted. */
|
|
33
|
+
export const COORD_LIMIT = 1_000_000
|
|
34
|
+
/** Zoom bounds, matching the page's wheel clamps. */
|
|
35
|
+
export const SCALE_MIN = 0.25
|
|
36
|
+
export const SCALE_MAX = 3
|
|
37
|
+
/** Document shape caps: a layout taxonomy, not a database. */
|
|
38
|
+
export const LAYOUT_NODE_CAP = 256
|
|
39
|
+
export const LAYOUT_FRAME_CAP = 96
|
|
40
|
+
|
|
41
|
+
function clampCoord(v: unknown): number | undefined {
|
|
42
|
+
const n = typeof v === 'number' ? v : Number.NaN
|
|
43
|
+
if (!Number.isFinite(n)) return undefined
|
|
44
|
+
return Math.max(-COORD_LIMIT, Math.min(COORD_LIMIT, Math.round(n)))
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function clampPoint(raw: unknown): LayoutPoint | undefined {
|
|
48
|
+
if (raw === null || typeof raw !== 'object') return undefined
|
|
49
|
+
const rec = raw as Record<string, unknown>
|
|
50
|
+
const x = clampCoord(rec.x)
|
|
51
|
+
const y = clampCoord(rec.y)
|
|
52
|
+
return x === undefined || y === undefined ? undefined : { x, y }
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function clampRect(raw: unknown): LayoutRect | undefined {
|
|
56
|
+
const point = clampPoint(raw)
|
|
57
|
+
if (point === undefined) return undefined
|
|
58
|
+
const rec = raw as Record<string, unknown>
|
|
59
|
+
const w = clampCoord(rec.w)
|
|
60
|
+
const h = clampCoord(rec.h)
|
|
61
|
+
if (w === undefined || h === undefined || w <= 0 || h <= 0) return undefined
|
|
62
|
+
return { ...point, w: Math.min(w, COORD_LIMIT), h: Math.min(h, COORD_LIMIT) }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Normalize an untrusted layout document exactly as the host does:
|
|
67
|
+
* version!==1 rejects the whole doc; non-finite coordinates drop the
|
|
68
|
+
* point; coordinates round and clamp to ±COORD_LIMIT; scale clamps to
|
|
69
|
+
* [SCALE_MIN, SCALE_MAX]; node keys cap at 128 chars; canvas frame names cap at 40,
|
|
70
|
+
* roster:<name> reserves seven extra characters; rects need w>0 and h>0; caps are
|
|
71
|
+
* first-wins in insertion order - entries beyond are silently dropped,
|
|
72
|
+
* never refused (an overflow renders, it just does not persist).
|
|
73
|
+
*/
|
|
74
|
+
const validFrame = (name: string): boolean => name !== '' && !name.includes('/') && (name.startsWith('roster:') ? name.length > 7 && name.length <= 47 : name.length <= 40)
|
|
75
|
+
|
|
76
|
+
export function clampDoc(raw: unknown): LayoutDoc | undefined {
|
|
77
|
+
if (raw === null || typeof raw !== 'object') return undefined
|
|
78
|
+
const rec = raw as Record<string, unknown>
|
|
79
|
+
if (rec.version !== 1) return undefined
|
|
80
|
+
const vpRaw = rec.viewport
|
|
81
|
+
if (vpRaw === null || typeof vpRaw !== 'object') return undefined
|
|
82
|
+
const vp = vpRaw as Record<string, unknown>
|
|
83
|
+
const vx = clampCoord(vp.x)
|
|
84
|
+
const vy = clampCoord(vp.y)
|
|
85
|
+
const vsRaw = vp.scale
|
|
86
|
+
const vsNum = typeof vsRaw === 'number' ? vsRaw : Number.NaN
|
|
87
|
+
if (vx === undefined || vy === undefined || !Number.isFinite(vsNum)) return undefined
|
|
88
|
+
const scale = Math.max(SCALE_MIN, Math.min(SCALE_MAX, vsNum))
|
|
89
|
+
const nodes: Record<string, LayoutPoint> = {}
|
|
90
|
+
if (rec.nodes !== null && typeof rec.nodes === 'object') {
|
|
91
|
+
for (const [id, point] of Object.entries(rec.nodes as Record<string, unknown>)) {
|
|
92
|
+
if (typeof id !== 'string' || id === '' || id.length > 128) continue
|
|
93
|
+
const p = clampPoint(point)
|
|
94
|
+
if (p !== undefined) nodes[id] = p
|
|
95
|
+
if (Object.keys(nodes).length >= LAYOUT_NODE_CAP) break
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const frames: Record<string, LayoutRect> = {}
|
|
99
|
+
if (rec.frames !== null && typeof rec.frames === 'object') {
|
|
100
|
+
for (const [name, rect] of Object.entries(rec.frames as Record<string, unknown>)) {
|
|
101
|
+
if (!validFrame(name)) continue
|
|
102
|
+
const r = clampRect(rect)
|
|
103
|
+
if (r !== undefined) frames[name] = r
|
|
104
|
+
if (Object.keys(frames).length >= LAYOUT_FRAME_CAP) break
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return { version: 1, viewport: { x: vx, y: vy, scale }, nodes, frames }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Build a save payload from trusted in-memory state. Pre-clamps with the
|
|
112
|
+
* same mirror discipline and truncates in roster insertion order, so the
|
|
113
|
+
* document we send is already the document the host will normalize to -
|
|
114
|
+
* the save response is then a fixpoint of our payload, which the save
|
|
115
|
+
* loop relies on to tell "our own save echoed back" from "someone else
|
|
116
|
+
* edited while the request was in flight".
|
|
117
|
+
*/
|
|
118
|
+
export function buildLayoutDoc(
|
|
119
|
+
viewport: LayoutViewport,
|
|
120
|
+
nodes: ReadonlyMap<string, LayoutPoint>,
|
|
121
|
+
frames: ReadonlyMap<string, LayoutRect>,
|
|
122
|
+
): LayoutDoc {
|
|
123
|
+
const clamp = (n: number): number => Math.max(-COORD_LIMIT, Math.min(COORD_LIMIT, Math.round(n)))
|
|
124
|
+
const docNodes: Record<string, LayoutPoint> = {}
|
|
125
|
+
for (const [id, p] of nodes) {
|
|
126
|
+
if (typeof id !== 'string' || id === '' || id.length > 128) continue
|
|
127
|
+
docNodes[id] = { x: clamp(p.x), y: clamp(p.y) }
|
|
128
|
+
if (Object.keys(docNodes).length >= LAYOUT_NODE_CAP) break
|
|
129
|
+
}
|
|
130
|
+
const docFrames: Record<string, LayoutRect> = {}
|
|
131
|
+
for (const [name, r] of frames) {
|
|
132
|
+
if (!validFrame(name)) continue
|
|
133
|
+
const w = clamp(r.w)
|
|
134
|
+
const h = clamp(r.h)
|
|
135
|
+
if (w <= 0 || h <= 0) continue
|
|
136
|
+
docFrames[name] = { x: clamp(r.x), y: clamp(r.y), w: Math.min(w, COORD_LIMIT), h: Math.min(h, COORD_LIMIT) }
|
|
137
|
+
if (Object.keys(docFrames).length >= LAYOUT_FRAME_CAP) break
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
version: 1,
|
|
141
|
+
viewport: { x: clamp(viewport.x), y: clamp(viewport.y), scale: Math.max(SCALE_MIN, Math.min(SCALE_MAX, viewport.scale)) },
|
|
142
|
+
nodes: docNodes,
|
|
143
|
+
frames: docFrames,
|
|
144
|
+
}
|
|
145
|
+
}
|