@khorsheed/dsh-client-message-tools 0.3.2 → 0.3.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.
@@ -10,7 +10,10 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
10
10
  * restoration is impossible — and the divider carries a「已恢复」badge while
11
11
  * a live restore row cites the span (withdrawing the restored rows clears
12
12
  * the badge and re-enables the action). The「重新编辑」action was removed
13
- * once withdrawals backfill the draft automatically.
13
+ * once withdrawals backfill the draft automatically. Replayed images render
14
+ * through the host's gallery surface (see message-images.ts): the pre-0.2.1
15
+ * `renderMessageImages` owner prop when the host still passes it, otherwise
16
+ * the root-scoped `conversation.images.content` factory.
14
17
  */
15
18
  import { useState } from 'react';
16
19
  import { Button } from '@deepseek-ai/dsh-client-ui-primitives';
@@ -18,14 +21,11 @@ import { IconChevronDownOutlineMedium, IconChevronRightOutlineMedium } from './i
18
21
  import { IconUndoOutlineMedium } from './icons-local.js';
19
22
  import { collectWithdrawnEntries, countHiddenInSpan, foldHiddenRanges, hasRestoreForSpan, isRestoreSuperseded, } from './withdrawn-node.js';
20
23
  import { chatHookOf } from './chat-hook.js';
24
+ import { renderImageGallery } from './message-images.js';
21
25
  import css from './WithdrawnDividerView.module.css';
22
26
  /** The withdrawal divider: collapsed marker row plus the expandable replay. */
23
- export function WithdrawnDividerView({ node, t, restoreMessage, renderMessageImages, ...standard }) {
27
+ export function WithdrawnDividerView({ node, t, restoreMessage, renderMessageImages, loadImage, renderFactorySlot, ...standard }) {
24
28
  const data = node.data;
25
- // The gallery closure is a required owner prop of every `conversation.chat.node`
26
- // renderer; widening it to `| undefined` keeps the degrade path explicit — a
27
- // composition without the attachment UI replays text only instead of throwing.
28
- const renderImages = renderMessageImages;
29
29
  const [expanded, setExpanded] = useState(false);
30
30
  const [entries, setEntries] = useState(null);
31
31
  const [busy, setBusy] = useState(false);
@@ -65,5 +65,5 @@ export function WithdrawnDividerView({ node, t, restoreMessage, renderMessageIma
65
65
  .catch(() => { setFailed(true); })
66
66
  .finally(() => { setBusy(false); });
67
67
  };
68
- return (_jsxs("div", { className: css.row, children: [_jsxs("button", { type: "button", className: css.marker, "aria-expanded": expanded, "aria-label": t('withdrawn.expand'), onClick: toggle, children: [_jsx("span", { className: css.leading, "aria-hidden": true, children: expanded ? _jsx(IconChevronDownOutlineMedium, {}) : _jsx(IconChevronRightOutlineMedium, {}) }), _jsx("span", { className: css.title, children: t('withdrawn.divider', { count }) }), restored && (_jsxs("span", { className: css.badge, children: [_jsx(IconUndoOutlineMedium, {}), t('withdrawn.restored')] }))] }), expanded && (_jsxs("div", { className: css.body, children: [entries === null || entries.length === 0 ? (_jsx("div", { className: css.empty, children: t('withdrawn.empty') })) : (entries.map((entry, index) => (_jsxs("div", { className: entry.kind === 'user' ? css.entryUser : css.entryAssistant, children: [_jsx("div", { className: css.entryKind, children: entry.kind === 'user' ? t('withdrawn.entryUser') : t('withdrawn.entryAssistant') }), entry.text !== '' && _jsx("div", { className: css.textRun, children: entry.text }), renderImages !== undefined && entry.images.length > 0 && (_jsx("div", { className: css.entryImages, children: renderImages({ images: entry.images, align: 'end' }) }))] }, index)))), _jsxs("div", { className: css.restoreRow, children: [_jsx(Button, { variant: "outline", disabled: busy || restored || superseded, onClick: restore, children: t('withdrawn.restore') }), failed && _jsx("span", { className: css.restoreFailed, role: "status", children: t('withdrawn.restoreFailed') })] })] }))] }));
68
+ return (_jsxs("div", { className: css.row, children: [_jsxs("button", { type: "button", className: css.marker, "aria-expanded": expanded, "aria-label": t('withdrawn.expand'), onClick: toggle, children: [_jsx("span", { className: css.leading, "aria-hidden": true, children: expanded ? _jsx(IconChevronDownOutlineMedium, {}) : _jsx(IconChevronRightOutlineMedium, {}) }), _jsx("span", { className: css.title, children: t('withdrawn.divider', { count }) }), restored && (_jsxs("span", { className: css.badge, children: [_jsx(IconUndoOutlineMedium, {}), t('withdrawn.restored')] }))] }), expanded && (_jsxs("div", { className: css.body, children: [entries === null || entries.length === 0 ? (_jsx("div", { className: css.empty, children: t('withdrawn.empty') })) : (entries.map((entry, index) => (_jsxs("div", { className: entry.kind === 'user' ? css.entryUser : css.entryAssistant, children: [_jsx("div", { className: css.entryKind, children: entry.kind === 'user' ? t('withdrawn.entryUser') : t('withdrawn.entryAssistant') }), entry.text !== '' && _jsx("div", { className: css.textRun, children: entry.text }), entry.images.length > 0 && (_jsx("div", { className: css.entryImages, children: renderImageGallery(renderMessageImages, renderFactorySlot, loadImage, { images: entry.images, align: 'end' }) }))] }, index)))), _jsxs("div", { className: css.restoreRow, children: [_jsx(Button, { variant: "outline", disabled: busy || restored || superseded, onClick: restore, children: t('withdrawn.restore') }), failed && _jsx("span", { className: css.restoreFailed, role: "status", children: t('withdrawn.restoreFailed') })] })] }))] }));
69
69
  }
@@ -9,6 +9,9 @@ const EMPTY_CHAT = {
9
9
  nodes: {
10
10
  get: () => undefined,
11
11
  source: () => ({ getSnapshot: () => undefined, subscribe: () => () => { } }),
12
+ // Host 0.2.1 added this required store face; the frozen empty snapshot
13
+ // reports every node as not belonging to the latest exchange.
14
+ bottomSource: () => ({ getSnapshot: () => false, subscribe: () => () => { } }),
12
15
  turnDataSource: () => ({ getSnapshot: () => [], subscribe: () => () => { } }),
13
16
  processSource: () => ({ getSnapshot: () => undefined, subscribe: () => () => { } }),
14
17
  values: () => [],
@@ -2,10 +2,16 @@
2
2
  * DOM hider: hide EVERY chat row whose node anchor falls inside a withdrawn
3
3
  * span — all node kinds, not just user messages — through a dynamic
4
4
  * stylesheet keyed on the row's `data-chat-flow-key` attribute
5
- * (ChatNodeSeat.tsx). The projection itself offers no suppression seam (see
6
- * README), so this works at the DOM layer. The attribute is an undocumented
7
- * surface: the first time a non-empty rule set is computed, the hider probes
8
- * for it (after a frame, so React has committed). A page restored onto a tab
5
+ * (ChatNodeSeat.tsx). Host 0.1.7-alpha.1's conversation groups wrap a turn's
6
+ * process rows in a Group seat whose CONTAINER carries the group key as its
7
+ * flow key (ChatGroupSeat.tsx): member rules hide the rows inside, but the
8
+ * container itself (the「已调用工具」fold header) would show through, so the
9
+ * rule set also covers fully-hidden groups' container keys plus the composite
10
+ * `["<nodeKey>","<groupPart>"]` row keys the plain node-key rules never
11
+ * reach. The projection itself offers no suppression seam (see README), so
12
+ * this works at the DOM layer. The attribute is an undocumented surface: the
13
+ * first time a non-empty rule set is computed, the hider probes for it (after
14
+ * a frame, so React has committed). A page restored onto a tab
9
15
  * where the chat rows are not mounted yet (the trace tab, or the chat area
10
16
  * still mounting) makes that first probe miss, so a miss does NOT disable
11
17
  * the hider outright: it enters a bounded retry — a MutationObserver waits
@@ -20,6 +26,7 @@
20
26
  */
21
27
  import type { Context } from '@deepseek-ai/cordis';
22
28
  import type { ChatConversationViewNode } from '@deepseek-ai/dsh-client-ui-chat/client';
29
+ import type { ConversationGroupedView } from '@deepseek-ai/dsh-client-ui-conversation/client';
23
30
  /**
24
31
  * Flow keys of every chat node inside a hidden span. The withdrawal divider
25
32
  * itself (`message-tools-withdrawn`, anchored at the span's exclusive end) is
@@ -34,6 +41,21 @@ import type { ChatConversationViewNode } from '@deepseek-ai/dsh-client-ui-chat/c
34
41
  * @returns the flow keys to hide, in node order.
35
42
  */
36
43
  export declare function hiddenFlowKeys(nodes: readonly ChatConversationViewNode[], ranges?: readonly number[]): string[];
44
+ /**
45
+ * Flow keys the grouped rendering (host 0.1.7-alpha.1's conversation groups)
46
+ * adds on top of {@link hiddenFlowKeys}. A Group seat's container row carries
47
+ * the GROUP key as its `data-chat-flow-key`, so member rules leave the fold
48
+ * header visible: hide the container when every member's node key is hidden
49
+ * (a group straddling a span boundary keeps its header for the visible
50
+ * members). A member's composite groupPart row (`["<nodeKey>","<part>"]`,
51
+ * ChatNodeSeat — e.g. the reasoning pane) is never reached by the plain
52
+ * node-key rule either, so hidden members contribute those keys on top,
53
+ * whether or not their group hides as a whole.
54
+ * @param view - the chat target's grouped reader (undefined on pre-group hosts).
55
+ * @param hiddenNodeKeys - node keys the plain rules already hide.
56
+ * @returns additional flow keys to hide, in root-entry order.
57
+ */
58
+ export declare function hiddenGroupFlowKeys(view: ConversationGroupedView<unknown> | undefined, hiddenNodeKeys: ReadonlySet<string>): string[];
37
59
  /**
38
60
  * Render the display rules for one rule set.
39
61
  * @param keys - flow keys to hide.
@@ -53,7 +75,8 @@ export interface DomHiderOptions {
53
75
  }
54
76
  /**
55
77
  * Install the hider: one shared style element, rebound whenever the selected
56
- * session changes, rewritten only when the span set or the node count moves.
78
+ * session changes, rewritten only when the span set, the node count, or the
79
+ * hidden group keys move.
57
80
  * @param ctx - client root context (reads the sessions service).
58
81
  * @param options - probe retry tuning.
59
82
  * @returns disposer removing the stylesheet and every subscription.
@@ -49,6 +49,64 @@ export function hiddenFlowKeys(nodes, ranges) {
49
49
  }
50
50
  return keys;
51
51
  }
52
+ /**
53
+ * Flow keys the grouped rendering (host 0.1.7-alpha.1's conversation groups)
54
+ * adds on top of {@link hiddenFlowKeys}. A Group seat's container row carries
55
+ * the GROUP key as its `data-chat-flow-key`, so member rules leave the fold
56
+ * header visible: hide the container when every member's node key is hidden
57
+ * (a group straddling a span boundary keeps its header for the visible
58
+ * members). A member's composite groupPart row (`["<nodeKey>","<part>"]`,
59
+ * ChatNodeSeat — e.g. the reasoning pane) is never reached by the plain
60
+ * node-key rule either, so hidden members contribute those keys on top,
61
+ * whether or not their group hides as a whole.
62
+ * @param view - the chat target's grouped reader (undefined on pre-group hosts).
63
+ * @param hiddenNodeKeys - node keys the plain rules already hide.
64
+ * @returns additional flow keys to hide, in root-entry order.
65
+ */
66
+ export function hiddenGroupFlowKeys(view, hiddenNodeKeys) {
67
+ if (view === undefined || hiddenNodeKeys.size === 0)
68
+ return [];
69
+ const keys = [];
70
+ for (const entry of view.entries) {
71
+ if (entry.kind !== 'group')
72
+ continue;
73
+ const members = view.groupSource(entry.key).getSnapshot()?.members ?? [];
74
+ if (members.length === 0)
75
+ continue;
76
+ let hidden = 0;
77
+ for (const member of members) {
78
+ if (!hiddenNodeKeys.has(member.key))
79
+ continue;
80
+ hidden += 1;
81
+ if (member.groupPart !== undefined && member.groupPart !== 'response') {
82
+ keys.push(JSON.stringify([member.key, member.groupPart]));
83
+ }
84
+ }
85
+ if (hidden === members.length)
86
+ keys.push(entry.key);
87
+ }
88
+ return keys;
89
+ }
90
+ /**
91
+ * The chat target's grouped reader on hosts with conversation groups
92
+ * (0.1.7-alpha.1); earlier hosts carry no `views.grouped` and degrade to
93
+ * undefined — their ungrouped rows are covered by the plain node-key rules.
94
+ * @param ctx - client root context.
95
+ * @param sessionId - owning session.
96
+ * @returns the grouped reader, or undefined when the host or session lacks it.
97
+ */
98
+ function groupedChatViewOf(ctx, sessionId) {
99
+ const uiConversation = ctx.get('uiConversation');
100
+ if (uiConversation === undefined)
101
+ return undefined;
102
+ try {
103
+ const views = uiConversation.binding(sessionId).snapshot.getSnapshot().views;
104
+ return typeof views.grouped === 'function' ? views.grouped('chat') : undefined;
105
+ }
106
+ catch {
107
+ return undefined; // unknown session — the caller's undefined branch
108
+ }
109
+ }
52
110
  /**
53
111
  * Render the display rules for one rule set.
54
112
  * @param keys - flow keys to hide.
@@ -61,7 +119,8 @@ export function renderHiderRules(keys) {
61
119
  }
62
120
  /**
63
121
  * Install the hider: one shared style element, rebound whenever the selected
64
- * session changes, rewritten only when the span set or the node count moves.
122
+ * session changes, rewritten only when the span set, the node count, or the
123
+ * hidden group keys move.
65
124
  * @param ctx - client root context (reads the sessions service).
66
125
  * @param options - probe retry tuning.
67
126
  * @returns disposer removing the stylesheet and every subscription.
@@ -89,11 +148,19 @@ export function installDomHider(ctx, options = {}) {
89
148
  latest = chat;
90
149
  const nodes = chat.nodes.values();
91
150
  const ranges = foldHiddenRanges(nodes);
92
- const nextSignature = `${ranges.join(',')}:${nodes.length}`;
151
+ const nodeKeys = hiddenFlowKeys(nodes, ranges);
152
+ // Group membership only moves with node changes, and the assembler runs
153
+ // group definitions inside the same publish this snapshot reports, so the
154
+ // grouped reader is current here; its keys join the signature so a
155
+ // grouping-only delta still rewrites the rules.
156
+ const groupKeys = activeSession === undefined
157
+ ? []
158
+ : hiddenGroupFlowKeys(groupedChatViewOf(ctx, activeSession), new Set(nodeKeys));
159
+ const nextSignature = `${ranges.join(',')}:${nodes.length}:${groupKeys.join(',')}`;
93
160
  if (nextSignature === signature)
94
161
  return;
95
162
  signature = nextSignature;
96
- style.textContent = renderHiderRules(hiddenFlowKeys(nodes, ranges));
163
+ style.textContent = renderHiderRules([...nodeKeys, ...groupKeys]);
97
164
  };
98
165
  const probeFound = () => document.querySelector('[data-chat-flow-key]') !== null;
99
166
  const stopRetry = () => {
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Cross-host message-image gallery dispatch shared by the two chat-node views.
3
+ * Hosts before 0.2.1-alpha.3 pass a `renderMessageImages` owner prop with the
4
+ * session-authorized loader bound inside; 0.2.1-alpha.3 removed that prop when
5
+ * the images slot split into `conversation.chat.user.images` /
6
+ * `conversation.chat.message.images`, with the official gallery now behind the
7
+ * root-scoped `conversation.images.content` factory (ui-attachment) reached
8
+ * through the framework `renderFactorySlot` seat. The factory outlet renders
9
+ * nothing while the factory is unregistered, which matches the official
10
+ * omit-on-absence behavior of the unfilled images slots.
11
+ */
12
+ import type { ReactNode } from 'react';
13
+ import type { MessageImageLoader, MessageImagesOwnerProps } from '@deepseek-ai/dsh-client-ui-conversation/client';
14
+ import type { RenderFactorySlot } from '@deepseek-ai/dsh-client-ui-slots';
15
+ /** The gallery input one view owns: the owner props minus the loader. */
16
+ export type MessageImagesInput = Omit<MessageImagesOwnerProps, 'loadImage'>;
17
+ /**
18
+ * Render one image group through the host's gallery surface. The legacy owner
19
+ * prop wins when present: on hosts that still pass it (before 0.2.1-alpha.3)
20
+ * the factory either has no seat (0.1.5) or is never registered, while the
21
+ * prop always carries a working gallery. On 0.2.1-alpha.3+ the prop is absent
22
+ * and the factory renders the official gallery.
23
+ * @param legacy - the pre-0.2.1 owner-prop closure, when the host passes it.
24
+ * @param renderFactorySlot - the framework factory seat.
25
+ * @param loadImage - the session-authorized loader from `ChatNodeOwnerProps`.
26
+ * @param input - image sources and layout hints.
27
+ * @returns the gallery occurrence, or null when the composition has none.
28
+ */
29
+ export declare function renderImageGallery(legacy: ((owner: MessageImagesInput) => ReactNode) | undefined, renderFactorySlot: RenderFactorySlot, loadImage: MessageImageLoader, input: MessageImagesInput): ReactNode;
30
+ //# sourceMappingURL=message-images.d.ts.map
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Render one image group through the host's gallery surface. The legacy owner
3
+ * prop wins when present: on hosts that still pass it (before 0.2.1-alpha.3)
4
+ * the factory either has no seat (0.1.5) or is never registered, while the
5
+ * prop always carries a working gallery. On 0.2.1-alpha.3+ the prop is absent
6
+ * and the factory renders the official gallery.
7
+ * @param legacy - the pre-0.2.1 owner-prop closure, when the host passes it.
8
+ * @param renderFactorySlot - the framework factory seat.
9
+ * @param loadImage - the session-authorized loader from `ChatNodeOwnerProps`.
10
+ * @param input - image sources and layout hints.
11
+ * @returns the gallery occurrence, or null when the composition has none.
12
+ */
13
+ export function renderImageGallery(legacy, renderFactorySlot, loadImage, input) {
14
+ if (legacy !== undefined)
15
+ return legacy(input);
16
+ return renderFactorySlot('conversation.images.content', { ...input, loadImage });
17
+ }
@@ -2,9 +2,24 @@
2
2
  * Slot-facing types of the message-tools client half: the injected action
3
3
  * face and the composed props of its two `conversation.chat.node` entries.
4
4
  */
5
+ import type { ReactNode } from 'react';
5
6
  import type { ModelSelection } from '@deepseek-ai/dsh-api-remotes/client';
6
7
  import type { ModelDirectoryState } from '@deepseek-ai/dsh-client-ui-model-selection/client';
7
- import type { HostObservable, InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
8
+ import type { MessageImagesOwnerProps } from '@deepseek-ai/dsh-client-ui-conversation/client';
9
+ import type { HostObservable, InjectFace, PropsLocale, PropsRenderFactories, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
10
+ /**
11
+ * The pre-0.2.1 image-gallery owner prop. Hosts before 0.2.1-alpha.3 pass a
12
+ * `renderMessageImages` closure in `ChatNodeOwnerProps` (the session-authorized
13
+ * loader is bound inside it); 0.2.1-alpha.3 removed the prop when the images
14
+ * slot split into `conversation.chat.user.images` /
15
+ * `conversation.chat.message.images` plus the root-scoped
16
+ * `conversation.images.content` factory. The views prefer this prop when the
17
+ * host still passes it and otherwise render through the factory seat
18
+ * (`PropsRenderFactories`), so one build serves both host lines.
19
+ */
20
+ export interface LegacyMessageImagesProp {
21
+ readonly renderMessageImages?: ((owner: Omit<MessageImagesOwnerProps, 'loadImage'>) => ReactNode) | undefined;
22
+ }
8
23
  /** Injected action face of the shadowed user-message entry. */
9
24
  export interface MessageToolsInjected {
10
25
  hooks: {
@@ -33,12 +48,12 @@ export interface MessageToolsInjected {
33
48
  backfillDraft: (text: string) => void;
34
49
  }
35
50
  /** Full props of the shadowed 'user'/'steering'/'message-tools-edited'/'message-tools-restored' renderer (all keys share it). */
36
- export type UserMessageViewProps = PropsRuntime<'conversation.chat.node', 'user' | 'steering' | 'message-tools-edited' | 'message-tools-restored'> & InjectFace<MessageToolsInjected> & PropsLocale<'message-tools'>;
51
+ export type UserMessageViewProps = PropsRuntime<'conversation.chat.node', 'user' | 'steering' | 'message-tools-edited' | 'message-tools-restored'> & PropsRenderFactories & InjectFace<MessageToolsInjected> & PropsLocale<'message-tools'> & LegacyMessageImagesProp;
37
52
  /** Injected action face of the withdrawal divider entry. */
38
53
  export interface WithdrawnDividerInjected {
39
54
  /** Restore the span's withdrawn user message as a fresh tail message. */
40
55
  restoreMessage: (targetSeq: number) => Promise<void>;
41
56
  }
42
57
  /** Full props of the withdrawal divider renderer. */
43
- export type WithdrawnDividerViewProps = PropsRuntime<'conversation.chat.node', 'message-tools-withdrawn'> & InjectFace<WithdrawnDividerInjected> & PropsLocale<'message-tools'>;
58
+ export type WithdrawnDividerViewProps = PropsRuntime<'conversation.chat.node', 'message-tools-withdrawn'> & PropsRenderFactories & InjectFace<WithdrawnDividerInjected> & PropsLocale<'message-tools'> & LegacyMessageImagesProp;
44
59
  //# sourceMappingURL=slots.d.ts.map
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "cordis",
8
8
  "messages"
9
9
  ],
10
- "version": "0.3.2",
10
+ "version": "0.3.4",
11
11
  "type": "module",
12
12
  "main": "lib/index.js",
13
13
  "types": "lib/types/index.d.ts",
@@ -16,10 +16,6 @@
16
16
  "types": "./lib/types/index.d.ts",
17
17
  "default": "./lib/index.js"
18
18
  },
19
- "./invariant": {
20
- "types": "./lib/types/invariant.d.ts",
21
- "default": "./lib/invariant.js"
22
- },
23
19
  "./client": {
24
20
  "types": "./lib/types/client/index.d.ts",
25
21
  "default": "./lib/client.js"
@@ -55,7 +51,7 @@
55
51
  },
56
52
  "compat": {
57
53
  "minHost": "0.1.5-rc.1",
58
- "verifiedHost": "0.1.7-rc.2"
54
+ "verifiedHost": "0.2.1-rc.1"
59
55
  }
60
56
  },
61
57
  "license": "MIT",
@@ -64,16 +60,15 @@
64
60
  },
65
61
  "peerDependencies": {
66
62
  "@deepseek-ai/cordis": "^4.0.1",
67
- "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.6",
68
- "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.6",
69
- "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.6",
70
- "@deepseek-ai/dsh-client-ui-model-selection": "^0.1.0-rc.6",
71
- "@deepseek-ai/dsh-client-ui-primitives": "^0.1.0-rc.6",
72
- "@deepseek-ai/dsh-client-ui-slots": "^0.1.0-rc.6",
73
- "@deepseek-ai/dsh-invariants": "^0.1.0-rc.6",
74
- "@deepseek-ai/dsh-llm": "^0.1.0-rc.6",
75
- "@deepseek-ai/dsh-session": "^0.1.0-rc.6",
76
- "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.6",
63
+ "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-rc.1",
64
+ "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-rc.1",
65
+ "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-rc.1",
66
+ "@deepseek-ai/dsh-client-ui-model-selection": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-rc.1",
67
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-rc.1",
68
+ "@deepseek-ai/dsh-client-ui-slots": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-rc.1",
69
+ "@deepseek-ai/dsh-llm": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-rc.1",
70
+ "@deepseek-ai/dsh-session": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-rc.1",
71
+ "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-rc.1",
77
72
  "react": "^18.2.0"
78
73
  },
79
74
  "files": [
@@ -86,5 +81,8 @@
86
81
  "LICENSE",
87
82
  "locale/*.json",
88
83
  "CHANGELOG.md"
89
- ]
84
+ ],
85
+ "engines": {
86
+ "dsh": ">=0.1.5-rc.1 <0.3.0-0"
87
+ }
90
88
  }
package/lib/invariant.js DELETED
@@ -1,27 +0,0 @@
1
- //#region lib/types/invariant.js
2
- /**
3
- * Package-owned invariant companion for `@khorsheed/dsh-client-message-tools`.
4
- * @module @khorsheed/dsh-client-message-tools/invariant
5
- */
6
- const PACKAGE_NAME = "@khorsheed/dsh-client-message-tools";
7
- /** Cordis companion plugin name. */
8
- const name = "client-message-tools-invariant";
9
- /** Service required before the companion can reserve package ownership. */
10
- const inject = ["invariants"];
11
- /**
12
- * No runtime invariant: the withdrawal write passes through Session.append,
13
- * whose surface validation rejects any replacement that misses a shadowed
14
- * surface node, and the client contributions (one Definition, two slot
15
- * entries) ride the slot/declaration lifecycles disposed with the plugin
16
- * fiber. The package's unit tests exercise the plan fold and the projection
17
- * helpers, so no second authority exists to check at runtime.
18
- */
19
- const install = () => {};
20
- /**
21
- * Register this package's invariant companion.
22
- * @param ctx - Cordis context carrying the invariant service.
23
- * @returns the installed registration's disposer after setup succeeds.
24
- */
25
- const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
26
- //#endregion
27
- export { apply, inject, name };
@@ -1,16 +0,0 @@
1
- /**
2
- * Package-owned invariant companion for `@khorsheed/dsh-client-message-tools`.
3
- * @module @khorsheed/dsh-client-message-tools/invariant
4
- */
5
- import type { Context } from '@deepseek-ai/cordis';
6
- /** Cordis companion plugin name. */
7
- export declare const name = "client-message-tools-invariant";
8
- /** Service required before the companion can reserve package ownership. */
9
- export declare const inject: string[];
10
- /**
11
- * Register this package's invariant companion.
12
- * @param ctx - Cordis context carrying the invariant service.
13
- * @returns the installed registration's disposer after setup succeeds.
14
- */
15
- export declare const apply: (ctx: Context) => Promise<() => void>;
16
- //# sourceMappingURL=invariant.d.ts.map
@@ -1,25 +0,0 @@
1
- /**
2
- * Package-owned invariant companion for `@khorsheed/dsh-client-message-tools`.
3
- * @module @khorsheed/dsh-client-message-tools/invariant
4
- */
5
- const PACKAGE_NAME = '@khorsheed/dsh-client-message-tools';
6
- /** Cordis companion plugin name. */
7
- export const name = 'client-message-tools-invariant';
8
- /** Service required before the companion can reserve package ownership. */
9
- export const inject = ['invariants'];
10
- /**
11
- * No runtime invariant: the withdrawal write passes through Session.append,
12
- * whose surface validation rejects any replacement that misses a shadowed
13
- * surface node, and the client contributions (one Definition, two slot
14
- * entries) ride the slot/declaration lifecycles disposed with the plugin
15
- * fiber. The package's unit tests exercise the plan fold and the projection
16
- * helpers, so no second authority exists to check at runtime.
17
- */
18
- const install = () => { };
19
- /**
20
- * Register this package's invariant companion.
21
- * @param ctx - Cordis context carrying the invariant service.
22
- * @returns the installed registration's disposer after setup succeeds.
23
- */
24
- export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
25
- /* jscpd:ignore-end */