@tivility/dsh-session-share 0.3.4 → 0.3.6

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 CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  A link that opens one session.
4
4
 
5
+ Targets DeepSeek Harness **0.1.x** (`@deepseek-ai/dsh-* ~0.1.1-rc.2`).
6
+
5
7
  ## The gap this fills
6
8
 
7
9
  The harness's GUI opens wherever it was left. There is no URL that means *this
@@ -15,11 +15,38 @@ import { jsx as _jsx } from "react/jsx-runtime";
15
15
  * @module @tivility/dsh-session-share/client/ShareLink
16
16
  */
17
17
  import { useCallback, useState } from 'react';
18
- import { Button, IconCheckOutline16, IconLinkOutline16, writeClipboard, } from '@deepseek-ai/dsh-client-ui-primitives';
18
+ import * as Primitives from '@deepseek-ai/dsh-client-ui-primitives';
19
19
  import { shareQuery } from '../param.js';
20
20
  import { SHARE_NS } from './namespace.js';
21
21
  /** How long the copied state shows, in ms — matched to the harness's own copy controls. */
22
22
  const COPIED_MS = 1000;
23
+ const { Button, writeClipboard } = Primitives;
24
+ /** The fallback for a host that exports none of the requested names. */
25
+ const NoIcon = () => null;
26
+ /**
27
+ * Pick the first icon a host's primitives export under any of `names`.
28
+ *
29
+ * The primitives package is not bundled: the page's loader hands this plugin
30
+ * whatever release the host is running. dsh 0.1.7 renamed the fixed-size
31
+ * `…Outline16` icons to weight-suffixed `…OutlineRegular` ones, so a static
32
+ * import resolves to `undefined` on one side of that release and crashes the
33
+ * header slot. Looking the names up at run time keeps one build working on
34
+ * both; a host exporting neither gets no glyph rather than a broken header.
35
+ * @param exports - the primitives module's export table.
36
+ * @param names - candidate export names, newest first.
37
+ * @returns the first function export found, or a component that renders nothing.
38
+ */
39
+ export function resolveIcon(exports, ...names) {
40
+ for (const name of names) {
41
+ const candidate = exports[name];
42
+ if (typeof candidate === 'function')
43
+ return candidate;
44
+ }
45
+ return NoIcon;
46
+ }
47
+ const primitiveExports = Primitives;
48
+ const IconCheck = resolveIcon(primitiveExports, 'IconCheckOutlineRegular', 'IconCheckOutline16');
49
+ const IconLink = resolveIcon(primitiveExports, 'IconLinkOutlineRegular', 'IconLinkOutline16');
23
50
  /**
24
51
  * Render the copy-link control for the current session.
25
52
  * @param props - composed slot props.
@@ -43,6 +70,6 @@ export function ShareLink({ sessionId, t }) {
43
70
  return (_jsx(Button, { variant: "ghost", size: "sm", onClick: onCopy,
44
71
  // The URL itself is the most useful hover text: it is what gets copied,
45
72
  // and seeing it is how someone learns the format exists.
46
- title: copied ? t('copied') : `${t('hint')}\n${url}`, icon: copied ? _jsx(IconCheckOutline16, { size: 14 }) : _jsx(IconLinkOutline16, { size: 14 }), children: copied ? t('copied') : t('copy') }));
73
+ title: copied ? t('copied') : `${t('hint')}\n${url}`, icon: copied ? _jsx(IconCheck, { size: 14 }) : _jsx(IconLink, { size: 14 }), children: copied ? t('copied') : t('copy') }));
47
74
  }
48
75
  //# sourceMappingURL=ShareLink.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ShareLink.js","sourceRoot":"","sources":["../../src/client/ShareLink.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAC7C,OAAO,EACL,MAAM,EACN,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,GACf,MAAM,uCAAuC,CAAA;AAI9C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEzC,2FAA2F;AAC3F,MAAM,SAAS,GAAG,IAAI,CAAA;AAOtB;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,EAAE,SAAS,EAAE,CAAC,EAAkB;IACxD,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC3C,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,IAAI,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAA;IAExE,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE;QAC9B,IAAI,MAAM;YAAE,OAAM;QAClB,KAAK,cAAc,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE;YACzC,wEAAwE;YACxE,gEAAgE;YAChE,IAAI,CAAC,QAAQ;gBAAE,OAAM;YACrB,SAAS,CAAC,IAAI,CAAC,CAAA;YACf,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,KAAK,CAAC,CAAA,CAAC,CAAC,EAAE,SAAS,CAAC,CAAA;QAC1D,CAAC,CAAC,CAAA;IACJ,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAA;IAEjB,OAAO,CACL,KAAC,MAAM,IACL,OAAO,EAAC,OAAO,EACf,IAAI,EAAC,IAAI,EACT,OAAO,EAAE,MAAM;QACf,wEAAwE;QACxE,yDAAyD;QACzD,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,GAAG,EAAE,EACpD,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,KAAC,kBAAkB,IAAC,IAAI,EAAE,EAAE,GAAI,CAAC,CAAC,CAAC,KAAC,iBAAiB,IAAC,IAAI,EAAE,EAAE,GAAI,YAEhF,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAC1B,CACV,CAAA;AACH,CAAC"}
1
+ {"version":3,"file":"ShareLink.js","sourceRoot":"","sources":["../../src/client/ShareLink.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAE7C,OAAO,KAAK,UAAU,MAAM,uCAAuC,CAAA;AAInE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEzC,2FAA2F;AAC3F,MAAM,SAAS,GAAG,IAAI,CAAA;AAEtB,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,UAAU,CAAA;AAK7C,wEAAwE;AACxE,MAAM,MAAM,GAAkB,GAAG,EAAE,CAAC,IAAI,CAAA;AAExC;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,WAAW,CAAC,OAA0C,EAAE,GAAG,KAAwB;IACjG,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;QAC/B,IAAI,OAAO,SAAS,KAAK,UAAU;YAAE,OAAO,SAA0B,CAAA;IACxE,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED,MAAM,gBAAgB,GAAG,UAA0D,CAAA;AACnF,MAAM,SAAS,GAAG,WAAW,CAAC,gBAAgB,EAAE,yBAAyB,EAAE,oBAAoB,CAAC,CAAA;AAChG,MAAM,QAAQ,GAAG,WAAW,CAAC,gBAAgB,EAAE,wBAAwB,EAAE,mBAAmB,CAAC,CAAA;AAO7F;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,EAAE,SAAS,EAAE,CAAC,EAAkB;IACxD,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC3C,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,IAAI,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,CAAA;IAExE,MAAM,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE;QAC9B,IAAI,MAAM;YAAE,OAAM;QAClB,KAAK,cAAc,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE;YACzC,wEAAwE;YACxE,gEAAgE;YAChE,IAAI,CAAC,QAAQ;gBAAE,OAAM;YACrB,SAAS,CAAC,IAAI,CAAC,CAAA;YACf,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,KAAK,CAAC,CAAA,CAAC,CAAC,EAAE,SAAS,CAAC,CAAA;QAC1D,CAAC,CAAC,CAAA;IACJ,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAA;IAEjB,OAAO,CACL,KAAC,MAAM,IACL,OAAO,EAAC,OAAO,EACf,IAAI,EAAC,IAAI,EACT,OAAO,EAAE,MAAM;QACf,wEAAwE;QACxE,yDAAyD;QACzD,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,GAAG,EAAE,EACpD,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,KAAC,SAAS,IAAC,IAAI,EAAE,EAAE,GAAI,CAAC,CAAC,CAAC,KAAC,QAAQ,IAAC,IAAI,EAAE,EAAE,GAAI,YAE9D,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAC1B,CACV,CAAA;AACH,CAAC"}
@@ -28,7 +28,7 @@ import { ShareLink } from './ShareLink.js';
28
28
  export { ShareLink } from './ShareLink.js';
29
29
  export { SHARE_NS } from './namespace.js';
30
30
  /** Client-side services this plugin drives. */
31
- export const inject = ['sessions', 'slots', 'locale'];
31
+ export const inject = ['sessions', 'uiWorkspace', 'slots', 'locale'];
32
32
  /**
33
33
  * Remove the parameter from the address bar once it has been acted on.
34
34
  *
@@ -62,7 +62,7 @@ function openRequestedSession(ctx) {
62
62
  const state = ctx.sessions.list.getSnapshot();
63
63
  if (state.byId[requested] !== undefined) {
64
64
  done = true;
65
- ctx.sessions.open(requested);
65
+ ctx.uiWorkspace.openSession(requested);
66
66
  stripParam();
67
67
  return;
68
68
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"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"}
package/lib/client.js CHANGED
@@ -1,9 +1,37 @@
1
1
  window.__ModuleLoader__.load({ id: "@tivility/dsh-session-share", factory: (require) => {
2
2
  var module = { exports: {} }; var exports = module.exports;
3
3
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
+ //#region \0rolldown/runtime.js
5
+ var __create = Object.create;
6
+ var __defProp = Object.defineProperty;
7
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
8
+ var __getOwnPropNames = Object.getOwnPropertyNames;
9
+ var __getProtoOf = Object.getPrototypeOf;
10
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
14
+ key = keys[i];
15
+ if (!__hasOwnProp.call(to, key) && key !== except) {
16
+ __defProp(to, key, {
17
+ get: ((k) => from[k]).bind(null, key),
18
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
19
+ });
20
+ }
21
+ }
22
+ }
23
+ return to;
24
+ };
25
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
26
+ value: mod,
27
+ enumerable: true
28
+ }) : target, mod));
29
+
30
+ //#endregion
4
31
  let react_jsx_runtime = require("react/jsx-runtime");
5
32
  let react = require("react");
6
33
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
34
+ _deepseek_ai_dsh_client_ui_primitives = __toESM(_deepseek_ai_dsh_client_ui_primitives);
7
35
 
8
36
  //#region lib/param.js
9
37
  /**
@@ -77,6 +105,32 @@ const SHARE_NS = "session.share";
77
105
  */
78
106
  /** How long the copied state shows, in ms — matched to the harness's own copy controls. */
79
107
  const COPIED_MS = 1e3;
108
+ const { Button, writeClipboard } = _deepseek_ai_dsh_client_ui_primitives;
109
+ /** The fallback for a host that exports none of the requested names. */
110
+ const NoIcon = () => null;
111
+ /**
112
+ * Pick the first icon a host's primitives export under any of `names`.
113
+ *
114
+ * The primitives package is not bundled: the page's loader hands this plugin
115
+ * whatever release the host is running. dsh 0.1.7 renamed the fixed-size
116
+ * `…Outline16` icons to weight-suffixed `…OutlineRegular` ones, so a static
117
+ * import resolves to `undefined` on one side of that release and crashes the
118
+ * header slot. Looking the names up at run time keeps one build working on
119
+ * both; a host exporting neither gets no glyph rather than a broken header.
120
+ * @param exports - the primitives module's export table.
121
+ * @param names - candidate export names, newest first.
122
+ * @returns the first function export found, or a component that renders nothing.
123
+ */
124
+ function resolveIcon(exports, ...names) {
125
+ for (const name of names) {
126
+ const candidate = exports[name];
127
+ if (typeof candidate === "function") return candidate;
128
+ }
129
+ return NoIcon;
130
+ }
131
+ const primitiveExports = _deepseek_ai_dsh_client_ui_primitives;
132
+ const IconCheck = resolveIcon(primitiveExports, "IconCheckOutlineRegular", "IconCheckOutline16");
133
+ const IconLink = resolveIcon(primitiveExports, "IconLinkOutlineRegular", "IconLinkOutline16");
80
134
  /**
81
135
  * Render the copy-link control for the current session.
82
136
  * @param props - composed slot props.
@@ -85,12 +139,12 @@ const COPIED_MS = 1e3;
85
139
  function ShareLink({ sessionId, t }) {
86
140
  const [copied, setCopied] = (0, react.useState)(false);
87
141
  const url = `${window.location.origin}/${shareQuery(String(sessionId))}`;
88
- return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
142
+ return (0, react_jsx_runtime.jsx)(Button, {
89
143
  variant: "ghost",
90
144
  size: "sm",
91
145
  onClick: (0, react.useCallback)(() => {
92
146
  if (copied) return;
93
- (0, _deepseek_ai_dsh_client_ui_primitives.writeClipboard)(url).then((accepted) => {
147
+ writeClipboard(url).then((accepted) => {
94
148
  if (!accepted) return;
95
149
  setCopied(true);
96
150
  window.setTimeout(() => {
@@ -99,7 +153,7 @@ function ShareLink({ sessionId, t }) {
99
153
  });
100
154
  }, [copied, url]),
101
155
  title: copied ? t("copied") : `${t("hint")}\n${url}`,
102
- icon: copied ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutline16, { size: 14 }) : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconLinkOutline16, { size: 14 }),
156
+ icon: copied ? (0, react_jsx_runtime.jsx)(IconCheck, { size: 14 }) : (0, react_jsx_runtime.jsx)(IconLink, { size: 14 }),
103
157
  children: copied ? t("copied") : t("copy")
104
158
  });
105
159
  }
@@ -132,6 +186,7 @@ function ShareLink({ sessionId, t }) {
132
186
  /** Client-side services this plugin drives. */
133
187
  const inject = [
134
188
  "sessions",
189
+ "uiWorkspace",
135
190
  "slots",
136
191
  "locale"
137
192
  ];
@@ -163,7 +218,7 @@ function openRequestedSession(ctx) {
163
218
  const state = ctx.sessions.list.getSnapshot();
164
219
  if (state.byId[requested] !== void 0) {
165
220
  done = true;
166
- ctx.sessions.open(requested);
221
+ ctx.uiWorkspace.openSession(requested);
167
222
  stripParam();
168
223
  return;
169
224
  }
package/lib/client.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":["Button","IconCheckOutline16","IconLinkOutline16"],"sources":["param.js","client/locales.js","client/namespace.js","client/ShareLink.js","client/index.js"],"sourcesContent":["/**\n * The one fact both halves of this plugin have to agree on.\n *\n * The query parameter is a constant rather than configuration because the two\n * halves cannot share a configuration value: the browser bundle is fetched\n * outside the loader's config tree and receives only what its own `apply`\n * is handed, while the link the host writes into the system prompt is built\n * on the other side of the wire. A constant is the honest form of a value\n * that must match in two places.\n * @module @tivility/dsh-session-share/param\n */\n/** Query parameter naming the session to open on load. */\nexport const SESSION_PARAM = 'session';\n/**\n * Build the query a share link carries.\n * @param sessionId - the session to open.\n * @returns the query string, question mark included.\n */\nexport function shareQuery(sessionId) {\n return `?${SESSION_PARAM}=${encodeURIComponent(sessionId)}`;\n}\n//# sourceMappingURL=param.js.map","/** Copy for the session-header share control. */\n/** English copy. */\nexport const en = {\n copy: 'Copy link',\n copied: 'Copied',\n hint: 'Copy a link that opens this session',\n};\n/** Chinese copy. */\nexport const zh = {\n copy: '复制链接',\n copied: '已复制',\n hint: '复制一个直接打开这条会话的链接',\n};\n//# sourceMappingURL=locales.js.map","/**\n * The locale namespace this bundle registers, and the key union its copy\n * satisfies.\n *\n * Kept in its own module because the declaration merge below has to be visible\n * to both the registration site and the component, and importing the component\n * from the registration site (or the reverse) would make that a cycle.\n * @module @tivility/dsh-session-share/client/namespace\n */\n/** Locale namespace for the session-header share control. */\nexport const SHARE_NS = 'session.share';\n//# sourceMappingURL=namespace.js.map","import { jsx as _jsx } from \"react/jsx-runtime\";\n/**\n * The session header's \"copy link\" control.\n *\n * Without it the feature is unreachable by a person: the link format lives in\n * the system prompt, which teaches the *model* to hand out links, and leaves\n * whoever is looking at the GUI to construct one from a session id they cannot\n * see. This is the one affordance that makes it a feature rather than a\n * convention.\n *\n * The origin comes from `window.location`, so the link is always the address\n * this browser reached the harness at — the loopback URL when that is how you\n * opened it, the LAN address when it is not. Nothing to configure, and nothing\n * that can drift from where the server actually answers.\n * @module @tivility/dsh-session-share/client/ShareLink\n */\nimport { useCallback, useState } from 'react';\nimport { Button, IconCheckOutline16, IconLinkOutline16, writeClipboard, } from '@deepseek-ai/dsh-client-ui-primitives';\nimport { shareQuery } from '../param.js';\nimport { SHARE_NS } from './namespace.js';\n/** How long the copied state shows, in ms — matched to the harness's own copy controls. */\nconst COPIED_MS = 1000;\n/**\n * Render the copy-link control for the current session.\n * @param props - composed slot props.\n * @returns the control.\n */\nexport function ShareLink({ sessionId, t }) {\n const [copied, setCopied] = useState(false);\n const url = `${window.location.origin}/${shareQuery(String(sessionId))}`;\n const onCopy = useCallback(() => {\n if (copied)\n return;\n void writeClipboard(url).then((accepted) => {\n // A refused write (denied permission, insecure context) leaves the flag\n // alone: the control must never claim a copy the host declined.\n if (!accepted)\n return;\n setCopied(true);\n window.setTimeout(() => { setCopied(false); }, COPIED_MS);\n });\n }, [copied, url]);\n return (_jsx(Button, { variant: \"ghost\", size: \"sm\", onClick: onCopy, \n // The URL itself is the most useful hover text: it is what gets copied,\n // and seeing it is how someone learns the format exists.\n title: copied ? t('copied') : `${t('hint')}\\n${url}`, icon: copied ? _jsx(IconCheckOutline16, { size: 14 }) : _jsx(IconLinkOutline16, { size: 14 }), children: copied ? t('copied') : t('copy') }));\n}\n//# sourceMappingURL=ShareLink.js.map","/**\n * The browser half: open the session a link names, and offer a way to get one.\n *\n * The harness's GUI has no routing — the whole client is searched in vain for\n * `pushState`, `location.hash`, or `searchParams`. The selected session lives\n * in the sessions manager and is restored from persisted state on load, so a\n * URL naming one has nowhere to be read. This adds that step, and the control\n * that makes it reachable by a person rather than only by the model.\n *\n * It deliberately hides nothing. The sidebar, the other sessions, and the\n * composer are all exactly as they would be — the link decides where you land,\n * not what you can see.\n *\n * ## Why the context is typed here\n *\n * The two halves of this package compile in one TypeScript program, and the\n * node half pulls in the harness's HOST augmentations of `Context` — where\n * `sessions` is a different service with the same name. Importing\n * `ClientContext` would therefore resolve `ctx.sessions` to the host's shape.\n * The harness avoids this with separate client and host programs; this package\n * states the members it uses instead.\n * @module @tivility/dsh-session-share/client\n */\nimport { SESSION_PARAM } from '../param.js';\nimport { en, zh } from './locales.js';\nimport { SHARE_NS } from './namespace.js';\nimport { ShareLink } from './ShareLink.js';\nexport { ShareLink } from './ShareLink.js';\nexport { SHARE_NS } from './namespace.js';\n/** Client-side services this plugin drives. */\nexport const inject = ['sessions', 'slots', 'locale'];\n/**\n * Remove the parameter from the address bar once it has been acted on.\n *\n * The selection is persisted by the runtime, so leaving the parameter in place\n * would make every later reload jump back to the linked session — fighting the\n * user each time they navigate away and refresh. Consuming it once makes the\n * link mean \"start here\", which is what a link means.\n */\nfunction stripParam() {\n const url = new URL(window.location.href);\n if (!url.searchParams.has(SESSION_PARAM))\n return;\n url.searchParams.delete(SESSION_PARAM);\n window.history.replaceState(window.history.state, '', `${url.pathname}${url.search}${url.hash}`);\n}\n/**\n * Open the session a `?session=` parameter names, once the list can carry it.\n * @param ctx - the client root context.\n */\nfunction openRequestedSession(ctx) {\n const requested = new URL(window.location.href).searchParams.get(SESSION_PARAM);\n // No parameter is the overwhelmingly common case — every ordinary visit — so\n // this costs nothing at all when it has nothing to do.\n if (requested === null || requested === '')\n return;\n ctx.effect(() => {\n let done = false;\n const attempt = () => {\n if (done)\n return;\n const state = ctx.sessions.list.getSnapshot();\n if (state.byId[requested] !== undefined) {\n done = true;\n ctx.sessions.open(requested);\n stripParam();\n return;\n }\n // The list arrives asynchronously, so an id that is absent right now may\n // simply not have loaded. The phase is what separates \"not yet\" from \"no\n // such session\" — a timeout would guess at it.\n if (state.phase === 'ready') {\n done = true;\n stripParam();\n ctx.logger?.warn?.(`session-share: no session ${requested} in this harness`);\n }\n };\n const unsubscribe = ctx.sessions.list.subscribe(attempt);\n // The list may already be ready before this plugin activates, in which case\n // no change is ever published and the subscription alone would wait forever.\n attempt();\n return unsubscribe;\n });\n}\n/**\n * Read the link, and offer one.\n * @param ctx - the client root context.\n */\nexport function apply(ctx) {\n openRequestedSession(ctx);\n ctx.effect(() => ctx.locale.register(SHARE_NS, { zh, en }));\n // Declaration-gated since dsh 0.1.3: registering into a slot before its\n // parent declares it throws, so the registration waits behind slots.inject.\n ctx.slots.inject('conversation.session.header.utilities', () => ctx.slots.register({\n // The header's utility band, not the title row: this is a control, and the\n // band beside the breadcrumb is where static session context belongs.\n name: 'conversation.session.header.utilities',\n id: 'session-share',\n locale: SHARE_NS,\n }, ShareLink));\n}\n//# sourceMappingURL=index.js.map"],"mappings":";;;;;;;;;;;;;;;;;;;;AAYA,MAAa,gBAAgB;;;;;;AAM7B,SAAgB,WAAW,WAAW;AAClC,QAAO,IAAI,cAAc,GAAG,mBAAmB,UAAU;;;;;;;ACjB7D,MAAa,KAAK;CACd,MAAM;CACN,QAAQ;CACR,MAAM;CACT;;AAED,MAAa,KAAK;CACd,MAAM;CACN,QAAQ;CACR,MAAM;CACT;;;;;;;;;;;;;;ACFD,MAAa,WAAW;;;;;;;;;;;;;;;;;;;;ACWxB,MAAM,YAAY;;;;;;AAMlB,SAAgB,UAAU,EAAE,WAAW,KAAK;CACxC,MAAM,CAAC,QAAQ,iCAAsB,MAAM;CAC3C,MAAM,MAAM,GAAG,OAAO,SAAS,OAAO,GAAG,WAAW,OAAO,UAAU,CAAC;AAatE,mCAAaA,8CAAQ;EAAE,SAAS;EAAS,MAAM;EAAM,sCAZpB;AAC7B,OAAI,OACA;AACJ,6DAAoB,IAAI,CAAC,MAAM,aAAa;AAGxC,QAAI,CAAC,SACD;AACJ,cAAU,KAAK;AACf,WAAO,iBAAiB;AAAE,eAAU,MAAM;OAAK,UAAU;KAC3D;KACH,CAAC,QAAQ,IAAI,CAAC;EAIb,OAAO,SAAS,EAAE,SAAS,GAAG,GAAG,EAAE,OAAO,CAAC,IAAI;EAAO,MAAM,oCAAcC,0DAAoB,EAAE,MAAM,IAAI,CAAC,8BAAQC,yDAAmB,EAAE,MAAM,IAAI,CAAC;EAAE,UAAU,SAAS,EAAE,SAAS,GAAG,EAAE,OAAO;EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACf1M,MAAa,SAAS;CAAC;CAAY;CAAS;CAAS;;;;;;;;;AASrD,SAAS,aAAa;CAClB,MAAM,MAAM,IAAI,IAAI,OAAO,SAAS,KAAK;AACzC,KAAI,CAAC,IAAI,aAAa,IAAI,cAAc,CACpC;AACJ,KAAI,aAAa,OAAO,cAAc;AACtC,QAAO,QAAQ,aAAa,OAAO,QAAQ,OAAO,IAAI,GAAG,IAAI,WAAW,IAAI,SAAS,IAAI,OAAO;;;;;;AAMpG,SAAS,qBAAqB,KAAK;CAC/B,MAAM,YAAY,IAAI,IAAI,OAAO,SAAS,KAAK,CAAC,aAAa,IAAI,cAAc;AAG/E,KAAI,cAAc,QAAQ,cAAc,GACpC;AACJ,KAAI,aAAa;EACb,IAAI,OAAO;EACX,MAAM,gBAAgB;AAClB,OAAI,KACA;GACJ,MAAM,QAAQ,IAAI,SAAS,KAAK,aAAa;AAC7C,OAAI,MAAM,KAAK,eAAe,QAAW;AACrC,WAAO;AACP,QAAI,SAAS,KAAK,UAAU;AAC5B,gBAAY;AACZ;;AAKJ,OAAI,MAAM,UAAU,SAAS;AACzB,WAAO;AACP,gBAAY;AACZ,QAAI,QAAQ,OAAO,6BAA6B,UAAU,kBAAkB;;;EAGpF,MAAM,cAAc,IAAI,SAAS,KAAK,UAAU,QAAQ;AAGxD,WAAS;AACT,SAAO;GACT;;;;;;AAMN,SAAgB,MAAM,KAAK;AACvB,sBAAqB,IAAI;AACzB,KAAI,aAAa,IAAI,OAAO,SAAS,UAAU;EAAE;EAAI;EAAI,CAAC,CAAC;AAG3D,KAAI,MAAM,OAAO,+CAA+C,IAAI,MAAM,SAAS;EAG/E,MAAM;EACN,IAAI;EACJ,QAAQ;EACX,EAAE,UAAU,CAAC"}
1
+ {"version":3,"file":"client.js","names":["Primitives"],"sources":["param.js","client/locales.js","client/namespace.js","client/ShareLink.js","client/index.js"],"sourcesContent":["/**\n * The one fact both halves of this plugin have to agree on.\n *\n * The query parameter is a constant rather than configuration because the two\n * halves cannot share a configuration value: the browser bundle is fetched\n * outside the loader's config tree and receives only what its own `apply`\n * is handed, while the link the host writes into the system prompt is built\n * on the other side of the wire. A constant is the honest form of a value\n * that must match in two places.\n * @module @tivility/dsh-session-share/param\n */\n/** Query parameter naming the session to open on load. */\nexport const SESSION_PARAM = 'session';\n/**\n * Build the query a share link carries.\n * @param sessionId - the session to open.\n * @returns the query string, question mark included.\n */\nexport function shareQuery(sessionId) {\n return `?${SESSION_PARAM}=${encodeURIComponent(sessionId)}`;\n}\n//# sourceMappingURL=param.js.map","/** Copy for the session-header share control. */\n/** English copy. */\nexport const en = {\n copy: 'Copy link',\n copied: 'Copied',\n hint: 'Copy a link that opens this session',\n};\n/** Chinese copy. */\nexport const zh = {\n copy: '复制链接',\n copied: '已复制',\n hint: '复制一个直接打开这条会话的链接',\n};\n//# sourceMappingURL=locales.js.map","/**\n * The locale namespace this bundle registers, and the key union its copy\n * satisfies.\n *\n * Kept in its own module because the declaration merge below has to be visible\n * to both the registration site and the component, and importing the component\n * from the registration site (or the reverse) would make that a cycle.\n * @module @tivility/dsh-session-share/client/namespace\n */\n/** Locale namespace for the session-header share control. */\nexport const SHARE_NS = 'session.share';\n//# sourceMappingURL=namespace.js.map","import { jsx as _jsx } from \"react/jsx-runtime\";\n/**\n * The session header's \"copy link\" control.\n *\n * Without it the feature is unreachable by a person: the link format lives in\n * the system prompt, which teaches the *model* to hand out links, and leaves\n * whoever is looking at the GUI to construct one from a session id they cannot\n * see. This is the one affordance that makes it a feature rather than a\n * convention.\n *\n * The origin comes from `window.location`, so the link is always the address\n * this browser reached the harness at — the loopback URL when that is how you\n * opened it, the LAN address when it is not. Nothing to configure, and nothing\n * that can drift from where the server actually answers.\n * @module @tivility/dsh-session-share/client/ShareLink\n */\nimport { useCallback, useState } from 'react';\nimport * as Primitives from '@deepseek-ai/dsh-client-ui-primitives';\nimport { shareQuery } from '../param.js';\nimport { SHARE_NS } from './namespace.js';\n/** How long the copied state shows, in ms — matched to the harness's own copy controls. */\nconst COPIED_MS = 1000;\nconst { Button, writeClipboard } = Primitives;\n/** The fallback for a host that exports none of the requested names. */\nconst NoIcon = () => null;\n/**\n * Pick the first icon a host's primitives export under any of `names`.\n *\n * The primitives package is not bundled: the page's loader hands this plugin\n * whatever release the host is running. dsh 0.1.7 renamed the fixed-size\n * `…Outline16` icons to weight-suffixed `…OutlineRegular` ones, so a static\n * import resolves to `undefined` on one side of that release and crashes the\n * header slot. Looking the names up at run time keeps one build working on\n * both; a host exporting neither gets no glyph rather than a broken header.\n * @param exports - the primitives module's export table.\n * @param names - candidate export names, newest first.\n * @returns the first function export found, or a component that renders nothing.\n */\nexport function resolveIcon(exports, ...names) {\n for (const name of names) {\n const candidate = exports[name];\n if (typeof candidate === 'function')\n return candidate;\n }\n return NoIcon;\n}\nconst primitiveExports = Primitives;\nconst IconCheck = resolveIcon(primitiveExports, 'IconCheckOutlineRegular', 'IconCheckOutline16');\nconst IconLink = resolveIcon(primitiveExports, 'IconLinkOutlineRegular', 'IconLinkOutline16');\n/**\n * Render the copy-link control for the current session.\n * @param props - composed slot props.\n * @returns the control.\n */\nexport function ShareLink({ sessionId, t }) {\n const [copied, setCopied] = useState(false);\n const url = `${window.location.origin}/${shareQuery(String(sessionId))}`;\n const onCopy = useCallback(() => {\n if (copied)\n return;\n void writeClipboard(url).then((accepted) => {\n // A refused write (denied permission, insecure context) leaves the flag\n // alone: the control must never claim a copy the host declined.\n if (!accepted)\n return;\n setCopied(true);\n window.setTimeout(() => { setCopied(false); }, COPIED_MS);\n });\n }, [copied, url]);\n return (_jsx(Button, { variant: \"ghost\", size: \"sm\", onClick: onCopy, \n // The URL itself is the most useful hover text: it is what gets copied,\n // and seeing it is how someone learns the format exists.\n title: copied ? t('copied') : `${t('hint')}\\n${url}`, icon: copied ? _jsx(IconCheck, { size: 14 }) : _jsx(IconLink, { size: 14 }), children: copied ? t('copied') : t('copy') }));\n}\n//# sourceMappingURL=ShareLink.js.map","/**\n * The browser half: open the session a link names, and offer a way to get one.\n *\n * The harness's GUI has no routing — the whole client is searched in vain for\n * `pushState`, `location.hash`, or `searchParams`. The selected session lives\n * in the sessions manager and is restored from persisted state on load, so a\n * URL naming one has nowhere to be read. This adds that step, and the control\n * that makes it reachable by a person rather than only by the model.\n *\n * It deliberately hides nothing. The sidebar, the other sessions, and the\n * composer are all exactly as they would be — the link decides where you land,\n * not what you can see.\n *\n * ## Why the context is typed here\n *\n * The two halves of this package compile in one TypeScript program, and the\n * node half pulls in the harness's HOST augmentations of `Context` — where\n * `sessions` is a different service with the same name. Importing\n * `ClientContext` would therefore resolve `ctx.sessions` to the host's shape.\n * The harness avoids this with separate client and host programs; this package\n * states the members it uses instead.\n * @module @tivility/dsh-session-share/client\n */\nimport { SESSION_PARAM } from '../param.js';\nimport { en, zh } from './locales.js';\nimport { SHARE_NS } from './namespace.js';\nimport { ShareLink } from './ShareLink.js';\nexport { ShareLink } from './ShareLink.js';\nexport { SHARE_NS } from './namespace.js';\n/** Client-side services this plugin drives. */\nexport const inject = ['sessions', 'uiWorkspace', 'slots', 'locale'];\n/**\n * Remove the parameter from the address bar once it has been acted on.\n *\n * The selection is persisted by the runtime, so leaving the parameter in place\n * would make every later reload jump back to the linked session — fighting the\n * user each time they navigate away and refresh. Consuming it once makes the\n * link mean \"start here\", which is what a link means.\n */\nfunction stripParam() {\n const url = new URL(window.location.href);\n if (!url.searchParams.has(SESSION_PARAM))\n return;\n url.searchParams.delete(SESSION_PARAM);\n window.history.replaceState(window.history.state, '', `${url.pathname}${url.search}${url.hash}`);\n}\n/**\n * Open the session a `?session=` parameter names, once the list can carry it.\n * @param ctx - the client root context.\n */\nfunction openRequestedSession(ctx) {\n const requested = new URL(window.location.href).searchParams.get(SESSION_PARAM);\n // No parameter is the overwhelmingly common case — every ordinary visit — so\n // this costs nothing at all when it has nothing to do.\n if (requested === null || requested === '')\n return;\n ctx.effect(() => {\n let done = false;\n const attempt = () => {\n if (done)\n return;\n const state = ctx.sessions.list.getSnapshot();\n if (state.byId[requested] !== undefined) {\n done = true;\n ctx.uiWorkspace.openSession(requested);\n stripParam();\n return;\n }\n // The list arrives asynchronously, so an id that is absent right now may\n // simply not have loaded. The phase is what separates \"not yet\" from \"no\n // such session\" — a timeout would guess at it.\n if (state.phase === 'ready') {\n done = true;\n stripParam();\n ctx.logger?.warn?.(`session-share: no session ${requested} in this harness`);\n }\n };\n const unsubscribe = ctx.sessions.list.subscribe(attempt);\n // The list may already be ready before this plugin activates, in which case\n // no change is ever published and the subscription alone would wait forever.\n attempt();\n return unsubscribe;\n });\n}\n/**\n * Read the link, and offer one.\n * @param ctx - the client root context.\n */\nexport function apply(ctx) {\n openRequestedSession(ctx);\n ctx.effect(() => ctx.locale.register(SHARE_NS, { zh, en }));\n // Declaration-gated since dsh 0.1.3: registering into a slot before its\n // parent declares it throws, so the registration waits behind slots.inject.\n ctx.slots.inject('conversation.session.header.utilities', () => ctx.slots.register({\n // The header's utility band, not the title row: this is a control, and the\n // band beside the breadcrumb is where static session context belongs.\n name: 'conversation.session.header.utilities',\n id: 'session-share',\n locale: SHARE_NS,\n }, ShareLink));\n}\n//# sourceMappingURL=index.js.map"],"mappings":"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"}
@@ -13,8 +13,27 @@
13
13
  * that can drift from where the server actually answers.
14
14
  * @module @tivility/dsh-session-share/client/ShareLink
15
15
  */
16
+ import type { ReactElement } from 'react';
16
17
  import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
17
18
  import { SHARE_NS } from './namespace.js';
19
+ /** One icon component, as both generations of the host primitives declare it. */
20
+ export type IconComponent = (props: {
21
+ size?: number;
22
+ }) => ReactElement | null;
23
+ /**
24
+ * Pick the first icon a host's primitives export under any of `names`.
25
+ *
26
+ * The primitives package is not bundled: the page's loader hands this plugin
27
+ * whatever release the host is running. dsh 0.1.7 renamed the fixed-size
28
+ * `…Outline16` icons to weight-suffixed `…OutlineRegular` ones, so a static
29
+ * import resolves to `undefined` on one side of that release and crashes the
30
+ * header slot. Looking the names up at run time keeps one build working on
31
+ * both; a host exporting neither gets no glyph rather than a broken header.
32
+ * @param exports - the primitives module's export table.
33
+ * @param names - candidate export names, newest first.
34
+ * @returns the first function export found, or a component that renders nothing.
35
+ */
36
+ export declare function resolveIcon(exports: Readonly<Record<string, unknown>>, ...names: readonly string[]): IconComponent;
18
37
  /** Full component props: the framework's session context plus this bundle's copy. */
19
38
  export type ShareLinkProps = PropsRuntime<'conversation.session.header.utilities'> & PropsLocale<typeof SHARE_NS>;
20
39
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ShareLink.d.ts","sourceRoot":"","sources":["../../../src/client/ShareLink.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AASH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAIjF,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAKzC,qFAAqF;AACrF,MAAM,MAAM,cAAc,GACxB,YAAY,CAAC,uCAAuC,CAAC,GACnD,WAAW,CAAC,OAAO,QAAQ,CAAC,CAAA;AAEhC;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,cAAc,+BA4BzD"}
1
+ {"version":3,"file":"ShareLink.d.ts","sourceRoot":"","sources":["../../../src/client/ShareLink.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,OAAO,CAAA;AAEzC,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAIjF,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAOzC,iFAAiF;AACjF,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,YAAY,GAAG,IAAI,CAAA;AAK7E;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,aAAa,CAMlH;AAMD,qFAAqF;AACrF,MAAM,MAAM,cAAc,GACxB,YAAY,CAAC,uCAAuC,CAAC,GACnD,WAAW,CAAC,OAAO,QAAQ,CAAC,CAAA;AAEhC;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,EAAE,cAAc,+BA4BzD"}
@@ -36,11 +36,14 @@ interface SessionsFace {
36
36
  getSnapshot(): SessionListSnapshot;
37
37
  subscribe(listener: () => void): () => void;
38
38
  };
39
+ }
40
+ /** The workspace navigation service that selects the main-view session (dsh ≥0.2). */
41
+ interface UiWorkspaceFace {
39
42
  /**
40
- * Select a session as current. Fails loud on an id the list does not carry,
41
- * which is why the phase below is consulted first.
43
+ * Select a session and show its conversation as one navigation action. The
44
+ * list phase below is consulted first so only listed ids reach it.
42
45
  */
43
- open(id: string): void;
46
+ openSession(id: string): void;
44
47
  }
45
48
  /** The slot registry, narrowed to the one registration this plugin makes. */
46
49
  interface SlotsFace {
@@ -60,6 +63,7 @@ interface LocaleFace {
60
63
  /** The client context members this plugin uses. */
61
64
  interface ShareContext {
62
65
  readonly sessions: SessionsFace;
66
+ readonly uiWorkspace: UiWorkspaceFace;
63
67
  readonly slots: SlotsFace;
64
68
  readonly locale: LocaleFace;
65
69
  effect(run: () => () => void): unknown;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAOH,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEzC,mDAAmD;AACnD,UAAU,mBAAmB;IAC3B,yCAAyC;IACzC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IAChD,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAA;CACpC;AAED,kEAAkE;AAClE,UAAU,YAAY;IACpB,QAAQ,CAAC,IAAI,EAAE;QACb,WAAW,IAAI,mBAAmB,CAAA;QAClC,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAA;KAC5C,CAAA;IACD;;;OAGG;IACH,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;CACvB;AAED,6EAA6E;AAC7E,UAAU,SAAS;IACjB,QAAQ,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,SAAS,EAAE,OAAO,GAAG,MAAM,IAAI,CAAA;IAC9G,iGAAiG;IACjG,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,MAAM,IAAI,GAAG,MAAM,IAAI,CAAA;CAC7D;AAED,wEAAwE;AACxE,UAAU,UAAU;IAClB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,IAAI,CAAA;CAC/E;AAED,mDAAmD;AACnD,UAAU,YAAY;IACpB,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAA;IAC/B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAA;IACzB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;IAC3B,MAAM,CAAC,GAAG,EAAE,MAAM,MAAM,IAAI,GAAG,OAAO,CAAA;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAA;CACnD;AAED,+CAA+C;AAC/C,eAAO,MAAM,MAAM,UAAkC,CAAA;AAuDrD;;;GAGG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,CAa7C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAOH,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEzC,mDAAmD;AACnD,UAAU,mBAAmB;IAC3B,yCAAyC;IACzC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IAChD,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAA;CACpC;AAED,kEAAkE;AAClE,UAAU,YAAY;IACpB,QAAQ,CAAC,IAAI,EAAE;QACb,WAAW,IAAI,mBAAmB,CAAA;QAClC,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAA;KAC5C,CAAA;CACF;AAED,sFAAsF;AACtF,UAAU,eAAe;IACvB;;;OAGG;IACH,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAA;CAC9B;AAED,6EAA6E;AAC7E,UAAU,SAAS;IACjB,QAAQ,CAAC,IAAI,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,SAAS,EAAE,OAAO,GAAG,MAAM,IAAI,CAAA;IAC9G,iGAAiG;IACjG,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,MAAM,IAAI,GAAG,MAAM,IAAI,CAAA;CAC7D;AAED,wEAAwE;AACxE,UAAU,UAAU;IAClB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,IAAI,CAAA;CAC/E;AAED,mDAAmD;AACnD,UAAU,YAAY;IACpB,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAA;IAC/B,QAAQ,CAAC,WAAW,EAAE,eAAe,CAAA;IACrC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAA;IACzB,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAA;IAC3B,MAAM,CAAC,GAAG,EAAE,MAAM,MAAM,IAAI,GAAG,OAAO,CAAA;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAA;CACnD;AAED,+CAA+C;AAC/C,eAAO,MAAM,MAAM,UAAiD,CAAA;AAuDpE;;;GAGG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,CAa7C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tivility/dsh-session-share",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
4
4
  "description": "Link straight to one DeepSeek Harness session: the GUI opens on it instead of wherever it was left.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -48,9 +48,9 @@
48
48
  },
49
49
  "peerDependencies": {
50
50
  "@deepseek-ai/cordis": "*",
51
+ "@deepseek-ai/dsh-agent": ">=0.1.1-rc.2",
51
52
  "@deepseek-ai/dsh-host-webserver": ">=0.1.1-rc.2",
52
- "@deepseek-ai/schemastery": "*",
53
- "@deepseek-ai/dsh-agent": ">=0.1.1-rc.2"
53
+ "@deepseek-ai/schemastery": "*"
54
54
  },
55
55
  "peerDependenciesMeta": {
56
56
  "@deepseek-ai/dsh-system-prompt": {
@@ -70,7 +70,7 @@
70
70
  "@deepseek-ai/dsh-client-ui-slots": "0.1.1-rc.2",
71
71
  "@deepseek-ai/dsh-host-webserver": "0.1.1-rc.2",
72
72
  "@deepseek-ai/dsh-system-prompt": "0.1.1-rc.2",
73
- "@deepseek-ai/schemastery": "*",
73
+ "@deepseek-ai/schemastery": "^3.18.4",
74
74
  "@testing-library/react": "^16.1.0",
75
75
  "@types/react": "~18.3.1",
76
76
  "jsdom": "^26.0.0",
@@ -15,12 +15,8 @@
15
15
  */
16
16
 
17
17
  import { useCallback, useState } from 'react'
18
- import {
19
- Button,
20
- IconCheckOutline16,
21
- IconLinkOutline16,
22
- writeClipboard,
23
- } from '@deepseek-ai/dsh-client-ui-primitives'
18
+ import type { ReactElement } from 'react'
19
+ import * as Primitives from '@deepseek-ai/dsh-client-ui-primitives'
24
20
  import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots'
25
21
  // Type-only: pulls the ui-conversation SlotMap merge that declares this seat.
26
22
  import type {} from '@deepseek-ai/dsh-client-ui-conversation/client'
@@ -30,6 +26,39 @@ import { SHARE_NS } from './namespace.js'
30
26
  /** How long the copied state shows, in ms — matched to the harness's own copy controls. */
31
27
  const COPIED_MS = 1000
32
28
 
29
+ const { Button, writeClipboard } = Primitives
30
+
31
+ /** One icon component, as both generations of the host primitives declare it. */
32
+ export type IconComponent = (props: { size?: number }) => ReactElement | null
33
+
34
+ /** The fallback for a host that exports none of the requested names. */
35
+ const NoIcon: IconComponent = () => null
36
+
37
+ /**
38
+ * Pick the first icon a host's primitives export under any of `names`.
39
+ *
40
+ * The primitives package is not bundled: the page's loader hands this plugin
41
+ * whatever release the host is running. dsh 0.1.7 renamed the fixed-size
42
+ * `…Outline16` icons to weight-suffixed `…OutlineRegular` ones, so a static
43
+ * import resolves to `undefined` on one side of that release and crashes the
44
+ * header slot. Looking the names up at run time keeps one build working on
45
+ * both; a host exporting neither gets no glyph rather than a broken header.
46
+ * @param exports - the primitives module's export table.
47
+ * @param names - candidate export names, newest first.
48
+ * @returns the first function export found, or a component that renders nothing.
49
+ */
50
+ export function resolveIcon(exports: Readonly<Record<string, unknown>>, ...names: readonly string[]): IconComponent {
51
+ for (const name of names) {
52
+ const candidate = exports[name]
53
+ if (typeof candidate === 'function') return candidate as IconComponent
54
+ }
55
+ return NoIcon
56
+ }
57
+
58
+ const primitiveExports = Primitives as unknown as Readonly<Record<string, unknown>>
59
+ const IconCheck = resolveIcon(primitiveExports, 'IconCheckOutlineRegular', 'IconCheckOutline16')
60
+ const IconLink = resolveIcon(primitiveExports, 'IconLinkOutlineRegular', 'IconLinkOutline16')
61
+
33
62
  /** Full component props: the framework's session context plus this bundle's copy. */
34
63
  export type ShareLinkProps =
35
64
  PropsRuntime<'conversation.session.header.utilities'>
@@ -63,7 +92,7 @@ export function ShareLink({ sessionId, t }: ShareLinkProps) {
63
92
  // The URL itself is the most useful hover text: it is what gets copied,
64
93
  // and seeing it is how someone learns the format exists.
65
94
  title={copied ? t('copied') : `${t('hint')}\n${url}`}
66
- icon={copied ? <IconCheckOutline16 size={14} /> : <IconLinkOutline16 size={14} />}
95
+ icon={copied ? <IconCheck size={14} /> : <IconLink size={14} />}
67
96
  >
68
97
  {copied ? t('copied') : t('copy')}
69
98
  </Button>
@@ -44,11 +44,15 @@ interface SessionsFace {
44
44
  getSnapshot(): SessionListSnapshot
45
45
  subscribe(listener: () => void): () => void
46
46
  }
47
+ }
48
+
49
+ /** The workspace navigation service that selects the main-view session (dsh ≥0.2). */
50
+ interface UiWorkspaceFace {
47
51
  /**
48
- * Select a session as current. Fails loud on an id the list does not carry,
49
- * which is why the phase below is consulted first.
52
+ * Select a session and show its conversation as one navigation action. The
53
+ * list phase below is consulted first so only listed ids reach it.
50
54
  */
51
- open(id: string): void
55
+ openSession(id: string): void
52
56
  }
53
57
 
54
58
  /** The slot registry, narrowed to the one registration this plugin makes. */
@@ -66,6 +70,7 @@ interface LocaleFace {
66
70
  /** The client context members this plugin uses. */
67
71
  interface ShareContext {
68
72
  readonly sessions: SessionsFace
73
+ readonly uiWorkspace: UiWorkspaceFace
69
74
  readonly slots: SlotsFace
70
75
  readonly locale: LocaleFace
71
76
  effect(run: () => () => void): unknown
@@ -73,7 +78,7 @@ interface ShareContext {
73
78
  }
74
79
 
75
80
  /** Client-side services this plugin drives. */
76
- export const inject = ['sessions', 'slots', 'locale']
81
+ export const inject = ['sessions', 'uiWorkspace', 'slots', 'locale']
77
82
 
78
83
  /**
79
84
  * Remove the parameter from the address bar once it has been acted on.
@@ -107,7 +112,7 @@ function openRequestedSession(ctx: ShareContext): void {
107
112
  const state = ctx.sessions.list.getSnapshot()
108
113
  if (state.byId[requested] !== undefined) {
109
114
  done = true
110
- ctx.sessions.open(requested)
115
+ ctx.uiWorkspace.openSession(requested)
111
116
  stripParam()
112
117
  return
113
118
  }