@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.
package/lib/client.js CHANGED
@@ -65,18 +65,20 @@ const text = {
65
65
  settingsMode: "继续灰影",
66
66
  modeFixed: "固定文本",
67
67
  modeAuto: "模型生成",
68
- settingsModeHint: "输入框为空时显示的灰色继续文本:Tab 填入,点击发送。",
68
+ settingsModeHint: "输入框为空时显示建议;按 Tab 填入,点击直接发送。",
69
+ continueSourceLabel: "内容来源",
69
70
  continueTextLabel: "固定文本内容",
70
71
  continueTextPlaceholder: "留空使用默认「继续」",
71
- ghostModelLabel: "灰影模型",
72
- ghostModelHint: "只在上一轮结束后生成一次,并缓存在这个会话中;留空跟随会话或宿主默认。",
73
- welcomeBackGroup: "欢迎回来",
74
- recapEnabledLabel: "欢迎回来摘要",
75
- recapEnabledHint: "回到空闲的会话时,在对话顶部生成回顾卡片。",
76
- recapMinutesLabel: "摘要阈值(分钟)",
77
- compactEnabledLabel: "压缩建议",
78
- compactEnabledHint: "空闲较久时,回到会话会建议先压缩上下文。",
79
- compactMinutesLabel: "建议阈值(分钟)",
72
+ ghostModelLabel: "生成模型",
73
+ ghostModelHint: "每轮结束后生成一次并缓存;不选择时使用当前会话或宿主的默认模型。",
74
+ welcomeBackGroup: "回到会话时",
75
+ recapEnabledLabel: "显示会话摘要",
76
+ recapEnabledHint: "在对话中回顾上次进展。",
77
+ recapMinutesLabel: "离开多久后显示摘要",
78
+ compactEnabledLabel: "建议压缩上下文",
79
+ compactEnabledHint: "长时间离开后,建议先压缩上下文。",
80
+ compactMinutesLabel: "离开多久后显示建议",
81
+ minutesUnit: "分钟",
80
82
  modelLabel: "摘要模型",
81
83
  modelFollowOption: "当前会话 / 宿主默认模型",
82
84
  modelGroupHint: "只用于欢迎回来摘要;留空跟随会话或宿主默认。",
@@ -119,18 +121,20 @@ const text = {
119
121
  settingsMode: "Continue ghost",
120
122
  modeFixed: "Fixed text",
121
123
  modeAuto: "Model-generated",
122
- settingsModeHint: "The grey continuation shown on an empty composer: Tab fills it, clicking sends it.",
124
+ settingsModeHint: "Show a suggestion when the composer is empty. Press Tab to fill it, or click to send.",
125
+ continueSourceLabel: "Source",
123
126
  continueTextLabel: "Fixed text",
124
127
  continueTextPlaceholder: "Empty uses the default \"Continue\"",
125
- ghostModelLabel: "Ghost model",
126
- ghostModelHint: "Generated once after the previous turn ends and cached for this session; empty follows the conversation or host default.",
127
- welcomeBackGroup: "Welcome back",
128
- recapEnabledLabel: "Welcome-back recap",
129
- recapEnabledHint: "Shows a recap card at the top of the conversation when you return to an idle session.",
130
- recapMinutesLabel: "Recap threshold (minutes)",
131
- compactEnabledLabel: "Compaction suggestion",
132
- compactEnabledHint: "Suggests compacting the context when you return after a longer idle stretch.",
133
- compactMinutesLabel: "Suggestion threshold (minutes)",
128
+ ghostModelLabel: "Generation model",
129
+ ghostModelHint: "Generated once after each turn and cached. The default follows the current conversation or host.",
130
+ welcomeBackGroup: "When you return",
131
+ recapEnabledLabel: "Show session recap",
132
+ recapEnabledHint: "Review your previous progress in the conversation.",
133
+ recapMinutesLabel: "Show recap after",
134
+ compactEnabledLabel: "Suggest context compaction",
135
+ compactEnabledHint: "Suggest compacting the context after a long time away.",
136
+ compactMinutesLabel: "Show suggestion after",
137
+ minutesUnit: "minutes",
134
138
  modelLabel: "Recap model",
135
139
  modelFollowOption: "Current conversation / host default",
136
140
  modelGroupHint: "Used only for the welcome-back recap; empty follows the conversation or host default.",
@@ -418,6 +422,17 @@ ${scope} {
418
422
  /* --- Layout scaffolding. --- */
419
423
  & .dsh-ui-stack { display: flex; flex-direction: column; gap: 12px; }
420
424
  & .dsh-ui-stack-lg { display: flex; flex-direction: column; gap: 20px; }
425
+ /* Plugin detail pages share one reading column. These are layout recipes;
426
+ * controls keep their own primitive styles. Form spacing follows the host's
427
+ * settings-form/fields.module.css and SettingsForm.module.css. */
428
+ & .dsh-ui-page { display: flex; flex-direction: column; gap: 16px; width: 100%; max-width: 760px; min-width: 0; }
429
+ & .dsh-ui-form { display: flex; flex-direction: column; gap: 0; min-width: 0; }
430
+ &.dsh-ui-form > .dsh-ui-field, & .dsh-ui-form > .dsh-ui-field { padding: 12px 0; }
431
+ & .dsh-ui-form-footer { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; padding-top: 16px; min-width: 0; }
432
+ & .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; }
433
+ @media (max-width: 560px) {
434
+ & .dsh-ui-fields-grid { grid-template-columns: minmax(0, 1fr); }
435
+ }
421
436
  & .dsh-ui-row { display: flex; align-items: center; gap: 8px; min-width: 0; }
422
437
  & .dsh-ui-row-wrap { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
423
438
  & .dsh-ui-spacer { flex: 1; min-width: 0; }
@@ -445,6 +460,9 @@ ${scope} {
445
460
  * official primitive, so this only owns the vertical rhythm. --- */
446
461
  & .dsh-ui-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
447
462
  & .dsh-ui-field + .dsh-ui-field { border-top: 0.5px solid var(--dsw-alias-border-l2); padding-top: 12px; }
463
+ /* Grid fields share a row, so the stacked-field divider must not win later in
464
+ * the cascade. Reset it here, after the field recipe. */
465
+ & .dsh-ui-fields-grid > .dsh-ui-field { padding: 0; border: 0; }
448
466
  & .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); }
449
467
  & .dsh-ui-label-row { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
450
468
  & .dsh-ui-help { font-size: 12px; line-height: 1.6; color: var(--dsw-alias-label-secondary); }
@@ -635,7 +653,7 @@ ${scope} {
635
653
  & *, & *::before, & *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; }
636
654
  }
637
655
  }
638
- `.replace(/^& (\.dsh-ui-[a-z0-9-]+)(?![+>~])/gm, (_match, className) => `&${className}, & ${className}`);
656
+ `.replace(/^& (\.dsh-ui-[a-z0-9-]+)(?=\s*\{)/gm, (_match, className) => `&${className}, & ${className}`);
639
657
  }
640
658
  //#endregion
641
659
  //#region ../dsh-model-route/src/route.ts
@@ -867,7 +885,14 @@ function useModelCatalog(load, options = {}) {
867
885
  refresh
868
886
  };
869
887
  }
870
- /** Also accepts a mapped state from a caller that owns broader async orchestration. */
888
+ /**
889
+ * Also accepts a mapped state from a caller that owns broader async orchestration.
890
+ *
891
+ * The dsh-ui-* classes carry the styling and resolve through the consuming
892
+ * plugin's own officialUiCss scope (every consumer mounts its root class, so
893
+ * e.g. `.dsh-model-hub .dsh-ui-loading` paints this); dsh-model-catalog-status
894
+ * stays as a structural hook for tests and layout, never a colour source.
895
+ */
871
896
  function ModelCatalogStatus({ state, locale }) {
872
897
  const zh = locale?.toLowerCase().startsWith("zh") === true;
873
898
  const copy = zh ? {
@@ -883,15 +908,17 @@ function ModelCatalogStatus({ state, locale }) {
883
908
  };
884
909
  if (!state.loading && !state.error && state.failures.length === 0) return null;
885
910
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
886
- className: "dsh-model-catalog-status",
911
+ className: "dsh-model-catalog-status dsh-ui-stack",
887
912
  lang: zh ? "zh" : "en",
888
913
  children: [
889
914
  state.loading ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
890
915
  role: "status",
916
+ className: "dsh-ui-loading",
891
917
  children: copy.loading
892
918
  }) : null,
893
919
  state.error ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
894
920
  role: "alert",
921
+ className: "dsh-ui-error dsh-ui-wrap",
895
922
  children: [
896
923
  copy.error,
897
924
  ": ",
@@ -900,20 +927,27 @@ function ModelCatalogStatus({ state, locale }) {
900
927
  }) : null,
901
928
  state.failures.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
902
929
  role: "status",
903
- 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: [
904
- failure.name || failure.id,
905
- ": ",
906
- failure.message
907
- ] }, `${failure.id}:${index}`)) })]
930
+ className: "dsh-ui-meta",
931
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", { children: copy.partial }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
932
+ className: "dsh-ui-list",
933
+ children: state.failures.map((failure, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [
934
+ failure.name || failure.id,
935
+ ": ",
936
+ failure.message
937
+ ] }, `${failure.id}:${index}`))
938
+ })]
908
939
  }) : null,
909
- state.error || state.failures.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
910
- type: "button",
911
- size: "sm",
912
- disabled: state.loading,
913
- onClick: () => {
914
- state.refresh();
915
- },
916
- children: copy.retry
940
+ state.error || state.failures.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
941
+ className: "dsh-ui-actions",
942
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
943
+ type: "button",
944
+ size: "sm",
945
+ disabled: state.loading,
946
+ onClick: () => {
947
+ state.refresh();
948
+ },
949
+ children: copy.retry
950
+ })
917
951
  }) : null
918
952
  ]
919
953
  });
@@ -973,7 +1007,8 @@ function groupModelMenuChoices(choices, query) {
973
1007
  * Sticky group headings, subsequence ranking, highlight walking and focus
974
1008
  * hand-back all match the host. SYNC POINT: when the host's ModelSelect or
975
1009
  * ModelSelect.module.css changes, this copy must be re-transcribed; styles
976
- * below may only reference --dsw-* theme tokens, never literal colors.
1010
+ * below may only reference allowlisted theme tokens (the --dsw-* set plus the
1011
+ * host's --ds-* motion tokens), never literal colors.
977
1012
  *
978
1013
  * It statically imports the primitives, so only browser clients should load
979
1014
  * this entry; host code and node tests use the core entry (`./index.ts`).
@@ -1481,7 +1516,8 @@ function ModelMenu(props) {
1481
1516
  * sticky group headings (MenuGroup's own CSS), and the l1-stroke prominent
1482
1517
  * elevation at portal z-index 1100. The trigger mirrors the composer's 28px
1483
1518
  * model pill, chevron rotating open. MenuSurface paints fill and backdrop.
1484
- * Only --dsw-* theme tokens may appear here — a literal color is a bug.
1519
+ * Only allowlisted --dsw- and --ds- theme tokens may appear here — a literal
1520
+ * color is a bug.
1485
1521
  */
1486
1522
  const modelMenuCss = `
1487
1523
  .dsh-model-menu-root { min-width: 0; position: relative; display: inline-flex; }
@@ -1504,12 +1540,14 @@ const modelMenuCss = `
1504
1540
  display: flex;
1505
1541
  }
1506
1542
  .dsh-model-menu-trigger:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }
1507
- .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)); }
1543
+ .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)); }
1508
1544
  .dsh-model-menu-trigger:disabled { color: var(--dsw-alias-label-dimmed); cursor: default; }
1509
1545
  .dsh-model-menu-triggerLabel { text-overflow: ellipsis; white-space: nowrap; min-width: 0; overflow: hidden; }
1510
1546
  .dsh-model-menu-triggerEffort { text-overflow: ellipsis; white-space: nowrap; min-width: 0; color: var(--dsw-alias-label-caption); flex-shrink: 1000; overflow: hidden; }
1511
- .dsh-model-menu-chevron { color: var(--dsw-alias-label-caption); flex: none; transition: transform 0.12s; }
1547
+ .dsh-model-menu-chevron { color: var(--dsw-alias-label-caption); flex: none; transition: transform var(--ds-transition-duration) var(--ds-ease-in-out); }
1512
1548
  .dsh-model-menu-chevronOpen { transform: rotate(180deg); }
1549
+ /* Portal overlay: the host publishes no z-index token, so the card keeps the
1550
+ * native menu layer's 1100 verbatim. */
1513
1551
  .dsh-model-menu-menu {
1514
1552
  z-index: 1100;
1515
1553
  --dsw-elevation-stroke-color: var(--dsw-alias-border-l1);
@@ -1535,6 +1573,8 @@ const modelMenuCss = `
1535
1573
  .dsh-model-menu-searchWithQuery { padding-right: 34px; }
1536
1574
  .dsh-model-menu-searchRow .dsh-model-menu-search input { padding: 0; font-size: 12px; line-height: normal; }
1537
1575
  .dsh-model-menu-searchRow .dsh-model-menu-search input::placeholder { color: var(--dsw-alias-label-caption); }
1576
+ /* The clear button is a circle by geometry (border-radius: 50%), a shape the
1577
+ * radius token scale does not describe. */
1538
1578
  .dsh-model-menu-searchClear {
1539
1579
  width: 24px;
1540
1580
  height: 24px;
@@ -1624,25 +1664,88 @@ ${modelMenuCss}
1624
1664
  min-width: 0;
1625
1665
  }
1626
1666
  .${FREE_CHAT_ROOT} .dsh-free-alert { margin: 0; }
1627
- /* Settings page: a feature is its toggle row plus the nested well that holds
1628
- * the fields the switch gates. The well reuses the nested-card surface
1629
- * (layer-2 on layer-1) so the grouping reads without another heading. */
1667
+ /* Settings page: one quiet reading surface. Rules, not nested wells, separate
1668
+ * sections; dependent controls align with the feature they belong to. */
1669
+ .${FREE_CHAT_ROOT} .dsm-settings {
1670
+ display: flex;
1671
+ flex-direction: column;
1672
+ gap: 20px;
1673
+ min-width: 0;
1674
+ }
1675
+ .${FREE_CHAT_ROOT} .dsm-setting {
1676
+ display: flex;
1677
+ flex-direction: column;
1678
+ gap: 12px;
1679
+ min-width: 0;
1680
+ }
1681
+ .${FREE_CHAT_ROOT} .dsm-setting + .dsm-setting {
1682
+ padding-top: 20px;
1683
+ border-top: 0.5px solid var(--dsw-alias-border-l2);
1684
+ }
1685
+ .${FREE_CHAT_ROOT} .dsm-setting-header {
1686
+ display: flex;
1687
+ flex-direction: column;
1688
+ gap: 4px;
1689
+ }
1690
+ .${FREE_CHAT_ROOT} .dsm-ghost-controls {
1691
+ display: grid;
1692
+ grid-template-columns: minmax(220px, 0.8fr) minmax(0, 1.2fr);
1693
+ align-items: start;
1694
+ gap: 16px;
1695
+ }
1696
+ /* SegmentedTabs is 42px tall; its adjacent text controls share that baseline. */
1697
+ .${FREE_CHAT_ROOT} .dsm-ghost-controls .dsh-model-menu-trigger,
1698
+ .${FREE_CHAT_ROOT} .dsm-ghost-controls .dsm-ghost-input {
1699
+ height: 42px;
1700
+ }
1630
1701
  .${FREE_CHAT_ROOT} .dsm-feature + .dsm-feature {
1702
+ margin-top: 4px;
1631
1703
  border-top: 0.5px solid var(--dsw-alias-border-l2);
1632
1704
  }
1633
- .${FREE_CHAT_ROOT} .dsm-subs {
1705
+ .${FREE_CHAT_ROOT} .dsm-feature > .dsh-ui-toggle-row { padding: 8px 0; }
1706
+ .${FREE_CHAT_ROOT} .dsm-feature-options {
1634
1707
  display: flex;
1635
1708
  flex-direction: column;
1636
- gap: 12px;
1637
- margin: 0 0 4px;
1638
- padding: 12px;
1639
- border-radius: var(--dsw-radius-md);
1640
- background: var(--dsw-alias-bg-layer-2);
1709
+ gap: 8px;
1710
+ padding: 4px 0 8px;
1641
1711
  }
1642
- .${FREE_CHAT_ROOT} .dsm-subs[data-disabled='true'] .dsh-ui-label {
1712
+ .${FREE_CHAT_ROOT} .dsm-feature-options[data-disabled='true'] .dsh-ui-label,
1713
+ .${FREE_CHAT_ROOT} .dsm-feature-options[data-disabled='true'] .dsh-ui-meta {
1643
1714
  color: var(--dsw-alias-label-tertiary);
1644
1715
  }
1645
- .${FREE_CHAT_ROOT} .dsm-minutes { width: 120px; }
1716
+ .${FREE_CHAT_ROOT} .dsm-compact-options { max-width: calc(50% - 10px); }
1717
+ .${FREE_CHAT_ROOT} .dsm-model-field .dsh-model-menu-root,
1718
+ .${FREE_CHAT_ROOT} .dsm-model-field .dsh-model-menu-trigger {
1719
+ width: 100%;
1720
+ max-width: none;
1721
+ }
1722
+ .${FREE_CHAT_ROOT} .dsm-model-field .dsh-model-menu-trigger {
1723
+ justify-content: space-between;
1724
+ height: 32px;
1725
+ padding: 0 10px;
1726
+ border: 0.5px solid var(--dsw-alias-border-l4);
1727
+ border-radius: var(--dsw-radius-md);
1728
+ background: var(--dsw-alias-bg-layer-3);
1729
+ color: var(--dsw-alias-label-primary);
1730
+ }
1731
+ .${FREE_CHAT_ROOT} .dsm-model-field .dsh-model-menu-triggerLabel {
1732
+ flex: 1;
1733
+ text-align: left;
1734
+ }
1735
+ .${FREE_CHAT_ROOT} .dsm-settings-footer .dsh-ui-notice--error {
1736
+ flex: 0 0 100%;
1737
+ min-width: 0;
1738
+ }
1739
+ .${FREE_CHAT_ROOT} .dsm-minutes-control {
1740
+ display: flex;
1741
+ align-items: center;
1742
+ gap: 8px;
1743
+ }
1744
+ .${FREE_CHAT_ROOT} .dsm-minutes { width: 88px; }
1745
+ @media (max-width: 560px) {
1746
+ .${FREE_CHAT_ROOT} .dsm-ghost-controls { grid-template-columns: minmax(0, 1fr); }
1747
+ .${FREE_CHAT_ROOT} .dsm-compact-options { max-width: none; }
1748
+ }
1646
1749
  /* Welcome-back card: one flat full-width row at the latest turn's tail in the
1647
1750
  * chat flow — a single bordered surface with the recap laid out inline, no
1648
1751
  * nested box. */
@@ -1703,20 +1806,6 @@ ${modelMenuCss}
1703
1806
  `;
1704
1807
  //#endregion
1705
1808
  //#region src/free-panel.tsx
1706
- function FreeChatIcon({ size }) {
1707
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
1708
- width: size,
1709
- height: size,
1710
- viewBox: "0 0 16 16",
1711
- "aria-hidden": "true",
1712
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1713
- d: "M2.5 3.5h11v7.5h-4.2L6 13.5V11H2.5z",
1714
- fill: "none",
1715
- stroke: "currentColor",
1716
- strokeWidth: "1.2"
1717
- })
1718
- });
1719
- }
1720
1809
  /** Create failures used to surface inside the standalone panel. The panel is gone,
1721
1810
  * so they get a small overlay instead; closing it dismisses the stored notice. */
1722
1811
  function CreateNoticeDialog(props) {
@@ -1914,7 +2003,7 @@ function TemporaryWorkspacePicker(props) {
1914
2003
  }] : [], {
1915
2004
  id: "::temporary-workspace",
1916
2005
  label: uiText(locale, "tempWorkspace"),
1917
- icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FreeChatIcon, { size: 16 }),
2006
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconNewChatOutlineRegular, { size: 16 }),
1918
2007
  disabled: busy
1919
2008
  }],
1920
2009
  onSelect: (id) => {
@@ -1927,6 +2016,7 @@ function TemporaryWorkspacePicker(props) {
1927
2016
  }),
1928
2017
  props.open && workspaces.phase === "pending" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1929
2018
  role: "status",
2019
+ className: `dsh-free-chat dsh-ui-loading`,
1930
2020
  children: props.t("picker.loading")
1931
2021
  }),
1932
2022
  props.renderSlot(TEMP_WORKSPACE_FLOW_SLOT, {
@@ -1962,6 +2052,7 @@ function TemporaryWorkspacePicker(props) {
1962
2052
  }),
1963
2053
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
1964
2054
  open: failure !== void 0,
2055
+ className: FREE_CHAT_ROOT,
1965
2056
  title: props.t("folderError.title"),
1966
2057
  closeLabel: props.t("close"),
1967
2058
  onClose: () => setFailure(void 0),
@@ -1986,6 +2077,7 @@ function TemporaryWorkspaceNotice({ model, locale }) {
1986
2077
  const state = (0, react.useSyncExternalStore)(model.subscribe, model.getSnapshot, model.getSnapshot);
1987
2078
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
1988
2079
  open: state.failure !== void 0,
2080
+ className: FREE_CHAT_ROOT,
1989
2081
  title: uiText(locale, "createFailed"),
1990
2082
  closeLabel: uiText(locale, "close"),
1991
2083
  onClose: model.dismissFailure,
@@ -2795,11 +2887,11 @@ function createContinueModel(host) {
2795
2887
  load(sessionId) {
2796
2888
  if (sessionId === "" || lifetime.signal.aborted || inflight.has(sessionId)) return;
2797
2889
  const current = read(sessionId);
2798
- if (current.text !== void 0 && current.seq === void 0) return;
2890
+ if (current.text !== void 0 && current.seq === void 0 && current.pending !== true) return;
2799
2891
  const ticket = new AbortController();
2800
2892
  inflight.set(sessionId, ticket);
2801
2893
  const signal = AbortSignal.any([lifetime.signal, ticket.signal]);
2802
- callContinueSuggest(host, sessionId, current.seq, signal).then((value) => {
2894
+ callContinueSuggest(host, sessionId, current.text ? current.seq : void 0, signal).then((value) => {
2803
2895
  if (signal.aborted || inflight.get(sessionId) !== ticket) return;
2804
2896
  write(sessionId, value);
2805
2897
  }).catch(() => {}).finally(() => {
@@ -2838,7 +2930,9 @@ async function callContinueSuggest(host, sessionId, knownSeq, signal) {
2838
2930
  const seq = typeof value?.seq === "number" && Number.isSafeInteger(value.seq) && value.seq >= 0 ? value.seq : void 0;
2839
2931
  return {
2840
2932
  text,
2841
- ...seq === void 0 ? {} : { seq }
2933
+ ...seq === void 0 ? {} : { seq },
2934
+ ...value?.pending === true ? { pending: true } : {},
2935
+ ...value?.fallback === true ? { fallback: true } : {}
2842
2936
  };
2843
2937
  }
2844
2938
  function createPresenceConfigModel(host, delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms))) {
@@ -3295,8 +3389,10 @@ function ContinueGhost(props) {
3295
3389
  const blank = props.useSession?.((state) => state.blank) ?? true;
3296
3390
  const running = props.useSessionStatus?.((state) => state.get(sessionId)?.running === true) ?? false;
3297
3391
  const snapshot = (0, react.useSyncExternalStore)(props.model.subscribe, () => props.model.getSnapshot(sessionId), () => props.model.getSnapshot(sessionId));
3298
- const text = snapshot.text ?? uiText(props.locale, "continueDefault");
3299
- const active = sessionId !== "" && !blank && bare && draft === "" && phase === "plain";
3392
+ const shown = running || snapshot.pending === true || snapshot.text === void 0 ? "" : snapshot.text ?? (snapshot.fallback === true ? uiText(props.locale, "continueDefault") : "");
3393
+ const idle = sessionId !== "" && !blank && bare && draft === "" && phase === "plain" && !running;
3394
+ const active = shown !== "" && idle;
3395
+ const text = shown;
3300
3396
  const latest = (0, react.useRef)({
3301
3397
  active,
3302
3398
  text
@@ -3312,18 +3408,18 @@ function ContinueGhost(props) {
3312
3408
  const finished = wasRunning.current && !running;
3313
3409
  wasRunning.current = running;
3314
3410
  if (finished && sessionId !== "") props.model.invalidate(sessionId);
3315
- if (active && !running) props.model.load(sessionId);
3411
+ if (idle && !running) props.model.load(sessionId);
3316
3412
  }, [
3317
3413
  props.model,
3318
- active,
3414
+ idle,
3319
3415
  running,
3320
3416
  sessionId
3321
3417
  ]);
3322
3418
  (0, react.useEffect)(() => {
3323
- if (active && !running && snapshot.text === void 0) props.model.load(sessionId);
3419
+ if (idle && !running && snapshot.text === void 0) props.model.load(sessionId);
3324
3420
  }, [
3325
3421
  props.model,
3326
- active,
3422
+ idle,
3327
3423
  running,
3328
3424
  sessionId,
3329
3425
  snapshot
@@ -3618,118 +3714,136 @@ function SessionManagerSettings(props) {
3618
3714
  });
3619
3715
  };
3620
3716
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3621
- className: `${FREE_CHAT_ROOT} dsh-ui-panel`,
3622
- children: [
3623
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
3624
- className: "dsh-ui-card",
3717
+ className: `${FREE_CHAT_ROOT} dsh-ui-page`,
3718
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3719
+ className: "dsm-settings",
3720
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
3721
+ className: "dsm-setting",
3722
+ "aria-labelledby": `${tabsId}-ghost-heading`,
3625
3723
  children: [
3626
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
3627
- className: "dsh-ui-heading",
3628
- children: copy("settingsMode")
3629
- }),
3630
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3631
- className: "dsh-ui-hint",
3632
- children: copy("settingsModeHint")
3633
- }),
3634
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.SegmentedTabs, {
3635
- label: copy("settingsMode"),
3636
- items: [{
3637
- id: `${tabsId}-fixed`,
3638
- panelId: fixedPanelId,
3639
- value: "fixed",
3640
- label: copy("modeFixed")
3641
- }, {
3642
- id: `${tabsId}-auto`,
3643
- panelId: autoPanelId,
3644
- value: "auto",
3645
- label: copy("modeAuto")
3646
- }],
3647
- value: draft.continueMode,
3648
- onChange: (value) => edit({
3649
- ...draft,
3650
- continueMode: value
3651
- })
3652
- }) }),
3653
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3654
- role: "tabpanel",
3655
- id: fixedPanelId,
3656
- "aria-labelledby": `${tabsId}-fixed`,
3657
- hidden: draft.continueMode !== "fixed",
3658
- children: draft.continueMode === "fixed" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3659
- className: "dsh-ui-field",
3660
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3661
- className: "dsh-ui-label",
3662
- children: copy("continueTextLabel")
3663
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
3664
- value: draft.continueText,
3665
- placeholder: copy("continueTextPlaceholder"),
3666
- onChange: (event) => edit({
3667
- ...draft,
3668
- continueText: event.target.value
3669
- })
3670
- })]
3671
- }) : null
3724
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
3725
+ className: "dsm-setting-header",
3726
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
3727
+ id: `${tabsId}-ghost-heading`,
3728
+ className: "dsh-ui-title",
3729
+ children: copy("settingsMode")
3730
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3731
+ className: "dsh-ui-hint",
3732
+ children: copy("settingsModeHint")
3733
+ })]
3672
3734
  }),
3673
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3674
- role: "tabpanel",
3675
- id: autoPanelId,
3676
- "aria-labelledby": `${tabsId}-auto`,
3677
- hidden: draft.continueMode !== "auto",
3678
- children: draft.continueMode === "auto" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3679
- className: "dsh-ui-field",
3680
- children: [
3681
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3735
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3736
+ className: "dsm-ghost-controls",
3737
+ children: [
3738
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3739
+ className: "dsh-ui-field",
3740
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3682
3741
  className: "dsh-ui-label",
3683
- children: copy("ghostModelLabel")
3684
- }),
3685
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelMenu, {
3686
- locale: props.locale,
3687
- open: ghostMenuOpen,
3688
- onOpenChange: setGhostMenuOpen,
3689
- listClassName: FREE_CHAT_ROOT,
3690
- anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3691
- type: "button",
3692
- className: "dsh-model-menu-trigger",
3693
- "aria-label": `${copy("ghostModelLabel")}: ${ghostLabel}`,
3694
- "aria-haspopup": "menu",
3695
- "aria-expanded": ghostMenuOpen,
3696
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3697
- className: "dsh-model-menu-triggerLabel",
3698
- children: ghostLabel
3699
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { className: `dsh-model-menu-chevron${ghostMenuOpen ? " dsh-model-menu-chevronOpen" : ""}` })]
3700
- }),
3701
- choices: selectableChoices,
3702
- selected: ghostRoute,
3703
- onPick: (route) => edit({
3704
- ...draft,
3705
- ghostModel: modelRouteKey(route.provider, route.model)
3706
- }),
3707
- leading: [{
3708
- id: "follow",
3709
- label: copy("modelFollowOption"),
3710
- selected: !ghostRoute
3742
+ children: copy("continueSourceLabel")
3743
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.SegmentedTabs, {
3744
+ label: copy("continueSourceLabel"),
3745
+ items: [{
3746
+ id: `${tabsId}-fixed`,
3747
+ panelId: fixedPanelId,
3748
+ value: "fixed",
3749
+ label: copy("modeFixed")
3750
+ }, {
3751
+ id: `${tabsId}-auto`,
3752
+ panelId: autoPanelId,
3753
+ value: "auto",
3754
+ label: copy("modeAuto")
3711
3755
  }],
3712
- onPickLeading: () => edit({
3756
+ value: draft.continueMode,
3757
+ onChange: (value) => edit({
3713
3758
  ...draft,
3714
- ghostModel: ""
3715
- }),
3716
- modelValue: ghostLabel
3717
- }) }),
3718
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3719
- className: "dsh-ui-hint",
3720
- children: copy("ghostModelHint")
3721
- })
3722
- ]
3723
- }) : null
3724
- })
3759
+ continueMode: value
3760
+ })
3761
+ })]
3762
+ }),
3763
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3764
+ role: "tabpanel",
3765
+ id: fixedPanelId,
3766
+ "aria-labelledby": `${tabsId}-fixed`,
3767
+ hidden: draft.continueMode !== "fixed",
3768
+ children: draft.continueMode === "fixed" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3769
+ className: "dsh-ui-field",
3770
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3771
+ className: "dsh-ui-label",
3772
+ children: copy("continueTextLabel")
3773
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
3774
+ className: "dsm-ghost-input",
3775
+ value: draft.continueText,
3776
+ placeholder: copy("continueTextPlaceholder"),
3777
+ onChange: (event) => edit({
3778
+ ...draft,
3779
+ continueText: event.target.value
3780
+ })
3781
+ })]
3782
+ }) : null
3783
+ }),
3784
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3785
+ role: "tabpanel",
3786
+ id: autoPanelId,
3787
+ "aria-labelledby": `${tabsId}-auto`,
3788
+ hidden: draft.continueMode !== "auto",
3789
+ children: draft.continueMode === "auto" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3790
+ className: "dsh-ui-field dsm-model-field",
3791
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3792
+ className: "dsh-ui-label",
3793
+ children: copy("ghostModelLabel")
3794
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelMenu, {
3795
+ locale: props.locale,
3796
+ open: ghostMenuOpen,
3797
+ onOpenChange: setGhostMenuOpen,
3798
+ listClassName: FREE_CHAT_ROOT,
3799
+ anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3800
+ type: "button",
3801
+ className: "dsh-model-menu-trigger",
3802
+ "aria-label": `${copy("ghostModelLabel")}: ${ghostLabel}`,
3803
+ "aria-haspopup": "menu",
3804
+ "aria-expanded": ghostMenuOpen,
3805
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3806
+ className: "dsh-model-menu-triggerLabel",
3807
+ children: ghostLabel
3808
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { className: `dsh-model-menu-chevron${ghostMenuOpen ? " dsh-model-menu-chevronOpen" : ""}` })]
3809
+ }),
3810
+ choices: selectableChoices,
3811
+ selected: ghostRoute,
3812
+ onPick: (route) => edit({
3813
+ ...draft,
3814
+ ghostModel: modelRouteKey(route.provider, route.model)
3815
+ }),
3816
+ leading: [{
3817
+ id: "follow",
3818
+ label: copy("modelFollowOption"),
3819
+ selected: !ghostRoute
3820
+ }],
3821
+ onPickLeading: () => edit({
3822
+ ...draft,
3823
+ ghostModel: ""
3824
+ }),
3825
+ modelValue: ghostLabel
3826
+ })]
3827
+ }) : null
3828
+ })
3829
+ ]
3830
+ }),
3831
+ draft.continueMode === "auto" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3832
+ className: "dsh-ui-hint",
3833
+ children: copy("ghostModelHint")
3834
+ }) : null
3725
3835
  ]
3726
- }),
3727
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
3728
- className: "dsh-ui-card",
3836
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
3837
+ className: "dsm-setting",
3838
+ "aria-labelledby": `${tabsId}-return-heading`,
3729
3839
  children: [
3730
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
3731
- className: "dsh-ui-heading",
3732
- children: copy("welcomeBackGroup")
3840
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("header", {
3841
+ className: "dsm-setting-header",
3842
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
3843
+ id: `${tabsId}-return-heading`,
3844
+ className: "dsh-ui-title",
3845
+ children: copy("welcomeBackGroup")
3846
+ })
3733
3847
  }),
3734
3848
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3735
3849
  className: "dsm-feature",
@@ -3753,84 +3867,82 @@ function SessionManagerSettings(props) {
3753
3867
  })
3754
3868
  })]
3755
3869
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3756
- className: "dsm-subs",
3870
+ className: "dsm-feature-options",
3757
3871
  "data-disabled": draft.recapEnabled ? void 0 : "true",
3758
- children: [
3759
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3872
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3873
+ className: "dsh-ui-fields-grid",
3874
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3760
3875
  className: "dsh-ui-field",
3761
3876
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3762
3877
  className: "dsh-ui-label",
3763
3878
  children: copy("recapMinutesLabel")
3764
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
3765
- className: "dsm-minutes",
3766
- value: draft.recapMinutes,
3767
- inputMode: "numeric",
3768
- disabled: !draft.recapEnabled,
3769
- "aria-invalid": recapInvalid || void 0,
3770
- "aria-describedby": recapInvalid ? `${tabsId}-recap-error` : void 0,
3771
- onChange: (event) => edit({
3772
- ...draft,
3773
- recapMinutes: event.target.value
3774
- })
3879
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3880
+ className: "dsm-minutes-control",
3881
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
3882
+ className: "dsm-minutes",
3883
+ value: draft.recapMinutes,
3884
+ inputMode: "numeric",
3885
+ disabled: !draft.recapEnabled,
3886
+ "aria-invalid": recapInvalid || void 0,
3887
+ "aria-describedby": recapInvalid ? `${tabsId}-recap-error` : void 0,
3888
+ onChange: (event) => edit({
3889
+ ...draft,
3890
+ recapMinutes: event.target.value
3891
+ })
3892
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3893
+ className: "dsh-ui-meta",
3894
+ children: copy("minutesUnit")
3895
+ })]
3775
3896
  })]
3776
3897
  }), recapInvalid ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3777
3898
  id: `${tabsId}-recap-error`,
3778
3899
  className: "dsh-ui-error",
3779
3900
  role: "alert",
3780
3901
  children: copy("minutesInvalid")
3781
- }) : null] }),
3782
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3783
- className: "dsh-ui-field",
3784
- children: [
3785
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3786
- className: "dsh-ui-label",
3787
- children: copy("modelLabel")
3902
+ }) : null] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3903
+ className: "dsh-ui-field dsm-model-field",
3904
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3905
+ className: "dsh-ui-label",
3906
+ children: copy("modelLabel")
3907
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelMenu, {
3908
+ locale: props.locale,
3909
+ open: menuOpen,
3910
+ onOpenChange: setMenuOpen,
3911
+ listClassName: FREE_CHAT_ROOT,
3912
+ anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3913
+ type: "button",
3914
+ className: "dsh-model-menu-trigger",
3915
+ disabled: !draft.recapEnabled,
3916
+ "aria-label": `${copy("modelLabel")}: ${selectedLabel}`,
3917
+ "aria-haspopup": "menu",
3918
+ "aria-expanded": menuOpen,
3919
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3920
+ className: "dsh-model-menu-triggerLabel",
3921
+ children: selectedLabel
3922
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { className: `dsh-model-menu-chevron${menuOpen ? " dsh-model-menu-chevronOpen" : ""}` })]
3788
3923
  }),
3789
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelMenu, {
3790
- locale: props.locale,
3791
- open: menuOpen,
3792
- onOpenChange: setMenuOpen,
3793
- listClassName: FREE_CHAT_ROOT,
3794
- anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3795
- type: "button",
3796
- className: "dsh-model-menu-trigger",
3797
- disabled: !draft.recapEnabled,
3798
- "aria-label": `${copy("modelLabel")}: ${selectedLabel}`,
3799
- "aria-haspopup": "menu",
3800
- "aria-expanded": menuOpen,
3801
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3802
- className: "dsh-model-menu-triggerLabel",
3803
- children: selectedLabel
3804
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineRegular, { className: `dsh-model-menu-chevron${menuOpen ? " dsh-model-menu-chevronOpen" : ""}` })]
3805
- }),
3806
- choices: selectableChoices,
3807
- selected: selectedRoute,
3808
- onPick: (route) => edit({
3809
- ...draft,
3810
- model: modelRouteKey(route.provider, route.model)
3811
- }),
3812
- leading: [{
3813
- id: "follow",
3814
- label: copy("modelFollowOption"),
3815
- selected: !selectedRoute
3816
- }],
3817
- onPickLeading: () => edit({
3818
- ...draft,
3819
- model: ""
3820
- }),
3821
- modelValue: selectedLabel
3822
- }) }),
3823
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3824
- className: "dsh-ui-hint",
3825
- children: copy("modelGroupHint")
3826
- })
3827
- ]
3828
- }),
3829
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelCatalogStatus, {
3830
- state: catalog,
3831
- locale: props.locale
3832
- })
3833
- ]
3924
+ choices: selectableChoices,
3925
+ selected: selectedRoute,
3926
+ onPick: (route) => edit({
3927
+ ...draft,
3928
+ model: modelRouteKey(route.provider, route.model)
3929
+ }),
3930
+ leading: [{
3931
+ id: "follow",
3932
+ label: copy("modelFollowOption"),
3933
+ selected: !selectedRoute
3934
+ }],
3935
+ onPickLeading: () => edit({
3936
+ ...draft,
3937
+ model: ""
3938
+ }),
3939
+ modelValue: selectedLabel
3940
+ })]
3941
+ })]
3942
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ModelCatalogStatus, {
3943
+ state: catalog,
3944
+ locale: props.locale
3945
+ })]
3834
3946
  })]
3835
3947
  }),
3836
3948
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -3855,24 +3967,30 @@ function SessionManagerSettings(props) {
3855
3967
  })
3856
3968
  })]
3857
3969
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3858
- className: "dsm-subs",
3970
+ className: "dsm-feature-options dsm-compact-options",
3859
3971
  "data-disabled": draft.compactEnabled ? void 0 : "true",
3860
3972
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3861
3973
  className: "dsh-ui-field",
3862
3974
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3863
3975
  className: "dsh-ui-label",
3864
3976
  children: copy("compactMinutesLabel")
3865
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
3866
- className: "dsm-minutes",
3867
- value: draft.compactMinutes,
3868
- inputMode: "numeric",
3869
- disabled: !draft.compactEnabled,
3870
- "aria-invalid": compactInvalid || void 0,
3871
- "aria-describedby": compactInvalid ? `${tabsId}-compact-error` : void 0,
3872
- onChange: (event) => edit({
3873
- ...draft,
3874
- compactMinutes: event.target.value
3875
- })
3977
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3978
+ className: "dsm-minutes-control",
3979
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Input, {
3980
+ className: "dsm-minutes",
3981
+ value: draft.compactMinutes,
3982
+ inputMode: "numeric",
3983
+ disabled: !draft.compactEnabled,
3984
+ "aria-invalid": compactInvalid || void 0,
3985
+ "aria-describedby": compactInvalid ? `${tabsId}-compact-error` : void 0,
3986
+ onChange: (event) => edit({
3987
+ ...draft,
3988
+ compactMinutes: event.target.value
3989
+ })
3990
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3991
+ className: "dsh-ui-meta",
3992
+ children: copy("minutesUnit")
3993
+ })]
3876
3994
  })]
3877
3995
  }), compactInvalid ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3878
3996
  id: `${tabsId}-compact-error`,
@@ -3883,34 +4001,33 @@ function SessionManagerSettings(props) {
3883
4001
  })]
3884
4002
  })
3885
4003
  ]
3886
- }),
3887
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3888
- className: "dsh-ui-actions",
3889
- children: [
3890
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
3891
- variant: "primary",
3892
- disabled: invalid || snapshot.saving,
3893
- onClick: save,
3894
- children: snapshot.saving ? copy("settingsSaving") : copy("saveSettings")
3895
- }),
3896
- snapshot.saved ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3897
- className: "dsh-ui-notice",
3898
- role: "status",
3899
- children: copy("settingsSaved")
3900
- }) : null,
3901
- externalChange ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3902
- className: "dsh-ui-notice dsh-ui-notice--error",
3903
- role: "alert",
3904
- children: copy("externalChange")
3905
- }) : null,
3906
- snapshot.failure ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3907
- className: "dsh-ui-notice dsh-ui-notice--error",
3908
- role: "alert",
3909
- children: failureText(props.locale, snapshot.failure)
3910
- }) : null
3911
- ]
3912
- })
3913
- ]
4004
+ })]
4005
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4006
+ className: "dsh-ui-form-footer dsm-settings-footer",
4007
+ children: [
4008
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
4009
+ variant: "primary",
4010
+ disabled: invalid || snapshot.saving,
4011
+ onClick: save,
4012
+ children: snapshot.saving ? copy("settingsSaving") : copy("saveSettings")
4013
+ }),
4014
+ snapshot.saved ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4015
+ className: "dsh-ui-notice",
4016
+ role: "status",
4017
+ children: copy("settingsSaved")
4018
+ }) : null,
4019
+ externalChange ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4020
+ className: "dsh-ui-notice dsh-ui-notice--error",
4021
+ role: "alert",
4022
+ children: copy("externalChange")
4023
+ }) : null,
4024
+ snapshot.failure ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4025
+ className: "dsh-ui-notice dsh-ui-notice--error",
4026
+ role: "alert",
4027
+ children: failureText(props.locale, snapshot.failure)
4028
+ }) : null
4029
+ ]
4030
+ })]
3914
4031
  });
3915
4032
  }
3916
4033
  //#endregion