@klarkxy/dsh-session-manager 0.3.0 → 0.3.2

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.
@@ -59,18 +59,20 @@ const text = {
59
59
  settingsMode: "继续灰影",
60
60
  modeFixed: "固定文本",
61
61
  modeAuto: "模型生成",
62
- settingsModeHint: "输入框为空时显示的灰色继续文本:Tab 填入,点击发送。",
62
+ settingsModeHint: "输入框为空时显示建议;按 Tab 填入,点击直接发送。",
63
+ continueSourceLabel: "内容来源",
63
64
  continueTextLabel: "固定文本内容",
64
65
  continueTextPlaceholder: "留空使用默认「继续」",
65
- ghostModelLabel: "灰影模型",
66
- ghostModelHint: "只在上一轮结束后生成一次,并缓存在这个会话中;留空跟随会话或宿主默认。",
67
- welcomeBackGroup: "欢迎回来",
68
- recapEnabledLabel: "欢迎回来摘要",
69
- recapEnabledHint: "回到空闲的会话时,在对话顶部生成回顾卡片。",
70
- recapMinutesLabel: "摘要阈值(分钟)",
71
- compactEnabledLabel: "压缩建议",
72
- compactEnabledHint: "空闲较久时,回到会话会建议先压缩上下文。",
73
- compactMinutesLabel: "建议阈值(分钟)",
66
+ ghostModelLabel: "生成模型",
67
+ ghostModelHint: "每轮结束后生成一次并缓存;不选择时使用当前会话或宿主的默认模型。",
68
+ welcomeBackGroup: "回到会话时",
69
+ recapEnabledLabel: "显示会话摘要",
70
+ recapEnabledHint: "在对话中回顾上次进展。",
71
+ recapMinutesLabel: "离开多久后显示摘要",
72
+ compactEnabledLabel: "建议压缩上下文",
73
+ compactEnabledHint: "长时间离开后,建议先压缩上下文。",
74
+ compactMinutesLabel: "离开多久后显示建议",
75
+ minutesUnit: "分钟",
74
76
  modelLabel: "摘要模型",
75
77
  modelFollowOption: "当前会话 / 宿主默认模型",
76
78
  modelGroupHint: "只用于欢迎回来摘要;留空跟随会话或宿主默认。",
@@ -113,18 +115,20 @@ const text = {
113
115
  settingsMode: "Continue ghost",
114
116
  modeFixed: "Fixed text",
115
117
  modeAuto: "Model-generated",
116
- settingsModeHint: "The grey continuation shown on an empty composer: Tab fills it, clicking sends it.",
118
+ settingsModeHint: "Show a suggestion when the composer is empty. Press Tab to fill it, or click to send.",
119
+ continueSourceLabel: "Source",
117
120
  continueTextLabel: "Fixed text",
118
121
  continueTextPlaceholder: "Empty uses the default \"Continue\"",
119
- ghostModelLabel: "Ghost model",
120
- ghostModelHint: "Generated once after the previous turn ends and cached for this session; empty follows the conversation or host default.",
121
- welcomeBackGroup: "Welcome back",
122
- recapEnabledLabel: "Welcome-back recap",
123
- recapEnabledHint: "Shows a recap card at the top of the conversation when you return to an idle session.",
124
- recapMinutesLabel: "Recap threshold (minutes)",
125
- compactEnabledLabel: "Compaction suggestion",
126
- compactEnabledHint: "Suggests compacting the context when you return after a longer idle stretch.",
127
- compactMinutesLabel: "Suggestion threshold (minutes)",
122
+ ghostModelLabel: "Generation model",
123
+ ghostModelHint: "Generated once after each turn and cached. The default follows the current conversation or host.",
124
+ welcomeBackGroup: "When you return",
125
+ recapEnabledLabel: "Show session recap",
126
+ recapEnabledHint: "Review your previous progress in the conversation.",
127
+ recapMinutesLabel: "Show recap after",
128
+ compactEnabledLabel: "Suggest context compaction",
129
+ compactEnabledHint: "Suggest compacting the context after a long time away.",
130
+ compactMinutesLabel: "Show suggestion after",
131
+ minutesUnit: "minutes",
128
132
  modelLabel: "Recap model",
129
133
  modelFollowOption: "Current conversation / host default",
130
134
  modelGroupHint: "Used only for the welcome-back recap; empty follows the conversation or host default.",
@@ -412,6 +416,17 @@ ${scope} {
412
416
  /* --- Layout scaffolding. --- */
413
417
  & .dsh-ui-stack { display: flex; flex-direction: column; gap: 12px; }
414
418
  & .dsh-ui-stack-lg { display: flex; flex-direction: column; gap: 20px; }
419
+ /* Plugin detail pages share one reading column. These are layout recipes;
420
+ * controls keep their own primitive styles. Form spacing follows the host's
421
+ * settings-form/fields.module.css and SettingsForm.module.css. */
422
+ & .dsh-ui-page { display: flex; flex-direction: column; gap: 16px; width: 100%; max-width: 760px; min-width: 0; }
423
+ & .dsh-ui-form { display: flex; flex-direction: column; gap: 0; min-width: 0; }
424
+ &.dsh-ui-form > .dsh-ui-field, & .dsh-ui-form > .dsh-ui-field { padding: 12px 0; }
425
+ & .dsh-ui-form-footer { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; padding-top: 16px; min-width: 0; }
426
+ & .dsh-ui-fields-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px 20px; min-width: 0; margin: 0; padding: 0; border: 0; }
427
+ @media (max-width: 560px) {
428
+ & .dsh-ui-fields-grid { grid-template-columns: minmax(0, 1fr); }
429
+ }
415
430
  & .dsh-ui-row { display: flex; align-items: center; gap: 8px; min-width: 0; }
416
431
  & .dsh-ui-row-wrap { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
417
432
  & .dsh-ui-spacer { flex: 1; min-width: 0; }
@@ -439,6 +454,9 @@ ${scope} {
439
454
  * official primitive, so this only owns the vertical rhythm. --- */
440
455
  & .dsh-ui-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
441
456
  & .dsh-ui-field + .dsh-ui-field { border-top: 0.5px solid var(--dsw-alias-border-l2); padding-top: 12px; }
457
+ /* Grid fields share a row, so the stacked-field divider must not win later in
458
+ * the cascade. Reset it here, after the field recipe. */
459
+ & .dsh-ui-fields-grid > .dsh-ui-field { padding: 0; border: 0; }
442
460
  & .dsh-ui-label { display: flex; align-items: center; gap: 6px; font-size: 13px; line-height: 20px; font-weight: 500; color: var(--dsw-alias-label-primary); }
443
461
  & .dsh-ui-label-row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
444
462
  & .dsh-ui-help { font-size: 12px; line-height: 1.6; color: var(--dsw-alias-label-secondary); }
@@ -629,7 +647,7 @@ ${scope} {
629
647
  & *, & *::before, & *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
630
648
  }
631
649
  }
632
- `.replace(/^& (\.dsh-ui-[a-z0-9-]+)(?![+>~])/gm, (_match, className) => `&${className}, & ${className}`);
650
+ `.replace(/^& (\.dsh-ui-[a-z0-9-]+)(?=\s*\{)/gm, (_match, className) => `&${className}, & ${className}`);
633
651
  }
634
652
  //#endregion
635
653
  //#region ../dsh-model-route/src/route.ts
@@ -861,7 +879,14 @@ function useModelCatalog(load, options = {}) {
861
879
  refresh
862
880
  };
863
881
  }
864
- /** Also accepts a mapped state from a caller that owns broader async orchestration. */
882
+ /**
883
+ * Also accepts a mapped state from a caller that owns broader async orchestration.
884
+ *
885
+ * The dsh-ui-* classes carry the styling and resolve through the consuming
886
+ * plugin's own officialUiCss scope (every consumer mounts its root class, so
887
+ * e.g. `.dsh-model-hub .dsh-ui-loading` paints this); dsh-model-catalog-status
888
+ * stays as a structural hook for tests and layout, never a colour source.
889
+ */
865
890
  function ModelCatalogStatus({ state, locale }) {
866
891
  const zh = locale?.toLowerCase().startsWith("zh") === true;
867
892
  const copy = zh ? {
@@ -877,15 +902,17 @@ function ModelCatalogStatus({ state, locale }) {
877
902
  };
878
903
  if (!state.loading && !state.error && state.failures.length === 0) return null;
879
904
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
880
- className: "dsh-model-catalog-status",
905
+ className: "dsh-model-catalog-status dsh-ui-stack",
881
906
  lang: zh ? "zh" : "en",
882
907
  children: [
883
908
  state.loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
884
909
  role: "status",
910
+ className: "dsh-ui-loading",
885
911
  children: copy.loading
886
912
  }) : null,
887
913
  state.error ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
888
914
  role: "alert",
915
+ className: "dsh-ui-error dsh-ui-wrap",
889
916
  children: [
890
917
  copy.error,
891
918
  ": ",
@@ -894,20 +921,27 @@ function ModelCatalogStatus({ state, locale }) {
894
921
  }) : null,
895
922
  state.failures.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
896
923
  role: "status",
897
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: copy.partial }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", { children: state.failures.map((failure, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [
898
- failure.name || failure.id,
899
- ": ",
900
- failure.message
901
- ] }, `${failure.id}:${index}`)) })]
924
+ className: "dsh-ui-meta",
925
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: copy.partial }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
926
+ className: "dsh-ui-list",
927
+ children: state.failures.map((failure, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [
928
+ failure.name || failure.id,
929
+ ": ",
930
+ failure.message
931
+ ] }, `${failure.id}:${index}`))
932
+ })]
902
933
  }) : null,
903
- state.error || state.failures.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
904
- type: "button",
905
- size: "sm",
906
- disabled: state.loading,
907
- onClick: () => {
908
- state.refresh();
909
- },
910
- children: copy.retry
934
+ state.error || state.failures.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
935
+ className: "dsh-ui-actions",
936
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
937
+ type: "button",
938
+ size: "sm",
939
+ disabled: state.loading,
940
+ onClick: () => {
941
+ state.refresh();
942
+ },
943
+ children: copy.retry
944
+ })
911
945
  }) : null
912
946
  ]
913
947
  });
@@ -967,7 +1001,8 @@ function groupModelMenuChoices(choices, query) {
967
1001
  * Sticky group headings, subsequence ranking, highlight walking and focus
968
1002
  * hand-back all match the host. SYNC POINT: when the host's ModelSelect or
969
1003
  * ModelSelect.module.css changes, this copy must be re-transcribed; styles
970
- * below may only reference --dsw-* theme tokens, never literal colors.
1004
+ * below may only reference allowlisted theme tokens (the --dsw-* set plus the
1005
+ * host's --ds-* motion tokens), never literal colors.
971
1006
  *
972
1007
  * It statically imports the primitives, so only browser clients should load
973
1008
  * this entry; host code and node tests use the core entry (`./index.ts`).
@@ -1475,7 +1510,8 @@ function ModelMenu(props) {
1475
1510
  * sticky group headings (MenuGroup's own CSS), and the l1-stroke prominent
1476
1511
  * elevation at portal z-index 1100. The trigger mirrors the composer's 28px
1477
1512
  * model pill, chevron rotating open. MenuSurface paints fill and backdrop.
1478
- * Only --dsw-* theme tokens may appear here — a literal color is a bug.
1513
+ * Only allowlisted --dsw- and --ds- theme tokens may appear here — a literal
1514
+ * color is a bug.
1479
1515
  */
1480
1516
  const modelMenuCss = `
1481
1517
  .dsh-model-menu-root { min-width: 0; position: relative; display: inline-flex; }
@@ -1498,12 +1534,14 @@ const modelMenuCss = `
1498
1534
  display: flex;
1499
1535
  }
1500
1536
  .dsh-model-menu-trigger:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }
1501
- .dsh-model-menu-trigger:focus-visible:not([data-selection-focus]) { box-shadow: 0 0 0 2px var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary)); }
1537
+ .dsh-model-menu-trigger:focus-visible:not([data-selection-focus]) { box-shadow: 0 0 0 var(--dsw-focus-ring-width) var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary)); }
1502
1538
  .dsh-model-menu-trigger:disabled { color: var(--dsw-alias-label-dimmed); cursor: default; }
1503
1539
  .dsh-model-menu-triggerLabel { text-overflow: ellipsis; white-space: nowrap; min-width: 0; overflow: hidden; }
1504
1540
  .dsh-model-menu-triggerEffort { text-overflow: ellipsis; white-space: nowrap; min-width: 0; color: var(--dsw-alias-label-caption); flex-shrink: 1000; overflow: hidden; }
1505
- .dsh-model-menu-chevron { color: var(--dsw-alias-label-caption); flex: none; transition: transform 0.12s; }
1541
+ .dsh-model-menu-chevron { color: var(--dsw-alias-label-caption); flex: none; transition: transform var(--ds-transition-duration) var(--ds-ease-in-out); }
1506
1542
  .dsh-model-menu-chevronOpen { transform: rotate(180deg); }
1543
+ /* Portal overlay: the host publishes no z-index token, so the card keeps the
1544
+ * native menu layer's 1100 verbatim. */
1507
1545
  .dsh-model-menu-menu {
1508
1546
  z-index: 1100;
1509
1547
  --dsw-elevation-stroke-color: var(--dsw-alias-border-l1);
@@ -1529,6 +1567,8 @@ const modelMenuCss = `
1529
1567
  .dsh-model-menu-searchWithQuery { padding-right: 34px; }
1530
1568
  .dsh-model-menu-searchRow .dsh-model-menu-search input { padding: 0; font-size: 12px; line-height: normal; }
1531
1569
  .dsh-model-menu-searchRow .dsh-model-menu-search input::placeholder { color: var(--dsw-alias-label-caption); }
1570
+ /* The clear button is a circle by geometry (border-radius: 50%), a shape the
1571
+ * radius token scale does not describe. */
1532
1572
  .dsh-model-menu-searchClear {
1533
1573
  width: 24px;
1534
1574
  height: 24px;
@@ -1618,25 +1658,88 @@ ${modelMenuCss}
1618
1658
  min-width: 0;
1619
1659
  }
1620
1660
  .${FREE_CHAT_ROOT} .dsh-free-alert { margin: 0; }
1621
- /* Settings page: a feature is its toggle row plus the nested well that holds
1622
- * the fields the switch gates. The well reuses the nested-card surface
1623
- * (layer-2 on layer-1) so the grouping reads without another heading. */
1661
+ /* Settings page: one quiet reading surface. Rules, not nested wells, separate
1662
+ * sections; dependent controls align with the feature they belong to. */
1663
+ .${FREE_CHAT_ROOT} .dsm-settings {
1664
+ display: flex;
1665
+ flex-direction: column;
1666
+ gap: 20px;
1667
+ min-width: 0;
1668
+ }
1669
+ .${FREE_CHAT_ROOT} .dsm-setting {
1670
+ display: flex;
1671
+ flex-direction: column;
1672
+ gap: 12px;
1673
+ min-width: 0;
1674
+ }
1675
+ .${FREE_CHAT_ROOT} .dsm-setting + .dsm-setting {
1676
+ padding-top: 20px;
1677
+ border-top: 0.5px solid var(--dsw-alias-border-l2);
1678
+ }
1679
+ .${FREE_CHAT_ROOT} .dsm-setting-header {
1680
+ display: flex;
1681
+ flex-direction: column;
1682
+ gap: 4px;
1683
+ }
1684
+ .${FREE_CHAT_ROOT} .dsm-ghost-controls {
1685
+ display: grid;
1686
+ grid-template-columns: minmax(220px, 0.8fr) minmax(0, 1.2fr);
1687
+ align-items: start;
1688
+ gap: 16px;
1689
+ }
1690
+ /* SegmentedTabs is 42px tall; its adjacent text controls share that baseline. */
1691
+ .${FREE_CHAT_ROOT} .dsm-ghost-controls .dsh-model-menu-trigger,
1692
+ .${FREE_CHAT_ROOT} .dsm-ghost-controls .dsm-ghost-input {
1693
+ height: 42px;
1694
+ }
1624
1695
  .${FREE_CHAT_ROOT} .dsm-feature + .dsm-feature {
1696
+ margin-top: 4px;
1625
1697
  border-top: 0.5px solid var(--dsw-alias-border-l2);
1626
1698
  }
1627
- .${FREE_CHAT_ROOT} .dsm-subs {
1699
+ .${FREE_CHAT_ROOT} .dsm-feature > .dsh-ui-toggle-row { padding: 8px 0; }
1700
+ .${FREE_CHAT_ROOT} .dsm-feature-options {
1628
1701
  display: flex;
1629
1702
  flex-direction: column;
1630
- gap: 12px;
1631
- margin: 0 0 4px;
1632
- padding: 12px;
1633
- border-radius: var(--dsw-radius-md);
1634
- background: var(--dsw-alias-bg-layer-2);
1703
+ gap: 8px;
1704
+ padding: 4px 0 8px;
1635
1705
  }
1636
- .${FREE_CHAT_ROOT} .dsm-subs[data-disabled='true'] .dsh-ui-label {
1706
+ .${FREE_CHAT_ROOT} .dsm-feature-options[data-disabled='true'] .dsh-ui-label,
1707
+ .${FREE_CHAT_ROOT} .dsm-feature-options[data-disabled='true'] .dsh-ui-meta {
1637
1708
  color: var(--dsw-alias-label-tertiary);
1638
1709
  }
1639
- .${FREE_CHAT_ROOT} .dsm-minutes { width: 120px; }
1710
+ .${FREE_CHAT_ROOT} .dsm-compact-options { max-width: calc(50% - 10px); }
1711
+ .${FREE_CHAT_ROOT} .dsm-model-field .dsh-model-menu-root,
1712
+ .${FREE_CHAT_ROOT} .dsm-model-field .dsh-model-menu-trigger {
1713
+ width: 100%;
1714
+ max-width: none;
1715
+ }
1716
+ .${FREE_CHAT_ROOT} .dsm-model-field .dsh-model-menu-trigger {
1717
+ justify-content: space-between;
1718
+ height: 32px;
1719
+ padding: 0 10px;
1720
+ border: 0.5px solid var(--dsw-alias-border-l4);
1721
+ border-radius: var(--dsw-radius-md);
1722
+ background: var(--dsw-alias-bg-layer-3);
1723
+ color: var(--dsw-alias-label-primary);
1724
+ }
1725
+ .${FREE_CHAT_ROOT} .dsm-model-field .dsh-model-menu-triggerLabel {
1726
+ flex: 1;
1727
+ text-align: left;
1728
+ }
1729
+ .${FREE_CHAT_ROOT} .dsm-settings-footer .dsh-ui-notice--error {
1730
+ flex: 0 0 100%;
1731
+ min-width: 0;
1732
+ }
1733
+ .${FREE_CHAT_ROOT} .dsm-minutes-control {
1734
+ display: flex;
1735
+ align-items: center;
1736
+ gap: 8px;
1737
+ }
1738
+ .${FREE_CHAT_ROOT} .dsm-minutes { width: 88px; }
1739
+ @media (max-width: 560px) {
1740
+ .${FREE_CHAT_ROOT} .dsm-ghost-controls { grid-template-columns: minmax(0, 1fr); }
1741
+ .${FREE_CHAT_ROOT} .dsm-compact-options { max-width: none; }
1742
+ }
1640
1743
  /* Welcome-back card: one flat full-width row at the latest turn's tail in the
1641
1744
  * chat flow — a single bordered surface with the recap laid out inline, no
1642
1745
  * nested box. */
@@ -1697,20 +1800,6 @@ ${modelMenuCss}
1697
1800
  `;
1698
1801
  //#endregion
1699
1802
  //#region src/free-panel.tsx
1700
- function FreeChatIcon({ size }) {
1701
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
1702
- width: size,
1703
- height: size,
1704
- viewBox: "0 0 16 16",
1705
- "aria-hidden": "true",
1706
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1707
- d: "M2.5 3.5h11v7.5h-4.2L6 13.5V11H2.5z",
1708
- fill: "none",
1709
- stroke: "currentColor",
1710
- strokeWidth: "1.2"
1711
- })
1712
- });
1713
- }
1714
1803
  /** Create failures used to surface inside the standalone panel. The panel is gone,
1715
1804
  * so they get a small overlay instead; closing it dismisses the stored notice. */
1716
1805
  function CreateNoticeDialog(props) {
@@ -1908,7 +1997,7 @@ function TemporaryWorkspacePicker(props) {
1908
1997
  }] : [], {
1909
1998
  id: "::temporary-workspace",
1910
1999
  label: uiText(locale, "tempWorkspace"),
1911
- icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FreeChatIcon, { size: 16 }),
2000
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconNewChatOutlineRegular, { size: 16 }),
1912
2001
  disabled: busy
1913
2002
  }],
1914
2003
  onSelect: (id) => {
@@ -1921,6 +2010,7 @@ function TemporaryWorkspacePicker(props) {
1921
2010
  }),
1922
2011
  props.open && workspaces.phase === "pending" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1923
2012
  role: "status",
2013
+ className: `dsh-free-chat dsh-ui-loading`,
1924
2014
  children: props.t("picker.loading")
1925
2015
  }),
1926
2016
  props.renderSlot(TEMP_WORKSPACE_FLOW_SLOT, {
@@ -1956,6 +2046,7 @@ function TemporaryWorkspacePicker(props) {
1956
2046
  }),
1957
2047
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
1958
2048
  open: failure !== void 0,
2049
+ className: FREE_CHAT_ROOT,
1959
2050
  title: props.t("folderError.title"),
1960
2051
  closeLabel: props.t("close"),
1961
2052
  onClose: () => setFailure(void 0),
@@ -1980,6 +2071,7 @@ function TemporaryWorkspaceNotice({ model, locale }) {
1980
2071
  const state = (0, react.useSyncExternalStore)(model.subscribe, model.getSnapshot, model.getSnapshot);
1981
2072
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
1982
2073
  open: state.failure !== void 0,
2074
+ className: FREE_CHAT_ROOT,
1983
2075
  title: uiText(locale, "createFailed"),
1984
2076
  closeLabel: uiText(locale, "close"),
1985
2077
  onClose: model.dismissFailure,
@@ -2789,11 +2881,11 @@ function createContinueModel(host) {
2789
2881
  load(sessionId) {
2790
2882
  if (sessionId === "" || lifetime.signal.aborted || inflight.has(sessionId)) return;
2791
2883
  const current = read(sessionId);
2792
- if (current.text !== void 0 && current.seq === void 0) return;
2884
+ if (current.text !== void 0 && current.seq === void 0 && current.pending !== true) return;
2793
2885
  const ticket = new AbortController();
2794
2886
  inflight.set(sessionId, ticket);
2795
2887
  const signal = AbortSignal.any([lifetime.signal, ticket.signal]);
2796
- callContinueSuggest(host, sessionId, current.seq, signal).then((value) => {
2888
+ callContinueSuggest(host, sessionId, current.text ? current.seq : void 0, signal).then((value) => {
2797
2889
  if (signal.aborted || inflight.get(sessionId) !== ticket) return;
2798
2890
  write(sessionId, value);
2799
2891
  }).catch(() => {}).finally(() => {
@@ -2832,7 +2924,9 @@ async function callContinueSuggest(host, sessionId, knownSeq, signal) {
2832
2924
  const seq = typeof value?.seq === "number" && Number.isSafeInteger(value.seq) && value.seq >= 0 ? value.seq : void 0;
2833
2925
  return {
2834
2926
  text,
2835
- ...seq === void 0 ? {} : { seq }
2927
+ ...seq === void 0 ? {} : { seq },
2928
+ ...value?.pending === true ? { pending: true } : {},
2929
+ ...value?.fallback === true ? { fallback: true } : {}
2836
2930
  };
2837
2931
  }
2838
2932
  function createPresenceConfigModel(host, delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms))) {
@@ -3289,8 +3383,10 @@ function ContinueGhost(props) {
3289
3383
  const blank = props.useSession?.((state) => state.blank) ?? true;
3290
3384
  const running = props.useSessionStatus?.((state) => state.get(sessionId)?.running === true) ?? false;
3291
3385
  const snapshot = (0, react.useSyncExternalStore)(props.model.subscribe, () => props.model.getSnapshot(sessionId), () => props.model.getSnapshot(sessionId));
3292
- const text = snapshot.text ?? uiText(props.locale, "continueDefault");
3293
- const active = sessionId !== "" && !blank && bare && draft === "" && phase === "plain";
3386
+ const shown = running || snapshot.pending === true || snapshot.text === void 0 ? "" : snapshot.text ?? (snapshot.fallback === true ? uiText(props.locale, "continueDefault") : "");
3387
+ const idle = sessionId !== "" && !blank && bare && draft === "" && phase === "plain" && !running;
3388
+ const active = shown !== "" && idle;
3389
+ const text = shown;
3294
3390
  const latest = (0, react.useRef)({
3295
3391
  active,
3296
3392
  text
@@ -3306,18 +3402,18 @@ function ContinueGhost(props) {
3306
3402
  const finished = wasRunning.current && !running;
3307
3403
  wasRunning.current = running;
3308
3404
  if (finished && sessionId !== "") props.model.invalidate(sessionId);
3309
- if (active && !running) props.model.load(sessionId);
3405
+ if (idle && !running) props.model.load(sessionId);
3310
3406
  }, [
3311
3407
  props.model,
3312
- active,
3408
+ idle,
3313
3409
  running,
3314
3410
  sessionId
3315
3411
  ]);
3316
3412
  (0, react.useEffect)(() => {
3317
- if (active && !running && snapshot.text === void 0) props.model.load(sessionId);
3413
+ if (idle && !running && snapshot.text === void 0) props.model.load(sessionId);
3318
3414
  }, [
3319
3415
  props.model,
3320
- active,
3416
+ idle,
3321
3417
  running,
3322
3418
  sessionId,
3323
3419
  snapshot
@@ -3612,118 +3708,136 @@ function SessionManagerSettings(props) {
3612
3708
  });
3613
3709
  };
3614
3710
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3615
- className: `${FREE_CHAT_ROOT} dsh-ui-panel`,
3616
- children: [
3617
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
3618
- className: "dsh-ui-card",
3711
+ className: `${FREE_CHAT_ROOT} dsh-ui-page`,
3712
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3713
+ className: "dsm-settings",
3714
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
3715
+ className: "dsm-setting",
3716
+ "aria-labelledby": `${tabsId}-ghost-heading`,
3619
3717
  children: [
3620
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
3621
- className: "dsh-ui-heading",
3622
- children: copy("settingsMode")
3623
- }),
3624
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3625
- className: "dsh-ui-hint",
3626
- children: copy("settingsModeHint")
3627
- }),
3628
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.SegmentedTabs, {
3629
- label: copy("settingsMode"),
3630
- items: [{
3631
- id: `${tabsId}-fixed`,
3632
- panelId: fixedPanelId,
3633
- value: "fixed",
3634
- label: copy("modeFixed")
3635
- }, {
3636
- id: `${tabsId}-auto`,
3637
- panelId: autoPanelId,
3638
- value: "auto",
3639
- label: copy("modeAuto")
3640
- }],
3641
- value: draft.continueMode,
3642
- onChange: (value) => edit({
3643
- ...draft,
3644
- continueMode: value
3645
- })
3646
- }) }),
3647
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3648
- role: "tabpanel",
3649
- id: fixedPanelId,
3650
- "aria-labelledby": `${tabsId}-fixed`,
3651
- hidden: draft.continueMode !== "fixed",
3652
- children: draft.continueMode === "fixed" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3653
- className: "dsh-ui-field",
3654
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3655
- className: "dsh-ui-label",
3656
- children: copy("continueTextLabel")
3657
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
3658
- value: draft.continueText,
3659
- placeholder: copy("continueTextPlaceholder"),
3660
- onChange: (event) => edit({
3661
- ...draft,
3662
- continueText: event.target.value
3663
- })
3664
- })]
3665
- }) : null
3718
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
3719
+ className: "dsm-setting-header",
3720
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
3721
+ id: `${tabsId}-ghost-heading`,
3722
+ className: "dsh-ui-title",
3723
+ children: copy("settingsMode")
3724
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3725
+ className: "dsh-ui-hint",
3726
+ children: copy("settingsModeHint")
3727
+ })]
3666
3728
  }),
3667
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3668
- role: "tabpanel",
3669
- id: autoPanelId,
3670
- "aria-labelledby": `${tabsId}-auto`,
3671
- hidden: draft.continueMode !== "auto",
3672
- children: draft.continueMode === "auto" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3673
- className: "dsh-ui-field",
3674
- children: [
3675
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3729
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3730
+ className: "dsm-ghost-controls",
3731
+ children: [
3732
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3733
+ className: "dsh-ui-field",
3734
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3676
3735
  className: "dsh-ui-label",
3677
- children: copy("ghostModelLabel")
3678
- }),
3679
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelMenu, {
3680
- locale: props.locale,
3681
- open: ghostMenuOpen,
3682
- onOpenChange: setGhostMenuOpen,
3683
- listClassName: FREE_CHAT_ROOT,
3684
- anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3685
- type: "button",
3686
- className: "dsh-model-menu-trigger",
3687
- "aria-label": `${copy("ghostModelLabel")}: ${ghostLabel}`,
3688
- "aria-haspopup": "menu",
3689
- "aria-expanded": ghostMenuOpen,
3690
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3691
- className: "dsh-model-menu-triggerLabel",
3692
- children: ghostLabel
3693
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { className: `dsh-model-menu-chevron${ghostMenuOpen ? " dsh-model-menu-chevronOpen" : ""}` })]
3694
- }),
3695
- choices: selectableChoices,
3696
- selected: ghostRoute,
3697
- onPick: (route) => edit({
3698
- ...draft,
3699
- ghostModel: modelRouteKey(route.provider, route.model)
3700
- }),
3701
- leading: [{
3702
- id: "follow",
3703
- label: copy("modelFollowOption"),
3704
- selected: !ghostRoute
3736
+ children: copy("continueSourceLabel")
3737
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.SegmentedTabs, {
3738
+ label: copy("continueSourceLabel"),
3739
+ items: [{
3740
+ id: `${tabsId}-fixed`,
3741
+ panelId: fixedPanelId,
3742
+ value: "fixed",
3743
+ label: copy("modeFixed")
3744
+ }, {
3745
+ id: `${tabsId}-auto`,
3746
+ panelId: autoPanelId,
3747
+ value: "auto",
3748
+ label: copy("modeAuto")
3705
3749
  }],
3706
- onPickLeading: () => edit({
3750
+ value: draft.continueMode,
3751
+ onChange: (value) => edit({
3707
3752
  ...draft,
3708
- ghostModel: ""
3709
- }),
3710
- modelValue: ghostLabel
3711
- }) }),
3712
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3713
- className: "dsh-ui-hint",
3714
- children: copy("ghostModelHint")
3715
- })
3716
- ]
3717
- }) : null
3718
- })
3753
+ continueMode: value
3754
+ })
3755
+ })]
3756
+ }),
3757
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3758
+ role: "tabpanel",
3759
+ id: fixedPanelId,
3760
+ "aria-labelledby": `${tabsId}-fixed`,
3761
+ hidden: draft.continueMode !== "fixed",
3762
+ children: draft.continueMode === "fixed" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3763
+ className: "dsh-ui-field",
3764
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3765
+ className: "dsh-ui-label",
3766
+ children: copy("continueTextLabel")
3767
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
3768
+ className: "dsm-ghost-input",
3769
+ value: draft.continueText,
3770
+ placeholder: copy("continueTextPlaceholder"),
3771
+ onChange: (event) => edit({
3772
+ ...draft,
3773
+ continueText: event.target.value
3774
+ })
3775
+ })]
3776
+ }) : null
3777
+ }),
3778
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3779
+ role: "tabpanel",
3780
+ id: autoPanelId,
3781
+ "aria-labelledby": `${tabsId}-auto`,
3782
+ hidden: draft.continueMode !== "auto",
3783
+ children: draft.continueMode === "auto" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3784
+ className: "dsh-ui-field dsm-model-field",
3785
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3786
+ className: "dsh-ui-label",
3787
+ children: copy("ghostModelLabel")
3788
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelMenu, {
3789
+ locale: props.locale,
3790
+ open: ghostMenuOpen,
3791
+ onOpenChange: setGhostMenuOpen,
3792
+ listClassName: FREE_CHAT_ROOT,
3793
+ anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3794
+ type: "button",
3795
+ className: "dsh-model-menu-trigger",
3796
+ "aria-label": `${copy("ghostModelLabel")}: ${ghostLabel}`,
3797
+ "aria-haspopup": "menu",
3798
+ "aria-expanded": ghostMenuOpen,
3799
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3800
+ className: "dsh-model-menu-triggerLabel",
3801
+ children: ghostLabel
3802
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { className: `dsh-model-menu-chevron${ghostMenuOpen ? " dsh-model-menu-chevronOpen" : ""}` })]
3803
+ }),
3804
+ choices: selectableChoices,
3805
+ selected: ghostRoute,
3806
+ onPick: (route) => edit({
3807
+ ...draft,
3808
+ ghostModel: modelRouteKey(route.provider, route.model)
3809
+ }),
3810
+ leading: [{
3811
+ id: "follow",
3812
+ label: copy("modelFollowOption"),
3813
+ selected: !ghostRoute
3814
+ }],
3815
+ onPickLeading: () => edit({
3816
+ ...draft,
3817
+ ghostModel: ""
3818
+ }),
3819
+ modelValue: ghostLabel
3820
+ })]
3821
+ }) : null
3822
+ })
3823
+ ]
3824
+ }),
3825
+ draft.continueMode === "auto" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3826
+ className: "dsh-ui-hint",
3827
+ children: copy("ghostModelHint")
3828
+ }) : null
3719
3829
  ]
3720
- }),
3721
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
3722
- className: "dsh-ui-card",
3830
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
3831
+ className: "dsm-setting",
3832
+ "aria-labelledby": `${tabsId}-return-heading`,
3723
3833
  children: [
3724
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
3725
- className: "dsh-ui-heading",
3726
- children: copy("welcomeBackGroup")
3834
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("header", {
3835
+ className: "dsm-setting-header",
3836
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
3837
+ id: `${tabsId}-return-heading`,
3838
+ className: "dsh-ui-title",
3839
+ children: copy("welcomeBackGroup")
3840
+ })
3727
3841
  }),
3728
3842
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3729
3843
  className: "dsm-feature",
@@ -3747,84 +3861,82 @@ function SessionManagerSettings(props) {
3747
3861
  })
3748
3862
  })]
3749
3863
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3750
- className: "dsm-subs",
3864
+ className: "dsm-feature-options",
3751
3865
  "data-disabled": draft.recapEnabled ? void 0 : "true",
3752
- children: [
3753
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3866
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3867
+ className: "dsh-ui-fields-grid",
3868
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3754
3869
  className: "dsh-ui-field",
3755
3870
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3756
3871
  className: "dsh-ui-label",
3757
3872
  children: copy("recapMinutesLabel")
3758
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
3759
- className: "dsm-minutes",
3760
- value: draft.recapMinutes,
3761
- inputMode: "numeric",
3762
- disabled: !draft.recapEnabled,
3763
- "aria-invalid": recapInvalid || void 0,
3764
- "aria-describedby": recapInvalid ? `${tabsId}-recap-error` : void 0,
3765
- onChange: (event) => edit({
3766
- ...draft,
3767
- recapMinutes: event.target.value
3768
- })
3873
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3874
+ className: "dsm-minutes-control",
3875
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
3876
+ className: "dsm-minutes",
3877
+ value: draft.recapMinutes,
3878
+ inputMode: "numeric",
3879
+ disabled: !draft.recapEnabled,
3880
+ "aria-invalid": recapInvalid || void 0,
3881
+ "aria-describedby": recapInvalid ? `${tabsId}-recap-error` : void 0,
3882
+ onChange: (event) => edit({
3883
+ ...draft,
3884
+ recapMinutes: event.target.value
3885
+ })
3886
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3887
+ className: "dsh-ui-meta",
3888
+ children: copy("minutesUnit")
3889
+ })]
3769
3890
  })]
3770
3891
  }), recapInvalid ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3771
3892
  id: `${tabsId}-recap-error`,
3772
3893
  className: "dsh-ui-error",
3773
3894
  role: "alert",
3774
3895
  children: copy("minutesInvalid")
3775
- }) : null] }),
3776
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3777
- className: "dsh-ui-field",
3778
- children: [
3779
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3780
- className: "dsh-ui-label",
3781
- children: copy("modelLabel")
3896
+ }) : null] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3897
+ className: "dsh-ui-field dsm-model-field",
3898
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3899
+ className: "dsh-ui-label",
3900
+ children: copy("modelLabel")
3901
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelMenu, {
3902
+ locale: props.locale,
3903
+ open: menuOpen,
3904
+ onOpenChange: setMenuOpen,
3905
+ listClassName: FREE_CHAT_ROOT,
3906
+ anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3907
+ type: "button",
3908
+ className: "dsh-model-menu-trigger",
3909
+ disabled: !draft.recapEnabled,
3910
+ "aria-label": `${copy("modelLabel")}: ${selectedLabel}`,
3911
+ "aria-haspopup": "menu",
3912
+ "aria-expanded": menuOpen,
3913
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3914
+ className: "dsh-model-menu-triggerLabel",
3915
+ children: selectedLabel
3916
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { className: `dsh-model-menu-chevron${menuOpen ? " dsh-model-menu-chevronOpen" : ""}` })]
3782
3917
  }),
3783
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelMenu, {
3784
- locale: props.locale,
3785
- open: menuOpen,
3786
- onOpenChange: setMenuOpen,
3787
- listClassName: FREE_CHAT_ROOT,
3788
- anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3789
- type: "button",
3790
- className: "dsh-model-menu-trigger",
3791
- disabled: !draft.recapEnabled,
3792
- "aria-label": `${copy("modelLabel")}: ${selectedLabel}`,
3793
- "aria-haspopup": "menu",
3794
- "aria-expanded": menuOpen,
3795
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3796
- className: "dsh-model-menu-triggerLabel",
3797
- children: selectedLabel
3798
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { className: `dsh-model-menu-chevron${menuOpen ? " dsh-model-menu-chevronOpen" : ""}` })]
3799
- }),
3800
- choices: selectableChoices,
3801
- selected: selectedRoute,
3802
- onPick: (route) => edit({
3803
- ...draft,
3804
- model: modelRouteKey(route.provider, route.model)
3805
- }),
3806
- leading: [{
3807
- id: "follow",
3808
- label: copy("modelFollowOption"),
3809
- selected: !selectedRoute
3810
- }],
3811
- onPickLeading: () => edit({
3812
- ...draft,
3813
- model: ""
3814
- }),
3815
- modelValue: selectedLabel
3816
- }) }),
3817
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3818
- className: "dsh-ui-hint",
3819
- children: copy("modelGroupHint")
3820
- })
3821
- ]
3822
- }),
3823
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelCatalogStatus, {
3824
- state: catalog,
3825
- locale: props.locale
3826
- })
3827
- ]
3918
+ choices: selectableChoices,
3919
+ selected: selectedRoute,
3920
+ onPick: (route) => edit({
3921
+ ...draft,
3922
+ model: modelRouteKey(route.provider, route.model)
3923
+ }),
3924
+ leading: [{
3925
+ id: "follow",
3926
+ label: copy("modelFollowOption"),
3927
+ selected: !selectedRoute
3928
+ }],
3929
+ onPickLeading: () => edit({
3930
+ ...draft,
3931
+ model: ""
3932
+ }),
3933
+ modelValue: selectedLabel
3934
+ })]
3935
+ })]
3936
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelCatalogStatus, {
3937
+ state: catalog,
3938
+ locale: props.locale
3939
+ })]
3828
3940
  })]
3829
3941
  }),
3830
3942
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -3849,24 +3961,30 @@ function SessionManagerSettings(props) {
3849
3961
  })
3850
3962
  })]
3851
3963
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3852
- className: "dsm-subs",
3964
+ className: "dsm-feature-options dsm-compact-options",
3853
3965
  "data-disabled": draft.compactEnabled ? void 0 : "true",
3854
3966
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3855
3967
  className: "dsh-ui-field",
3856
3968
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3857
3969
  className: "dsh-ui-label",
3858
3970
  children: copy("compactMinutesLabel")
3859
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
3860
- className: "dsm-minutes",
3861
- value: draft.compactMinutes,
3862
- inputMode: "numeric",
3863
- disabled: !draft.compactEnabled,
3864
- "aria-invalid": compactInvalid || void 0,
3865
- "aria-describedby": compactInvalid ? `${tabsId}-compact-error` : void 0,
3866
- onChange: (event) => edit({
3867
- ...draft,
3868
- compactMinutes: event.target.value
3869
- })
3971
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3972
+ className: "dsm-minutes-control",
3973
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
3974
+ className: "dsm-minutes",
3975
+ value: draft.compactMinutes,
3976
+ inputMode: "numeric",
3977
+ disabled: !draft.compactEnabled,
3978
+ "aria-invalid": compactInvalid || void 0,
3979
+ "aria-describedby": compactInvalid ? `${tabsId}-compact-error` : void 0,
3980
+ onChange: (event) => edit({
3981
+ ...draft,
3982
+ compactMinutes: event.target.value
3983
+ })
3984
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3985
+ className: "dsh-ui-meta",
3986
+ children: copy("minutesUnit")
3987
+ })]
3870
3988
  })]
3871
3989
  }), compactInvalid ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3872
3990
  id: `${tabsId}-compact-error`,
@@ -3877,34 +3995,33 @@ function SessionManagerSettings(props) {
3877
3995
  })]
3878
3996
  })
3879
3997
  ]
3880
- }),
3881
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3882
- className: "dsh-ui-actions",
3883
- children: [
3884
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
3885
- variant: "primary",
3886
- disabled: invalid || snapshot.saving,
3887
- onClick: save,
3888
- children: snapshot.saving ? copy("settingsSaving") : copy("saveSettings")
3889
- }),
3890
- snapshot.saved ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3891
- className: "dsh-ui-notice",
3892
- role: "status",
3893
- children: copy("settingsSaved")
3894
- }) : null,
3895
- externalChange ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3896
- className: "dsh-ui-notice dsh-ui-notice--error",
3897
- role: "alert",
3898
- children: copy("externalChange")
3899
- }) : null,
3900
- snapshot.failure ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3901
- className: "dsh-ui-notice dsh-ui-notice--error",
3902
- role: "alert",
3903
- children: failureText(props.locale, snapshot.failure)
3904
- }) : null
3905
- ]
3906
- })
3907
- ]
3998
+ })]
3999
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4000
+ className: "dsh-ui-form-footer dsm-settings-footer",
4001
+ children: [
4002
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
4003
+ variant: "primary",
4004
+ disabled: invalid || snapshot.saving,
4005
+ onClick: save,
4006
+ children: snapshot.saving ? copy("settingsSaving") : copy("saveSettings")
4007
+ }),
4008
+ snapshot.saved ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4009
+ className: "dsh-ui-notice",
4010
+ role: "status",
4011
+ children: copy("settingsSaved")
4012
+ }) : null,
4013
+ externalChange ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4014
+ className: "dsh-ui-notice dsh-ui-notice--error",
4015
+ role: "alert",
4016
+ children: copy("externalChange")
4017
+ }) : null,
4018
+ snapshot.failure ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4019
+ className: "dsh-ui-notice dsh-ui-notice--error",
4020
+ role: "alert",
4021
+ children: failureText(props.locale, snapshot.failure)
4022
+ }) : null
4023
+ ]
4024
+ })]
3908
4025
  });
3909
4026
  }
3910
4027
  //#endregion