dsh-grok-subscription 0.1.12 → 1.0.0

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
@@ -25,7 +25,7 @@ dsh plugin --profile web add BaronCyrus/dsh-grok-subscription
25
25
  # 或本地路径
26
26
  # dsh plugin --profile web add /absolute/path/to/dsh-grok-subscription
27
27
  # 或 npm(发布后)
28
- # dsh plugin --profile web add dsh-grok-subscription@0.1.12
28
+ # dsh plugin --profile web add dsh-grok-subscription@1.0.0
29
29
  ```
30
30
 
31
31
  然后重启 `dsh web`,打开 **Settings → Grok 订阅**。也可以在设置页点击“CLI 登录”或“设备码登录”;设备码流程会在启动 DSH 的终端中显示提示。登录完成后点击“从 Grok CLI 拉取”可立即同步;Chat 模型列表会随之刷新。
@@ -46,6 +46,14 @@ npm test
46
46
  npm run build
47
47
  ```
48
48
 
49
+ ## v1.0.0
50
+
51
+ 首个稳定版,已发布 npm:`dsh-grok-subscription@1.0.0`。内置模型选择器现可通过 `model.reasoning`(efforts + defaultEffort)展示 Grok Build 的 reasoning effort 子菜单(low/medium/high/xhigh),与 Codex 一致。修复 duck `listModels`/`resolveModel` 此前省略该元数据的问题。
52
+
53
+ ## v0.1.13
54
+
55
+ Chat 输入区模型选择旁增加 Codex 风格的每周剩余额度徽章(如 `16%`);悬停/点击显示「每周额度 剩余 N% · 重置于 M/D HH:mm」。仅在当前会话 provider 为 `grok-build` 且用量 `ok` 时显示。Settings 中 Pull/登录成功后会派发刷新事件更新徽章。本地 0.1.13 供复测,**未发 npm**。升级后请用新 token URL 硬刷新。
56
+
49
57
  ## v0.1.12
50
58
 
51
59
  升级后请用 `dsh web` 新打印的带 token URL 打开,并硬刷新(Ctrl+Shift+R),避免旧 `/plugins` client 缓存。
@@ -115,7 +123,15 @@ dsh plugin --profile web add BaronCyrus/dsh-grok-subscription
115
123
 
116
124
  Reinstall after upgrades, restart `dsh web`, then open **Settings → Grok Subscription**.
117
125
 
118
- ### v0.1.12
126
+ ### v1.0.0
127
+
128
+ First stable release, published to npm as `dsh-grok-subscription@1.0.0`. Stock model picker now shows Grok Build reasoning effort (low/medium/high/xhigh) via `model.reasoning` metadata (`efforts` + `defaultEffort`), matching Codex. Fixes duck `listModels`/`resolveModel` omitting that shape.
129
+
130
+ ### v0.1.13
131
+
132
+ Chat 输入区模型选择旁增加 Codex 风格的每周剩余额度徽章(如 `16%`);悬停/点击显示「每周额度 剩余 N% · 重置于 M/D HH:mm」。仅在当前会话 provider 为 `grok-build` 且用量 `ok` 时显示。Settings 中 Pull/登录成功后会派发刷新事件更新徽章。本地 0.1.13 供复测,**未发 npm**。升级后请用新 token URL 硬刷新。
133
+
134
+ ## v0.1.12
119
135
 
120
136
  After upgrading, open the fresh token URL from `dsh web` and hard-refresh (Ctrl+Shift+R) so the old immutable `/plugins` client is not reused.
121
137
 
package/lib/client.js CHANGED
@@ -28,13 +28,13 @@ __export(client_exports, {
28
28
  pickCopy: () => pickCopy
29
29
  });
30
30
  module.exports = __toCommonJS(client_exports);
31
- var import_react = require("react");
31
+ var import_react2 = require("react");
32
32
 
33
33
  // src/locales.js
34
34
  var zh = {
35
35
  nav: "Grok \u8BA2\u9605",
36
36
  title: "Grok \u8BA2\u9605",
37
- subtitle: "\u7528 SuperGrok / X Premium\uFF08Grok Build\uFF09\u4F1A\u8BDD\uFF0C\u800C\u4E0D\u662F XAI_API_KEY\u3002",
37
+ subtitle: "\u7528 SuperGrok / X Premium\uFF08Grok Build\uFF09\u4F1A\u8BDD\uFF0C\u800C\u4E0D\u662F XAI_API_KEY\u3002\xB7 1.0.0",
38
38
  signedIn: "\u5DF2\u767B\u5F55",
39
39
  signedOut: "\u672A\u767B\u5F55",
40
40
  account: "\u8D26\u6237",
@@ -72,12 +72,16 @@ var zh = {
72
72
  usageProduct: "\u4EA7\u54C1\u660E\u7EC6",
73
73
  usageFetchedAt: "\u6700\u8FD1\u5237\u65B0",
74
74
  usageRefreshOk: "\u7528\u91CF\u5DF2\u5237\u65B0",
75
- catalogRefreshOk: "\u6A21\u578B\u76EE\u5F55\u5DF2\u5237\u65B0"
75
+ catalogRefreshOk: "\u6A21\u578B\u76EE\u5F55\u5DF2\u5237\u65B0",
76
+ composerQuotaDetails: "\u6BCF\u5468\u989D\u5EA6",
77
+ composerQuotaRemaining: "\u6BCF\u5468\u989D\u5EA6 \u5269\u4F59 {remaining}%",
78
+ composerQuotaResets: "\u91CD\u7F6E\u4E8E {reset}",
79
+ composerQuotaResetUnknown: "\u91CD\u7F6E\u65F6\u95F4\u672A\u77E5"
76
80
  };
77
81
  var en = {
78
82
  nav: "Grok Subscription",
79
83
  title: "Grok Subscription",
80
- subtitle: "Use a SuperGrok / X Premium (Grok Build) session, not XAI_API_KEY.",
84
+ subtitle: "Use a SuperGrok / X Premium (Grok Build) session, not XAI_API_KEY. \xB7 1.0.0",
81
85
  signedIn: "Signed in",
82
86
  signedOut: "Signed out",
83
87
  account: "Account",
@@ -115,7 +119,11 @@ var en = {
115
119
  usageProduct: "Product breakdown",
116
120
  usageFetchedAt: "Last refreshed",
117
121
  usageRefreshOk: "Usage refreshed",
118
- catalogRefreshOk: "Model catalog refreshed"
122
+ catalogRefreshOk: "Model catalog refreshed",
123
+ composerQuotaDetails: "Weekly quota",
124
+ composerQuotaRemaining: "Weekly quota \xB7 {remaining}% left",
125
+ composerQuotaResets: "Resets {reset}",
126
+ composerQuotaResetUnknown: "Reset time unknown"
119
127
  };
120
128
 
121
129
  // src/rpc-contract.js
@@ -146,6 +154,7 @@ function unwrap(response) {
146
154
  }
147
155
 
148
156
  // src/constants.js
157
+ var PROVIDER_ID = "grok-build";
149
158
  var LOCALE_NS = "settings.grokSubscription";
150
159
  var USAGE_PAGE_URL = "https://grok.com/?_s=usage";
151
160
  var SESSION_AUTH_MODES = Object.freeze(["oidc", "external", "web_login", "grok"]);
@@ -156,9 +165,339 @@ var REQUEST_IMAGE_PIXEL_BUDGET = 2048 * 2048;
156
165
  var REQUEST_IMAGE_MAX_BYTES = 1024 * 1024;
157
166
  var FALLBACK_MODEL_IDS = Object.freeze(["grok-4.7", "grok-4.6", "grok-4.5"]);
158
167
 
159
- // src/client.jsx
168
+ // src/client-composer-quota.jsx
169
+ var import_react = require("react");
170
+ var import_react_dom = require("react-dom");
171
+
172
+ // src/client-composer-quota-shared.js
173
+ var QUICK_QUOTA_REFRESH_EVENT = "dsh-grok-subscription:refresh-quick-quota";
174
+ var QUICK_QUOTA_REFRESH_MS = 6e4;
175
+ var COMPOSER_QUOTA_STYLE = `
176
+ .grokComposerQuota:focus-visible{outline:1px solid var(--dsw-alias-border-l3);outline-offset:2px}
177
+ .grokComposerQuota{display:inline-flex;align-items:center;gap:9px;flex:0 0 auto;height:28px;box-sizing:border-box;padding:0 5px;border:0;border-radius:6px;background:transparent;cursor:pointer;color:var(--dsw-alias-label-secondary);font-family:inherit;font-size:12px;line-height:20px;font-weight:500;font-variant-numeric:tabular-nums;white-space:nowrap}
178
+ .grokComposerQuota:hover,.grokComposerQuota[aria-expanded=true]{background:var(--dsw-alias-interactive-bg-hover)}
179
+ .grokQuotaPopover{position:fixed;z-index:1000;width:max-content;max-width:calc(100vw - 24px);max-height:calc(100vh - 24px);overflow:auto;box-sizing:border-box;padding:8px 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:9px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);box-shadow:0 4px 16px #0002;font-size:12px;line-height:20px;outline:none}
180
+ .grokQuotaDetail>div{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
181
+ .grokQuotaDetail strong{font-weight:500}
182
+ .grokQuotaReset{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px}
183
+ `;
184
+ function fillTemplate(text, values) {
185
+ return Object.entries(values).reduce(
186
+ (next, [key, value]) => next.replaceAll(`{${key}}`, String(value)),
187
+ String(text ?? "")
188
+ );
189
+ }
190
+ function formatRemainingPercent(value) {
191
+ if (typeof value !== "number" || !Number.isFinite(value)) return void 0;
192
+ const rounded = Math.round(value * 10) / 10;
193
+ return Number.isInteger(rounded) ? String(rounded) : rounded.toFixed(1);
194
+ }
195
+ function formatShortReset(usage) {
196
+ if (!usage || typeof usage !== "object") return void 0;
197
+ const iso = typeof usage.periodEnd === "string" ? usage.periodEnd : void 0;
198
+ if (iso) {
199
+ const ms = Date.parse(iso);
200
+ if (Number.isFinite(ms)) {
201
+ return new Date(ms).toLocaleString(void 0, {
202
+ month: "numeric",
203
+ day: "numeric",
204
+ hour: "2-digit",
205
+ minute: "2-digit"
206
+ });
207
+ }
208
+ }
209
+ const local = typeof usage.periodEndLocal === "string" ? usage.periodEndLocal.trim() : "";
210
+ if (!local) return void 0;
211
+ const match = local.match(/(\d{4})[/-](\d{1,2})[/-](\d{1,2})\s+(\d{1,2}):(\d{2})/);
212
+ if (match) {
213
+ return `${Number(match[2])}/${Number(match[3])} ${match[4]}:${match[5]}`;
214
+ }
215
+ return local;
216
+ }
217
+ function isComposerQuotaEnabled(provider, usage) {
218
+ if (provider !== PROVIDER_ID) return false;
219
+ if (!usage || usage.status !== "ok") return false;
220
+ return typeof usage.remainingPercent === "number" && Number.isFinite(usage.remainingPercent);
221
+ }
222
+ function notifyQuickQuota() {
223
+ try {
224
+ if (typeof window !== "undefined") {
225
+ window.dispatchEvent(new Event(QUICK_QUOTA_REFRESH_EVENT));
226
+ }
227
+ } catch {
228
+ }
229
+ }
230
+
231
+ // src/client-composer-quota.jsx
160
232
  var import_jsx_runtime = require("react/jsx-runtime");
161
- var inject = ["slots", "locale", "connection", "settingsScope"];
233
+ var QUICK_RPC_TIMEOUT_MS = 12e3;
234
+ async function quickCall(rpc, endpoint) {
235
+ const controller = typeof AbortController !== "undefined" ? new AbortController() : void 0;
236
+ let timer;
237
+ try {
238
+ const call = rpc.call(CHANNEL, endpoint, {}, controller?.signal);
239
+ const timeout = new Promise((_, reject) => {
240
+ timer = setTimeout(() => {
241
+ try {
242
+ controller?.abort();
243
+ } catch {
244
+ }
245
+ reject(new Error(`Request timed out after ${QUICK_RPC_TIMEOUT_MS}ms`));
246
+ }, QUICK_RPC_TIMEOUT_MS);
247
+ });
248
+ return unwrap(await Promise.race([call, timeout]));
249
+ } finally {
250
+ if (timer) clearTimeout(timer);
251
+ }
252
+ }
253
+ function useAnchoredPositionFallback({ open, anchorRef }) {
254
+ const [position, setPosition] = (0, import_react.useState)(null);
255
+ (0, import_react.useEffect)(() => {
256
+ if (!open || !anchorRef?.current) {
257
+ setPosition(null);
258
+ return void 0;
259
+ }
260
+ const place = () => {
261
+ const rect = anchorRef.current.getBoundingClientRect();
262
+ setPosition({
263
+ position: "fixed",
264
+ left: Math.max(12, Math.min(rect.left, window.innerWidth - 12)),
265
+ top: Math.max(12, rect.top - 8),
266
+ transform: "translateY(-100%)"
267
+ });
268
+ };
269
+ place();
270
+ window.addEventListener("resize", place);
271
+ window.addEventListener("scroll", place, true);
272
+ return () => {
273
+ window.removeEventListener("resize", place);
274
+ window.removeEventListener("scroll", place, true);
275
+ };
276
+ }, [open, anchorRef]);
277
+ return position;
278
+ }
279
+ function useDismissOnOutsidePointerFallback(triggerRef, open, dismiss, panelRef) {
280
+ (0, import_react.useEffect)(() => {
281
+ if (!open) return void 0;
282
+ const onPointer = (event) => {
283
+ const target = event.target;
284
+ if (triggerRef.current?.contains?.(target) || panelRef.current?.contains?.(target)) return;
285
+ dismiss();
286
+ };
287
+ document.addEventListener("pointerdown", onPointer, true);
288
+ return () => document.removeEventListener("pointerdown", onPointer, true);
289
+ }, [open, triggerRef, panelRef, dismiss]);
290
+ }
291
+ function loadAnchoringHooks() {
292
+ try {
293
+ const req = typeof require === "function" ? require : void 0;
294
+ const mod = req?.("@deepseek-ai/dsh-client-ui-primitives");
295
+ if (mod?.useAnchoredPosition && mod?.useDismissOnOutsidePointer) {
296
+ return {
297
+ useAnchoredPosition: mod.useAnchoredPosition,
298
+ useDismissOnOutsidePointer: mod.useDismissOnOutsidePointer
299
+ };
300
+ }
301
+ } catch {
302
+ }
303
+ return {
304
+ useAnchoredPosition: useAnchoredPositionFallback,
305
+ useDismissOnOutsidePointer: useDismissOnOutsidePointerFallback
306
+ };
307
+ }
308
+ var anchoring = loadAnchoringHooks();
309
+ function useGrokQuickQuota(rpc, enabled) {
310
+ const [usage, setUsage] = (0, import_react.useState)(void 0);
311
+ (0, import_react.useEffect)(() => {
312
+ if (!enabled) {
313
+ setUsage(void 0);
314
+ return void 0;
315
+ }
316
+ let live = true;
317
+ let loading = false;
318
+ const accept = (next) => {
319
+ if (!live) return;
320
+ if (next && next.status === "ok" && typeof next.remainingPercent === "number" && Number.isFinite(next.remainingPercent)) {
321
+ setUsage(next);
322
+ } else {
323
+ setUsage(void 0);
324
+ }
325
+ };
326
+ const softRefresh = () => {
327
+ void quickCall(rpc, "usage/refresh").then((value) => {
328
+ if (value?.usage) accept(value.usage);
329
+ }).catch(() => {
330
+ });
331
+ };
332
+ const load = async () => {
333
+ if (loading) return;
334
+ loading = true;
335
+ try {
336
+ let status;
337
+ try {
338
+ status = await quickCall(rpc, "status");
339
+ } catch {
340
+ status = void 0;
341
+ }
342
+ if (!live) return;
343
+ if (status?.account?.signedIn !== true) {
344
+ try {
345
+ const value = await quickCall(rpc, "usage");
346
+ accept(value?.usage);
347
+ } catch {
348
+ accept(void 0);
349
+ }
350
+ return;
351
+ }
352
+ let next = status?.usage;
353
+ if (!next || next.status !== "ok") {
354
+ try {
355
+ const value = await quickCall(rpc, "usage");
356
+ next = value?.usage ?? next;
357
+ } catch {
358
+ }
359
+ }
360
+ if (!live) return;
361
+ accept(next);
362
+ softRefresh();
363
+ } catch {
364
+ if (live) setUsage(void 0);
365
+ } finally {
366
+ loading = false;
367
+ }
368
+ };
369
+ const refresh = () => {
370
+ void load();
371
+ };
372
+ void load();
373
+ const timer = window.setInterval(refresh, QUICK_QUOTA_REFRESH_MS);
374
+ window.addEventListener(QUICK_QUOTA_REFRESH_EVENT, refresh);
375
+ return () => {
376
+ live = false;
377
+ window.clearInterval(timer);
378
+ window.removeEventListener(QUICK_QUOTA_REFRESH_EVENT, refresh);
379
+ };
380
+ }, [rpc, enabled]);
381
+ return usage;
382
+ }
383
+ function GrokComposerQuota({ rpc, t, directory }) {
384
+ const modelState = (0, import_react.useSyncExternalStore)(
385
+ (listener) => directory.subscribe(listener),
386
+ () => directory.getSnapshot()
387
+ );
388
+ const current = modelState?.current;
389
+ const provider = current?.provider;
390
+ const providerEnabled = provider === PROVIDER_ID;
391
+ const usage = useGrokQuickQuota(rpc, providerEnabled);
392
+ const enabled = isComposerQuotaEnabled(provider, usage);
393
+ const remaining = enabled ? formatRemainingPercent(usage.remainingPercent) : void 0;
394
+ const [open, setOpen] = (0, import_react.useState)(false);
395
+ const trigger = (0, import_react.useRef)(null);
396
+ const panel = (0, import_react.useRef)(null);
397
+ const pinned = (0, import_react.useRef)(false);
398
+ const dismissTimer = (0, import_react.useRef)(null);
399
+ const enter = () => {
400
+ clearTimeout(dismissTimer.current);
401
+ setOpen(true);
402
+ };
403
+ const leave = () => {
404
+ if (!pinned.current) dismissTimer.current = setTimeout(() => setOpen(false), 150);
405
+ };
406
+ const dismiss = () => {
407
+ pinned.current = false;
408
+ setOpen(false);
409
+ };
410
+ (0, import_react.useEffect)(() => () => clearTimeout(dismissTimer.current), []);
411
+ const id = (0, import_react.useId)();
412
+ const visible = open && enabled && remaining !== void 0;
413
+ const position = anchoring.useAnchoredPosition({
414
+ open: visible,
415
+ anchorRef: trigger,
416
+ panelRef: panel,
417
+ side: "top",
418
+ gap: 8,
419
+ margin: 12
420
+ });
421
+ anchoring.useDismissOnOutsidePointer(trigger, visible, dismiss, panel);
422
+ (0, import_react.useEffect)(() => {
423
+ setOpen(false);
424
+ }, [current?.model, enabled]);
425
+ (0, import_react.useEffect)(() => {
426
+ if (!visible) return void 0;
427
+ const escape = (event) => {
428
+ if (event.key !== "Escape") return;
429
+ event.preventDefault();
430
+ dismiss();
431
+ trigger.current?.focus?.();
432
+ };
433
+ document.addEventListener("keydown", escape);
434
+ return () => document.removeEventListener("keydown", escape);
435
+ }, [visible]);
436
+ if (!enabled || remaining === void 0) return null;
437
+ const reset = formatShortReset(usage);
438
+ const remainingLine = fillTemplate(t("composerQuotaRemaining"), { remaining });
439
+ const resetLine = reset ? fillTemplate(t("composerQuotaResets"), { reset }) : t("composerQuotaResetUnknown");
440
+ const detailsLabel = `${remainingLine} ${resetLine}`;
441
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
442
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
443
+ "button",
444
+ {
445
+ ref: trigger,
446
+ type: "button",
447
+ className: "grokComposerQuota",
448
+ title: detailsLabel,
449
+ "aria-label": `${t("composerQuotaDetails")}: ${detailsLabel}`,
450
+ "aria-haspopup": "dialog",
451
+ "aria-expanded": visible,
452
+ "aria-controls": visible ? id : void 0,
453
+ onMouseEnter: enter,
454
+ onMouseLeave: leave,
455
+ onClick: () => {
456
+ if (pinned.current) dismiss();
457
+ else {
458
+ pinned.current = true;
459
+ setOpen(true);
460
+ requestAnimationFrame(() => panel.current?.focus?.());
461
+ }
462
+ },
463
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: `${remaining}%` })
464
+ }
465
+ ),
466
+ visible ? (0, import_react_dom.createPortal)(
467
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
468
+ "section",
469
+ {
470
+ ref: panel,
471
+ id,
472
+ role: "dialog",
473
+ "aria-label": t("composerQuotaDetails"),
474
+ className: "grokQuotaPopover",
475
+ tabIndex: -1,
476
+ onMouseEnter: enter,
477
+ onMouseLeave: leave,
478
+ style: { ...position || {}, visibility: position ? "visible" : "hidden" },
479
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "grokQuotaDetail", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
480
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: remainingLine }),
481
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "grokQuotaReset", children: resetLine })
482
+ ] }) })
483
+ }
484
+ ),
485
+ document.body
486
+ ) : null
487
+ ] });
488
+ }
489
+
490
+ // src/client.jsx
491
+ var import_jsx_runtime2 = require("react/jsx-runtime");
492
+ var inject = [
493
+ "slots",
494
+ "locale",
495
+ "connection",
496
+ "settingsScope",
497
+ "modelDirectories",
498
+ "sessions",
499
+ "remote"
500
+ ];
162
501
  var RPC_CALL_TIMEOUT_MS = 12e3;
163
502
  function pickCopy(locale) {
164
503
  const language = typeof locale === "string" ? locale : locale?.language ?? locale?.lang;
@@ -199,18 +538,18 @@ function UsagePanel({ usage, t, usageBusy, onRefresh, signedIn }) {
199
538
  const used = ok ? formatPercent(usage.usedPercent) : void 0;
200
539
  const remaining = ok ? formatPercent(usage.remainingPercent) : void 0;
201
540
  const resetLabel = usage?.periodEndLocal || usage?.periodEnd;
202
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "usageBlock", children: [
203
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: t("usageTitle") }),
204
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "muted", children: t("usageSubtitle") }),
205
- ok && used !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
206
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { children: [
541
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "usageBlock", children: [
542
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: t("usageTitle") }),
543
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "muted", children: t("usageSubtitle") }),
544
+ ok && used !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
545
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { children: [
207
546
  t("usageUsed"),
208
547
  ": ",
209
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("strong", { children: [
548
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("strong", { children: [
210
549
  used,
211
550
  "%"
212
551
  ] }),
213
- remaining !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
552
+ remaining !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
214
553
  " \xB7 ",
215
554
  t("usageRemaining"),
216
555
  " ",
@@ -218,46 +557,46 @@ function UsagePanel({ usage, t, usageBusy, onRefresh, signedIn }) {
218
557
  "%"
219
558
  ] }) : null
220
559
  ] }),
221
- resetLabel ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "muted", children: [
560
+ resetLabel ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "muted", children: [
222
561
  t("usageReset"),
223
562
  ": ",
224
563
  resetLabel,
225
- usage.periodEnd && usage.periodEndLocal ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
564
+ usage.periodEnd && usage.periodEndLocal ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
226
565
  " (",
227
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: usage.periodEnd }),
566
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { children: usage.periodEnd }),
228
567
  ")"
229
568
  ] }) : null
230
569
  ] }) : null,
231
- Array.isArray(usage.productUsage) && usage.productUsage.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
232
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "muted", children: t("usageProduct") }),
233
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { children: usage.productUsage.map((row, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { children: [
570
+ Array.isArray(usage.productUsage) && usage.productUsage.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
571
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "muted", children: t("usageProduct") }),
572
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ul", { children: usage.productUsage.map((row, index) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("li", { children: [
234
573
  row.name ?? "\u2014",
235
574
  typeof row.usedPercent === "number" ? ` \xB7 ${formatPercent(row.usedPercent)}%` : ""
236
575
  ] }, `${row.name ?? "row"}-${index}`)) })
237
576
  ] }) : null,
238
- usage.fetchedAt ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "muted", children: [
577
+ usage.fetchedAt ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "muted", children: [
239
578
  t("usageFetchedAt"),
240
579
  ": ",
241
580
  usage.fetchedAt
242
581
  ] }) : null
243
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { children: [
582
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { children: [
244
583
  t("usageUnavailable"),
245
584
  usage?.reason ? `: ${usage.reason}` : ""
246
585
  ] }),
247
- usageBusy ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "muted", children: t("busyUsage") }) : null,
248
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "row", children: [
249
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", disabled: Boolean(usageBusy) || !signedIn, onClick: onRefresh, children: t("usageRefresh") }),
250
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: USAGE_PAGE_URL, target: "_blank", rel: "noreferrer", children: t("usageOpenGrok") })
586
+ usageBusy ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "muted", children: t("busyUsage") }) : null,
587
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "row", children: [
588
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", disabled: Boolean(usageBusy) || !signedIn, onClick: onRefresh, children: t("usageRefresh") }),
589
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("a", { href: USAGE_PAGE_URL, target: "_blank", rel: "noreferrer", children: t("usageOpenGrok") })
251
590
  ] })
252
591
  ] });
253
592
  }
254
593
  function GrokSubscriptionSection({ rpc, t }) {
255
- const [busy, setBusy] = (0, import_react.useState)("");
256
- const [usageBusy, setUsageBusy] = (0, import_react.useState)(false);
257
- const [error, setError] = (0, import_react.useState)("");
258
- const [notice, setNotice] = (0, import_react.useState)("");
259
- const [status, setStatus] = (0, import_react.useState)(void 0);
260
- const initialUsageKick = (0, import_react.useRef)(false);
594
+ const [busy, setBusy] = (0, import_react2.useState)("");
595
+ const [usageBusy, setUsageBusy] = (0, import_react2.useState)(false);
596
+ const [error, setError] = (0, import_react2.useState)("");
597
+ const [notice, setNotice] = (0, import_react2.useState)("");
598
+ const [status, setStatus] = (0, import_react2.useState)(void 0);
599
+ const initialUsageKick = (0, import_react2.useRef)(false);
261
600
  const applyPartial = (value) => {
262
601
  if (value?.account || value?.catalog || value?.usage) {
263
602
  setStatus((current) => ({ ...current, ...value }));
@@ -269,13 +608,14 @@ function GrokSubscriptionSection({ rpc, t }) {
269
608
  setError("");
270
609
  return value;
271
610
  };
272
- (0, import_react.useEffect)(() => {
611
+ (0, import_react2.useEffect)(() => {
273
612
  void load().then((value) => {
274
613
  if (initialUsageKick.current) return;
275
614
  if (value?.account?.signedIn !== true) return;
276
615
  initialUsageKick.current = true;
277
616
  void callRpc(rpc, "usage/refresh", {}).then((partial) => {
278
617
  applyPartial(partial);
618
+ notifyQuickQuota();
279
619
  }).catch(() => {
280
620
  });
281
621
  }).catch((item) => {
@@ -290,6 +630,7 @@ function GrokSubscriptionSection({ rpc, t }) {
290
630
  });
291
631
  void callRpc(rpc, "usage/refresh", {}).then((partial) => {
292
632
  applyPartial(partial);
633
+ notifyQuickQuota();
293
634
  }).catch(() => {
294
635
  });
295
636
  };
@@ -322,6 +663,9 @@ function GrokSubscriptionSection({ rpc, t }) {
322
663
  "usage/refresh": "usageRefreshOk"
323
664
  }[endpoint];
324
665
  if (successKey) setNotice(t(successKey));
666
+ if (endpoint === "usage/refresh" && value?.ok !== false && !value?.error) {
667
+ notifyQuickQuota();
668
+ }
325
669
  }
326
670
  } catch (item) {
327
671
  setNotice("");
@@ -337,8 +681,8 @@ function GrokSubscriptionSection({ rpc, t }) {
337
681
  const catalog = status?.catalog;
338
682
  const models = catalog?.models ?? [];
339
683
  const signedIn = account?.signedIn === true;
340
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "grokSubscription", children: [
341
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: `
684
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("section", { className: "grokSubscription", children: [
685
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("style", { children: `
342
686
  .grokSubscription { display: grid; gap: 12px; max-width: 42rem; }
343
687
  .grokSubscription h2 { margin: 0 0 4px; font-size: 1.15rem; }
344
688
  .grokSubscription p, .grokSubscription li { line-height: 1.5; }
@@ -351,35 +695,35 @@ function GrokSubscriptionSection({ rpc, t }) {
351
695
  .grokSubscription .usageBlock { display: grid; gap: 8px; padding: 10px 0; border-top: 1px solid color-mix(in srgb, currentColor 18%, transparent); }
352
696
  .grokSubscription a { color: inherit; }
353
697
  ` }),
354
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
355
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: t("title") }),
356
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "muted", children: t("subtitle") })
698
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
699
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { children: t("title") }),
700
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "muted", children: t("subtitle") })
357
701
  ] }),
358
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
359
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("strong", { children: [
702
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
703
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("strong", { children: [
360
704
  t("account"),
361
705
  ": "
362
706
  ] }),
363
707
  signedIn ? `${t("signedIn")} \xB7 ${account.maskedAccount ?? t("unknownAccount")}` : t("signedOut")
364
708
  ] }),
365
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "row", children: [
366
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", disabled: Boolean(busy), onClick: () => void run("login/cli"), children: t("loginCli") }),
367
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", disabled: Boolean(busy), onClick: () => void run("login/device"), children: t("loginDevice") }),
368
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", disabled: Boolean(busy), onClick: () => void run("pull"), children: t("pull") }),
369
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { type: "button", disabled: Boolean(busy) || !signedIn, onClick: () => void run("logout"), children: t("logout") })
709
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "row", children: [
710
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", disabled: Boolean(busy), onClick: () => void run("login/cli"), children: t("loginCli") }),
711
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", disabled: Boolean(busy), onClick: () => void run("login/device"), children: t("loginDevice") }),
712
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", disabled: Boolean(busy), onClick: () => void run("pull"), children: t("pull") }),
713
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", disabled: Boolean(busy) || !signedIn, onClick: () => void run("logout"), children: t("logout") })
370
714
  ] }),
371
- busy ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "muted", children: t("busy") }) : null,
372
- notice ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "notice", children: notice }) : null,
373
- error ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "error", children: [
715
+ busy ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "muted", children: t("busy") }) : null,
716
+ notice ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "notice", children: notice }) : null,
717
+ error ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "error", children: [
374
718
  t("error"),
375
719
  ": ",
376
720
  error
377
721
  ] }) : null,
378
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "muted", children: t("loginHint") }),
379
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "muted", children: t("deviceHint") }),
380
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "muted", children: t("pullHint") }),
381
- status?.cliAvailable === false ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "muted", children: t("cliMissing") }) : null,
382
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
722
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "muted", children: t("loginHint") }),
723
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "muted", children: t("deviceHint") }),
724
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "muted", children: t("pullHint") }),
725
+ status?.cliAvailable === false ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "muted", children: t("cliMissing") }) : null,
726
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
383
727
  UsagePanel,
384
728
  {
385
729
  usage: status?.usage,
@@ -389,21 +733,21 @@ function GrokSubscriptionSection({ rpc, t }) {
389
733
  onRefresh: () => void run("usage/refresh")
390
734
  }
391
735
  ),
392
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
393
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: t("models") }),
394
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "muted", children: sourceLabel(catalog?.source, t) }),
395
- models.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: t("noModels") }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { children: models.map((model) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { children: [
736
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
737
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { children: t("models") }),
738
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "muted", children: sourceLabel(catalog?.source, t) }),
739
+ models.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { children: t("noModels") }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("ul", { children: models.map((model) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("li", { children: [
396
740
  model.name,
397
741
  " ",
398
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("code", { children: model.id })
742
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("code", { children: model.id })
399
743
  ] }, model.id)) }),
400
- catalog?.error ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "error", children: [
744
+ catalog?.error ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "error", children: [
401
745
  t("catalogError"),
402
746
  ": ",
403
747
  catalog.error
404
748
  ] }) : null
405
749
  ] }),
406
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "muted", children: t("caveats") })
750
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "muted", children: t("caveats") })
407
751
  ] });
408
752
  }
409
753
  function apply(ctx) {
@@ -432,6 +776,14 @@ function apply(ctx) {
432
776
  }
433
777
  return pickCopy(ctx.locale)[key] ?? key;
434
778
  };
779
+ ctx.effect?.(() => {
780
+ if (typeof document === "undefined") return void 0;
781
+ const tag = document.createElement("style");
782
+ tag.dataset.plugin = "dsh-grok-subscription";
783
+ tag.textContent = COMPOSER_QUOTA_STYLE;
784
+ document.head.append(tag);
785
+ return () => tag.remove();
786
+ }, "grok-subscription: composer-quota-style");
435
787
  ctx.slots.inject("settings.section", () => ctx.slots.register({
436
788
  name: "settings.section",
437
789
  id: "grok-subscription",
@@ -440,5 +792,38 @@ function apply(ctx) {
440
792
  locale: LOCALE_NS,
441
793
  inject: () => ({ rpc, t })
442
794
  }, GrokSubscriptionSection));
795
+ const installDirectorySlots = (scope) => {
796
+ let modelDirectories;
797
+ try {
798
+ modelDirectories = typeof scope.get === "function" ? scope.get("modelDirectories") : void 0;
799
+ } catch {
800
+ modelDirectories = void 0;
801
+ }
802
+ if (!modelDirectories?.directoryFor) {
803
+ try {
804
+ ctx.logger?.warn?.("Grok composer quota skipped: modelDirectories unavailable");
805
+ } catch {
806
+ }
807
+ return;
808
+ }
809
+ scope.slots.inject("conversation.input.right", () => scope.slots.register({
810
+ name: "conversation.input.right",
811
+ id: "grok-subscription-quota",
812
+ order: 16,
813
+ locale: LOCALE_NS,
814
+ inject: (sessionId) => ({
815
+ rpc,
816
+ t,
817
+ directory: modelDirectories.directoryFor(sessionId).store
818
+ })
819
+ }, GrokComposerQuota));
820
+ };
821
+ try {
822
+ const remoteSession = typeof ctx.get === "function" ? ctx.get("remote.session") : void 0;
823
+ if (remoteSession === void 0) installDirectorySlots(ctx);
824
+ else ctx.inject(["remote.session"], installDirectorySlots);
825
+ } catch {
826
+ installDirectorySlots(ctx);
827
+ }
443
828
  }
444
829
  return module.exports; } });
package/lib/index.js CHANGED
@@ -325,6 +325,7 @@ function fallbackModels() {
325
325
  maxTokens: 5e5,
326
326
  reasoning: true,
327
327
  reasoningEfforts: id === "grok-4.5" ? ["low", "medium", "high"] : ["low", "medium", "high", "xhigh"],
328
+ defaultEffort: "high",
328
329
  source: "fallback"
329
330
  }));
330
331
  }
@@ -362,13 +363,28 @@ function toPiModels(models) {
362
363
  };
363
364
  });
364
365
  }
366
+ function reasoningInfoOf(model) {
367
+ if (model?.reasoning === false) return void 0;
368
+ const efforts = Array.isArray(model?.reasoningEfforts) && model.reasoningEfforts.length ? model.reasoningEfforts : ["low", "medium", "high", "xhigh"];
369
+ const title = (id) => `${id.charAt(0).toUpperCase()}${id.slice(1)}`;
370
+ const preferred = model?.defaultEffort && efforts.includes(model.defaultEffort) ? model.defaultEffort : efforts.includes("high") ? "high" : efforts[efforts.length - 1];
371
+ return {
372
+ efforts: efforts.map((id) => ({ id, name: title(id) })),
373
+ defaultEffort: preferred
374
+ };
375
+ }
365
376
  function toLlmModels(models) {
366
- return models.map((model) => ({
367
- provider: PROVIDER_ID,
368
- id: model.id,
369
- name: model.name,
370
- inputModalities: ["text"]
371
- }));
377
+ return models.map((model) => {
378
+ const info = {
379
+ provider: PROVIDER_ID,
380
+ id: model.id,
381
+ name: model.name,
382
+ inputModalities: ["text"]
383
+ };
384
+ const reasoning = reasoningInfoOf(model);
385
+ if (reasoning) info.reasoning = reasoning;
386
+ return info;
387
+ });
372
388
  }
373
389
  async function fetchLiveCatalog(accessToken, options = {}) {
374
390
  const fetchImpl = options.fetch ?? globalThis.fetch;
@@ -942,13 +958,18 @@ function createDuckAdapter(session) {
942
958
  },
943
959
  async resolveModel(provider, model) {
944
960
  const found = list().find((item) => item.id === model);
945
- return {
961
+ const raw = session.publicAccount()?.signedIn === true ? session.models().find((item) => item.id === model) : void 0;
962
+ const info = {
946
963
  provider,
947
964
  id: model,
948
965
  name: found?.name ?? model,
949
966
  inputModalities: ["text"],
950
- context: { contextWindow: 5e5 }
967
+ context: { contextWindow: raw?.contextWindow ?? 5e5 }
951
968
  };
969
+ const reasoning = reasoningInfoOf(raw);
970
+ if (reasoning) info.reasoning = reasoning;
971
+ else if (found?.reasoning) info.reasoning = found.reasoning;
972
+ return info;
952
973
  },
953
974
  async prepareCall(provider, model, signal) {
954
975
  const resolved = await this.resolveModel(provider, model, signal);
@@ -1145,7 +1166,8 @@ async function createGrokBuildAdapter(session, options = {}) {
1145
1166
  requestImagePixelBudget: REQUEST_IMAGE_PIXEL_BUDGET,
1146
1167
  requestImageMaxBytes: REQUEST_IMAGE_MAX_BYTES,
1147
1168
  cacheRetention: "short",
1148
- transport: "sse"
1169
+ transport: "sse",
1170
+ reasoning: "high"
1149
1171
  });
1150
1172
  const LlmError = dshLlm?.LlmError;
1151
1173
  const adapter = new dshPi.PiAiAdapter({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-grok-subscription",
3
- "version": "0.1.12",
3
+ "version": "1.0.0",
4
4
  "description": "Use a SuperGrok or X Premium Grok Build subscription in DeepSeek Harness",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -23,8 +23,11 @@
23
23
  },
24
24
  "client": {
25
25
  "inject": [
26
+ "@deepseek-ai/dsh-api-remotes",
26
27
  "@deepseek-ai/dsh-client-connection",
27
28
  "@deepseek-ai/dsh-client-locale",
29
+ "@deepseek-ai/dsh-client-ui-conversation",
30
+ "@deepseek-ai/dsh-client-ui-model-selection",
28
31
  "@deepseek-ai/dsh-client-ui-settings",
29
32
  "@deepseek-ai/dsh-client-ui-slots"
30
33
  ],
@@ -60,7 +63,11 @@
60
63
  "@deepseek-ai/dsh-web": "^0.1.5-rc.2",
61
64
  "@earendil-works/pi-ai": "^0.82.1",
62
65
  "react": "^18.2.0",
63
- "react-dom": "^18.2.0"
66
+ "react-dom": "^18.2.0",
67
+ "@deepseek-ai/dsh-api-remotes": "^0.1.5-rc.2",
68
+ "@deepseek-ai/dsh-client-ui-conversation": "^0.1.5-rc.2",
69
+ "@deepseek-ai/dsh-client-ui-model-selection": "^0.1.5-rc.2",
70
+ "@deepseek-ai/dsh-client-ui-primitives": "^0.1.5-rc.2"
64
71
  },
65
72
  "peerDependenciesMeta": {
66
73
  "@deepseek-ai/dsh-client-connection": {
@@ -98,6 +105,18 @@
98
105
  },
99
106
  "react-dom": {
100
107
  "optional": true
108
+ },
109
+ "@deepseek-ai/dsh-api-remotes": {
110
+ "optional": true
111
+ },
112
+ "@deepseek-ai/dsh-client-ui-conversation": {
113
+ "optional": true
114
+ },
115
+ "@deepseek-ai/dsh-client-ui-model-selection": {
116
+ "optional": true
117
+ },
118
+ "@deepseek-ai/dsh-client-ui-primitives": {
119
+ "optional": true
101
120
  }
102
121
  },
103
122
  "devDependencies": {