dsh-later 1.2.0 → 1.3.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/lib/client.js CHANGED
@@ -4,9 +4,11 @@ window.__ModuleLoader__.load({
4
4
  var module = { exports: {} };
5
5
  var exports = module.exports;
6
6
  "use strict";
7
+ var __create = Object.create;
7
8
  var __defProp = Object.defineProperty;
8
9
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
9
10
  var __getOwnPropNames = Object.getOwnPropertyNames;
11
+ var __getProtoOf = Object.getPrototypeOf;
10
12
  var __hasOwnProp = Object.prototype.hasOwnProperty;
11
13
  var __export = (target, all) => {
12
14
  for (var name2 in all)
@@ -20,6 +22,14 @@ var __copyProps = (to, from, except, desc) => {
20
22
  }
21
23
  return to;
22
24
  };
25
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
26
+ // If the importer is in node compatibility mode or this is not an ESM
27
+ // file that has been converted to a CommonJS file using a Babel-
28
+ // compatible transform (i.e. "__esModule" has not been set), then set
29
+ // "default" to the CommonJS "module.exports" for node compatibility.
30
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
31
+ mod
32
+ ));
23
33
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
24
34
 
25
35
  // src/client/index.tsx
@@ -78,25 +88,27 @@ var COMPONENTS = [
78
88
  " margin: 0 auto calc(0px - var(--dsh-composer-stack-gap) - 3px);",
79
89
  " padding: 0 var(--dsh-composer-dock-inset);",
80
90
  "}",
81
- "/* \u9762\u677F\u4E0E QueueDock .panel \u4E00\u81F4\uFF1Abg tip\u3001\u9876\u90E8\u5706\u89D2\u3001::after \u753B\u63CF\u8FB9\uFF08\u7559\u5E95\u8FB9\u5F00\u53E3\uFF09\u3002 */",
91
+ "/* \u9762\u677F\u4E0E QueueDock .panel \u4E00\u81F4\uFF1Abg menu + backdrop-filter\u3001\u9876\u90E8\u5706\u89D2\u3001::before \u753B\u63CF\u8FB9\uFF08\u7559\u5E95\u8FB9\u5F00\u53E3\uFF09\u3002 */",
82
92
  ".ss-dock-body {",
83
93
  " position: relative; overflow: hidden; width: 100%; padding: 2px 0;",
84
- " background: var(--dsw-specific-tip);",
85
- " border-radius: 12px 12px 0 0;",
94
+ " isolation: isolate;",
95
+ " border-radius: var(--dsw-radius-lg) var(--dsw-radius-lg) 0 0;",
86
96
  " --dsh-scrollbar-thumb: var(--dsw-alias-scrollbar-bg-l2);",
87
97
  " --dsh-scrollbar-thumb-hover: var(--dsw-alias-scrollbar-hover-l2);",
88
98
  "}",
89
- ".ss-dock-body::after {",
90
- " content: ''; position: absolute; inset: 0; pointer-events: none;",
91
- " border: 1px solid var(--dsw-alias-border-l1); border-bottom: none; border-radius: inherit;",
99
+ ".ss-dock-body::before {",
100
+ " z-index: -1; border-radius: inherit; background: var(--dsw-specific-menu);",
101
+ " backdrop-filter: var(--dsw-menu-backdrop-filter); content: '';",
102
+ " position: absolute; inset: 0; pointer-events: none;",
103
+ " border: 1px solid var(--dsw-alias-border-l1); border-bottom: none;",
92
104
  "}",
93
105
  ".ss-dock-header {",
94
106
  " box-sizing: border-box; display: flex; align-items: center; gap: 10px;",
95
107
  " width: 100%; height: 36px; padding: 4px 12px;",
96
- " background: none; border: none; border-radius: 8px; cursor: pointer; text-align: left;",
108
+ " background: none; border: none; border-radius: var(--dsw-radius-md); cursor: pointer; text-align: left;",
97
109
  " color: var(--dsw-alias-label-primary);",
98
110
  "}",
99
- ".ss-dock-header:focus-visible { outline: 2px solid var(--dsw-alias-label-tertiary); outline-offset: -2px; }",
111
+ ".ss-dock-header:focus-visible { outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary)); outline-offset: -2px; }",
100
112
  ".ss-dock-lead { display: grid; place-items: center; color: var(--dsw-alias-label-tertiary); flex: none; }",
101
113
  ".ss-dock-count {",
102
114
  " flex: auto; min-width: 0;",
@@ -189,13 +201,30 @@ var COMPONENTS = [
189
201
  " background-repeat: no-repeat;",
190
202
  "}",
191
203
  ".ss-dock-actions { display: flex; align-items: center; gap: 10px; flex: none; }",
204
+ "/* DockTip\uFF1A\u9010\u5B57\u5BF9\u9F50\u5B98\u65B9 Tooltip.module.css .bubble\uFF08portal: true \u5C42\uFF09\u3002 */",
205
+ ".ss-dock-tip-anchor { display: inline-grid; flex: none; }",
206
+ ".ss-dock-tip {",
207
+ " position: fixed; z-index: 1100;",
208
+ " display: inline-flex; align-items: center; gap: 8px;",
209
+ " width: max-content; max-width: 50vw;",
210
+ " padding: 3px 7px; border-radius: var(--dsw-radius-sm);",
211
+ " background: var(--dsw-alias-tooltip-bg); color: var(--dsw-static-neutral-bluish-00);",
212
+ " font-size: 13px; line-height: 20px;",
213
+ " white-space: pre-line; overflow-wrap: break-word;",
214
+ " pointer-events: none;",
215
+ " transform: translateX(-50%);",
216
+ " animation: ss-dock-tip-in 150ms var(--ds-ease-in-out);",
217
+ "}",
218
+ '.ss-dock-tip[data-side="top"] { transform: translate(-50%, -100%); }',
219
+ "@keyframes ss-dock-tip-in { from { opacity: 0; } }",
220
+ "@media (prefers-reduced-motion: reduce) { .ss-dock-tip { animation: none; } }",
192
221
  ".ss-dock-action {",
193
222
  " display: grid; place-items: center; width: 28px; height: 28px; padding: 0; flex: none;",
194
223
  " border: none; border-radius: 999px; background: none; cursor: pointer;",
195
224
  " color: var(--dsw-alias-label-tertiary);",
196
225
  "}",
197
226
  ".ss-dock-action:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }",
198
- ".ss-dock-action:focus-visible { outline: 2px solid var(--dsw-alias-label-tertiary); outline-offset: -2px; }",
227
+ ".ss-dock-action:focus-visible { outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary)); outline-offset: -2px; }",
199
228
  ".ss-dock-action:disabled { cursor: default; opacity: 0.45; }",
200
229
  "/* \u63D2\u8BDD\u5B8C\u6210\u6001\uFF1AQueueDock \u65E0\u6B64\u6001\uFF0C\u7528\u6210\u529F\u8272\u505A\u8F7B\u63D0\u793A\uFF08\u53E0\u52A0 disabled \u534A\u900F\u660E\uFF09\u3002 */",
201
230
  ".ss-dock-action-steer.ss-done { color: var(--dsw-alias-state-success-primary); }",
@@ -245,19 +274,40 @@ var COMPONENTS = [
245
274
  ".ss-dock-editing { flex-wrap: wrap; }",
246
275
  "",
247
276
  "/* ==================== \u9762\u677F ==================== */",
248
- "/* \u5BF9\u9F50\u5B98\u65B9 popover panel\uFF1Az-index 100\u3001border-inverted\u3001radius 12\u3001\u5B57\u53F7 12\u3001secondary \u6587\u5B57 */",
277
+ "/*",
278
+ " * \u62AC\u5347\u9762\u9010\u9879\u5BF9\u9F50\u5B98\u65B9 PickerPopover\uFF08@deepseek-ai/dsh-client-ui-schedule \u7684",
279
+ " * PickerPopover.module.css + primitives MenuSurface.module.css\uFF09\uFF1A",
280
+ " * \u80CC\u666F --dsw-menu-surface-fill\uFF08\u5E26\u900F\u660E\u5EA6\u7684\u83DC\u5355\u9762\uFF09+ blur(40px) \u6BDB\u73BB\u7483",
281
+ " * \u63CF\u8FB9\u8D70\u4E3B\u9898\u7684 --dsw-elevation-stroke\uFF080 0 0 .5px\uFF09\uFF0C\u800C\u4E0D\u662F\u624B\u5199 1px \u2014\u2014",
282
+ " * 0.5px \u63CF\u8FB9\u662F\u9AD8\u5206\u5C4F\u4E0B\u7684\u6B63\u786E\u7EC6\u7EBF\uFF0C1px \u5728 1x \u4E0A\u8FC7\u91CD\u3001\u5728 2x \u4E0A\u53C8\u53D1\u865A\u3002",
283
+ " * \u9634\u5F71 --dsw-elevation-prominent\uFF08\u542B\u63CF\u8FB9\u5C42\uFF0C\u4E0D\u662F\u7B2C\u4E8C\u5957\u9634\u5F71\uFF09\u3002",
284
+ " * \u5706\u89D2 16px = --dsw-radius-lg\uFF08\u5B98\u65B9\u9762\u677F\u540C\u4E00\u6863\uFF1B\u65E7\u7684 12px \u662F --dsw-radius-md\uFF09\u3002",
285
+ " * z-index 1100 = \u5B98\u65B9\u6D6E\u5C42\u6863\uFF08\u65E7\u7684 101 \u662F\u81EA\u9020\u503C\uFF0C\u6392\u5728 dock \u4E4B\u4E0B\uFF09\u3002",
286
+ " *",
287
+ " * \u26A0\uFE0F \u52FF\u518D\u5F15\u5165 --dsw-shadow-lv3 / --dsw-alias-border-inverted\uFF1A\u90A3\u662F\u66F4\u65E9\u8BBE\u8BA1\u4EE3\u6B21\u7684",
288
+ " * token\uFF0C\u6DF7\u7528\u4F1A\u8BA9\u9762\u677F\u5728\u6D45\u8272/\u6DF1\u8272\u4E0B\u90FD\u504F\u79BB\u5B98\u65B9\u89C2\u611F\uFF08issue #24\uFF09\u3002",
289
+ " */",
249
290
  ".ss-backdrop {",
250
- " position: fixed; inset: 0; z-index: 100; background: transparent;",
291
+ " position: fixed; inset: 0; z-index: 1099; background: transparent;",
251
292
  "}",
252
293
  ".ss-panel {",
253
- " position: fixed; z-index: 101;",
294
+ " position: fixed; top: auto; left: auto; z-index: 1100;",
295
+ " box-sizing: border-box; display: flex; flex-direction: column;",
254
296
  " width: min(340px, calc(100vw - 24px));",
255
- " background: var(--dsw-specific-menu);",
297
+ " padding: 12px;",
298
+ " background: var(--dsw-menu-surface-fill);",
299
+ " backdrop-filter: var(--dsw-menu-backdrop-filter);",
300
+ " -webkit-backdrop-filter: var(--dsw-menu-backdrop-filter);",
301
+ " border: 0; border-radius: var(--dsw-radius-lg);",
302
+ " box-shadow: var(--dsw-elevation-prominent);",
303
+ " /* \u63CF\u8FB9\u4E0E\u9634\u5F71\u540C\u53D8\u91CF\uFF1A--dsw-elevation-prominent \u81EA\u8EAB\u542B --dsw-elevation-stroke\uFF0C",
304
+ " \u8FD9\u91CC\u53EA\u9700\u7ED9 stroke \u989C\u8272\u3002\u5B98\u65B9 schedule/input-trigger/subagent \u4E09\u4E2A\u5305\u4E00\u81F4\u53D6 l1\u3002 */",
305
+ " --dsw-elevation-stroke-color: var(--dsw-alias-border-l1);",
256
306
  " color: var(--dsw-alias-label-secondary);",
257
- " border: 1px solid var(--dsw-alias-border-inverted); border-radius: 12px;",
258
- " box-shadow: var(--dsw-shadow-lv3); padding: 12px; box-sizing: border-box;",
259
307
  " font-size: 12px; line-height: 20px; font-family: var(--dsw-font-family);",
260
308
  "}",
309
+ /* 兜底定位分支(无官方 useAnchoredPosition 的旧代次宿主)才用 bottom,
310
+ 有官方锚定时 left/top 由 hook 注入,这里只兜住首帧测量前的 top:auto。 */
261
311
  ".ss-panel-header {",
262
312
  " display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px;",
263
313
  "}",
@@ -635,7 +685,8 @@ function injectStyles() {
635
685
  }
636
686
 
637
687
  // src/client/components/SchedButton.tsx
638
- var import_react6 = require("react");
688
+ var import_react7 = require("react");
689
+ var import_dsh_client_ui_primitives3 = require("@deepseek-ai/dsh-client-ui-primitives");
639
690
 
640
691
  // src/time-utils.ts
641
692
  function detectTimeZone() {
@@ -879,7 +930,9 @@ function useSchedT(locale) {
879
930
  }
880
931
 
881
932
  // src/client/components/SchedPanel.tsx
882
- var import_react3 = require("react");
933
+ var import_react4 = require("react");
934
+ var import_react_dom = require("react-dom");
935
+ var import_dsh_client_ui_primitives2 = require("@deepseek-ai/dsh-client-ui-primitives");
883
936
 
884
937
  // src/smart-window.ts
885
938
  var DEFAULT_SMART_WINDOW = Object.freeze({
@@ -894,13 +947,13 @@ function isValidHhmm(value) {
894
947
  return typeof value === "string" && HHMM_RE.test(value);
895
948
  }
896
949
  function sanitizeSmartWindowConfig(raw) {
897
- const pick = (key, fallback) => isValidHhmm(raw?.[key]) ? raw[key] : fallback;
950
+ const pick2 = (key, fallback) => isValidHhmm(raw?.[key]) ? raw[key] : fallback;
898
951
  return {
899
- workStart: pick("workStart", DEFAULT_SMART_WINDOW.workStart),
900
- workEnd: pick("workEnd", DEFAULT_SMART_WINDOW.workEnd),
901
- lunchStart: pick("lunchStart", DEFAULT_SMART_WINDOW.lunchStart),
902
- lunchEnd: pick("lunchEnd", DEFAULT_SMART_WINDOW.lunchEnd),
903
- eveningEnd: pick("eveningEnd", DEFAULT_SMART_WINDOW.eveningEnd)
952
+ workStart: pick2("workStart", DEFAULT_SMART_WINDOW.workStart),
953
+ workEnd: pick2("workEnd", DEFAULT_SMART_WINDOW.workEnd),
954
+ lunchStart: pick2("lunchStart", DEFAULT_SMART_WINDOW.lunchStart),
955
+ lunchEnd: pick2("lunchEnd", DEFAULT_SMART_WINDOW.lunchEnd),
956
+ eveningEnd: pick2("eveningEnd", DEFAULT_SMART_WINDOW.eveningEnd)
904
957
  };
905
958
  }
906
959
  var SMART_MIN_DELAY_MS = 2 * 60 * 1e3;
@@ -1035,8 +1088,21 @@ function epochFromLocal(date, time, timeZone) {
1035
1088
  if (hour > 23 || minute > 59 || second > 59 || month < 1 || month > 12 || day < 1 || day > 31) {
1036
1089
  return void 0;
1037
1090
  }
1038
- const approx = Date.UTC(year, month - 1, day, 0, 0, 0, 0);
1039
- return resolveWallClock(approx, timeZone, hour, minute, second);
1091
+ const localEpoch = Date.UTC(year, month - 1, day, hour, minute, second, 0);
1092
+ const offsets = /* @__PURE__ */ new Set();
1093
+ for (let delta = -2; delta <= 2; delta += 1) {
1094
+ offsets.add(offsetOf(localEpoch + delta * DAY_MS2, timeZone));
1095
+ }
1096
+ const candidates = [];
1097
+ for (const offset of offsets) {
1098
+ const candidate = localEpoch - offset;
1099
+ const f = localFieldsOf(candidate, timeZone);
1100
+ if (f.year === year && f.month === month && f.day === day && f.hour === hour && f.minute === minute && f.second === second) {
1101
+ candidates.push(candidate);
1102
+ }
1103
+ }
1104
+ candidates.sort((a, b) => a - b);
1105
+ return candidates[0];
1040
1106
  }
1041
1107
  function nextSmartAt(now, timeZone, window2 = DEFAULT_SMART_WINDOW) {
1042
1108
  let target;
@@ -1062,6 +1128,7 @@ function nextSmartAt(now, timeZone, window2 = DEFAULT_SMART_WINDOW) {
1062
1128
  }
1063
1129
 
1064
1130
  // src/client/components/TaskList.tsx
1131
+ var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
1065
1132
  var import_jsx_runtime = require("react/jsx-runtime");
1066
1133
  function scheduleStateOf(item, now) {
1067
1134
  return Date.parse(item.scheduled_at) <= now ? "overdue" : "scheduled";
@@ -1095,7 +1162,7 @@ function TaskList({ items, now, deliveredIds, cancellingIds, onDelete, timeZone,
1095
1162
  event.stopPropagation();
1096
1163
  onDelete(item.id);
1097
1164
  },
1098
- children: "\u2715"
1165
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.IconCloseOutlineRegular, { size: 14 })
1099
1166
  }
1100
1167
  )
1101
1168
  ] }, item.id);
@@ -1113,6 +1180,96 @@ function useNow(intervalMs = 1e3) {
1113
1180
  return now;
1114
1181
  }
1115
1182
 
1183
+ // src/client/primitives-compat.ts
1184
+ var import_react3 = require("react");
1185
+ var primitives = __toESM(require("@deepseek-ai/dsh-client-ui-primitives"), 1);
1186
+ function pick(name2) {
1187
+ return primitives[name2];
1188
+ }
1189
+ var hostUseAnchoredPosition = pick("useAnchoredPosition");
1190
+ var hostUseDismissOnOutsidePointer = pick("useDismissOnOutsidePointer");
1191
+ function useLegacyAnchoredPosition({
1192
+ open,
1193
+ anchorRef,
1194
+ panelRef,
1195
+ side = "bottom",
1196
+ align = "start",
1197
+ gap,
1198
+ margin
1199
+ }) {
1200
+ const [position, setPosition] = (0, import_react3.useState)(null);
1201
+ (0, import_react3.useLayoutEffect)(() => {
1202
+ if (!open) {
1203
+ setPosition(null);
1204
+ return void 0;
1205
+ }
1206
+ const measure = () => {
1207
+ const anchor = anchorRef.current;
1208
+ const panel2 = panelRef.current;
1209
+ if (anchor === null || panel2 === null) return;
1210
+ const rect = anchor.getBoundingClientRect();
1211
+ const panelWidth = panel2.offsetWidth;
1212
+ const panelHeight = panel2.offsetHeight;
1213
+ const viewportWidth = window.innerWidth;
1214
+ const viewportHeight = window.innerHeight;
1215
+ const left = align === "end" ? rect.right - panelWidth : rect.left;
1216
+ const rawTop = side === "top" ? rect.top - panelHeight - gap : rect.bottom + gap;
1217
+ const clampedLeft = Math.min(
1218
+ Math.max(margin, left),
1219
+ Math.max(margin, viewportWidth - panelWidth - margin)
1220
+ );
1221
+ const overflowsTop = rawTop < margin;
1222
+ const overflowsBottom = rawTop + panelHeight > viewportHeight - margin;
1223
+ const top = overflowsTop && !overflowsBottom ? rect.bottom + gap : overflowsBottom && !overflowsTop ? rect.top - panelHeight - gap : rawTop;
1224
+ setPosition({
1225
+ left: `${Math.round(clampedLeft)}px`,
1226
+ top: `${Math.round(Math.max(margin, Math.min(top, viewportHeight - panelHeight - margin)))}px`
1227
+ });
1228
+ };
1229
+ measure();
1230
+ window.addEventListener("scroll", measure, true);
1231
+ window.addEventListener("resize", measure);
1232
+ const panel = panelRef.current;
1233
+ const observer = typeof ResizeObserver === "undefined" || panel === null ? void 0 : new ResizeObserver(measure);
1234
+ if (observer !== void 0 && panel !== null) observer.observe(panel);
1235
+ return () => {
1236
+ window.removeEventListener("scroll", measure, true);
1237
+ window.removeEventListener("resize", measure);
1238
+ observer?.disconnect();
1239
+ };
1240
+ }, [open, anchorRef, panelRef, side, align, gap, margin]);
1241
+ return position;
1242
+ }
1243
+ function noopDismiss() {
1244
+ }
1245
+ var anchorImpl = hostUseAnchoredPosition ?? useLegacyAnchoredPosition;
1246
+ var dismissImpl = hostUseDismissOnOutsidePointer ?? noopDismiss;
1247
+ var hasOfficialOutsideDismiss = hostUseDismissOnOutsidePointer !== void 0;
1248
+ var hasOfficialAnchoredPosition = hostUseAnchoredPosition !== void 0;
1249
+ function usePanelAnchorPosition(options) {
1250
+ return anchorImpl(options);
1251
+ }
1252
+ function usePanelOutsideDismiss(root, open, setOpen, portal) {
1253
+ return dismissImpl(root, open, setOpen, portal);
1254
+ }
1255
+ var PANEL_MEASURE_STYLE = {
1256
+ visibility: "hidden",
1257
+ left: 0,
1258
+ top: 0
1259
+ };
1260
+ function useEscapeToClose(open, setOpen) {
1261
+ const setOpenRef = (0, import_react3.useRef)(setOpen);
1262
+ setOpenRef.current = setOpen;
1263
+ (0, import_react3.useEffect)(() => {
1264
+ if (!open) return void 0;
1265
+ const onKey = (event) => {
1266
+ if (event.key === "Escape") setOpenRef.current(false);
1267
+ };
1268
+ window.addEventListener("keydown", onKey, true);
1269
+ return () => window.removeEventListener("keydown", onKey, true);
1270
+ }, [open]);
1271
+ }
1272
+
1116
1273
  // src/client/components/SchedPanel.tsx
1117
1274
  var import_jsx_runtime2 = require("react/jsx-runtime");
1118
1275
  function atOnDay(dayOffset, hhmm, timeZone, now) {
@@ -1135,22 +1292,36 @@ function SchedPanel({
1135
1292
  onCreate,
1136
1293
  onDelete,
1137
1294
  bottom,
1295
+ anchorRef,
1296
+ panelRef: externalPanelRef,
1138
1297
  smartWindow = DEFAULT_SMART_WINDOW,
1139
1298
  promptLimits
1140
1299
  }) {
1141
1300
  const now = useNow(1e3);
1142
- const [selected, setSelected] = (0, import_react3.useState)("after-600");
1143
- const [customDate, setCustomDate] = (0, import_react3.useState)(() => {
1301
+ const localPanelRef = (0, import_react4.useRef)(null);
1302
+ const panelRef = externalPanelRef ?? localPanelRef;
1303
+ const anchored = usePanelAnchorPosition({
1304
+ open: true,
1305
+ anchorRef: anchorRef ?? { current: null },
1306
+ panelRef,
1307
+ side: "top",
1308
+ align: "start",
1309
+ gap: 4,
1310
+ margin: 12
1311
+ });
1312
+ const panelStyle = hasOfficialAnchoredPosition ? anchored ?? PANEL_MEASURE_STYLE : { bottom };
1313
+ const [selected, setSelected] = (0, import_react4.useState)("after-600");
1314
+ const [customDate, setCustomDate] = (0, import_react4.useState)(() => {
1144
1315
  const f = localFieldsOf(Date.now(), timeZone);
1145
1316
  return `${String(f.year).padStart(4, "0")}-${String(f.month).padStart(2, "0")}-${String(f.day).padStart(2, "0")}`;
1146
1317
  });
1147
- const [customTime, setCustomTime] = (0, import_react3.useState)("18:00");
1148
- const [error, setError] = (0, import_react3.useState)(null);
1149
- const [cancelling, setCancelling] = (0, import_react3.useState)(/* @__PURE__ */ new Set());
1150
- const [delivered, setDelivered] = (0, import_react3.useState)(/* @__PURE__ */ new Set());
1151
- const deliveredTimers = (0, import_react3.useRef)([]);
1152
- const prevIds = (0, import_react3.useRef)(null);
1153
- (0, import_react3.useEffect)(() => {
1318
+ const [customTime, setCustomTime] = (0, import_react4.useState)("18:00");
1319
+ const [error, setError] = (0, import_react4.useState)(null);
1320
+ const [cancelling, setCancelling] = (0, import_react4.useState)(/* @__PURE__ */ new Set());
1321
+ const [delivered, setDelivered] = (0, import_react4.useState)(/* @__PURE__ */ new Set());
1322
+ const deliveredTimers = (0, import_react4.useRef)([]);
1323
+ const prevIds = (0, import_react4.useRef)(null);
1324
+ (0, import_react4.useEffect)(() => {
1154
1325
  const currentIds = new Set(schedules.map((item) => item.id));
1155
1326
  const previous = prevIds.current;
1156
1327
  prevIds.current = currentIds;
@@ -1169,13 +1340,13 @@ function SchedPanel({
1169
1340
  deliveredTimers.current.push(timer);
1170
1341
  }
1171
1342
  }, [schedules, cancelling]);
1172
- (0, import_react3.useEffect)(
1343
+ (0, import_react4.useEffect)(
1173
1344
  () => () => {
1174
1345
  for (const timer of deliveredTimers.current) window.clearTimeout(timer);
1175
1346
  },
1176
1347
  []
1177
1348
  );
1178
- const quickOptions = (0, import_react3.useMemo)(() => {
1349
+ const quickOptions = (0, import_react4.useMemo)(() => {
1179
1350
  const options = [
1180
1351
  { kind: "after", seconds: 600, label: t.quick10m },
1181
1352
  { kind: "after", seconds: 3600, label: t.quick1h }
@@ -1200,7 +1371,7 @@ function SchedPanel({
1200
1371
  options.push({ kind: "custom", label: t.quickCustom });
1201
1372
  return options;
1202
1373
  }, [timeZone, now, t, smartWindow]);
1203
- const target = (0, import_react3.useMemo)(() => {
1374
+ const target = (0, import_react4.useMemo)(() => {
1204
1375
  if (selected === "custom") {
1205
1376
  const match = /^(\d{2}):(\d{2})$/.exec(customTime);
1206
1377
  if (match === null) return null;
@@ -1213,7 +1384,7 @@ function SchedPanel({
1213
1384
  if (option.kind === "after") return { after_seconds: option.seconds, epoch: now + option.seconds * 1e3 };
1214
1385
  return { at: option.at, epoch: option.epoch };
1215
1386
  }, [selected, customDate, customTime, timeZone, now, quickOptions]);
1216
- const targetLabel = (0, import_react3.useMemo)(() => {
1387
+ const targetLabel = (0, import_react4.useMemo)(() => {
1217
1388
  if (target === void 0 || target === null) return null;
1218
1389
  return `${formatAbsolute(target.epoch, timeZone, lang)} \xB7 ${formatRelative(target.epoch, now, lang)}`;
1219
1390
  }, [target, timeZone, now]);
@@ -1261,87 +1432,101 @@ function SchedPanel({
1261
1432
  };
1262
1433
  const promptEmpty = defaultPrompt.trim().length === 0;
1263
1434
  const canConfirm = !busy && !promptEmpty && target !== null;
1264
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "ss-panel", "data-ss-panel": "", role: "dialog", "aria-label": t.panelTitle, style: { bottom }, children: [
1265
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "ss-panel-header", children: [
1266
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "ss-panel-title", children: t.panelTitle }),
1267
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "ss-panel-close", "aria-label": t.close, onClick: onClose, children: "\u2715" })
1268
- ] }),
1269
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "ss-quick-grid", role: "radiogroup", "aria-label": t.panelTitle, children: quickOptions.map((option) => {
1270
- const key = keyOf(option);
1271
- const active = selected === key || option.kind === "custom" && selected === "custom";
1272
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1273
- "button",
1274
- {
1275
- type: "button",
1276
- role: "radio",
1277
- "aria-checked": active,
1278
- className: active ? "ss-quick-chip ss-active" : "ss-quick-chip",
1279
- onClick: () => {
1280
- setSelected(key);
1281
- setError(null);
1282
- },
1283
- children: option.label
1284
- },
1285
- key
1286
- );
1287
- }) }),
1288
- selected === "custom" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "ss-custom-row", children: [
1289
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1290
- "input",
1291
- {
1292
- type: "date",
1293
- className: "ss-input",
1294
- "aria-label": t.dateLabel,
1295
- value: customDate,
1296
- onChange: (event) => {
1297
- if (event.target.value) setCustomDate(event.target.value);
1435
+ const panel = /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1436
+ "div",
1437
+ {
1438
+ ref: panelRef,
1439
+ className: "ss-panel",
1440
+ "data-ss-panel": "",
1441
+ role: "dialog",
1442
+ "aria-label": t.panelTitle,
1443
+ style: panelStyle,
1444
+ onClick: (event) => event.stopPropagation(),
1445
+ children: [
1446
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "ss-panel-header", children: [
1447
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "ss-panel-title", children: t.panelTitle }),
1448
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "button", className: "ss-panel-close", "aria-label": t.close, onClick: onClose, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.IconCloseOutlineRegular, { size: 14 }) })
1449
+ ] }),
1450
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "ss-quick-grid", role: "radiogroup", "aria-label": t.panelTitle, children: quickOptions.map((option) => {
1451
+ const key = keyOf(option);
1452
+ const active = selected === key || option.kind === "custom" && selected === "custom";
1453
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1454
+ "button",
1455
+ {
1456
+ type: "button",
1457
+ role: "radio",
1458
+ "aria-checked": active,
1459
+ className: active ? "ss-quick-chip ss-active" : "ss-quick-chip",
1460
+ onClick: () => {
1461
+ setSelected(key);
1462
+ setError(null);
1463
+ },
1464
+ children: option.label
1465
+ },
1466
+ key
1467
+ );
1468
+ }) }),
1469
+ selected === "custom" && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "ss-custom-row", children: [
1470
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1471
+ "input",
1472
+ {
1473
+ type: "date",
1474
+ className: "ss-input",
1475
+ "aria-label": t.dateLabel,
1476
+ value: customDate,
1477
+ onChange: (event) => {
1478
+ if (event.target.value) setCustomDate(event.target.value);
1479
+ }
1480
+ }
1481
+ ),
1482
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1483
+ "input",
1484
+ {
1485
+ type: "time",
1486
+ className: "ss-input",
1487
+ "aria-label": t.timeLabel,
1488
+ value: customTime,
1489
+ onChange: (event) => {
1490
+ if (event.target.value) setCustomTime(event.target.value);
1491
+ }
1492
+ }
1493
+ )
1494
+ ] }),
1495
+ target !== null && targetLabel !== null && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "ss-hint", style: { margin: "6px 0 0" }, children: targetLabel }),
1496
+ error !== null && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "ss-error", role: "alert", style: { marginTop: 6 }, children: error }),
1497
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "ss-tasklist-head", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "ss-hint", children: [
1498
+ t.taskListTitle,
1499
+ schedules.length > 0 ? ` (${schedules.length})` : ""
1500
+ ] }) }),
1501
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1502
+ TaskList,
1503
+ {
1504
+ items: schedules,
1505
+ now,
1506
+ deliveredIds: delivered,
1507
+ cancellingIds: cancelling,
1508
+ onDelete: handleDelete,
1509
+ timeZone,
1510
+ t,
1511
+ lang
1298
1512
  }
1299
- }
1300
- ),
1301
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1302
- "input",
1303
- {
1304
- type: "time",
1305
- className: "ss-input",
1306
- "aria-label": t.timeLabel,
1307
- value: customTime,
1308
- onChange: (event) => {
1309
- if (event.target.value) setCustomTime(event.target.value);
1513
+ ),
1514
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "ss-footer", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1515
+ "button",
1516
+ {
1517
+ type: "button",
1518
+ className: "ss-confirm",
1519
+ disabled: !canConfirm,
1520
+ onClick: () => void handleConfirm(),
1521
+ children: busy ? t.sending : target !== null ? format(t.confirmAdd, { time: formatAbsolute(target.epoch, timeZone, lang) }) : t.confirmAddNoTime
1310
1522
  }
1311
- }
1312
- )
1313
- ] }),
1314
- target !== null && targetLabel !== null && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "ss-hint", style: { margin: "6px 0 0" }, children: targetLabel }),
1315
- error !== null && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "ss-error", role: "alert", style: { marginTop: 6 }, children: error }),
1316
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "ss-tasklist-head", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "ss-hint", children: [
1317
- t.taskListTitle,
1318
- schedules.length > 0 ? ` (${schedules.length})` : ""
1319
- ] }) }),
1320
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1321
- TaskList,
1322
- {
1323
- items: schedules,
1324
- now,
1325
- deliveredIds: delivered,
1326
- cancellingIds: cancelling,
1327
- onDelete: handleDelete,
1328
- timeZone,
1329
- t,
1330
- lang
1331
- }
1332
- ),
1333
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "ss-footer", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1334
- "button",
1335
- {
1336
- type: "button",
1337
- className: "ss-confirm",
1338
- disabled: !canConfirm,
1339
- onClick: () => void handleConfirm(),
1340
- children: busy ? t.sending : target !== null ? format(t.confirmAdd, { time: formatAbsolute(target.epoch, timeZone, lang) }) : t.confirmAddNoTime
1341
- }
1342
- ) }),
1343
- promptEmpty && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "ss-hint", style: { marginTop: 6 }, children: t.promptFromDraft })
1344
- ] });
1523
+ ) }),
1524
+ promptEmpty && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "ss-hint", style: { marginTop: 6 }, children: t.promptFromDraft })
1525
+ ]
1526
+ }
1527
+ );
1528
+ if (typeof document === "undefined") return panel;
1529
+ return (0, import_react_dom.createPortal)(panel, document.body);
1345
1530
  }
1346
1531
  function keyOf(option) {
1347
1532
  switch (option.kind) {
@@ -1357,7 +1542,7 @@ function keyOf(option) {
1357
1542
  }
1358
1543
 
1359
1544
  // src/client/hooks/useSchedules.ts
1360
- var import_react4 = require("react");
1545
+ var import_react5 = require("react");
1361
1546
 
1362
1547
  // src/client/local-store.ts
1363
1548
  var STORAGE_KEY = "dsh-later:pending";
@@ -1410,28 +1595,28 @@ var createLine = (input) => {
1410
1595
  var deleteLine = (id) => `/user-schedule-delete ${JSON.stringify({ id })}`;
1411
1596
  function useSchedules(inject2) {
1412
1597
  const { callCommand, sessionId, inputActions, input, useProjection, useInput } = inject2;
1413
- const [busy, setBusy] = (0, import_react4.useState)(false);
1414
- const [anchorBottom, setAnchorBottom] = (0, import_react4.useState)(80);
1415
- const [pendingSync, setPendingSync] = (0, import_react4.useState)(() => readPending());
1416
- const rowRef = (0, import_react4.useRef)(null);
1598
+ const [busy, setBusy] = (0, import_react5.useState)(false);
1599
+ const [anchorBottom, setAnchorBottom] = (0, import_react5.useState)(80);
1600
+ const [pendingSync, setPendingSync] = (0, import_react5.useState)(() => readPending());
1601
+ const rowRef = (0, import_react5.useRef)(null);
1417
1602
  const now = useNow(1e3);
1418
1603
  const draft = input?.draft ?? (typeof useInput === "function" ? useInput((s) => s.draft) : "") ?? "";
1419
1604
  const projection = typeof useProjection === "function" ? useProjection("userSchedules") : void 0;
1420
- const schedules = (0, import_react4.useMemo)(() => schedulesOf(projection), [projection]);
1421
- const nextEpoch = (0, import_react4.useMemo)(() => {
1605
+ const schedules = (0, import_react5.useMemo)(() => schedulesOf(projection), [projection]);
1606
+ const nextEpoch = (0, import_react5.useMemo)(() => {
1422
1607
  return schedules.map((item) => Date.parse(item.scheduled_at)).filter((value) => !Number.isNaN(value)).sort((a, b) => a - b)[0];
1423
1608
  }, [schedules]);
1424
1609
  const enabled = draft.trim().length > 0 || schedules.length > 0;
1425
- const reposition = (0, import_react4.useCallback)(() => {
1610
+ const reposition = (0, import_react5.useCallback)(() => {
1426
1611
  const el = rowRef.current;
1427
1612
  if (el === null) return;
1428
1613
  const rect = el.getBoundingClientRect();
1429
1614
  setAnchorBottom(Math.max(12, window.innerHeight - rect.top + 10));
1430
1615
  }, []);
1431
- const syncedPrompts = (0, import_react4.useMemo)(() => {
1616
+ const syncedPrompts = (0, import_react5.useMemo)(() => {
1432
1617
  return new Set(schedules.map((item) => item.prompt));
1433
1618
  }, [schedules]);
1434
- (0, import_react4.useEffect)(() => {
1619
+ (0, import_react5.useEffect)(() => {
1435
1620
  if (pendingSync.length === 0) return;
1436
1621
  const remaining = pendingSync.filter((item) => !syncedPrompts.has(item.payload.prompt));
1437
1622
  if (remaining.length !== pendingSync.length) {
@@ -1439,7 +1624,7 @@ function useSchedules(inject2) {
1439
1624
  writePendingLocal(remaining);
1440
1625
  }
1441
1626
  }, [syncedPrompts, pendingSync]);
1442
- (0, import_react4.useEffect)(() => {
1627
+ (0, import_react5.useEffect)(() => {
1443
1628
  if (pendingSync.length === 0 || !sessionId) return;
1444
1629
  let cancelled = false;
1445
1630
  const syncAll = async () => {
@@ -1467,7 +1652,7 @@ function useSchedules(inject2) {
1467
1652
  window.removeEventListener("online", onOnline);
1468
1653
  };
1469
1654
  }, [pendingSync, sessionId, callCommand]);
1470
- const handleCreate = (0, import_react4.useCallback)(async (inputPayload) => {
1655
+ const handleCreate = (0, import_react5.useCallback)(async (inputPayload) => {
1471
1656
  if (!sessionId) {
1472
1657
  throw new Error(CLIENT_ERR.NO_SESSION);
1473
1658
  }
@@ -1483,15 +1668,15 @@ function useSchedules(inject2) {
1483
1668
  setBusy(false);
1484
1669
  }
1485
1670
  }, [sessionId, callCommand]);
1486
- const handleDelete = (0, import_react4.useCallback)(async (id) => {
1671
+ const handleDelete = (0, import_react5.useCallback)(async (id) => {
1487
1672
  if (!sessionId) return;
1488
1673
  await callCommand(sessionId, deleteLine(id));
1489
1674
  }, [sessionId, callCommand]);
1490
- const handleCancelAll = (0, import_react4.useCallback)(async () => {
1675
+ const handleCancelAll = (0, import_react5.useCallback)(async () => {
1491
1676
  if (!sessionId) return;
1492
1677
  await Promise.all(schedules.map((item) => callCommand(sessionId, deleteLine(item.id))));
1493
1678
  }, [sessionId, schedules, callCommand]);
1494
- const handleClearDraft = (0, import_react4.useCallback)(() => {
1679
+ const handleClearDraft = (0, import_react5.useCallback)(() => {
1495
1680
  inputActions?.setDraft("");
1496
1681
  }, [inputActions]);
1497
1682
  return {
@@ -1519,7 +1704,7 @@ function writePendingLocal(pending) {
1519
1704
  }
1520
1705
 
1521
1706
  // src/client/hooks/useSchedulerSettings.ts
1522
- var import_react5 = require("react");
1707
+ var import_react6 = require("react");
1523
1708
  var CLIENT_DEFAULT_MAX_PROMPT_CHARS = 1e3;
1524
1709
  var FALLBACK_PROMPT = {
1525
1710
  allowLong: false,
@@ -1563,16 +1748,16 @@ function resolveFromSnapshot(snap) {
1563
1748
  var NOOP_SUBSCRIBE = () => () => void 0;
1564
1749
  var EMPTY_SNAPSHOT = { status: "unavailable" };
1565
1750
  function useSchedulerSettings(scope) {
1566
- const getSnapshot = (0, import_react5.useCallback)(
1751
+ const getSnapshot = (0, import_react6.useCallback)(
1567
1752
  () => scope === void 0 ? EMPTY_SNAPSHOT : scope.getSnapshot(),
1568
1753
  [scope]
1569
1754
  );
1570
- const subscribe = (0, import_react5.useCallback)(
1755
+ const subscribe = (0, import_react6.useCallback)(
1571
1756
  (onStoreChange) => scope === void 0 ? NOOP_SUBSCRIBE() : scope.subscribe(onStoreChange),
1572
1757
  [scope]
1573
1758
  );
1574
- const raw = (0, import_react5.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
1575
- return (0, import_react5.useMemo)(() => resolveFromSnapshot(raw), [raw]);
1759
+ const raw = (0, import_react6.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
1760
+ return (0, import_react6.useMemo)(() => resolveFromSnapshot(raw), [raw]);
1576
1761
  }
1577
1762
 
1578
1763
  // src/client/components/SchedButton.tsx
@@ -1581,7 +1766,7 @@ function SchedButton(props) {
1581
1766
  const { callCommand, sessionId, inputActions, input, useProjection, useInput, locale, schedulerScope } = props;
1582
1767
  const { lang, t } = useSchedT(locale);
1583
1768
  const { smartWindow, promptLimits, showButton } = useSchedulerSettings(schedulerScope);
1584
- const [open, setOpen] = (0, import_react6.useState)(false);
1769
+ const [open, setOpen] = (0, import_react7.useState)(false);
1585
1770
  const {
1586
1771
  draft,
1587
1772
  schedules,
@@ -1600,19 +1785,15 @@ function SchedButton(props) {
1600
1785
  useProjection,
1601
1786
  useInput
1602
1787
  });
1603
- (0, import_react6.useEffect)(() => {
1604
- if (!open) return;
1788
+ useEscapeToClose(open, setOpen);
1789
+ (0, import_react7.useEffect)(() => {
1790
+ if (!open) return void 0;
1605
1791
  reposition();
1606
1792
  window.addEventListener("resize", reposition);
1607
- const onKey = (event) => {
1608
- if (event.key === "Escape") setOpen(false);
1609
- };
1610
- window.addEventListener("keydown", onKey, true);
1611
- return () => {
1612
- window.removeEventListener("resize", reposition);
1613
- window.removeEventListener("keydown", onKey, true);
1614
- };
1793
+ return () => window.removeEventListener("resize", reposition);
1615
1794
  }, [open, reposition]);
1795
+ const panelRef = (0, import_react7.useRef)(null);
1796
+ usePanelOutsideDismiss(rowRef, open, setOpen, panelRef);
1616
1797
  if (!showButton) return null;
1617
1798
  const handleCreateWithErrorBoundary = async (inputPayload) => {
1618
1799
  try {
@@ -1633,14 +1814,11 @@ function SchedButton(props) {
1633
1814
  "aria-expanded": open,
1634
1815
  disabled: !enabled,
1635
1816
  onClick: () => setOpen((value) => !value),
1636
- children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
1637
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "12", cy: "12", r: "10" }),
1638
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("polyline", { points: "12 6 12 12 16 14" })
1639
- ] })
1817
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_dsh_client_ui_primitives3.IconClockOutlineRegular, { size: 16 })
1640
1818
  }
1641
1819
  ),
1642
1820
  open && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
1643
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "ss-backdrop", onClick: () => setOpen(false), "aria-hidden": "true" }),
1821
+ !hasOfficialOutsideDismiss && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "ss-backdrop", onClick: () => setOpen(false), "aria-hidden": "true" }),
1644
1822
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1645
1823
  SchedPanel,
1646
1824
  {
@@ -1654,6 +1832,8 @@ function SchedButton(props) {
1654
1832
  onCreate: handleCreateWithErrorBoundary,
1655
1833
  onDelete: (id) => void handleDelete(id),
1656
1834
  bottom: anchorBottom,
1835
+ anchorRef: rowRef,
1836
+ panelRef,
1657
1837
  smartWindow,
1658
1838
  promptLimits
1659
1839
  }
@@ -1663,7 +1843,9 @@ function SchedButton(props) {
1663
1843
  }
1664
1844
 
1665
1845
  // src/client/components/ScheduleDock.tsx
1666
- var import_react7 = require("react");
1846
+ var import_react8 = require("react");
1847
+ var import_react_dom2 = require("react-dom");
1848
+ var import_dsh_client_ui_primitives4 = require("@deepseek-ai/dsh-client-ui-primitives");
1667
1849
 
1668
1850
  // src/bar-geometry.ts
1669
1851
  var BAR_UNIT_MS = 36e5;
@@ -1774,8 +1956,8 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
1774
1956
  const now = useNow(1e3);
1775
1957
  const { t } = useSchedT(locale);
1776
1958
  const projection = typeof useProjection === "function" ? useProjection("userSchedules") : void 0;
1777
- const [dismissedPaused, setDismissedPaused] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
1778
- (0, import_react7.useEffect)(() => {
1959
+ const [dismissedPaused, setDismissedPaused] = (0, import_react8.useState)(/* @__PURE__ */ new Set());
1960
+ (0, import_react8.useEffect)(() => {
1779
1961
  const live = projection?.schedules;
1780
1962
  if (live === void 0) return;
1781
1963
  setDismissedPaused((current) => {
@@ -1788,8 +1970,8 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
1788
1970
  return changed ? nextSet : current;
1789
1971
  });
1790
1972
  }, [projection]);
1791
- const [promptOverrides, setPromptOverrides] = (0, import_react7.useState)(/* @__PURE__ */ new Map());
1792
- (0, import_react7.useEffect)(() => {
1973
+ const [promptOverrides, setPromptOverrides] = (0, import_react8.useState)(/* @__PURE__ */ new Map());
1974
+ (0, import_react8.useEffect)(() => {
1793
1975
  const live = projection?.schedules;
1794
1976
  if (live === void 0 || promptOverrides.size === 0) return;
1795
1977
  setPromptOverrides((current) => {
@@ -1806,7 +1988,7 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
1806
1988
  return changed ? nextMap : current;
1807
1989
  });
1808
1990
  }, [projection, promptOverrides]);
1809
- const schedules = (0, import_react7.useMemo)(
1991
+ const schedules = (0, import_react8.useMemo)(
1810
1992
  () => (projection?.schedules ?? []).filter((item) => !(item.status === "paused" && dismissedPaused.has(item.id))).map((item) => {
1811
1993
  const override = promptOverrides.get(item.id);
1812
1994
  return override === void 0 ? item : { ...item, prompt: override };
@@ -1815,17 +1997,17 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
1815
1997
  ),
1816
1998
  [projection, dismissedPaused, promptOverrides]
1817
1999
  );
1818
- const [collapsed, setCollapsed] = (0, import_react7.useState)(true);
1819
- const [cancelling, setCancelling] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
1820
- const [editingId, setEditingId] = (0, import_react7.useState)(null);
1821
- const [editingText, setEditingText] = (0, import_react7.useState)("");
1822
- const [editErr, setEditErr] = (0, import_react7.useState)(null);
1823
- const [saving, setSaving] = (0, import_react7.useState)(false);
1824
- const [steering, setSteering] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
1825
- const [steerDone, setSteerDone] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
1826
- const [steerErr, setSteerErr] = (0, import_react7.useState)(/* @__PURE__ */ new Map());
1827
- const [steerUnconfirmed, setSteerUnconfirmed] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
1828
- (0, import_react7.useEffect)(() => {
2000
+ const [collapsed, setCollapsed] = (0, import_react8.useState)(true);
2001
+ const [cancelling, setCancelling] = (0, import_react8.useState)(/* @__PURE__ */ new Set());
2002
+ const [editingId, setEditingId] = (0, import_react8.useState)(null);
2003
+ const [editingText, setEditingText] = (0, import_react8.useState)("");
2004
+ const [editErr, setEditErr] = (0, import_react8.useState)(null);
2005
+ const [saving, setSaving] = (0, import_react8.useState)(false);
2006
+ const [steering, setSteering] = (0, import_react8.useState)(/* @__PURE__ */ new Set());
2007
+ const [steerDone, setSteerDone] = (0, import_react8.useState)(/* @__PURE__ */ new Set());
2008
+ const [steerErr, setSteerErr] = (0, import_react8.useState)(/* @__PURE__ */ new Map());
2009
+ const [steerUnconfirmed, setSteerUnconfirmed] = (0, import_react8.useState)(/* @__PURE__ */ new Set());
2010
+ (0, import_react8.useEffect)(() => {
1829
2011
  const live = projection?.schedules;
1830
2012
  if (live === void 0) return;
1831
2013
  const present = new Set(live.filter((item) => item.status !== "paused").map((item) => item.id));
@@ -1842,7 +2024,7 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
1842
2024
  return changed ? next2 : current;
1843
2025
  });
1844
2026
  }, [projection]);
1845
- (0, import_react7.useEffect)(() => {
2027
+ (0, import_react8.useEffect)(() => {
1846
2028
  if (steerDone.size === 0) return void 0;
1847
2029
  const timer = window.setTimeout(() => {
1848
2030
  const live = projection?.schedules;
@@ -1863,11 +2045,11 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
1863
2045
  }, STEER_CONFIRM_WINDOW_MS);
1864
2046
  return () => window.clearTimeout(timer);
1865
2047
  }, [steerDone, projection]);
1866
- const [pausing, setPausing] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
1867
- const [resuming, setResuming] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
1868
- const [pauseErr, setPauseErr] = (0, import_react7.useState)(/* @__PURE__ */ new Map());
1869
- const firstSeenRef = (0, import_react7.useRef)(/* @__PURE__ */ new Map());
1870
- const lastActiveAtRef = (0, import_react7.useRef)(/* @__PURE__ */ new Map());
2048
+ const [pausing, setPausing] = (0, import_react8.useState)(/* @__PURE__ */ new Set());
2049
+ const [resuming, setResuming] = (0, import_react8.useState)(/* @__PURE__ */ new Set());
2050
+ const [pauseErr, setPauseErr] = (0, import_react8.useState)(/* @__PURE__ */ new Map());
2051
+ const firstSeenRef = (0, import_react8.useRef)(/* @__PURE__ */ new Map());
2052
+ const lastActiveAtRef = (0, import_react8.useRef)(/* @__PURE__ */ new Map());
1871
2053
  const wallClock = Date.now();
1872
2054
  {
1873
2055
  const next2 = new Map(lastActiveAtRef.current);
@@ -1888,8 +2070,8 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
1888
2070
  }
1889
2071
  if (changed) lastActiveAtRef.current = next2;
1890
2072
  }
1891
- const byId = (0, import_react7.useMemo)(() => new Map(schedules.map((item) => [item.id, item])), [schedules]);
1892
- (0, import_react7.useEffect)(() => {
2073
+ const byId = (0, import_react8.useMemo)(() => new Map(schedules.map((item) => [item.id, item])), [schedules]);
2074
+ (0, import_react8.useEffect)(() => {
1893
2075
  let changed = false;
1894
2076
  const next2 = new Map(firstSeenRef.current);
1895
2077
  for (const [id] of byId) {
@@ -1906,7 +2088,7 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
1906
2088
  }
1907
2089
  if (changed) firstSeenRef.current = next2;
1908
2090
  }, [byId]);
1909
- (0, import_react7.useEffect)(() => {
2091
+ (0, import_react8.useEffect)(() => {
1910
2092
  if (schedules.length <= 1) setCollapsed(true);
1911
2093
  }, [schedules.length]);
1912
2094
  if (schedules.length === 0 || sessionId === void 0) return null;
@@ -2088,7 +2270,7 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
2088
2270
  children: saving ? "\u2026" : t.editSave
2089
2271
  }
2090
2272
  ),
2091
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "ss-dock-action", onClick: cancelEdit, "aria-label": t.editCancel, children: "\u2715" }),
2273
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "ss-dock-action", onClick: cancelEdit, "aria-label": t.editCancel, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_dsh_client_ui_primitives4.IconCloseOutlineRegular, { size: 14 }) }),
2092
2274
  editErr !== null && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ss-dock-edit-err", children: editErr })
2093
2275
  ] }, item.id);
2094
2276
  }
@@ -2115,63 +2297,58 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
2115
2297
  ] })
2116
2298
  ] }),
2117
2299
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ss-dock-actions", children: [
2118
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2300
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DockTip, { label: t.editTask, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2119
2301
  "button",
2120
2302
  {
2121
2303
  type: "button",
2122
2304
  className: "ss-dock-action",
2123
- title: t.editTask,
2124
2305
  "aria-label": t.editTask,
2125
2306
  onClick: () => startEdit(item),
2126
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueueEditIcon, {})
2307
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_dsh_client_ui_primitives4.IconEditOutlineRegular, { size: 14 })
2127
2308
  }
2128
- ),
2129
- isPaused ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2309
+ ) }),
2310
+ isPaused ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DockTip, { label: t.resumeTask, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2130
2311
  "button",
2131
2312
  {
2132
2313
  type: "button",
2133
2314
  className: `ss-dock-action ss-paused-active${resuming.has(item.id) ? " ss-pending" : ""}`,
2134
- title: t.resumeTask,
2135
2315
  "aria-label": t.resumeTask,
2136
2316
  disabled: resuming.has(item.id),
2137
2317
  onClick: () => handleResume(item),
2138
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueueResumeIcon, {})
2318
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_dsh_client_ui_primitives4.IconPlayOutlineRegular, { size: 16 })
2139
2319
  }
2140
- ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2320
+ ) }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DockTip, { label: canPause(item, now) ? t.pauseTask : t.pauseUnsupportedKind, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2141
2321
  "button",
2142
2322
  {
2143
2323
  type: "button",
2144
2324
  className: `ss-dock-action${pausing.has(item.id) ? " ss-pending" : ""}`,
2145
- title: canPause(item, now) ? t.pauseTask : t.pauseUnsupportedKind,
2146
2325
  "aria-label": canPause(item, now) ? t.pauseTask : t.pauseUnsupportedKind,
2147
2326
  disabled: !canPause(item, now) || pausing.has(item.id),
2148
2327
  onClick: () => handlePause(item),
2149
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueuePauseIcon, {})
2328
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_dsh_client_ui_primitives4.IconPauseOutlineRegular, { size: 16 })
2150
2329
  }
2151
- ),
2152
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2330
+ ) }),
2331
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DockTip, { label: t.deleteTask, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2153
2332
  "button",
2154
2333
  {
2155
2334
  type: "button",
2156
2335
  className: "ss-dock-action",
2157
- title: t.deleteTask,
2158
2336
  "aria-label": t.deleteTask,
2159
2337
  onClick: () => handleCancel(item.id, isPaused ? "paused" : "active"),
2160
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueueDeleteIcon, {})
2338
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_dsh_client_ui_primitives4.IconTrashOutlineRegular, { size: 14 })
2161
2339
  }
2162
- ),
2163
- item.kind !== "every" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2340
+ ) }),
2341
+ item.kind !== "every" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DockTip, { label: steerDone.has(item.id) ? t.steerAlreadySent : t.steerTask, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2164
2342
  "button",
2165
2343
  {
2166
2344
  type: "button",
2167
2345
  className: `ss-dock-action ss-dock-action-steer${steering.has(item.id) ? " ss-pending" : ""}${steerDone.has(item.id) ? " ss-done" : ""}`,
2168
- title: steerDone.has(item.id) ? t.steerAlreadySent : t.steerTask,
2169
2346
  "aria-label": steerDone.has(item.id) ? t.steerAlreadySent : t.steerTask,
2170
2347
  disabled: steering.has(item.id) || steerDone.has(item.id),
2171
2348
  onClick: () => handleSteer(item),
2172
- children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueueSendIcon, {})
2349
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_dsh_client_ui_primitives4.IconSendOutlineRegular, { size: 16 })
2173
2350
  }
2174
- )
2351
+ ) })
2175
2352
  ] })
2176
2353
  ]
2177
2354
  },
@@ -2187,9 +2364,9 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
2187
2364
  "aria-expanded": !collapsed,
2188
2365
  onClick: () => setCollapsed((value) => !value),
2189
2366
  children: [
2190
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ss-dock-lead", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueueClockIcon, {}) }),
2367
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ss-dock-lead", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_dsh_client_ui_primitives4.IconClockOutlineRegular, { size: 16 }) }),
2191
2368
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ss-dock-count", children: format(t.panelCount, { n: schedules.length }) }),
2192
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: expanded ? "ss-dock-chevron ss-open" : "ss-dock-chevron", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueueChevronIcon, {}) })
2369
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: expanded ? "ss-dock-chevron ss-open" : "ss-dock-chevron", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_dsh_client_ui_primitives4.IconChevronDownOutlineRegular, { size: 14 }) })
2193
2370
  ]
2194
2371
  }
2195
2372
  ),
@@ -2208,7 +2385,7 @@ function MultiBar({
2208
2385
  const frozenSeg = frozen ? frozenBarSegments(item, frozenLeftMs ?? 0, firstSeen, renderedAt) : void 0;
2209
2386
  const activeSeg = frozen ? void 0 : barSegments(item, now, firstSeen);
2210
2387
  const { totalRatio, count } = frozenSeg ?? activeSeg ?? { totalRatio: 0, count: 1 };
2211
- const phaseAtRef = (0, import_react7.useRef)(null);
2388
+ const phaseAtRef = (0, import_react8.useRef)(null);
2212
2389
  if (frozen || prefersReducedMotion()) {
2213
2390
  phaseAtRef.current = null;
2214
2391
  } else if (phaseAtRef.current === null) {
@@ -2252,33 +2429,76 @@ function MultiBar({
2252
2429
  }
2253
2430
  );
2254
2431
  }
2255
- function QueueClockIcon() {
2256
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M7.00049 0.199829C3.24488 0.199829 0.199952 3.24408 0.199707 6.99963C0.199707 8.0414 0.434087 9.03061 0.854004 9.91467L1.11279 10.4576L2.19775 9.94202L1.94092 9.39905L1.81787 9.12268C1.5498 8.46885 1.40186 7.75171 1.40186 6.99963C1.4021 3.90808 3.90888 1.40198 7.00049 1.40198C10.0919 1.40219 12.5979 3.90821 12.5981 6.99963C12.5981 10.0913 10.0921 12.5981 7.00049 12.5983C6.36734 12.5983 5.90348 12.5535 5.49268 12.4401C5.08803 12.3283 4.7041 12.1414 4.24463 11.8209C3.57111 11.3511 2.60588 11.1855 1.81006 11.6881L1.79736 11.6959L1.78467 11.7047L1.25537 12.0778L1.65381 13.2672L2.46045 12.6989C2.75029 12.5214 3.18004 12.5442 3.55615 12.8063C4.10063 13.1861 4.60863 13.4423 5.17334 13.5983C5.73194 13.7525 6.31665 13.8004 7.00049 13.8004C10.7561 13.8002 13.8003 10.7553 13.8003 6.99963C13.8 3.24421 10.7559 0.200041 7.00049 0.199829ZM3.81201 7.47327V8.67542H7.11572V7.47327H3.81201ZM3.81201 6.34924H10.2173V5.14709H3.81201V6.34924Z", fill: "currentColor" }) });
2257
- }
2258
- function QueueChevronIcon() {
2259
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z", fill: "currentColor" }) });
2260
- }
2261
- function QueueEditIcon() {
2262
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M9.94076 1.34942C10.7047 0.90231 11.6503 0.902415 12.4143 1.34942C12.7061 1.52015 12.9688 1.79118 13.3104 2.13284C13.6521 2.47448 13.9231 2.73721 14.0939 3.02894C14.5408 3.79294 14.5409 4.73856 14.0939 5.50251C13.9231 5.79415 13.652 6.05704 13.3104 6.39861L6.65932 13.0497C6.28068 13.4284 6.00695 13.7108 5.66543 13.9097C5.32391 14.1085 4.94315 14.2074 4.42705 14.3498L3.24394 14.6761C2.77527 14.8054 2.34538 14.9262 2.00131 14.9684C1.65196 15.0112 1.17964 15.0013 0.810764 14.6325C0.441921 14.2637 0.432107 13.7913 0.47486 13.442C0.517035 13.0979 0.6379 12.668 0.767181 12.1993L1.09352 11.0162C1.23588 10.5001 1.33481 10.1193 1.5336 9.77784C1.7325 9.43632 2.0149 9.1626 2.39355 8.78395L9.04466 2.13284C9.38625 1.79126 9.64911 1.52016 9.94076 1.34942ZM15.5427 14.8398H7.55223L8.96707 13.425H15.5427V14.8398ZM3.39382 9.78422C2.965 10.213 2.84244 10.3436 2.75709 10.49C2.67183 10.6366 2.61862 10.8079 2.45733 11.3925L2.13099 12.5756C2.00183 13.0439 1.92194 13.3419 1.88863 13.5536C2.10041 13.5204 2.39872 13.4416 2.86764 13.3123L4.05075 12.9859C4.63544 12.8246 4.80669 12.7715 4.95323 12.6862C5.09968 12.6008 5.23022 12.4783 5.65905 12.0494L10.721 6.98644L8.45577 4.72121L3.39382 9.78422ZM11.7 2.57079C11.3774 2.38198 10.9777 2.38198 10.6551 2.57079C10.5602 2.62647 10.4487 2.72931 10.0449 3.13311L9.45604 3.72094L11.7213 5.98617L12.3102 5.39833C12.7139 4.99457 12.8168 4.88307 12.8725 4.78818C13.0613 4.46561 13.0612 4.06585 12.8725 3.74326C12.8169 3.64827 12.7146 3.53752 12.3102 3.13311C11.9057 2.72863 11.795 2.6264 11.7 2.57079Z", fill: "currentColor" }) });
2263
- }
2264
- function QueueDeleteIcon() {
2265
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M14.4782 4.84067L14.2138 10.1152C14.1102 12.1872 14.067 13.0115 13.3866 13.9607C13.1044 14.3546 12.7498 14.6912 12.3424 14.9535C11.8239 15.2872 11.2415 15.4316 10.5585 15.4998C9.88727 15.5668 9.04946 15.5656 7.99998 15.5656C6.95051 15.5656 6.1127 15.5668 5.44142 15.4998C4.75851 15.4316 4.17602 15.2872 3.65753 14.9535C3.25012 14.6912 2.89559 14.3546 2.61332 13.9607C1.93296 13.0115 1.88979 12.1872 1.78619 10.1152L1.52179 4.84067L2.89006 4.77277L3.15343 10.0463C3.26221 12.2218 3.32452 12.6015 3.72646 13.1624C3.90825 13.4161 4.13686 13.6334 4.39927 13.8023C4.66204 13.9714 5.00263 14.0792 5.57825 14.1367C6.16562 14.1953 6.92298 14.1963 7.99998 14.1963C9.07699 14.1963 9.83434 14.1953 10.4217 14.1367C10.9973 14.0792 11.3379 13.9714 11.6007 13.8023C11.8631 13.6334 12.0917 13.4161 12.2735 13.1624C12.6755 12.6015 12.7378 12.2218 12.8465 10.0463L13.1099 4.77277L14.4782 4.84067ZM5.43011 6.22849H6.7994V11.3909H5.43011V6.22849ZM9.20056 6.22849H10.5699V11.3909H9.20056V6.22849ZM8.53597 0.434431C9.17976 0.434431 9.6522 0.426926 10.0966 0.571258C10.2357 0.616451 10.3717 0.672554 10.502 0.738948C10.9182 0.951107 11.2464 1.29099 11.7015 1.74612L12.4978 2.54136H15.3742V3.91169H0.625732V2.54136H3.50218L4.29845 1.74612C4.75358 1.29099 5.08174 0.951107 5.49801 0.738948C5.62831 0.672554 5.76425 0.616451 5.90334 0.571258C6.34776 0.426926 6.82021 0.434431 7.46399 0.434431H8.53597ZM7.46399 1.80476C6.73208 1.80476 6.51641 1.81187 6.32617 1.87369C6.25545 1.89667 6.18668 1.92533 6.12041 1.95907C5.96398 2.03878 5.82348 2.16253 5.44142 2.54136H10.5585C10.1765 2.16253 10.036 2.03878 9.87955 1.95907C9.81329 1.92533 9.74452 1.89667 9.6738 1.87369C9.48356 1.81187 9.26789 1.80476 8.53597 1.80476H7.46399Z", fill: "currentColor" }) });
2266
- }
2267
- function QueueSendIcon() {
2268
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M7.24707 1.01771C7.52897 1.07653 7.77619 1.19694 8.00391 1.38001C8.19202 1.53136 8.39884 1.73784 8.61914 1.95814L12.6396 5.9806L11.6299 6.99134L7.71484 3.0763V13.0001H6.28516V3.0763L2.36914 6.99134L1.35938 5.9806L5.38086 1.95814C5.60116 1.73784 5.80798 1.53136 5.99609 1.38001C6.19476 1.22027 6.4385 1.06739 6.75195 1.01771C6.91296 0.992304 7.07471 0.997504 7.24707 1.01771Z", fill: "currentColor" }) });
2269
- }
2270
- function QueuePauseIcon() {
2271
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [
2272
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "3.6", y: "2.6", width: "3.2", height: "10.8", rx: "1.1", fill: "currentColor" }),
2273
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "9.2", y: "2.6", width: "3.2", height: "10.8", rx: "1.1", fill: "currentColor" })
2432
+ function DockTip({ label, children }) {
2433
+ const anchorRef = (0, import_react8.useRef)(null);
2434
+ const bubbleRef = (0, import_react8.useRef)(null);
2435
+ const [pos, setPos] = (0, import_react8.useState)(null);
2436
+ const timerRef = (0, import_react8.useRef)(null);
2437
+ const cancel = () => {
2438
+ if (timerRef.current !== null) {
2439
+ window.clearTimeout(timerRef.current);
2440
+ timerRef.current = null;
2441
+ }
2442
+ };
2443
+ const show = () => {
2444
+ const el = anchorRef.current;
2445
+ if (!el) return;
2446
+ const r = el.getBoundingClientRect();
2447
+ setPos({ left: r.left + r.width / 2, top: r.bottom + 8, side: "bottom" });
2448
+ };
2449
+ const enter = () => {
2450
+ cancel();
2451
+ timerRef.current = window.setTimeout(show, 500);
2452
+ };
2453
+ const leave = () => {
2454
+ cancel();
2455
+ setPos(null);
2456
+ };
2457
+ (0, import_react8.useEffect)(() => cancel, []);
2458
+ (0, import_react8.useLayoutEffect)(() => {
2459
+ if (!pos || !bubbleRef.current) return;
2460
+ const b = bubbleRef.current;
2461
+ const w = b.offsetWidth;
2462
+ const h = b.offsetHeight;
2463
+ const edge = 12;
2464
+ let left = pos.left;
2465
+ let top = pos.top;
2466
+ let side = pos.side;
2467
+ left = Math.max(edge + w / 2, Math.min(left, window.innerWidth - edge - w / 2));
2468
+ if (side === "bottom" && top + h > window.innerHeight - edge) {
2469
+ const anchorEl = anchorRef.current;
2470
+ const r = anchorEl.getBoundingClientRect();
2471
+ top = r.top - 8;
2472
+ side = "top";
2473
+ }
2474
+ b.style.left = `${left}px`;
2475
+ b.style.top = `${top}px`;
2476
+ b.dataset.side = side;
2477
+ b.style.visibility = "visible";
2478
+ }, [pos]);
2479
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
2480
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2481
+ "span",
2482
+ {
2483
+ ref: anchorRef,
2484
+ className: "ss-dock-tip-anchor",
2485
+ onPointerEnter: enter,
2486
+ onPointerLeave: leave,
2487
+ onFocus: enter,
2488
+ onBlur: leave,
2489
+ children
2490
+ }
2491
+ ),
2492
+ pos && typeof document !== "undefined" && (0, import_react_dom2.createPortal)(
2493
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { ref: bubbleRef, className: "ss-dock-tip", style: { left: pos.left, top: pos.top, visibility: "hidden" }, children: label }),
2494
+ document.body
2495
+ )
2274
2496
  ] });
2275
2497
  }
2276
- function QueueResumeIcon() {
2277
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M4.4 2.9c0-.6.66-1 1.18-.68l7.1 4.1c.52.3.52 1.06 0 1.36l-7.1 4.1A.8.8 0 0 1 4.4 11.1V2.9Z", fill: "currentColor" }) });
2278
- }
2279
2498
 
2280
2499
  // src/client/components/SchedulerSettingsCard.tsx
2281
- var import_react8 = require("react");
2500
+ var import_react9 = require("react");
2501
+ var import_dsh_client_ui_primitives5 = require("@deepseek-ai/dsh-client-ui-primitives");
2282
2502
  var import_jsx_runtime5 = require("react/jsx-runtime");
2283
2503
  var SECTIONS = [
2284
2504
  {
@@ -2345,22 +2565,50 @@ var SECTIONS = [
2345
2565
  defaultValue: "keep"
2346
2566
  }
2347
2567
  ]
2568
+ },
2569
+ {
2570
+ id: "advanced",
2571
+ titleKey: "sectionAdvanced",
2572
+ layout: "stack",
2573
+ beta: true,
2574
+ fields: [
2575
+ {
2576
+ kind: "boolean",
2577
+ key: "advancedSyntax",
2578
+ labelKey: "advancedSyntaxLabel",
2579
+ hintKey: "advancedSyntaxHint",
2580
+ defaultValue: true
2581
+ }
2582
+ ]
2348
2583
  }
2349
2584
  ];
2350
2585
  var FIELDS = SECTIONS.flatMap((s) => s.fields);
2351
- function SchedulerSettingsCard({ scope, t }) {
2352
- const [snapshot, setSnapshot] = (0, import_react8.useState)(() => scope.getSnapshot());
2353
- const [pending, setPending] = (0, import_react8.useState)({});
2354
- const [saving, setSaving] = (0, import_react8.useState)(false);
2355
- const [failed, setFailed] = (0, import_react8.useState)(false);
2356
- const [helpOpen, setHelpOpen] = (0, import_react8.useState)({});
2357
- (0, import_react8.useEffect)(() => {
2586
+ function SchedulerSettingsCard({ scope, t, surface }) {
2587
+ const [snapshot, setSnapshot] = (0, import_react9.useState)(() => scope.getSnapshot());
2588
+ const [pending, setPending] = (0, import_react9.useState)({});
2589
+ const [saving, setSaving] = (0, import_react9.useState)(false);
2590
+ const [failed, setFailed] = (0, import_react9.useState)(false);
2591
+ const [helpOpen, setHelpOpen] = (0, import_react9.useState)({});
2592
+ const SHOW_SETTINGS_KEY = "dsh-later:show-settings-section";
2593
+ const [showSettings, setShowSettings] = (0, import_react9.useState)(() => {
2594
+ if (typeof localStorage === "undefined") return false;
2595
+ return localStorage.getItem(SHOW_SETTINGS_KEY) === "true";
2596
+ });
2597
+ const toggleShowSettings = () => {
2598
+ const next = !showSettings;
2599
+ setShowSettings(next);
2600
+ if (typeof localStorage !== "undefined") {
2601
+ if (next) localStorage.setItem(SHOW_SETTINGS_KEY, "true");
2602
+ else localStorage.removeItem(SHOW_SETTINGS_KEY);
2603
+ }
2604
+ };
2605
+ (0, import_react9.useEffect)(() => {
2358
2606
  const initial = scope.getSnapshot();
2359
2607
  setSnapshot(initial);
2360
2608
  setPending({});
2361
2609
  if (initial.status === "ready") setFailed(false);
2362
2610
  }, [scope]);
2363
- (0, import_react8.useEffect)(() => {
2611
+ (0, import_react9.useEffect)(() => {
2364
2612
  return scope.subscribe(() => {
2365
2613
  const snap = scope.getSnapshot();
2366
2614
  setSnapshot(snap);
@@ -2438,11 +2686,11 @@ function SchedulerSettingsCard({ scope, t }) {
2438
2686
  setFieldPending(field.key, baselineValue(field), true);
2439
2687
  setFailed(false);
2440
2688
  };
2441
- const handleDiscard = (0, import_react8.useCallback)(() => {
2689
+ const handleDiscard = (0, import_react9.useCallback)(() => {
2442
2690
  setPending({});
2443
2691
  setFailed(false);
2444
2692
  }, []);
2445
- const handleSave = (0, import_react8.useCallback)(async () => {
2693
+ const handleSave = (0, import_react9.useCallback)(async () => {
2446
2694
  if (!dirty || saving || !writable) return;
2447
2695
  setSaving(true);
2448
2696
  setFailed(false);
@@ -2478,8 +2726,32 @@ function SchedulerSettingsCard({ scope, t }) {
2478
2726
  const confirmEnabled = (pending.confirmDelivery?.value ?? (value.confirmDelivery === false ? "false" : "true")) !== "false";
2479
2727
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-settings-form", children: [
2480
2728
  !writable && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ss-hint", role: "status", children: t("readOnly") }),
2729
+ surface === "detail" && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { className: "ss-section", "aria-labelledby": "ss-section-display-toggle", children: [
2730
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { className: "ss-section-heading", id: "ss-section-display-toggle", children: t("sectionDisplayToggle") }),
2731
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ss-section-fields", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-field ss-fieldToggle", children: [
2732
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-toggle-row", children: [
2733
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ss-label-group", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { className: "ss-toggle-label", htmlFor: "ss-show-settings", children: t("showInSettings") }) }),
2734
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2735
+ "button",
2736
+ {
2737
+ type: "button",
2738
+ id: "ss-show-settings",
2739
+ role: "switch",
2740
+ "aria-checked": showSettings,
2741
+ "aria-label": t("showInSettings"),
2742
+ className: "ss-toggle-switch",
2743
+ onClick: toggleShowSettings
2744
+ }
2745
+ )
2746
+ ] }),
2747
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ss-toggle-description", children: t("showInSettingsHint") })
2748
+ ] }) })
2749
+ ] }),
2481
2750
  SECTIONS.map((section) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { className: "ss-section", "aria-labelledby": `ss-section-${section.id}`, children: [
2482
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { className: "ss-section-heading", id: `ss-section-${section.id}`, children: t(section.titleKey) }),
2751
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("h3", { className: "ss-section-heading", id: `ss-section-${section.id}`, children: [
2752
+ t(section.titleKey),
2753
+ section.beta === true ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-section-beta", "aria-label": t("betaBadgeAria"), children: t("betaBadge") }) : null
2754
+ ] }),
2483
2755
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: section.layout === "grid" ? "ss-section-fields ss-section-fieldsGrid" : "ss-section-fields", children: section.fields.map((field) => {
2484
2756
  const invalid = invalidField(field);
2485
2757
  const isTime = field.kind === "time";
@@ -2538,11 +2810,7 @@ function SchedulerSettingsCard({ scope, t }) {
2538
2810
  "aria-expanded": helpOpen[field.key] === true,
2539
2811
  "aria-controls": `ss-help-${field.key}`,
2540
2812
  onClick: () => setHelpOpen((prev) => ({ ...prev, [field.key]: !prev[field.key] })),
2541
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { width: "12", height: "12", viewBox: "0 0 14 14", fill: "none", "aria-hidden": "true", strokeWidth: "1", children: [
2542
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M12.5757 7.00012C12.5757 3.92085 10.0794 1.42463 7.00012 1.42456C3.9208 1.42456 1.42456 3.9208 1.42456 7.00012C1.42463 10.0794 3.92085 12.5757 7.00012 12.5757C10.0793 12.5756 12.5756 10.0793 12.5757 7.00012ZM13.8002 7.00012C13.8001 10.7559 10.7559 13.8001 7.00012 13.8002C3.2443 13.8002 0.199291 10.7559 0.199219 7.00012C0.199219 3.24426 3.24426 0.199219 7.00012 0.199219C10.7559 0.199291 13.8002 3.2443 13.8002 7.00012Z", fill: "currentColor" }),
2543
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M7.6127 3.18921V4.55986H6.38735V3.18921H7.6127Z", fill: "currentColor" }),
2544
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M7.6127 5.68921V10.8109H6.38735V5.68921H7.6127Z", fill: "currentColor" })
2545
- ] })
2813
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_dsh_client_ui_primitives5.IconInfoOutlineRegular, { size: 12 })
2546
2814
  }
2547
2815
  )
2548
2816
  ] }),
@@ -3056,23 +3324,23 @@ function subscribeScheduleSummaryStore(listener) {
3056
3324
  }
3057
3325
 
3058
3326
  // src/client/useScheduleSummary.ts
3059
- var import_react9 = require("react");
3327
+ var import_react10 = require("react");
3060
3328
  var EMPTY_SUMMARY = /* @__PURE__ */ new Map();
3061
3329
  var noopSubscribe2 = () => () => void 0;
3062
3330
  var emptySnapshot = () => EMPTY_SUMMARY;
3063
3331
  var missingSnapshot = () => void 0;
3064
3332
  function useScheduleSummary(store) {
3065
- const registered = (0, import_react9.useSyncExternalStore)(subscribeScheduleSummaryStore, getScheduleSummaryStore, missingSnapshot);
3333
+ const registered = (0, import_react10.useSyncExternalStore)(subscribeScheduleSummaryStore, getScheduleSummaryStore, missingSnapshot);
3066
3334
  const target = store ?? registered;
3067
- const subscribe = (0, import_react9.useMemo)(
3335
+ const subscribe = (0, import_react10.useMemo)(
3068
3336
  () => target === void 0 ? noopSubscribe2 : (listener) => target.subscribe(listener),
3069
3337
  [target]
3070
3338
  );
3071
- const getSnapshot = (0, import_react9.useMemo)(
3339
+ const getSnapshot = (0, import_react10.useMemo)(
3072
3340
  () => target === void 0 ? emptySnapshot : () => target.getSnapshot(),
3073
3341
  [target]
3074
3342
  );
3075
- return (0, import_react9.useSyncExternalStore)(subscribe, getSnapshot, emptySnapshot);
3343
+ return (0, import_react10.useSyncExternalStore)(subscribe, getSnapshot, emptySnapshot);
3076
3344
  }
3077
3345
 
3078
3346
  // src/client/index.tsx
@@ -3122,6 +3390,11 @@ function apply(ctx) {
3122
3390
  sectionDisplay: "\u663E\u793A\u8BBE\u7F6E",
3123
3391
  sectionTime: "\u65F6\u95F4\u8BBE\u7F6E",
3124
3392
  sectionDelivery: "\u6295\u9012\u8BBE\u7F6E",
3393
+ sectionAdvanced: "\u9AD8\u7EA7\u8BED\u6CD5",
3394
+ betaBadge: "Beta",
3395
+ betaBadgeAria: "Beta \u529F\u80FD\uFF0C\u884C\u4E3A\u53EF\u80FD\u968F\u7248\u672C\u8C03\u6574",
3396
+ advancedSyntaxLabel: "\u542F\u7528\u591A\u6B21\u5199\u6CD5\uFF08+1h*3 / 15:32+16:32\uFF09",
3397
+ advancedSyntaxHint: "\u8BA9 /later \u4E0E /schedule \u652F\u6301\u4E00\u6B21\u5199\u591A\u6761\uFF1A+1h*3\uFF08\u7B49\u95F4\u9694 3 \u6B21\uFF09\u3001+1h+1h+0.5h\uFF08\u76F8\u5BF9\u5E8F\u5217\uFF09\u300115:32+16:32 \u4E0E 9:00+1d\uFF08\u951A\u70B9\u5E8F\u5217\uFF0C\u6309\u5899\u949F\u63A8\u8FDB\uFF0C\u8DE8\u590F\u4EE4\u65F6\u4E0D\u6F02\uFF09\u3002\u6BCF\u6761\u90FD\u662F\u72EC\u7ACB\u4EFB\u52A1\uFF0C\u53EF\u5355\u72EC\u53D6\u6D88\u6216\u7F16\u8F91\uFF1B\u5355\u6B21\u6700\u591A 10 \u6761\u3002\u6807\u8BB0\u4E3A Beta\uFF1A\u5C55\u5F00\u540E\u7684\u89C2\u611F\u4E0E\u6761\u6570\u4E0A\u9650\u4ECD\u9700\u89C2\u5BDF\u3002",
3125
3398
  showButtonLabel: "\u663E\u793A\u5B9A\u65F6\u6309\u94AE",
3126
3399
  showButtonHint: "\u5173\u95ED\u540E\u8F93\u5165\u6846\u53F3\u4FA7\u4E0D\u518D\u663E\u793A\u65F6\u949F\u6309\u94AE\uFF1B\u5DF2\u521B\u5EFA\u7684\u63D0\u9192\u4ECD\u4F1A\u7167\u5E38\u89E6\u53D1\uFF0C\u5E76\u5728\u8F93\u5165\u6846\u4E0B\u65B9\u7684\u5F85\u53D1\u9001\u5217\u8868\u4E2D\u663E\u793A\u3002",
3127
3400
  maxSchedulesLabel: "\u5355\u4F1A\u8BDD\u4EFB\u52A1\u4E0A\u9650",
@@ -3159,7 +3432,10 @@ function apply(ctx) {
3159
3432
  discard: "\u653E\u5F03\u4FEE\u6539",
3160
3433
  saveFailed: "\u4FDD\u5B58\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002",
3161
3434
  loading: "\u52A0\u8F7D\u4E2D\u2026",
3162
- unavailable: "\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002"
3435
+ unavailable: "\u8BBE\u7F6E\u6682\u4E0D\u53EF\u7528\u3002",
3436
+ sectionDisplayToggle: "\u663E\u793A\u8BBE\u7F6E",
3437
+ showInSettings: "\u5728\u8BBE\u7F6E\u4E2D\u663E\u793A",
3438
+ showInSettingsHint: "\u5728\u8BBE\u7F6E\u5BF9\u8BDD\u6846\u4E2D\u663E\u793A\u672C\u63D2\u4EF6\u7684\u8BBE\u7F6E\u9875\uFF08\u5237\u65B0\u9875\u9762\u540E\u751F\u6548\uFF09"
3163
3439
  },
3164
3440
  en: {
3165
3441
  title: "Session Scheduler",
@@ -3171,6 +3447,11 @@ function apply(ctx) {
3171
3447
  sectionDisplay: "Display",
3172
3448
  sectionTime: "Time windows",
3173
3449
  sectionDelivery: "Delivery",
3450
+ sectionAdvanced: "Advanced syntax",
3451
+ betaBadge: "Beta",
3452
+ betaBadgeAria: "Beta feature; behaviour may change between versions",
3453
+ advancedSyntaxLabel: "Multi-shot syntax (+1h*3 / 15:32+16:32)",
3454
+ advancedSyntaxHint: "Let /later and /schedule create several tasks at once: +1h*3 (same interval N times), +1h+1h+0.5h (relative chain), 15:32+16:32 and 9:00+1d (anchored on a wall clock \u2014 it keeps the clock time across DST). Each occurrence is an independent task you can cancel or edit on its own; up to 10 per command. Marked Beta: the expanded result and the 10-task cap still need real-world observation.",
3174
3455
  showButtonLabel: "Show schedule button",
3175
3456
  showButtonHint: "Hide the clock button on the input bar. Existing reminders keep firing and stay visible in the dock below the composer.",
3176
3457
  maxSchedulesLabel: "Max schedules per session",
@@ -3208,7 +3489,10 @@ function apply(ctx) {
3208
3489
  discard: "Discard",
3209
3490
  saveFailed: "Save failed, please try again.",
3210
3491
  loading: "Loading\u2026",
3211
- unavailable: "Settings unavailable."
3492
+ unavailable: "Settings unavailable.",
3493
+ sectionDisplayToggle: "Display",
3494
+ showInSettings: "Show in settings",
3495
+ showInSettingsHint: "Show this plugin's settings page in the settings dialog (refresh to take effect)"
3212
3496
  }
3213
3497
  }), "dsh-later: locale");
3214
3498
  }
@@ -3253,11 +3537,17 @@ function apply(ctx) {
3253
3537
  );
3254
3538
  };
3255
3539
  const cardT = locale === void 0 ? void 0 : locale.bind(NS);
3256
- const cardDeclaration = (slot, scope) => ({
3540
+ const cardDeclaration = (slot, scope, surface = "detail") => ({
3257
3541
  name: slot,
3542
+ id: SETTINGS_NS,
3543
+ order: 30,
3258
3544
  key: SETTINGS_NS,
3259
3545
  locale: NS,
3260
- inject: () => ({ scope, t: cardT })
3546
+ label: () => {
3547
+ const active = locale === void 0 ? "zh" : locale.getSnapshot().active;
3548
+ return active === "en" ? "Session Scheduler" : "\u5B9A\u65F6\u63D0\u9192";
3549
+ },
3550
+ inject: () => ({ scope, t: cardT, surface })
3261
3551
  });
3262
3552
  ctx.inject(["settingsScope"], () => {
3263
3553
  const binder = ctx.get("settingsScope");
@@ -3273,10 +3563,18 @@ function apply(ctx) {
3273
3563
  };
3274
3564
  mountComposer(scope);
3275
3565
  if (cardT === void 0) return;
3276
- ctx.slots.inject(
3277
- "settings.plugin.item",
3278
- () => ctx.slots.register(cardDeclaration("settings.plugin.item", scope), SchedulerSettingsCard)
3566
+ const SHOW_SETTINGS_KEY = "dsh-later:show-settings-section";
3567
+ const showSettingsSection = typeof localStorage !== "undefined" && localStorage.getItem(SHOW_SETTINGS_KEY) === "true";
3568
+ if (!showSettingsSection) return;
3569
+ const disposeSection = ctx.slots.inject(
3570
+ "settings.section",
3571
+ () => ctx.slots.register(cardDeclaration("settings.section", scope, "settings"), SchedulerSettingsCard)
3279
3572
  );
3573
+ if (typeof disposeSection === "function") {
3574
+ ctx.effect(() => () => {
3575
+ disposeSection();
3576
+ });
3577
+ }
3280
3578
  });
3281
3579
  ctx.inject(["configForms"], () => {
3282
3580
  const forms = ctx.get("configForms");
@@ -3297,11 +3595,23 @@ function apply(ctx) {
3297
3595
  [ENTRY_ID],
3298
3596
  () => ctx.slots.inject(
3299
3597
  "plugins.bundle.config",
3300
- () => ctx.slots.register(cardDeclaration("plugins.bundle.config", scope), SchedulerSettingsCard)
3598
+ () => ctx.slots.register(cardDeclaration("plugins.bundle.config", scope, "detail"), SchedulerSettingsCard)
3301
3599
  )
3302
3600
  ),
3303
3601
  "dsh-later: plugins-page card"
3304
3602
  );
3603
+ const SHOW_SETTINGS_KEY = "dsh-later:show-settings-section";
3604
+ const showSettingsSection = typeof localStorage !== "undefined" && localStorage.getItem(SHOW_SETTINGS_KEY) === "true";
3605
+ if (!showSettingsSection) return;
3606
+ const disposeSection = ctx.slots.inject(
3607
+ "settings.section",
3608
+ () => ctx.slots.register(cardDeclaration("settings.section", scope, "settings"), SchedulerSettingsCard)
3609
+ );
3610
+ if (typeof disposeSection === "function") {
3611
+ ctx.effect(() => () => {
3612
+ disposeSection();
3613
+ });
3614
+ }
3305
3615
  });
3306
3616
  }
3307
3617