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.
@@ -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/dsh-client-runtime/client'
16
- // Type-only: pulls the layout-owned slot declarations (sidebar footer,
17
- // shell.overlay) into this program.
18
- import type {} from '@deepseek-ai/dsh-client-ui-layout/client'
19
- // Type-only: pulls the conversation package's view-ring declaration
20
- // ('conversation.view') into this program.
21
- import type {} from '@deepseek-ai/dsh-client-ui-conversation/client'
22
- // Type-only: pulls the sidebar footer action owner props into this program.
23
- import type {} from '@deepseek-ai/dsh-client-ui-sidebar/client'
24
- // Type-only: pulls ctx.locale into this program.
25
- import type {} from '@deepseek-ai/dsh-client-locale/client'
26
- import { en, zh, type MultiWallKey } from './locales.ts'
27
- import { createWallStore } from './store.ts'
28
- import { createWallInjected } from './wall-injected.ts'
29
- import { WallView } from './WallView.tsx'
30
- import { WallToggle } from './WallToggle.tsx'
31
-
32
- export { WallView } from './WallView.tsx'
33
- export type { WallViewProps } from './WallView.tsx'
34
- export { WallToggle } from './WallToggle.tsx'
35
- export type { WallToggleProps } from './WallToggle.tsx'
36
- export type { MultiWallKey } from './locales.ts'
37
- export { createWallStore } from './store.ts'
38
- export type { WallState, WallActions } from './store.ts'
39
- export type { ProbeRow, StopRow, WallInjected } from './wall-injected.ts'
40
-
41
- declare module '@deepseek-ai/dsh-client-ui-slots' {
42
- interface LocaleNamespaceMap {
43
- /** Multi-window wall copy. */
44
- multiWall: MultiWallKey
45
- }
46
- }
47
-
48
- /** Dictionary namespace owned by this plugin. */
49
- const NS = 'multiWall'
50
-
51
- /** Required services: slots for both registrations, locale for copy. */
52
- export const inject = ['slots', 'locale']
53
-
54
- /**
55
- * Whether this page is an embedded wall pane. Panes load
56
- * `?multi-wall=embed`; such pages register no wall UI at all, which stops a
57
- * wall inside a wall (the pane would otherwise recursively embed the
58
- * serving instance).
59
- * @returns true when the query flag is present.
60
- */
61
- function isEmbeddedPane(): boolean {
62
- return new URLSearchParams(window.location.search).has('multi-wall')
63
- }
64
-
65
- /**
66
- * Client plugin body: register the dictionaries, the view-ring entry (the
67
- * wall), and the sidebar footer shortcut. Embedded panes register nothing.
68
- * @param ctx - client root context.
69
- */
70
- export function apply(ctx: ClientContext): void {
71
- if (isEmbeddedPane()) return
72
- ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'ui-multi-wall: dictionaries')
73
-
74
- // Registration-time text (the view tab label) reads through the bound
75
- // translate as a thunk, so it follows the active locale without
76
- // re-registration.
77
- const t = ctx.locale.bind(NS)
78
-
79
- // One wall store handle rides both registrations (ports, columns).
80
- const wallStore = createWallStore()
81
-
82
- // The wall itself: a 'conversation.view' ring entry. The header projects
83
- // the tab from the registration options; selecting it swaps the right
84
- // panel from the chat to the wall (official view-ring behavior).
85
- ctx.slots.inject('conversation.view', () => ctx.slots.register({
86
- name: 'conversation.view',
87
- id: 'multi-wall',
88
- order: 20,
89
- label: () => t('view.multiWall'),
90
- locale: NS,
91
- store: wallStore,
92
- inject: () => createWallInjected(),
93
- }, WallView))
94
-
95
- // The sidebar footer shortcut: jumps to the wall view. It owns no state —
96
- // the view ring decides what renders — so it is a plain action row.
97
- ctx.slots.inject('sidebar.footer.action', () => ctx.slots.register({
98
- name: 'sidebar.footer.action',
99
- id: 'multi-wall',
100
- order: 10,
101
- locale: NS,
102
- }, WallToggle))
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
+ }
@@ -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-runtime/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
+ }