dsh-multi-chat 1.0.3 → 1.0.4
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 +287 -269
- package/README.zh.md +269 -233
- package/lib/client.js +66 -28
- package/lib/client.js.map +1 -1
- package/lib/index.js +211 -22
- package/lib/invariant.js +23 -0
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/lib/types/client/WallToggle.js +2 -2
- package/lib/types/client/WallToggle.js.map +1 -1
- package/lib/types/client/WallView.js +8 -8
- package/lib/types/client/WallView.js.map +1 -1
- package/lib/types/client/index.d.ts +1 -1
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/index.js.map +1 -1
- package/lib/types/client/store.d.ts +1 -1
- package/lib/types/client/store.d.ts.map +1 -1
- package/lib/types/client/store.js +1 -1
- package/lib/types/client/store.js.map +1 -1
- package/lib/types/index.d.ts +80 -80
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +117 -12
- package/lib/types/index.js.map +1 -1
- package/package.json +139 -108
- package/scripts/check-platform-contract.mjs +171 -0
- package/src/client/WallToggle.tsx +52 -52
- package/src/client/WallView.tsx +406 -406
- package/src/client/index.ts +108 -103
- package/src/client/store.ts +40 -40
- package/src/index.ts +715 -618
- package/scripts/sync-vitest-paths.mjs +0 -63
package/src/client/index.ts
CHANGED
|
@@ -1,103 +1,108 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Multi-window wall plugin, browser half: contributes the wall as a
|
|
3
|
-
* `conversation.view` ring entry (the official replace-the-chat-surface
|
|
4
|
-
* mechanism — the header grows a "多窗口墙" tab and the right panel swaps to
|
|
5
|
-
* the wall) plus a sidebar footer shortcut that jumps to that view. No
|
|
6
|
-
* existing slot is replaced and no original interaction logic changes; the
|
|
7
|
-
* wall is pure UI over the node half's /multi/api probe routes.
|
|
8
|
-
*
|
|
9
|
-
* Recursion guard: a wall pane embeds each instance as
|
|
10
|
-
* `http://127.0.0.1:<port>/?multi-wall=embed`; the embedded page sees the
|
|
11
|
-
* query flag and registers nothing, so a pane can never grow a wall of its
|
|
12
|
-
* own. The wall also never renders the port it is served on (SELF_PORT is
|
|
13
|
-
* filtered at render time and by the node half's discovery).
|
|
14
|
-
*/
|
|
15
|
-
import type { ClientContext } from '@deepseek-ai/
|
|
16
|
-
// Type-only: pulls the
|
|
17
|
-
//
|
|
18
|
-
|
|
19
|
-
//
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
//
|
|
23
|
-
import type {} from '@deepseek-ai/dsh-client-ui-
|
|
24
|
-
// Type-only: pulls
|
|
25
|
-
|
|
26
|
-
import
|
|
27
|
-
|
|
28
|
-
import {
|
|
29
|
-
|
|
30
|
-
import {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
export {
|
|
38
|
-
export type {
|
|
39
|
-
export
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
//
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
//
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Multi-window wall plugin, browser half: contributes the wall as a
|
|
3
|
+
* `conversation.view` ring entry (the official replace-the-chat-surface
|
|
4
|
+
* mechanism — the header grows a "多窗口墙" tab and the right panel swaps to
|
|
5
|
+
* the wall) plus a sidebar footer shortcut that jumps to that view. No
|
|
6
|
+
* existing slot is replaced and no original interaction logic changes; the
|
|
7
|
+
* wall is pure UI over the node half's /multi/api probe routes.
|
|
8
|
+
*
|
|
9
|
+
* Recursion guard: a wall pane embeds each instance as
|
|
10
|
+
* `http://127.0.0.1:<port>/?multi-wall=embed`; the embedded page sees the
|
|
11
|
+
* query flag and registers nothing, so a pane can never grow a wall of its
|
|
12
|
+
* own. The wall also never renders the port it is served on (SELF_PORT is
|
|
13
|
+
* filtered at render time and by the node half's discovery).
|
|
14
|
+
*/
|
|
15
|
+
import type { Context as ClientContext } from '@deepseek-ai/cordis'
|
|
16
|
+
// Type-only: pulls ctx.slots (the renderer-owned SlotRegistry service) into
|
|
17
|
+
// this program. Must stay type-only — dsh-client-ui-renderer is a boot-graph
|
|
18
|
+
// plugin package, not a platform seed word, so a value import would not
|
|
19
|
+
// resolve inside the plugin bundle.
|
|
20
|
+
import type {} from '@deepseek-ai/dsh-client-ui-renderer/client'
|
|
21
|
+
// Type-only: pulls the layout-owned slot declarations (sidebar footer,
|
|
22
|
+
// shell.overlay) into this program.
|
|
23
|
+
import type {} from '@deepseek-ai/dsh-client-ui-layout/client'
|
|
24
|
+
// Type-only: pulls the conversation package's view-ring declaration
|
|
25
|
+
// ('conversation.view') into this program.
|
|
26
|
+
import type {} from '@deepseek-ai/dsh-client-ui-conversation/client'
|
|
27
|
+
// Type-only: pulls the sidebar footer action owner props into this program.
|
|
28
|
+
import type {} from '@deepseek-ai/dsh-client-ui-sidebar/client'
|
|
29
|
+
// Type-only: pulls ctx.locale into this program.
|
|
30
|
+
import type {} from '@deepseek-ai/dsh-client-locale/client'
|
|
31
|
+
import { en, zh, type MultiWallKey } from './locales.ts'
|
|
32
|
+
import { createWallStore } from './store.ts'
|
|
33
|
+
import { createWallInjected } from './wall-injected.ts'
|
|
34
|
+
import { WallView } from './WallView.tsx'
|
|
35
|
+
import { WallToggle } from './WallToggle.tsx'
|
|
36
|
+
|
|
37
|
+
export { WallView } from './WallView.tsx'
|
|
38
|
+
export type { WallViewProps } from './WallView.tsx'
|
|
39
|
+
export { WallToggle } from './WallToggle.tsx'
|
|
40
|
+
export type { WallToggleProps } from './WallToggle.tsx'
|
|
41
|
+
export type { MultiWallKey } from './locales.ts'
|
|
42
|
+
export { createWallStore } from './store.ts'
|
|
43
|
+
export type { WallState, WallActions } from './store.ts'
|
|
44
|
+
export type { ProbeRow, StopRow, WallInjected } from './wall-injected.ts'
|
|
45
|
+
|
|
46
|
+
declare module '@deepseek-ai/dsh-client-ui-slots' {
|
|
47
|
+
interface LocaleNamespaceMap {
|
|
48
|
+
/** Multi-window wall copy. */
|
|
49
|
+
multiWall: MultiWallKey
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Dictionary namespace owned by this plugin. */
|
|
54
|
+
const NS = 'multiWall'
|
|
55
|
+
|
|
56
|
+
/** Required services: slots for both registrations, locale for copy. */
|
|
57
|
+
export const inject = ['slots', 'locale']
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Whether this page is an embedded wall pane. Panes load
|
|
61
|
+
* `?multi-wall=embed`; such pages register no wall UI at all, which stops a
|
|
62
|
+
* wall inside a wall (the pane would otherwise recursively embed the
|
|
63
|
+
* serving instance).
|
|
64
|
+
* @returns true when the query flag is present.
|
|
65
|
+
*/
|
|
66
|
+
function isEmbeddedPane(): boolean {
|
|
67
|
+
return new URLSearchParams(window.location.search).has('multi-wall')
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Client plugin body: register the dictionaries, the view-ring entry (the
|
|
72
|
+
* wall), and the sidebar footer shortcut. Embedded panes register nothing.
|
|
73
|
+
* @param ctx - client root context.
|
|
74
|
+
*/
|
|
75
|
+
export function apply(ctx: ClientContext): void {
|
|
76
|
+
if (isEmbeddedPane()) return
|
|
77
|
+
ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'ui-multi-wall: dictionaries')
|
|
78
|
+
|
|
79
|
+
// Registration-time text (the view tab label) reads through the bound
|
|
80
|
+
// translate as a thunk, so it follows the active locale without
|
|
81
|
+
// re-registration.
|
|
82
|
+
const t = ctx.locale.bind(NS)
|
|
83
|
+
|
|
84
|
+
// One wall store handle rides both registrations (ports, columns).
|
|
85
|
+
const wallStore = createWallStore()
|
|
86
|
+
|
|
87
|
+
// The wall itself: a 'conversation.view' ring entry. The header projects
|
|
88
|
+
// the tab from the registration options; selecting it swaps the right
|
|
89
|
+
// panel from the chat to the wall (official view-ring behavior).
|
|
90
|
+
ctx.slots.inject('conversation.view', () => ctx.slots.register({
|
|
91
|
+
name: 'conversation.view',
|
|
92
|
+
id: 'multi-wall',
|
|
93
|
+
order: 20,
|
|
94
|
+
label: () => t('view.multiWall'),
|
|
95
|
+
locale: NS,
|
|
96
|
+
store: wallStore,
|
|
97
|
+
inject: () => createWallInjected(),
|
|
98
|
+
}, WallView))
|
|
99
|
+
|
|
100
|
+
// The sidebar footer shortcut: jumps to the wall view. It owns no state —
|
|
101
|
+
// the view ring decides what renders — so it is a plain action row.
|
|
102
|
+
ctx.slots.inject('sidebar.footer.action', () => ctx.slots.register({
|
|
103
|
+
name: 'sidebar.footer.action',
|
|
104
|
+
id: 'multi-wall',
|
|
105
|
+
order: 10,
|
|
106
|
+
locale: NS,
|
|
107
|
+
}, WallToggle))
|
|
108
|
+
}
|
package/src/client/store.ts
CHANGED
|
@@ -1,40 +1,40 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Wall store: which instances are shown and the grid columns. The ports list
|
|
3
|
-
* is the wall's whole business state — discovery writes it, removal filters
|
|
4
|
-
* it, and the grid renders from it. Open/closed is NOT stored here: the wall
|
|
5
|
-
* is a `conversation.view` ring entry, so the active view (chat store's
|
|
6
|
-
* `view` field) decides whether it renders.
|
|
7
|
-
*/
|
|
8
|
-
import { defineStore, type EngineStoreHandle } from '@deepseek-ai/dsh-client-
|
|
9
|
-
|
|
10
|
-
/** Wall viewing state: displayed ports and grid columns. */
|
|
11
|
-
export type WallState = {
|
|
12
|
-
ports: number[]
|
|
13
|
-
columns: string
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/** The wall store's complete write set. */
|
|
17
|
-
export type WallActions = {
|
|
18
|
-
setPorts: (draft: WallState, ports: number[]) => void
|
|
19
|
-
addPort: (draft: WallState, port: number) => void
|
|
20
|
-
removePort: (draft: WallState, port: number) => void
|
|
21
|
-
setColumns: (draft: WallState, columns: string) => void
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Create the wall store handle. Persisted under `dsh.multi-wall` so the port
|
|
26
|
-
* set and column choice survive view switches and reloads.
|
|
27
|
-
* @returns the store handle (spec + type + identity + factory in one).
|
|
28
|
-
*/
|
|
29
|
-
export function createWallStore(): EngineStoreHandle<WallState, WallActions> {
|
|
30
|
-
return defineStore({
|
|
31
|
-
init: (): WallState => ({ ports: [], columns: 'auto' }),
|
|
32
|
-
persist: 'dsh.multi-wall',
|
|
33
|
-
actions: {
|
|
34
|
-
setPorts: (d, ports: number[]) => { d.ports = ports },
|
|
35
|
-
addPort: (d, port: number) => { if (!d.ports.includes(port)) d.ports = [...d.ports, port] },
|
|
36
|
-
removePort: (d, port: number) => { d.ports = d.ports.filter(p => p !== port) },
|
|
37
|
-
setColumns: (d, columns: string) => { d.columns = columns },
|
|
38
|
-
},
|
|
39
|
-
})
|
|
40
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Wall store: which instances are shown and the grid columns. The ports list
|
|
3
|
+
* is the wall's whole business state — discovery writes it, removal filters
|
|
4
|
+
* it, and the grid renders from it. Open/closed is NOT stored here: the wall
|
|
5
|
+
* is a `conversation.view` ring entry, so the active view (chat store's
|
|
6
|
+
* `view` field) decides whether it renders.
|
|
7
|
+
*/
|
|
8
|
+
import { defineStore, type EngineStoreHandle } from '@deepseek-ai/dsh-client-store'
|
|
9
|
+
|
|
10
|
+
/** Wall viewing state: displayed ports and grid columns. */
|
|
11
|
+
export type WallState = {
|
|
12
|
+
ports: number[]
|
|
13
|
+
columns: string
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** The wall store's complete write set. */
|
|
17
|
+
export type WallActions = {
|
|
18
|
+
setPorts: (draft: WallState, ports: number[]) => void
|
|
19
|
+
addPort: (draft: WallState, port: number) => void
|
|
20
|
+
removePort: (draft: WallState, port: number) => void
|
|
21
|
+
setColumns: (draft: WallState, columns: string) => void
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Create the wall store handle. Persisted under `dsh.multi-wall` so the port
|
|
26
|
+
* set and column choice survive view switches and reloads.
|
|
27
|
+
* @returns the store handle (spec + type + identity + factory in one).
|
|
28
|
+
*/
|
|
29
|
+
export function createWallStore(): EngineStoreHandle<WallState, WallActions> {
|
|
30
|
+
return defineStore({
|
|
31
|
+
init: (): WallState => ({ ports: [], columns: 'auto' }),
|
|
32
|
+
persist: 'dsh.multi-wall',
|
|
33
|
+
actions: {
|
|
34
|
+
setPorts: (d, ports: number[]) => { d.ports = ports },
|
|
35
|
+
addPort: (d, port: number) => { if (!d.ports.includes(port)) d.ports = [...d.ports, port] },
|
|
36
|
+
removePort: (d, port: number) => { d.ports = d.ports.filter(p => p !== port) },
|
|
37
|
+
setColumns: (d, columns: string) => { d.columns = columns },
|
|
38
|
+
},
|
|
39
|
+
})
|
|
40
|
+
}
|