dsh-later 1.0.0 → 1.2.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
@@ -26,8 +26,15 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
26
26
  var index_exports = {};
27
27
  __export(index_exports, {
28
28
  apply: () => apply,
29
+ buildScheduleSummary: () => buildScheduleSummary,
30
+ createScheduleSummaryStore: () => createScheduleSummaryStore,
31
+ getScheduleSummaryStore: () => getScheduleSummaryStore,
29
32
  inject: () => inject,
30
- name: () => name
33
+ name: () => name,
34
+ schedulesOfProjection: () => schedulesOfProjection,
35
+ subscribeScheduleSummaryStore: () => subscribeScheduleSummaryStore,
36
+ summarizeScheduleGroup: () => summarizeScheduleGroup,
37
+ useScheduleSummary: () => useScheduleSummary
31
38
  });
32
39
  module.exports = __toCommonJS(index_exports);
33
40
 
@@ -131,8 +138,51 @@ var COMPONENTS = [
131
138
  ".ss-dock-bar-fill {",
132
139
  " position: relative; z-index: 1;",
133
140
  " height: 100%; border-radius: 999px; background: var(--dsw-alias-brand-primary);",
134
- " transition: width 1s linear;",
141
+ /* 活动期的推进由 CSS 动画驱动(见 ScheduleDock 的 fillStyle):
142
+ 旧实现是「每秒 tick 改一次宽度 + transition 补间」,1 分钟任务每秒跳约 8px,
143
+ 肉眼可见锯齿。改为动画后由合成器逐帧插值,真 60fps 且零重渲染。
144
+ 这里**不保留** transition: width —— 它与动画叠加会造成双重补间、反而更抖。 */
145
+ " /* \u6781\u77ED\u4EFB\u52A1/\u65E9\u671F\u6682\u505C\u65F6\u8FDB\u5EA6\u6BD4\u63A5\u8FD1 0\uFF1A\u7ED9\u6700\u5C0F\u53EF\u89C1\u5BBD\u5EA6\uFF0C\u4E14 active \u4E0E paused \u540C\u4E00\u89C4\u5219\uFF0C",
146
+ " \u907F\u514D\u6682\u505C\u524D\u540E\u4FDD\u5E95\u9608\u503C\u4E0D\u4E00\u81F4\u5BFC\u81F4\u6761\u957F\u8DF3\u53D8\u3002 */",
147
+ " min-width: 10px;",
135
148
  "}",
149
+ "/* \u8FDB\u5EA6\u63A8\u8FDB\uFF1ACSS \u52A8\u753B\u7EBF\u6027\u63A8\u8FDB\uFF08\u66FF\u4EE3\u300C\u6BCF\u79D2 tick \u6539\u5BBD\u5EA6 + transition \u8865\u95F4\u300D\uFF09\u3002",
150
+ " \u53C2\u6570\u7531 JS \u6CE8\u5165 --ss-bar-duration / --ss-bar-delay\uFF1A",
151
+ " duration \u56FA\u5B9A\u4E3A\u5B8C\u6574\u7A97\u53E3\uFF08\u5426\u5219\u6BCF\u6B21 tick \u90FD\u6539\u53D8\u53C2\u6570\u3001\u6D4F\u89C8\u5668\u4F1A\u91CD\u542F\u52A8\u753B\uFF09\uFF1B",
152
+ " delay \u4E3A -(\u5DF2\u8FC7\u53BB) \u7684\u8D1F\u503C\uFF08\u628A\u64AD\u653E\u5934\u5B9A\u4F4D\u5230\u7EDD\u5BF9\u76F8\u4F4D\uFF0C\u91CD\u6302\u8F7D\u540E\u4E0D\u5F52\u96F6\uFF09\u3002",
153
+ " JS \u4FA7\u53EA\u4F20\u53D8\u91CF\u3001\u4E0D\u5199 animationName \u7B80\u5199\uFF0C\u907F\u514D\u8986\u76D6\u8FD9\u91CC\u7684\u58F0\u660E\u3002",
154
+ " \u6CE8\u610F\u6B64\u5904**\u4E0D\u5E26** :not(.ss-paused)\uFF1A\u6682\u505C\u6001\u53E6\u6709 animation: none \u8986\u76D6\u3002 */",
155
+ ".ss-dock-bar-fill {",
156
+ " animation-name: ss-dock-bar-progress;",
157
+ " animation-duration: var(--ss-bar-duration, 3600s);",
158
+ " animation-delay: var(--ss-bar-delay, 0ms);",
159
+ " animation-timing-function: linear;",
160
+ " animation-fill-mode: forwards;",
161
+ " animation-iteration-count: 1;",
162
+ "}",
163
+ "@keyframes ss-dock-bar-progress { from { width: 0%; } to { width: 100%; } }",
164
+ "@media (prefers-reduced-motion: reduce) {",
165
+ " /* \u65E0\u969C\u788D\uFF1A\u5173\u6389\u9010\u5E27\u63A8\u8FDB\u3002\u6B64\u65F6 animation-fill-mode \u4F1A\u8BA9\u5BBD\u5EA6\u505C\u5728\u8D77\u59CB\u503C(0)\uFF0C",
166
+ " \u6545\u7531 JS \u4FA7\u6539\u8D70\u9759\u6001 width \u8DEF\u5F84\uFF08\u89C1 ScheduleDock \u7684 prefersReducedMotion\uFF09\u3002 */",
167
+ " .ss-dock-bar-fill { animation: none !important; }",
168
+ "}",
169
+ "/* \u6682\u505C\u6001\uFF08P1\uFF1A\u4E0D\u989D\u5916\u52A0\u6837\u5F0F\uFF09\u3002",
170
+ " \u6682\u505C = \u539F\u6761 + \u5B8C\u5168\u9759\u6B62\uFF1A\u4E0D\u53E0\u52A0\u659C\u7EB9/\u51B0\u5C01/\u963B\u585E\u5934\uFF0C\u4E5F\u4E0D\u6539\u5E95\u8272\u3001\u4E0D\u53D8\u8272\u3002",
171
+ " \u72B6\u6001\u7531\u300C\u52A8 / \u9759\u300D\u5BF9\u6BD4\u8868\u8FBE\u2014\u2014\u8FDB\u884C\u4E2D\u8FDB\u5EA6\u6761\u5728\u63A8\u8FDB\uFF0C\u6682\u505C\u65F6\u505C\u4F4F\u3002",
172
+ ' \u6CE8\u610F\uFF1A**\u4E0D\u989D\u5916\u53E0\u6D41\u52A8\u7EB9\u7406**\u3002\u5148\u524D\u8BEF\u628A"\u8FDB\u884C\u4E2D\u52A0\u6D41\u5149"\u5F53\u4F5C P1 \u7684\u4E00\u90E8\u5206\u5B9E\u73B0\uFF0C',
173
+ " \u4F46\u90A3\u4E0D\u5728 P1 \u5B9A\u4E49\u5185\uFF08P1 \u539F\u6587\uFF1A\u6682\u505C = \u539F\u6761 + \u9759\u6B62\uFF0C\u4E0D\u52A0\u4EFB\u4F55\u7EB9\u7406\uFF09\uFF0C\u5DF2\u79FB\u9664\u3002",
174
+ " \u53EA\u4FDD\u7559\u4E0B\u9762\u8FD9\u884C\u9632\u5FA1\uFF1A\u4E07\u4E00\u52A8\u753B\u56E0\u6545\u6B8B\u7559\uFF0C\u6682\u505C\u65F6\u5FC5\u987B\u505C\u4F4F\u3002",
175
+ " \uFF08\u51E0\u4F55\u4E0E\u4FDD\u5E95\u5BBD\u5EA6\u6CBF\u7528 .ss-dock-bar-fill \u7684\u516C\u5171\u89C4\u5219\uFF0C\u6545\u6682\u505C\u524D\u540E\u957F\u5EA6\u4E00\u81F4\u3002\uFF09 */",
176
+ ".ss-dock-row.ss-paused .ss-dock-bar-fill {",
177
+ " animation: none;",
178
+ "}",
179
+ "@media (prefers-reduced-motion: reduce) {",
180
+ " .ss-dock-row:not(.ss-paused) .ss-dock-bar-fill { animation: none; background: var(--dsw-alias-brand-primary); }",
181
+ "}",
182
+ ".ss-dock-row.ss-paused .ss-dock-row-countdown { color: var(--dsw-alias-label-tertiary); }",
183
+ ".ss-dock-row.ss-paused .ss-dock-row-time,",
184
+ ".ss-dock-row.ss-paused .ss-dock-row-prompt { color: var(--dsw-alias-label-secondary); }",
185
+ ".ss-dock-action.ss-paused-active { color: var(--dsw-alias-state-success-primary); }",
136
186
  "/* \u5206\u9694\u7EBF\uFF1Aabsolute \u8DE8\u6574\u4E2A bar \u753B N-1 \u6761\u7B49\u6BD4\u7AD6\u7EBF\uFF0C\u6E32\u67D3\u5728 fill \u4E4B\u524D\uFF08fill \u7528 z-index:1 \u76D6\u4F4F\u300C\u5DF2\u586B\u5145\u6BB5\u300D\u4E0A\u7684\u523B\u5EA6\uFF09\u3002 */",
137
187
  ".ss-dock-bar-divider {",
138
188
  " position: absolute; inset: 0; pointer-events: none;",
@@ -152,6 +202,29 @@ var COMPONENTS = [
152
202
  ".ss-dock-steer-err {",
153
203
  " color: var(--dsw-alias-state-warn-secondary); font-size: 12px; line-height: 16px;",
154
204
  "}",
205
+ "/*",
206
+ " * \u6295\u9012\u672A\u786E\u8BA4\u63D0\u793A\uFF1A\u6761\u76EE\u88AB\u5BBF\u4E3B\u4FDD\u7559\uFF08\u672A\u5199 dispatch\uFF09\uFF0C\u884C\u4ECD\u5728\u53F0\u4E0A\u3002",
207
+ ' * \u4E0E\u666E\u901A\u9519\u8BEF\uFF08\u7EAF\u6587\u5B57\uFF09\u533A\u5206\uFF1A\u5B83\u4E0D\u662F\u4E00\u4E2A"\u5931\u8D25"\uFF0C\u800C\u662F"\u7ED3\u679C\u672A\u77E5\u4E14\u53EF\u633D\u56DE"\uFF0C',
208
+ " * \u8BED\u6C14\u5E94\u662F\u63D0\u793A\u800C\u975E\u62A5\u9519\uFF0C\u6545\u7ED9\u6D45\u5E95 + \u8FB9\u6846 + \u53EF\u70B9\u7684\u91CD\u8BD5\u3002",
209
+ " */",
210
+ ".ss-dock-steer-warn {",
211
+ " display: flex; align-items: center; gap: 8px; flex-wrap: wrap;",
212
+ " margin-top: 4px; padding: 4px 8px; border-radius: 6px;",
213
+ " font-size: 12px; line-height: 16px;",
214
+ " color: var(--dsw-alias-state-warn-secondary);",
215
+ " background: color-mix(in srgb, var(--dsw-alias-state-warn-secondary) 12%, transparent);",
216
+ " border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-secondary) 32%, transparent);",
217
+ "}",
218
+ ".ss-dock-steer-retry {",
219
+ " margin-left: auto; padding: 1px 8px; border-radius: 5px; cursor: pointer;",
220
+ " font: inherit; font-size: 12px;",
221
+ " color: var(--dsw-alias-state-warn-secondary);",
222
+ " background: color-mix(in srgb, var(--dsw-alias-state-warn-secondary) 18%, transparent);",
223
+ " border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-secondary) 38%, transparent);",
224
+ "}",
225
+ ".ss-dock-steer-retry:hover {",
226
+ " background: color-mix(in srgb, var(--dsw-alias-state-warn-secondary) 28%, transparent);",
227
+ "}",
155
228
  "/* \u884C\u5185\u7F16\u8F91\uFF08QueueDock .editor \u540C\u6B3E\u8F93\u5165\u6846\uFF09\u3002 */",
156
229
  ".ss-dock-edit-input {",
157
230
  " box-sizing: border-box; flex: auto; min-width: 0; height: 28px; padding: 0 8px;",
@@ -170,23 +243,6 @@ var COMPONENTS = [
170
243
  " flex-basis: 100%; color: var(--dsw-alias-state-error-secondary); font-size: 12px; line-height: 16px;",
171
244
  "}",
172
245
  ".ss-dock-editing { flex-wrap: wrap; }",
173
- ".ss-toast-host {",
174
- " position: fixed; right: 16px; bottom: 96px; z-index: 300;",
175
- " display: flex; flex-direction: column; gap: 8px; pointer-events: none;",
176
- "}",
177
- ".ss-toast {",
178
- " pointer-events: auto; max-width: min(360px, calc(100vw - 32px));",
179
- " display: flex; align-items: center; gap: 8px;",
180
- " padding: 9px 12px; border-radius: 10px;",
181
- " background: var(--dsw-specific-menu); color: var(--dsw-alias-label-primary);",
182
- " border: 1px solid var(--dsw-alias-line-primary);",
183
- " box-shadow: 0 6px 20px rgba(0, 0, 0, 0.18);",
184
- " font-size: 13px; line-height: 18px;",
185
- " animation: ss-toast-in 180ms var(--ds-ease-out);",
186
- "}",
187
- ".ss-toast-icon { color: var(--dsw-alias-brand-primary); flex: none; }",
188
- ".ss-toast-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }",
189
- "@keyframes ss-toast-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }",
190
246
  "",
191
247
  "/* ==================== \u9762\u677F ==================== */",
192
248
  "/* \u5BF9\u9F50\u5B98\u65B9 popover panel\uFF1Az-index 100\u3001border-inverted\u3001radius 12\u3001\u5B57\u53F7 12\u3001secondary \u6587\u5B57 */",
@@ -253,23 +309,22 @@ var COMPONENTS = [
253
309
  ".ss-tasklist-head { margin-top: 10px; }",
254
310
  "",
255
311
  "/* ==================== \u8868\u5355\u5B57\u6BB5 ==================== */",
256
- "/* \u5BF9\u9F50\u5B98\u65B9 fields.module.css\uFF1Acolumn \u5E03\u5C40\u3001label \u5728\u4E0A 13px/500\u3001\u5B57\u6BB5\u95F4 border-top \u5206\u9694 */",
312
+ "/* \u5BF9\u9F50\u5B98\u65B9 fields.module.css\uFF1Acolumn \u5E03\u5C40\u3001label \u5728\u4E0A 13px/500\uFF0C\u5B57\u6BB5\u95F4\u65E0\u5206\u9694\u7EBF */",
257
313
  ".ss-field {",
258
314
  " display: flex; flex-direction: column; gap: 6px; padding: 12px 0;",
259
315
  "}",
260
- ".ss-field + .ss-field { border-top: 1px solid var(--dsw-alias-border-l2); }",
261
316
  ".ss-input {",
262
- " height: 34px; padding: 0 12px;",
263
- " border: 1px solid var(--dsw-alias-border-l2); border-radius: 8px;",
317
+ " min-height: 36px; padding: 0 12px;",
318
+ " border: .5px solid var(--dsw-alias-border-l4); border-radius: var(--dsw-radius-md);",
264
319
  " background: var(--dsw-alias-bg-layer-3); color: var(--dsw-alias-label-primary);",
265
- " font-size: 13px; line-height: 1.5; font-family: var(--dsw-font-family);",
320
+ " font: inherit; font-size: 13px; line-height: 1.5;",
266
321
  " flex: 1; min-width: 0; width: 100%; box-sizing: border-box;",
267
322
  "}",
268
323
  ".ss-input:focus-visible {",
269
- " border-color: var(--dsw-alias-brand-primary); outline: none;",
324
+ " outline: none; border-color: var(--dsw-alias-state-business-primary);",
270
325
  "}",
271
326
  ".ss-input:disabled { color: var(--dsw-alias-label-tertiary); cursor: default; }",
272
- ".ss-input.ss-inputInvalid { border-color: var(--dsw-alias-label-error); }",
327
+ ".ss-input.ss-inputInvalid { border-color: var(--dsw-alias-state-error-primary); }",
273
328
  "",
274
329
  "/* ==================== \u4EFB\u52A1\u5217\u8868 ==================== */",
275
330
  ".ss-tasks { max-height: 160px; overflow-y: auto; margin-bottom: 8px; }",
@@ -362,46 +417,156 @@ var COMPONENTS = [
362
417
  "/* \u7D2B\u4E3A\u5B9A\u65F6\u4E13\u5C5E\uFF08\u6D45\u6DF1\u901A\u7528\uFF0C\u5BF9\u767D/\u6DF1\u5E95\u5BF9\u6BD4\u5747 \u22653:1\uFF09\uFF1Burgent/overdue \u590D\u7528\u5BBF\u4E3B warn/error \u522B\u540D\u3002 */",
363
418
  ".ss-presence { display: inline-flex; flex: none; color: #8b5cf6; }",
364
419
  ".ss-presence-beside { margin-left: 4px; }",
420
+ "",
421
+ "/* \u2500\u2500 \u65E7\u7248\u70B9\u9635\u65F6\u949F\uFF08classic\uFF09 \u2500\u2500 */",
365
422
  ".ss-presence rect { fill: currentColor; }",
366
423
  ".ss-presence .ss-presence-ring { opacity: 0.8; animation: ss-presence-breathe 2.4s var(--ds-ease-in-out, ease-in-out) infinite; }",
367
424
  ".ss-presence .ss-presence-hand { opacity: 1; }",
368
- '.ss-presence[data-state="urgent"] { color: var(--dsw-alias-state-warn-secondary); }',
369
425
  '.ss-presence[data-state="urgent"] .ss-presence-ring { animation-name: ss-presence-pulse; animation-duration: 0.9s; }',
370
- '.ss-presence[data-state="overdue"] { color: var(--dsw-alias-state-error-primary); }',
371
426
  '.ss-presence[data-state="overdue"] .ss-presence-ring { animation: none; }',
427
+ "",
428
+ "/* \u65B0\u7248\u63CF\u8FB9\u65F6\u949F\uFF08modern\uFF09\u2014 \u5BF9\u9F50 DSH \u5B98\u65B9 spinner \u6837\u5F0F \u2500\u2500 */",
429
+ "/* \u53CC\u73AF\uFF1Atrack \u6052\u5B9A\u4E3A\u5E95\uFF08\u7ED9\u51FA\u300C\u603B\u7A97\u53E3\u300D\u7684\u89C6\u89C9\u53C2\u7167\uFF09\uFF0Cprog \u662F\u4ECE 12 \u70B9\u8D77\u7684\u8FDB\u5EA6\u5F27\u3002",
430
+ " \u65E0\u4ECE\u7B97\u8FDB\u5EA6\u65F6 JS \u628A prog \u7F6E\u4E3A display:none \u2014\u2014 \u6B64\u65F6\u89C6\u89C9\u4E0E\u6539\u9020\u524D\u7684\u5355\u73AF\u5B8C\u5168\u4E00\u81F4\u3002 */",
431
+ ".ss-presence .ss-clock-track {",
432
+ " fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round;",
433
+ " opacity: 0.25; animation: ss-clock-breathe 2.4s var(--ds-ease-in-out, ease-in-out) infinite;",
434
+ "}",
435
+ ".ss-presence .ss-clock-prog {",
436
+ " fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round;",
437
+ " opacity: 1; transition: stroke-dashoffset 0.5s var(--ds-ease-in-out, ease-in-out);",
438
+ "}",
439
+ ".ss-presence .ss-clock-hand { stroke: currentColor; stroke-width: 2; stroke-linecap: round; }",
440
+ ".ss-presence .ss-clock-hand-h { opacity: 1; }",
441
+ ".ss-presence .ss-clock-hand-m { opacity: 0.85; }",
442
+ "/* urgent \u53EA\u8109\u51B2\u5E95\u73AF\uFF1A\u8FDB\u5EA6\u5F27\u627F\u8F7D\u786E\u5B9A\u4FE1\u606F\uFF0C\u8DDF\u7740\u95EA\u4F1A\u8BA9\u6BD4\u4F8B\u4E0D\u53EF\u8BFB\u3002 */",
443
+ '.ss-presence[data-state="urgent"] .ss-clock-track { animation-name: ss-clock-pulse; animation-duration: 0.9s; }',
444
+ '.ss-presence[data-state="overdue"] .ss-clock-track { animation: none; opacity: 1; }',
445
+ "",
446
+ "/* \u2500\u2500 \u4E09\u6001\u989C\u8272 \u2500\u2500 */",
447
+ '.ss-presence[data-state="urgent"] { color: var(--dsw-alias-state-warn-secondary); }',
448
+ '.ss-presence[data-state="overdue"] { color: var(--dsw-alias-state-error-primary); }',
449
+ "",
450
+ "/* \u2500\u2500 \u52A8\u753B\u5173\u952E\u5E27 \u2500\u2500 */",
372
451
  "@keyframes ss-presence-breathe { 0%, 100% { opacity: 0.65; } 50% { opacity: 1; } }",
373
452
  "@keyframes ss-presence-pulse { 0%, 100% { opacity: 0.5; } 50% { opacity: 1; } }",
374
- "@media (prefers-reduced-motion: reduce) { .ss-presence .ss-presence-ring { animation: none; } }",
453
+ "@keyframes ss-clock-breathe { 0%, 100% { opacity: 0.65; } 50% { opacity: 1; } }",
454
+ "@keyframes ss-clock-pulse { 0%, 100% { opacity: 0.5; } 50% { opacity: 1; } }",
455
+ "@media (prefers-reduced-motion: reduce) {",
456
+ " .ss-presence .ss-presence-ring { animation: none; }",
457
+ " .ss-presence .ss-clock-track { animation: none; }",
458
+ ' /* \u51CF\u5C11\u52A8\u6548\uFF1A\u8FDB\u5EA6\u5F27\u7684\u4F4D\u79FB\u8FC7\u6E21\u4E5F\u4E00\u5E76\u505C\uFF0C\u907F\u514D"\u8FDB\u5EA6\u81EA\u5DF1\u5728\u722C"\u7684\u89C2\u611F\u3002 */',
459
+ " .ss-presence .ss-clock-prog { transition: none; }",
460
+ "}",
375
461
  "",
376
- "/* ==================== \u8BBE\u7F6E\u9875\uFF08\u5B9A\u65F6\u63D0\u9192\u5361\u7247\uFF09 ==================== */",
377
- "/* \u89C6\u89C9\u5BF9\u9F50\u5B98\u65B9 PluginCard\uFF08dsh-client-ui-settings-plugins \u79C1\u6709\u7EC4\u4EF6\uFF0C\u540C\u6784\u81EA\u5B9E\u73B0\uFF0C",
378
- " \u53C2\u8003 dsh-wakatime \u540C\u6B3E\u505A\u6CD5\uFF09\uFF1A<li> \u5916\u6846\u3001header \u6574\u5361\u6309\u94AE\u3001chevron\u3001\u6298\u53E0 body\u3001",
379
- " footer \u653E\u5F03/\u4FDD\u5B58\u3002\u7C7B\u540D\u7EDF\u4E00 ss-card- \u524D\u7F00\uFF0C\u907F\u514D\u4E0E\u9762\u677F\uFF08ss-footer/ss-field-*\uFF09\u51B2\u7A81\u3002 */",
380
- ".ss-card {",
381
- " border: 1px solid var(--dsw-alias-border-l2);",
382
- " background: var(--dsw-alias-bg-layer-3);",
383
- " border-radius: 12px; list-style: none;",
384
- " transition: border-color .16s, background .16s;",
385
- "}",
386
- ".ss-card:hover { border-color: var(--dsw-alias-label-dimmed); }",
387
- ".ss-cardOpen { background: var(--dsw-alias-bg-layer-2); border-color: var(--dsw-alias-label-dimmed); }",
388
- ".ss-card-header {",
389
- " appearance: none; width: 100%; font: inherit; color: inherit; text-align: left;",
390
- " cursor: pointer; background: none; border: 0; border-radius: 12px;",
391
- " align-items: center; gap: 12px; padding: 14px 16px; display: flex;",
392
- "}",
393
- ".ss-card-header:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: -2px; }",
394
- ".ss-card-headText { flex-direction: column; flex: 1; gap: 4px; min-width: 0; display: flex; }",
395
- ".ss-card-name { color: var(--dsw-alias-label-primary); font-size: 15px; font-weight: 600; line-height: 1.4; }",
396
- ".ss-card-description { color: var(--dsw-alias-label-tertiary); font-size: 13px; line-height: 1.5; }",
397
- ".ss-card-chevron { color: var(--dsw-alias-label-tertiary); flex: none; transition: transform .16s; }",
398
- ".ss-card-chevronOpen { transform: rotate(180deg); }",
399
- ".ss-card-body { border-top: 1px solid var(--dsw-alias-border-l2); margin: 0 16px; padding-bottom: 8px; }",
400
- ".ss-card-readOnly { color: var(--dsw-alias-label-tertiary); margin: 12px 0 0; font-size: 12px; line-height: 1.5; }",
401
- ".ss-card-pending {",
402
- " white-space: nowrap; background: var(--dsw-alias-bg-module-platform);",
403
- " color: var(--dsw-alias-label-secondary); border-radius: 999px; flex: none;",
404
- " padding: 1px 8px; font-size: 11px; font-weight: 500; line-height: 17px;",
462
+ "/* ==================== \u60AC\u6D6E\u5361\u7247\u72B6\u6001\u884C\u589E\u8865\uFF08issue #4\uFF09 ==================== */",
463
+ "/* \u4E0E\u5BBF\u4E3B .hoverStatus \u884C\u4E25\u683C\u540C\u6784\u3002\u5BBF\u4E3B StateDot \u5B9E\u6D4B\u7ED3\u6784\uFF08dsh-client-ui-primitives",
464
+ " \u7684 ._dot_* \u8FD0\u884C\u65F6\u6837\u5F0F\uFF0C10\xD710 relative + ::before 10px/inset:0 + ::after 6px/inset:2px\uFF0C",
465
+ " \u4E24\u5C42\u540C\u8272 \u2192 \u89C6\u89C9\u76F4\u5F84\u7EA6 8px\uFF09\uFF1A\u672C\u63D2\u4EF6\u6309\u4E0B\u8FF0\u540C\u6837\u7684\u53CC\u5C42\u5199\u6CD5\u81EA\u7ED8\uFF0C\u907F\u514D\u590D\u7528\u5176\u6784\u5EFA\u671F hash",
466
+ " \u7C7B\u540D\uFF08_dot_xxxxxx_n \u4E0D\u7A33\u5B9A\uFF0C\u5BBF\u4E3B\u5347\u7EA7\u4F1A\u9759\u9ED8\u5931\u6548\uFF09\u3002",
467
+ " \u989C\u8272\u8DDF\u968F\u5BBF\u4E3B\u8BED\u4E49\u8272\u677F\uFF0C\u4E0D\u5F15\u5165\u63D2\u4EF6\u4E13\u5C5E\u8272\u2014\u2014\u6587\u6848\u5DF2\u8BF4\u660E\u662F\u5B9A\u65F6\u63D0\u9192\uFF0C\u70B9\u4E0D\u5FC5\u518D\u627F\u62C5",
468
+ " \u300C\u533A\u5206\u6765\u6E90\u300D\u7684\u804C\u8D23\uFF1B\u6DF7\u5165\u7B2C\u4E94\u79CD\u989C\u8272\u53CD\u800C\u4E0E\u5BBF\u4E3B warning \u8BED\u4E49\u649E\u8F66\u3002",
469
+ "",
470
+ " \u26A0\uFE0F \u5DF2\u77E5\u9650\u5236\uFF08\u6D45\u8272\u9002\u914D\u5C1A\u672A\u5904\u7406\uFF09\uFF1A\u4EE5\u4E0B\u8272\u503C\u662F\u5728**\u5F53\u524D\u6DF1\u8272\u4E3B\u9898**\u4E0B\u4ECE\u5BBF\u4E3B",
471
+ " \u5B9E\u6D4B\u5F97\u5230\u7684\u8FD0\u884C\u65F6\u503C\uFF0C\u5BBF\u4E3B\u81EA\u8EAB\u5F15\u7528 --dsw-alias-* token\uFF0C\u4F1A\u968F\u4E3B\u9898\u53D8\u5316\uFF0C",
472
+ " \u800C\u6B64\u5904\u662F\u786C\u7F16\u7801\u5E38\u91CF\u3002\u56E0\u6B64\u5F53\u524D\u4EC5\u5728\u6DF1\u8272\u4E3B\u9898\u4E0B\u4E0E\u5BBF\u4E3B\u4E00\u81F4\uFF1B\u5207\u6362\u5230\u6D45\u8272\u4E3B\u9898/",
473
+ " \u5176\u4ED6\u914D\u8272\u65B9\u6848\u65F6\uFF0C\u672C\u884C\u4E0D\u4F1A\u8DDF\u968F\uFF0C\u53EF\u80FD\u4E0E\u8BE5\u5361\u7247\u5176\u4F59\u5185\u5BB9\u4E0D\u540C\u6B65\u3002",
474
+ " \u4FEE\u6CD5\uFF1A\u5B9E\u6D4B\u6D45\u8272\u4E3B\u9898\u4E0B\u8BE5\u5361\u7247\u7684\u5B9E\u9645\u5E95\u8272\u540E\uFF0C\u6539\u7528\u5BF9\u5E94 token\uFF08\u5F85\u529E\uFF09\u3002 */",
475
+ ".ss-hover-status {",
476
+ " display: flex; align-items: center; gap: 8px;",
477
+ " color: #adb2b8; font-size: 12px; line-height: 20px;",
478
+ "}",
479
+ "/* \u72B6\u6001\u70B9\uFF1A\u5BBF\u4E3B\u540C\u6B3E\u53CC\u5C42\u7ED3\u6784\u3002\u5173\u952E\u2014\u2014::before \u662F 10% \u900F\u660E\u5EA6\u7684**\u5149\u6655**\uFF0C",
480
+ " \u4E0D\u662F\u5B9E\u5FC3\u5916\u73AF\uFF1B::after \u624D\u662F 6px \u5B9E\u5FC3\u6838\u5FC3\u3002\u82E5 ::before \u4E0D\u8BBE opacity\uFF0C",
481
+ " \u5B83\u4F1A\u76D6\u4F4F\u6838\u5FC3\u5E76\u6E32\u67D3\u6210 10px \u5B9E\u5FC3\u5706\uFF08\u6BD4\u5BBF\u4E3B\u660E\u663E\u504F\u5927\u504F\u5B9E\uFF09\u3002 */",
482
+ ".ss-hover-status-dot {",
483
+ " position: relative; display: block; flex: none;",
484
+ " width: 10px; height: 10px;",
485
+ " color: #adb2b8;",
486
+ "}",
487
+ ".ss-hover-status-dot::before,",
488
+ ".ss-hover-status-dot::after {",
489
+ ' content: ""; position: absolute; border-radius: 50%; background: currentColor;',
490
+ "}",
491
+ ".ss-hover-status-dot::before { inset: 0; opacity: 0.1; }",
492
+ ".ss-hover-status-dot::after { inset: 2px; }",
493
+ "/* \u8BED\u4E49\u6620\u5C04\uFF08\u5BF9\u9F50\u5BBF\u4E3B done/ongoing/warning/error \u56DB\u6001\u8272\u503C\uFF09\uFF1A",
494
+ " scheduled \u2192 ongoing \u7070\uFF08\u4E2D\u6027\uFF1A\u5DF2\u6392\u671F\uFF0C\u65E0\u7D27\u8FEB\u6027\uFF09",
495
+ " urgent \u2192 warning \u7425\u73C0\uFF08\u22645min \u5373\u5C06\u89E6\u53D1\uFF09",
496
+ " overdue \u2192 error \u7EA2\uFF08\u5DF2\u5230\u671F\uFF0C\u7B49\u5F85\u4F1A\u8BDD\u7A7A\u95F2\u53D1\u9001\uFF09 */",
497
+ '.ss-hover-status[data-state="urgent"] .ss-hover-status-dot { color: #f59e0b; }',
498
+ '.ss-hover-status[data-state="overdue"] .ss-hover-status-dot { color: #f25a5a; }',
499
+ "",
500
+ "/* ==================== \u8BBE\u7F6E\u9875\uFF08\u5B9A\u65F6\u63D0\u9192\u8868\u5355\uFF09 ==================== */",
501
+ "/* \u89C6\u89C9\u5BF9\u9F50\u5B98\u65B9 SettingsForm\uFF08dsh-client-ui-primitives\uFF09\uFF1A\u88F8\u8868\u5355\uFF0C\u65E0\u5361\u7247\u5BB9\u5668\uFF0C",
502
+ " \u5B57\u6BB5\u6309 section \u5206\u7EC4\uFF0C\u6BCF\u7EC4\u6709\u6807\u9898\uFF0C\u5E95\u90E8\u4FDD\u5B58\u6309\u94AE\u3002\u7C7B\u540D\u7EDF\u4E00 ss- \u524D\u7F00\u3002 */",
503
+ ".ss-settings-form {",
504
+ " display: flex; flex-direction: column;",
505
+ "}",
506
+ "/* Section \u5206\u7EC4\uFF08\u5BF9\u9F50\u5B98\u65B9 AZSXYW_section \u7ED3\u6784\uFF09 */",
507
+ ".ss-section {",
508
+ " padding: 16px 0;",
509
+ "}",
510
+ ".ss-section-heading {",
511
+ " margin: 0; font-size: 13px; font-weight: 600; line-height: 1.5;",
512
+ " color: var(--dsw-alias-label-primary);",
513
+ "}",
514
+ ".ss-section-fields {",
515
+ " display: flex; flex-direction: column;",
516
+ "}",
517
+ /* 紧凑字段并排(对齐官方 hF0LTq_limits 网格:两等宽列、间距 16px) */
518
+ ".ss-section-fieldsGrid {",
519
+ " display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px;",
520
+ "}",
521
+ /* 帮助按钮(对齐官方 _helpButton_:24×24、radius 8px、12px 圆圈问号图标) */
522
+ ".ss-help-btn {",
523
+ " width: 24px; height: 24px; padding: 0; flex: none;",
524
+ " display: inline-flex; align-items: center; justify-content: center;",
525
+ " background: none; border: none; border-radius: 8px; cursor: pointer;",
526
+ " color: var(--dsw-alias-label-tertiary);",
527
+ "}",
528
+ ".ss-help-btn:hover, .ss-help-btnOpen { color: var(--dsw-alias-label-secondary); }",
529
+ ".ss-help-btn:focus-visible {",
530
+ " outline: 2px solid var(--dsw-alias-state-business-primary); outline-offset: -1px;",
531
+ "}",
532
+ /* 展开后的说明区(对齐官方 _help_:12px / 1.6 行高、顶部 10px、次级文字色) */
533
+ ".ss-help {",
534
+ " margin: 0; padding: 10px 0 0; font-size: 12px; line-height: 1.6;",
535
+ " color: var(--dsw-alias-label-secondary);",
536
+ "}",
537
+ ".ss-help p { margin: 0; }",
538
+ /* Toggle 行(对齐官方子智能体插件的开关行:label 左 + switch 右) */
539
+ ".ss-toggle-row {",
540
+ " display: flex; align-items: center; justify-content: space-between;",
541
+ " gap: 16px;",
542
+ "}",
543
+ ".ss-toggle-label {",
544
+ " flex: 1; min-width: 0; font-size: 13px; font-weight: 500; line-height: 1.5;",
545
+ " color: var(--dsw-alias-label-primary);",
546
+ "}",
547
+ ".ss-toggle-switch {",
548
+ " position: relative; width: 36px; height: 20px; flex: none;",
549
+ " background: var(--dsw-alias-bg-module-platform); border-radius: 999px;",
550
+ " cursor: pointer; transition: background var(--ds-transition-duration-fast) var(--ds-ease-in-out);",
551
+ " border: none; padding: 0;",
552
+ "}",
553
+ '.ss-toggle-switch[aria-checked="true"] { background: var(--dsw-alias-state-business-primary); }',
554
+ ".ss-toggle-switch::after {",
555
+ ' content: ""; position: absolute; top: 2px; left: 2px;',
556
+ " width: 16px; height: 16px; border-radius: 999px;",
557
+ " background: #fff; transition: transform var(--ds-transition-duration-fast) var(--ds-ease-in-out);",
558
+ "}",
559
+ '.ss-toggle-switch[aria-checked="true"]::after { transform: translateX(16px); }',
560
+ ".ss-toggle-switch:disabled { opacity: 0.4; cursor: default; }",
561
+ ".ss-toggle-switch:focus-visible {",
562
+ " outline: 2px solid var(--dsw-alias-state-business-primary); outline-offset: 2px;",
563
+ "}",
564
+ ".ss-toggle-description {",
565
+ " margin: 0; padding: 0 0 12px; font-size: 12px; line-height: 1.6;",
566
+ " color: var(--dsw-alias-label-secondary);",
567
+ "}",
568
+ ".ss-label-group {",
569
+ " display: flex; align-items: center; gap: 4px; flex: 1; min-width: 0;",
405
570
  "}",
406
571
  ".ss-card-fieldHead { align-items: center; gap: 8px; display: flex; }",
407
572
  ".ss-card-label {",
@@ -420,11 +585,21 @@ var COMPONENTS = [
420
585
  "}",
421
586
  ".ss-card-reset:hover:not(:disabled) { color: var(--dsw-alias-label-primary); }",
422
587
  ".ss-card-reset:disabled { cursor: default; }",
423
- ".ss-card-invalid { color: var(--dsw-alias-label-error); margin: 0; font-size: 12px; line-height: 1.5; }",
588
+ ".ss-card-invalid { color: var(--dsw-alias-state-error-primary); margin: 0; font-size: 12px; line-height: 1.5; }",
589
+ "/*",
590
+ " * \u9009\u9879\u98CE\u9669\u63D0\u793A\uFF08steer \u53EF\u80FD\u88AB\u56DE\u5408\u542F\u52A8\u541E\u6389 / discard \u4F1A\u8BA9\u9759\u9ED8\u4E22\u5931\u590D\u6D3B\uFF09\u3002",
591
+ ' * \u5E38\u9A7B\u663E\u793A\u800C\u975E tooltip\uFF1A\u8FD9\u51E0\u9879\u914D\u7F6E\u7684\u540E\u679C\u662F"\u9759\u9ED8\u5931\u8D25"\uFF0C\u85CF\u5728\u60AC\u6D6E\u63D0\u793A\u91CC\u7B49\u4E8E\u6CA1\u6709\u3002',
592
+ " */",
593
+ ".ss-card-risk {",
594
+ " margin: 6px 0 0; padding: 6px 9px; border-radius: 6px;",
595
+ " font-size: 12px; line-height: 1.55;",
596
+ " color: var(--dsw-alias-state-warn-secondary);",
597
+ " background: color-mix(in srgb, var(--dsw-alias-state-warn-secondary) 12%, transparent);",
598
+ " border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-secondary) 30%, transparent);",
599
+ "}",
424
600
  ".ss-card-footer {",
425
- " border-top: 1px solid var(--dsw-alias-border-l2);",
426
601
  " justify-content: flex-end; align-items: center; gap: 8px;",
427
- " padding: 12px 0 4px; display: flex;",
602
+ " padding-top: 16px; display: flex;",
428
603
  "}",
429
604
  ".ss-card-failed {",
430
605
  " min-width: 0; color: var(--dsw-alias-label-error); flex: 1; margin: 0;",
@@ -432,7 +607,7 @@ var COMPONENTS = [
432
607
  "}",
433
608
  ".ss-card-discard, .ss-card-save {",
434
609
  " appearance: none; font: inherit; cursor: pointer;",
435
- " border: 1px solid transparent; border-radius: 8px;",
610
+ " border: 1px solid transparent; border-radius: var(--dsw-radius-md);",
436
611
  " padding: 5px 14px; font-size: 13px; line-height: 1.5;",
437
612
  "}",
438
613
  ".ss-card-discard { border-color: var(--dsw-alias-border-l2); color: var(--dsw-alias-label-secondary); background: none; }",
@@ -441,7 +616,7 @@ var COMPONENTS = [
441
616
  ".ss-card-save:hover:not(:disabled) { background: var(--dsw-alias-button-primary-hover); }",
442
617
  ".ss-card-discard:disabled, .ss-card-save:disabled { opacity: 0.4; cursor: default; }",
443
618
  ".ss-card-discard:focus-visible, .ss-card-save:focus-visible {",
444
- " outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: 1px;",
619
+ " outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary)); outline-offset: 1px;",
445
620
  "}"
446
621
  ].join("\n");
447
622
  function injectStyles() {
@@ -561,6 +736,16 @@ var zh = {
561
736
  steerAlreadySent: "\u5DF2\u63D2\u8BDD",
562
737
  steerFailed: "\u63D2\u8BDD\u5931\u8D25\uFF1A{message}",
563
738
  steerUnsupportedKind: "\u5468\u671F\u63D0\u9192\u6682\u4E0D\u652F\u6301\u63D2\u8BDD",
739
+ /** 投递未确认(宿主保留条目,可重试) */
740
+ steerUnconfirmed: "\u6295\u9012\u672A\u786E\u8BA4\uFF0C\u63D0\u9192\u5DF2\u4FDD\u7559\uFF0C\u53EF\u91CD\u8BD5",
741
+ steerRetry: "\u91CD\u8BD5",
742
+ /** 暂停 / 恢复(仅 after;原地冻结进度条) */
743
+ pauseTask: "\u6682\u505C\u63D0\u9192",
744
+ resumeTask: "\u6062\u590D\u63D0\u9192",
745
+ pausedLabel: "\u5DF2\u6682\u505C",
746
+ pauseFailed: "\u6682\u505C\u5931\u8D25\uFF1A{message}",
747
+ resumeFailed: "\u6062\u590D\u5931\u8D25\uFF1A{message}",
748
+ pauseUnsupportedKind: "\u4EC5\u652F\u6301\u6682\u505C\u300C\u518D\u7B49 N \u5206\u949F\u300D\u7C7B\u63D0\u9192",
564
749
  /** dock 折叠头计数(QueueDock「N 条排队消息」样式) */
565
750
  panelCount: "{n} \u6761\u5B9A\u65F6\u63D0\u9192",
566
751
  /** 精准倒计时(dock 行 + 折叠头) */
@@ -587,6 +772,13 @@ var zh = {
587
772
  presenceOverdueAria: "\u6709 {n} \u6761\u5B9A\u65F6\u63D0\u9192\u5DF2\u5230\u671F\uFF0C\u7B49\u5F85\u53D1\u9001",
588
773
  presenceTooltip: "\u4E0B\u6B21 {time} \xB7 {n} \u6761\u4EFB\u52A1",
589
774
  presenceOverdueTooltip: "\u5DF2\u5230\u671F \xB7 {n} \u6761\u4EFB\u52A1\uFF08\u7B49\u5F85\u4F1A\u8BDD\u7A7A\u95F2\u53D1\u9001\uFF09",
775
+ /** 全部任务都处于暂停:没有排定的触发时刻,故不显示"下次"或"已到期"。 */
776
+ presencePausedAria: "\u6709 {n} \u6761\u5B9A\u65F6\u63D0\u9192\u5DF2\u6682\u505C",
777
+ presencePausedTooltip: "\u5DF2\u6682\u505C \xB7 {n} \u6761\u4EFB\u52A1",
778
+ /** 悬浮卡片状态区追加行(与宿主 hoverStatus 同构,纯追加不改写既有状态) */
779
+ hoverScheduleStatus: "\u6709 {n} \u6761\u5B9A\u65F6\u63D0\u9192\uFF0C\u4E0B\u6B21 {time}",
780
+ hoverScheduleOverdue: "\u6709 {n} \u6761\u5B9A\u65F6\u63D0\u9192\u5DF2\u5230\u671F\uFF0C\u7B49\u5F85\u53D1\u9001",
781
+ hoverSchedulePaused: "\u6709 {n} \u6761\u5B9A\u65F6\u63D0\u9192\u5DF2\u6682\u505C",
590
782
  relMinutes: "{m} \u5206\u540E",
591
783
  relHours: "{h} \u5C0F\u65F6\u540E",
592
784
  relTomorrow: "\u660E\u5929 {time}",
@@ -623,6 +815,15 @@ var en = {
623
815
  steerAlreadySent: "Steered",
624
816
  steerFailed: "Steer failed: {message}",
625
817
  steerUnsupportedKind: "Recurring reminders can't be steered",
818
+ /** Delivery unconfirmed (host kept the item; retryable) */
819
+ steerUnconfirmed: "Delivery unconfirmed \u2014 reminder kept, you can retry",
820
+ steerRetry: "Retry",
821
+ pauseTask: "Pause reminder",
822
+ resumeTask: "Resume reminder",
823
+ pausedLabel: "Paused",
824
+ pauseFailed: "Pause failed: {message}",
825
+ resumeFailed: "Resume failed: {message}",
826
+ pauseUnsupportedKind: 'Only "wait N minutes" (after) reminders can be paused',
626
827
  panelCount: "{n} scheduled reminders",
627
828
  countdownLeft: "in",
628
829
  dueAnyMoment: "Sending soon",
@@ -641,6 +842,11 @@ var en = {
641
842
  presenceOverdueAria: "{n} scheduled reminder(s) due, waiting to send",
642
843
  presenceTooltip: "Next at {time} \xB7 {n} task(s)",
643
844
  presenceOverdueTooltip: "Due \xB7 {n} task(s) (sends when the session is idle)",
845
+ presencePausedAria: "{n} paused reminder(s)",
846
+ presencePausedTooltip: "Paused \xB7 {n} task(s)",
847
+ hoverScheduleStatus: "{n} scheduled reminder(s), next {time}",
848
+ hoverScheduleOverdue: "{n} scheduled reminder(s) due, waiting to send",
849
+ hoverSchedulePaused: "{n} paused reminder(s)",
644
850
  relMinutes: "in {m} min",
645
851
  relHours: "in {h} h",
646
852
  relTomorrow: "Tomorrow {time}",
@@ -860,11 +1066,11 @@ var import_jsx_runtime = require("react/jsx-runtime");
860
1066
  function scheduleStateOf(item, now) {
861
1067
  return Date.parse(item.scheduled_at) <= now ? "overdue" : "scheduled";
862
1068
  }
863
- function TaskList({ items: items2, now, deliveredIds, cancellingIds, onDelete, timeZone, t, lang }) {
864
- if (items2.length === 0) {
1069
+ function TaskList({ items, now, deliveredIds, cancellingIds, onDelete, timeZone, t, lang }) {
1070
+ if (items.length === 0) {
865
1071
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ss-empty", "data-ss-empty": "", children: t.emptyTasks });
866
1072
  }
867
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "ss-tasks", "data-ss-tasks": "", children: items2.map((item) => {
1073
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "ss-tasks", "data-ss-tasks": "", children: items.map((item) => {
868
1074
  const dotState = deliveredIds?.has(item.id) ? "delivered" : cancellingIds?.has(item.id) ? "cancelled" : scheduleStateOf(item, now);
869
1075
  const isCancelled = dotState === "cancelled";
870
1076
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: isCancelled ? "ss-task cancelled" : "ss-task", "data-ss-task": item.id, children: [
@@ -1237,12 +1443,12 @@ function useSchedules(inject2) {
1237
1443
  if (pendingSync.length === 0 || !sessionId) return;
1238
1444
  let cancelled = false;
1239
1445
  const syncAll = async () => {
1240
- const items2 = [...pendingSync];
1241
- for (const item of items2) {
1446
+ const items = [...pendingSync];
1447
+ for (const item of items) {
1242
1448
  if (cancelled) return;
1243
1449
  try {
1244
1450
  const accepted = await callCommand(sessionId, createLine(item.payload));
1245
- if (accepted && !cancelled) {
1451
+ if (accepted.matched && !cancelled) {
1246
1452
  removePending(item.clientSeq);
1247
1453
  setPendingSync((prev) => prev.filter((p) => p.clientSeq !== item.clientSeq));
1248
1454
  }
@@ -1268,7 +1474,7 @@ function useSchedules(inject2) {
1268
1474
  setBusy(true);
1269
1475
  try {
1270
1476
  const accepted = await callCommand(sessionId, createLine(inputPayload));
1271
- if (!accepted) {
1477
+ if (!accepted.matched) {
1272
1478
  appendPending(inputPayload);
1273
1479
  setPendingSync((prev) => [...prev, { clientSeq: Date.now(), createdAt: Date.now(), payload: inputPayload }]);
1274
1480
  throw new Error(CLIENT_ERR.NOT_ACCEPTED);
@@ -1457,65 +1663,79 @@ function SchedButton(props) {
1457
1663
  }
1458
1664
 
1459
1665
  // src/client/components/ScheduleDock.tsx
1460
- var import_react8 = require("react");
1461
-
1462
- // src/client/toast.tsx
1463
- var import_client = require("react-dom/client");
1464
1666
  var import_react7 = require("react");
1465
- var import_jsx_runtime4 = require("react/jsx-runtime");
1466
- var listeners = /* @__PURE__ */ new Set();
1467
- var items = [];
1468
- var nextId = 1;
1469
- function emit() {
1470
- for (const listener of listeners) listener(items);
1471
- }
1472
- function showReminderToast(text, ttlMs = 5e3) {
1473
- const id = nextId++;
1474
- const item = { id, text };
1475
- items = [...items, item];
1476
- emit();
1477
- window.setTimeout(() => {
1478
- items = items.filter((existing) => existing.id !== id);
1479
- emit();
1480
- }, ttlMs);
1481
- }
1482
- function useToasts() {
1483
- const [state, setState] = (0, import_react7.useState)(items);
1484
- (0, import_react7.useEffect)(() => {
1485
- const listener = (next) => setState(next);
1486
- listeners.add(listener);
1487
- return () => {
1488
- listeners.delete(listener);
1489
- };
1490
- }, []);
1491
- return state;
1492
- }
1493
- function ReminderToastHost() {
1494
- const toasts = useToasts();
1495
- if (toasts.length === 0) return null;
1496
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "ss-toast-host", "data-ss-toast": "", children: toasts.map((item) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ss-toast", role: "status", children: [
1497
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ss-toast-icon", "aria-hidden": "true", children: "\u23F0" }),
1498
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ss-toast-text", children: item.text })
1499
- ] }, item.id)) });
1500
- }
1501
- var mounted = false;
1502
- function mountReminderToastHost() {
1503
- if (mounted) return () => void 0;
1504
- mounted = true;
1505
- const host = document.createElement("div");
1506
- host.setAttribute("data-ss-toast-root", "");
1507
- document.body.appendChild(host);
1508
- const root = (0, import_client.createRoot)(host);
1509
- root.render(/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ReminderToastHost, {}));
1510
- return () => {
1511
- root.unmount();
1512
- host.remove();
1513
- mounted = false;
1667
+
1668
+ // src/bar-geometry.ts
1669
+ var BAR_UNIT_MS = 36e5;
1670
+ function barWindow(item, end, now, firstSeen) {
1671
+ let start;
1672
+ if (item.kind === "after") {
1673
+ const windowSec = item.window_seconds ?? item.after_seconds;
1674
+ if (windowSec !== void 0) {
1675
+ start = end - windowSec * 1e3;
1676
+ } else if (item.created_at !== void 0) {
1677
+ const parsed = Date.parse(item.created_at);
1678
+ start = Number.isNaN(parsed) ? firstSeen.get(item.id) ?? now : parsed;
1679
+ } else {
1680
+ start = firstSeen.get(item.id) ?? now;
1681
+ }
1682
+ } else if (item.kind === "every" && item.every_seconds !== void 0) {
1683
+ start = end - item.every_seconds * 1e3;
1684
+ } else if (item.created_at !== void 0) {
1685
+ const parsed = Date.parse(item.created_at);
1686
+ start = Number.isNaN(parsed) ? firstSeen.get(item.id) ?? now : parsed;
1687
+ } else {
1688
+ start = firstSeen.get(item.id) ?? now;
1689
+ }
1690
+ return { start, totalMs: Math.max(1e3, end - start) };
1691
+ }
1692
+ function ratioAt(item, at, firstSeen) {
1693
+ const end = Date.parse(item.scheduled_at);
1694
+ const { start, totalMs } = barWindow(item, end, at, firstSeen);
1695
+ const elapsedMs = Math.min(Math.max(at - start, 0), totalMs);
1696
+ return {
1697
+ totalRatio: elapsedMs / totalMs,
1698
+ count: Math.max(1, Math.ceil(totalMs / BAR_UNIT_MS))
1699
+ };
1700
+ }
1701
+ function barSegments(item, now, firstSeen) {
1702
+ return ratioAt(item, now, firstSeen);
1703
+ }
1704
+ function frozenBarSegments(item, frozenLeftMs, firstSeen, renderedAt) {
1705
+ const windowSec = item.window_seconds ?? item.after_seconds;
1706
+ if (windowSec === void 0 || windowSec <= 0) {
1707
+ const end = Date.parse(item.scheduled_at);
1708
+ const pausedAt2 = Date.parse(item.paused_at ?? "");
1709
+ const exact = Number.isNaN(pausedAt2) ? end - Math.floor(frozenLeftMs / 1e3) * 1e3 : pausedAt2;
1710
+ return ratioAt(item, Number.isNaN(exact) ? end : exact, firstSeen);
1711
+ }
1712
+ const totalMs = Math.max(1e3, windowSec * 1e3);
1713
+ let leftMs = Math.min(Math.max(frozenLeftMs, 0), totalMs);
1714
+ const pausedAt = Date.parse(item.paused_at ?? "");
1715
+ if (renderedAt !== void 0 && !Number.isNaN(pausedAt) && pausedAt > renderedAt) {
1716
+ leftMs = Math.min(leftMs + (pausedAt - renderedAt), totalMs);
1717
+ }
1718
+ const elapsedMs = Math.min(Math.max(totalMs - leftMs, 0), totalMs);
1719
+ return {
1720
+ totalRatio: elapsedMs / totalMs,
1721
+ count: Math.max(1, Math.ceil(totalMs / BAR_UNIT_MS))
1722
+ };
1723
+ }
1724
+ function planBarAnimation(totalMs, elapsedMs) {
1725
+ if (!Number.isFinite(totalMs) || totalMs <= 0) return void 0;
1726
+ const raw = Number.isFinite(elapsedMs) ? elapsedMs : 0;
1727
+ const clamped = Math.min(Math.max(raw, 0), totalMs);
1728
+ const elapsed = clamped === 0 ? 0 : clamped;
1729
+ if (elapsed >= totalMs) return void 0;
1730
+ return {
1731
+ durationMs: totalMs,
1732
+ // -0 会在 CSS 里序列化成难看的 "-0ms",故显式归零
1733
+ delayMs: elapsed === 0 ? 0 : -elapsed
1514
1734
  };
1515
1735
  }
1516
1736
 
1517
1737
  // src/client/components/ScheduleDock.tsx
1518
- var import_jsx_runtime5 = require("react/jsx-runtime");
1738
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1519
1739
  function formatCountdown(ms) {
1520
1740
  const total = Math.max(0, Math.round(ms / 1e3));
1521
1741
  const h = Math.floor(total / 3600);
@@ -1525,53 +1745,151 @@ function formatCountdown(ms) {
1525
1745
  const ss = String(s).padStart(2, "0");
1526
1746
  return h > 0 ? `${h}:${mm}:${ss}` : `${mm}:${ss}`;
1527
1747
  }
1528
- var BAR_UNIT_MS = 36e5;
1529
- function barSegments(item, now, firstSeen) {
1530
- const end = Date.parse(item.scheduled_at);
1531
- let start;
1532
- if (item.kind === "after" && item.after_seconds !== void 0) {
1533
- start = end - item.after_seconds * 1e3;
1534
- } else if (item.kind === "every" && item.every_seconds !== void 0) {
1535
- start = end - item.every_seconds * 1e3;
1536
- } else if (item.created_at !== void 0) {
1537
- const parsed = Date.parse(item.created_at);
1538
- start = Number.isNaN(parsed) ? firstSeen.get(item.id) ?? now : parsed;
1539
- } else {
1540
- start = firstSeen.get(item.id) ?? now;
1748
+ function prefersReducedMotion() {
1749
+ try {
1750
+ return globalThis.matchMedia?.("(prefers-reduced-motion: reduce)").matches === true;
1751
+ } catch {
1752
+ return false;
1541
1753
  }
1542
- const totalMs = Math.max(1e3, end - start);
1543
- const elapsedMs = Math.min(Math.max(now - start, 0), totalMs);
1544
- const totalRatio = elapsedMs / totalMs;
1545
- const count = Math.max(1, Math.ceil(totalMs / BAR_UNIT_MS));
1546
- return { totalRatio, count };
1754
+ }
1755
+ function planBarAnimationFor(item, now, firstSeen) {
1756
+ const end = Date.parse(item.scheduled_at);
1757
+ if (!Number.isFinite(end)) return void 0;
1758
+ const { start, totalMs } = barWindow(item, end, now, firstSeen);
1759
+ return planBarAnimation(totalMs, now - start);
1547
1760
  }
1548
1761
  var deleteLine2 = (id) => `/user-schedule-delete ${JSON.stringify({ id })}`;
1549
1762
  var editLine = (id, prompt) => `/user-schedule-edit ${JSON.stringify({ id, prompt })}`;
1550
1763
  var steerLine = (id) => `/user-schedule-steer-now ${JSON.stringify({ id })}`;
1764
+ var STEER_CONFIRM_WINDOW_MS = 2600;
1765
+ var pauseLine = (id) => `/user-schedule-pause ${JSON.stringify({ id })}`;
1766
+ var resumeLine = (uid) => `/user-schedule-resume ${JSON.stringify({ uid })}`;
1767
+ function canPause(item, now) {
1768
+ if (item.status === "paused") return false;
1769
+ if (item.kind !== "after") return false;
1770
+ const epoch = Date.parse(item.scheduled_at);
1771
+ return Number.isFinite(epoch) && epoch > now;
1772
+ }
1551
1773
  function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
1552
1774
  const now = useNow(1e3);
1553
1775
  const { t } = useSchedT(locale);
1554
1776
  const projection = typeof useProjection === "function" ? useProjection("userSchedules") : void 0;
1555
- const schedules = (0, import_react8.useMemo)(
1556
- () => [...projection?.schedules ?? []].sort(
1777
+ const [dismissedPaused, setDismissedPaused] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
1778
+ (0, import_react7.useEffect)(() => {
1779
+ const live = projection?.schedules;
1780
+ if (live === void 0) return;
1781
+ setDismissedPaused((current) => {
1782
+ if (current.size === 0) return current;
1783
+ let changed = false;
1784
+ const nextSet = new Set(current);
1785
+ for (const item of live) {
1786
+ if (item.status !== "paused" && nextSet.delete(item.id)) changed = true;
1787
+ }
1788
+ return changed ? nextSet : current;
1789
+ });
1790
+ }, [projection]);
1791
+ const [promptOverrides, setPromptOverrides] = (0, import_react7.useState)(/* @__PURE__ */ new Map());
1792
+ (0, import_react7.useEffect)(() => {
1793
+ const live = projection?.schedules;
1794
+ if (live === void 0 || promptOverrides.size === 0) return;
1795
+ setPromptOverrides((current) => {
1796
+ if (current.size === 0) return current;
1797
+ let changed = false;
1798
+ const nextMap = new Map(current);
1799
+ for (const [id, text] of current) {
1800
+ const item = live.find((s) => s.id === id);
1801
+ if (item === void 0 || item.prompt === text) {
1802
+ nextMap.delete(id);
1803
+ changed = true;
1804
+ }
1805
+ }
1806
+ return changed ? nextMap : current;
1807
+ });
1808
+ }, [projection, promptOverrides]);
1809
+ const schedules = (0, import_react7.useMemo)(
1810
+ () => (projection?.schedules ?? []).filter((item) => !(item.status === "paused" && dismissedPaused.has(item.id))).map((item) => {
1811
+ const override = promptOverrides.get(item.id);
1812
+ return override === void 0 ? item : { ...item, prompt: override };
1813
+ }).sort(
1557
1814
  (a, b) => Date.parse(a.scheduled_at) - Date.parse(b.scheduled_at)
1558
1815
  ),
1559
- [projection]
1816
+ [projection, dismissedPaused, promptOverrides]
1560
1817
  );
1561
- const [collapsed, setCollapsed] = (0, import_react8.useState)(true);
1562
- const [cancelling, setCancelling] = (0, import_react8.useState)(/* @__PURE__ */ new Set());
1563
- const [editingId, setEditingId] = (0, import_react8.useState)(null);
1564
- const [editingText, setEditingText] = (0, import_react8.useState)("");
1565
- const [editErr, setEditErr] = (0, import_react8.useState)(null);
1566
- const [saving, setSaving] = (0, import_react8.useState)(false);
1567
- const [steering, setSteering] = (0, import_react8.useState)(/* @__PURE__ */ new Set());
1568
- const [steerDone, setSteerDone] = (0, import_react8.useState)(/* @__PURE__ */ new Set());
1569
- const [steerErr, setSteerErr] = (0, import_react8.useState)(/* @__PURE__ */ new Map());
1570
- const prevRef = (0, import_react8.useRef)(/* @__PURE__ */ new Map());
1571
- const suppressedRef = (0, import_react8.useRef)(/* @__PURE__ */ new Set());
1572
- const firstSeenRef = (0, import_react8.useRef)(/* @__PURE__ */ new Map());
1573
- const byId = (0, import_react8.useMemo)(() => new Map(schedules.map((item) => [item.id, item])), [schedules]);
1574
- (0, import_react8.useEffect)(() => {
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)(() => {
1829
+ const live = projection?.schedules;
1830
+ if (live === void 0) return;
1831
+ const present = new Set(live.filter((item) => item.status !== "paused").map((item) => item.id));
1832
+ setSteerDone((current) => {
1833
+ if (current.size === 0) return current;
1834
+ let changed = false;
1835
+ const next2 = new Set(current);
1836
+ for (const id of current) {
1837
+ if (!present.has(id)) {
1838
+ next2.delete(id);
1839
+ changed = true;
1840
+ }
1841
+ }
1842
+ return changed ? next2 : current;
1843
+ });
1844
+ }, [projection]);
1845
+ (0, import_react7.useEffect)(() => {
1846
+ if (steerDone.size === 0) return void 0;
1847
+ const timer = window.setTimeout(() => {
1848
+ const live = projection?.schedules;
1849
+ if (live === void 0) return;
1850
+ const present = new Set(live.filter((item) => item.status !== "paused").map((item) => item.id));
1851
+ setSteerUnconfirmed((current) => {
1852
+ let changed = false;
1853
+ const next2 = new Set(current);
1854
+ for (const id of steerDone) {
1855
+ if (present.has(id) && !next2.has(id)) {
1856
+ next2.add(id);
1857
+ changed = true;
1858
+ }
1859
+ if (!present.has(id) && next2.delete(id)) changed = true;
1860
+ }
1861
+ return changed ? next2 : current;
1862
+ });
1863
+ }, STEER_CONFIRM_WINDOW_MS);
1864
+ return () => window.clearTimeout(timer);
1865
+ }, [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());
1871
+ const wallClock = Date.now();
1872
+ {
1873
+ const next2 = new Map(lastActiveAtRef.current);
1874
+ let changed = false;
1875
+ for (const item of schedules) {
1876
+ if (item.status === "paused") continue;
1877
+ const prev = next2.get(item.id);
1878
+ if (prev === void 0 || wallClock > prev) {
1879
+ next2.set(item.id, wallClock);
1880
+ changed = true;
1881
+ }
1882
+ }
1883
+ for (const id of [...next2.keys()]) {
1884
+ if (!schedules.some((item) => item.id === id)) {
1885
+ next2.delete(id);
1886
+ changed = true;
1887
+ }
1888
+ }
1889
+ if (changed) lastActiveAtRef.current = next2;
1890
+ }
1891
+ const byId = (0, import_react7.useMemo)(() => new Map(schedules.map((item) => [item.id, item])), [schedules]);
1892
+ (0, import_react7.useEffect)(() => {
1575
1893
  let changed = false;
1576
1894
  const next2 = new Map(firstSeenRef.current);
1577
1895
  for (const [id] of byId) {
@@ -1587,32 +1905,30 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
1587
1905
  }
1588
1906
  }
1589
1907
  if (changed) firstSeenRef.current = next2;
1590
- const prev = prevRef.current;
1591
- if (prev.size > 0) {
1592
- for (const [id, prevItem] of prev) {
1593
- if (byId.has(id)) continue;
1594
- if (suppressedRef.current.has(id)) continue;
1595
- if (Date.parse(prevItem.scheduled_at) <= Date.now()) {
1596
- showReminderToast(prevItem.prompt);
1597
- }
1598
- }
1599
- }
1600
- prevRef.current = byId;
1601
1908
  }, [byId]);
1602
- const suppress = (id) => {
1603
- suppressedRef.current = new Set(suppressedRef.current).add(id);
1604
- };
1605
- (0, import_react8.useEffect)(() => {
1909
+ (0, import_react7.useEffect)(() => {
1606
1910
  if (schedules.length <= 1) setCollapsed(true);
1607
1911
  }, [schedules.length]);
1608
1912
  if (schedules.length === 0 || sessionId === void 0) return null;
1609
1913
  const next = schedules[0];
1610
1914
  if (next === void 0) return null;
1611
1915
  const expanded = schedules.length === 1 || !collapsed;
1612
- const handleCancel = (id) => {
1613
- suppress(id);
1916
+ const handleCancel = (id, status) => {
1614
1917
  setCancelling((current) => new Set(current).add(id));
1615
- void callCommand(sessionId, deleteLine2(id)).finally(() => {
1918
+ const restore = () => {
1919
+ setDismissedPaused((current) => {
1920
+ if (!current.has(id)) return current;
1921
+ const nextSet = new Set(current);
1922
+ nextSet.delete(id);
1923
+ return nextSet;
1924
+ });
1925
+ };
1926
+ if (status === "paused") {
1927
+ setDismissedPaused((current) => new Set(current).add(id));
1928
+ }
1929
+ void callCommand(sessionId, deleteLine2(id)).then((outcome) => {
1930
+ if (!outcome.matched) restore();
1931
+ }).catch(restore).finally(() => {
1616
1932
  window.setTimeout(() => {
1617
1933
  setCancelling((current) => {
1618
1934
  const nextSet = new Set(current);
@@ -1624,16 +1940,19 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
1624
1940
  };
1625
1941
  const handleSteer = (item) => {
1626
1942
  const id = item.id;
1627
- suppress(id);
1943
+ const wasPaused = item.status === "paused";
1628
1944
  setSteering((current) => new Set(current).add(id));
1629
1945
  setSteerErr((current) => {
1630
1946
  const next2 = new Map(current);
1631
1947
  next2.delete(id);
1632
1948
  return next2;
1633
1949
  });
1634
- void callCommand(sessionId, steerLine(id)).then((ok) => {
1635
- if (ok) {
1950
+ void callCommand(sessionId, steerLine(id)).then((outcome) => {
1951
+ if (outcome.matched) {
1636
1952
  setSteerDone((current) => new Set(current).add(id));
1953
+ if (wasPaused) {
1954
+ setDismissedPaused((current) => new Set(current).add(id));
1955
+ }
1637
1956
  } else {
1638
1957
  setSteerErr((current) => new Map(current).set(id, t.editErrNotAccepted));
1639
1958
  }
@@ -1647,6 +1966,67 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
1647
1966
  });
1648
1967
  });
1649
1968
  };
1969
+ const handleSteerRetry = (item) => {
1970
+ const id = item.id;
1971
+ setSteerUnconfirmed((current) => {
1972
+ if (!current.has(id)) return current;
1973
+ const next2 = new Set(current);
1974
+ next2.delete(id);
1975
+ return next2;
1976
+ });
1977
+ setSteerDone((current) => {
1978
+ if (!current.has(id)) return current;
1979
+ const next2 = new Set(current);
1980
+ next2.delete(id);
1981
+ return next2;
1982
+ });
1983
+ handleSteer(item);
1984
+ };
1985
+ const handlePause = (item) => {
1986
+ const id = item.id;
1987
+ if (!canPause(item, now)) return;
1988
+ setPausing((current) => new Set(current).add(id));
1989
+ setPauseErr((current) => {
1990
+ const next2 = new Map(current);
1991
+ next2.delete(id);
1992
+ return next2;
1993
+ });
1994
+ void callCommand(sessionId, pauseLine(id)).then((outcome) => {
1995
+ if (!outcome.matched) {
1996
+ setPauseErr((current) => new Map(current).set(id, t.editErrNotAccepted));
1997
+ }
1998
+ }).catch(() => {
1999
+ setPauseErr((current) => new Map(current).set(id, t.editErrCommandFailed));
2000
+ }).finally(() => {
2001
+ setPausing((current) => {
2002
+ const next2 = new Set(current);
2003
+ next2.delete(id);
2004
+ return next2;
2005
+ });
2006
+ });
2007
+ };
2008
+ const handleResume = (item) => {
2009
+ const uid = item.id;
2010
+ setResuming((current) => new Set(current).add(uid));
2011
+ setPauseErr((current) => {
2012
+ const next2 = new Map(current);
2013
+ next2.delete(uid);
2014
+ return next2;
2015
+ });
2016
+ void callCommand(sessionId, resumeLine(uid)).then((outcome) => {
2017
+ if (!outcome.matched) {
2018
+ setPauseErr((current) => new Map(current).set(uid, t.editErrNotAccepted));
2019
+ }
2020
+ }).catch(() => {
2021
+ setPauseErr((current) => new Map(current).set(uid, t.editErrCommandFailed));
2022
+ }).finally(() => {
2023
+ setResuming((current) => {
2024
+ const next2 = new Set(current);
2025
+ next2.delete(uid);
2026
+ return next2;
2027
+ });
2028
+ });
2029
+ };
1650
2030
  const startEdit = (item) => {
1651
2031
  setEditingId(item.id);
1652
2032
  setEditingText(item.prompt);
@@ -1663,12 +2043,15 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
1663
2043
  setEditErr(t.editErrEmpty);
1664
2044
  return;
1665
2045
  }
1666
- suppress(id);
1667
2046
  setSaving(true);
1668
2047
  setEditErr(null);
1669
- void callCommand(sessionId, editLine(id, trimmed)).then((ok) => {
1670
- if (!ok) setEditErr(format(t.editErrFailed, { message: t.editErrNotAccepted }));
1671
- else cancelEdit();
2048
+ void callCommand(sessionId, editLine(id, trimmed)).then((outcome) => {
2049
+ if (!outcome.matched) {
2050
+ setEditErr(format(t.editErrFailed, { message: t.editErrNotAccepted }));
2051
+ return;
2052
+ }
2053
+ setPromptOverrides((current) => new Map(current).set(id, trimmed));
2054
+ cancelEdit();
1672
2055
  }).catch(() => {
1673
2056
  setEditErr(format(t.editErrFailed, { message: t.editErrCommandFailed }));
1674
2057
  }).finally(() => setSaving(false));
@@ -1677,8 +2060,8 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
1677
2060
  const epoch = Date.parse(item.scheduled_at);
1678
2061
  const state = epoch <= now ? "overdue" : "scheduled";
1679
2062
  if (editingId === item.id) {
1680
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("li", { className: "ss-dock-row ss-editing", "data-ss-dock-row": item.id, children: [
1681
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2063
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("li", { className: "ss-dock-row ss-editing", "data-ss-dock-row": item.id, children: [
2064
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1682
2065
  "input",
1683
2066
  {
1684
2067
  className: "ss-dock-edit-input",
@@ -1695,7 +2078,7 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
1695
2078
  "aria-label": `${t.editTask}: ${item.prompt}`
1696
2079
  }
1697
2080
  ),
1698
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2081
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1699
2082
  "button",
1700
2083
  {
1701
2084
  type: "button",
@@ -1705,60 +2088,98 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
1705
2088
  children: saving ? "\u2026" : t.editSave
1706
2089
  }
1707
2090
  ),
1708
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "ss-dock-action", onClick: cancelEdit, "aria-label": t.editCancel, children: "\u2715" }),
1709
- editErr !== null && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-dock-edit-err", children: editErr })
2091
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "ss-dock-action", onClick: cancelEdit, "aria-label": t.editCancel, children: "\u2715" }),
2092
+ editErr !== null && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ss-dock-edit-err", children: editErr })
1710
2093
  ] }, item.id);
1711
2094
  }
1712
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("li", { className: "ss-dock-row", "data-ss-dock-row": item.id, children: [
1713
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-dock-preview", children: [
1714
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-dock-row-line", children: [
1715
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-dock-row-time", children: formatHhmm(epoch, detectTimeZone()) }),
1716
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: `ss-dock-row-countdown${state === "overdue" ? " ss-due" : ""}`, children: state === "overdue" ? t.dueAnyMoment : `${t.countdownLeft} ${formatCountdown(epoch - now)}` }),
1717
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-dock-row-prompt", title: item.prompt, children: item.prompt })
1718
- ] }),
1719
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(MultiBar, { item, now, firstSeen: firstSeenRef.current, t }),
1720
- steerErr.get(item.id) !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-dock-steer-err", children: steerErr.get(item.id) })
1721
- ] }),
1722
- /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-dock-actions", children: [
1723
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1724
- "button",
1725
- {
1726
- type: "button",
1727
- className: "ss-dock-action",
1728
- title: t.editTask,
1729
- "aria-label": t.editTask,
1730
- onClick: () => startEdit(item),
1731
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QueueEditIcon, {})
1732
- }
1733
- ),
1734
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1735
- "button",
1736
- {
1737
- type: "button",
1738
- className: "ss-dock-action",
1739
- title: t.deleteTask,
1740
- "aria-label": t.deleteTask,
1741
- onClick: () => handleCancel(item.id),
1742
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QueueDeleteIcon, {})
1743
- }
1744
- ),
1745
- item.kind !== "every" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1746
- "button",
1747
- {
1748
- type: "button",
1749
- className: `ss-dock-action ss-dock-action-steer${steering.has(item.id) ? " ss-pending" : ""}${steerDone.has(item.id) ? " ss-done" : ""}`,
1750
- title: steerDone.has(item.id) ? t.steerAlreadySent : t.steerTask,
1751
- "aria-label": steerDone.has(item.id) ? t.steerAlreadySent : t.steerTask,
1752
- disabled: steering.has(item.id) || steerDone.has(item.id),
1753
- onClick: () => handleSteer(item),
1754
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QueueSendIcon, {})
1755
- }
1756
- )
1757
- ] })
1758
- ] }, item.id);
2095
+ const isPaused = item.status === "paused";
2096
+ const frozenLeft = isPaused ? (item.remaining_seconds ?? 0) * 1e3 : epoch - now;
2097
+ const countdownText = isPaused ? t.pausedLabel : state === "overdue" ? t.dueAnyMoment : `${t.countdownLeft} ${formatCountdown(Math.max(0, frozenLeft))}`;
2098
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2099
+ "li",
2100
+ {
2101
+ className: `ss-dock-row${isPaused ? " ss-paused" : ""}`,
2102
+ "data-ss-dock-row": item.id,
2103
+ children: [
2104
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ss-dock-preview", children: [
2105
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ss-dock-row-line", children: [
2106
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ss-dock-row-time", children: formatHhmm(epoch, detectTimeZone()) }),
2107
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: `ss-dock-row-countdown${!isPaused && state === "overdue" ? " ss-due" : ""}${isPaused ? " ss-paused-label" : ""}`, children: countdownText }),
2108
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ss-dock-row-prompt", title: item.prompt, children: item.prompt })
2109
+ ] }),
2110
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MultiBar, { item, now: wallClock, firstSeen: firstSeenRef.current, t, frozen: isPaused, frozenLeftMs: frozenLeft, renderedAt: lastActiveAtRef.current.get(item.id) ?? wallClock }),
2111
+ (steerErr.get(item.id) ?? pauseErr.get(item.id)) !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ss-dock-steer-err", children: steerErr.get(item.id) ?? pauseErr.get(item.id) }),
2112
+ steerUnconfirmed.has(item.id) && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "ss-dock-steer-warn", role: "status", children: [
2113
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: t.steerUnconfirmed }),
2114
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "ss-dock-steer-retry", onClick: () => handleSteerRetry(item), children: t.steerRetry })
2115
+ ] })
2116
+ ] }),
2117
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ss-dock-actions", children: [
2118
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2119
+ "button",
2120
+ {
2121
+ type: "button",
2122
+ className: "ss-dock-action",
2123
+ title: t.editTask,
2124
+ "aria-label": t.editTask,
2125
+ onClick: () => startEdit(item),
2126
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueueEditIcon, {})
2127
+ }
2128
+ ),
2129
+ isPaused ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2130
+ "button",
2131
+ {
2132
+ type: "button",
2133
+ className: `ss-dock-action ss-paused-active${resuming.has(item.id) ? " ss-pending" : ""}`,
2134
+ title: t.resumeTask,
2135
+ "aria-label": t.resumeTask,
2136
+ disabled: resuming.has(item.id),
2137
+ onClick: () => handleResume(item),
2138
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueueResumeIcon, {})
2139
+ }
2140
+ ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2141
+ "button",
2142
+ {
2143
+ type: "button",
2144
+ className: `ss-dock-action${pausing.has(item.id) ? " ss-pending" : ""}`,
2145
+ title: canPause(item, now) ? t.pauseTask : t.pauseUnsupportedKind,
2146
+ "aria-label": canPause(item, now) ? t.pauseTask : t.pauseUnsupportedKind,
2147
+ disabled: !canPause(item, now) || pausing.has(item.id),
2148
+ onClick: () => handlePause(item),
2149
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueuePauseIcon, {})
2150
+ }
2151
+ ),
2152
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2153
+ "button",
2154
+ {
2155
+ type: "button",
2156
+ className: "ss-dock-action",
2157
+ title: t.deleteTask,
2158
+ "aria-label": t.deleteTask,
2159
+ onClick: () => handleCancel(item.id, isPaused ? "paused" : "active"),
2160
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueueDeleteIcon, {})
2161
+ }
2162
+ ),
2163
+ item.kind !== "every" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2164
+ "button",
2165
+ {
2166
+ type: "button",
2167
+ 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
+ "aria-label": steerDone.has(item.id) ? t.steerAlreadySent : t.steerTask,
2170
+ disabled: steering.has(item.id) || steerDone.has(item.id),
2171
+ onClick: () => handleSteer(item),
2172
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueueSendIcon, {})
2173
+ }
2174
+ )
2175
+ ] })
2176
+ ]
2177
+ },
2178
+ item.id
2179
+ );
1759
2180
  };
1760
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ss-dock-root", "data-ss-dock": "", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-dock-body", children: [
1761
- schedules.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
2181
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "ss-dock-root", "data-ss-dock": "", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ss-dock-body", children: [
2182
+ schedules.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1762
2183
  "button",
1763
2184
  {
1764
2185
  type: "button",
@@ -1766,23 +2187,48 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
1766
2187
  "aria-expanded": !collapsed,
1767
2188
  onClick: () => setCollapsed((value) => !value),
1768
2189
  children: [
1769
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-dock-lead", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QueueClockIcon, {}) }),
1770
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-dock-count", children: format(t.panelCount, { n: schedules.length }) }),
1771
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: expanded ? "ss-dock-chevron ss-open" : "ss-dock-chevron", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(QueueChevronIcon, {}) })
2190
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ss-dock-lead", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueueClockIcon, {}) }),
2191
+ /* @__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, {}) })
1772
2193
  ]
1773
2194
  }
1774
2195
  ),
1775
- expanded && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ul", { className: "ss-dock-list", children: schedules.map(renderRow) })
2196
+ expanded && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { className: "ss-dock-list", children: schedules.map(renderRow) })
1776
2197
  ] }) });
1777
2198
  }
1778
2199
  function MultiBar({
1779
2200
  item,
1780
2201
  now,
1781
2202
  firstSeen,
1782
- t
2203
+ t,
2204
+ frozen = false,
2205
+ frozenLeftMs,
2206
+ renderedAt
1783
2207
  }) {
1784
- const { totalRatio, count } = barSegments(item, now, firstSeen);
1785
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2208
+ const frozenSeg = frozen ? frozenBarSegments(item, frozenLeftMs ?? 0, firstSeen, renderedAt) : void 0;
2209
+ const activeSeg = frozen ? void 0 : barSegments(item, now, firstSeen);
2210
+ const { totalRatio, count } = frozenSeg ?? activeSeg ?? { totalRatio: 0, count: 1 };
2211
+ const phaseAtRef = (0, import_react7.useRef)(null);
2212
+ if (frozen || prefersReducedMotion()) {
2213
+ phaseAtRef.current = null;
2214
+ } else if (phaseAtRef.current === null) {
2215
+ phaseAtRef.current = now;
2216
+ }
2217
+ const anim = frozen || prefersReducedMotion() ? void 0 : planBarAnimationFor(item, phaseAtRef.current ?? now, firstSeen);
2218
+ const fillStyle = anim === void 0 ? { width: `${totalRatio * 100}%` } : {
2219
+ /**
2220
+ * 只注入**参数**(CSS 变量),动画的组装交给 CSS(见 styles.ts)。
2221
+ *
2222
+ * 这样做的原因:动画声明留在 CSS 里,JS 不碰 `animationName` 等简写属性
2223
+ * ——否则会整条覆盖 CSS 的声明。当前只有进度推进一个动画,但保持这个
2224
+ * 分工,将来若再加纹理/状态动效不必回头改 JS。
2225
+ */
2226
+ ["--ss-bar-duration"]: `${anim.durationMs}ms`,
2227
+ // 负 delay 把播放头定位到挂载时刻的绝对相位;此后恒定不变
2228
+ // (重算会让动画多跳——见上方 phaseAtRef 注释)。
2229
+ ["--ss-bar-delay"]: `${anim.delayMs}ms`
2230
+ };
2231
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1786
2232
  "div",
1787
2233
  {
1788
2234
  className: `ss-dock-bars${count > 4 ? " ss-dock-bars-compact" : ""}`,
@@ -1791,8 +2237,8 @@ function MultiBar({
1791
2237
  "aria-valuemax": 100,
1792
2238
  "aria-valuenow": Math.round(totalRatio * 100),
1793
2239
  "aria-label": t.panelTitle,
1794
- children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-dock-bar", children: [
1795
- count > 1 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2240
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ss-dock-bar", children: [
2241
+ count > 1 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1796
2242
  "div",
1797
2243
  {
1798
2244
  className: "ss-dock-bar-divider",
@@ -1801,55 +2247,120 @@ function MultiBar({
1801
2247
  }
1802
2248
  }
1803
2249
  ),
1804
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ss-dock-bar-fill", style: { width: `${totalRatio * 100}%` } })
2250
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "ss-dock-bar-fill", style: fillStyle })
1805
2251
  ] })
1806
2252
  }
1807
2253
  );
1808
2254
  }
1809
2255
  function QueueClockIcon() {
1810
- return /* @__PURE__ */ (0, import_jsx_runtime5.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_runtime5.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" }) });
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" }) });
1811
2257
  }
1812
2258
  function QueueChevronIcon() {
1813
- return /* @__PURE__ */ (0, import_jsx_runtime5.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_runtime5.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" }) });
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" }) });
1814
2260
  }
1815
2261
  function QueueEditIcon() {
1816
- return /* @__PURE__ */ (0, import_jsx_runtime5.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_runtime5.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" }) });
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" }) });
1817
2263
  }
1818
2264
  function QueueDeleteIcon() {
1819
- return /* @__PURE__ */ (0, import_jsx_runtime5.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_runtime5.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" }) });
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" }) });
1820
2266
  }
1821
2267
  function QueueSendIcon() {
1822
- return /* @__PURE__ */ (0, import_jsx_runtime5.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_runtime5.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" }) });
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" })
2274
+ ] });
2275
+ }
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" }) });
1823
2278
  }
1824
2279
 
1825
2280
  // src/client/components/SchedulerSettingsCard.tsx
1826
- var import_react9 = require("react");
1827
- var import_jsx_runtime6 = require("react/jsx-runtime");
1828
- var FIELDS = [
1829
- { kind: "boolean", key: "showButton", labelKey: "showButtonLabel", hintKey: "showButtonHint", defaultValue: true },
1830
- { kind: "number", key: "maxSchedules", labelKey: "maxSchedulesLabel", hintKey: "maxSchedulesHint", defaultValue: 100 },
1831
- { kind: "time", key: "workStart", labelKey: "workStartLabel", hintKey: "smartWindowHint" },
1832
- { kind: "time", key: "workEnd", labelKey: "workEndLabel" },
1833
- { kind: "time", key: "lunchStart", labelKey: "lunchStartLabel" },
1834
- { kind: "time", key: "lunchEnd", labelKey: "lunchEndLabel" },
1835
- { kind: "time", key: "eveningEnd", labelKey: "eveningEndLabel" }
2281
+ var import_react8 = require("react");
2282
+ var import_jsx_runtime5 = require("react/jsx-runtime");
2283
+ var SECTIONS = [
2284
+ {
2285
+ id: "display",
2286
+ titleKey: "sectionDisplay",
2287
+ layout: "stack",
2288
+ fields: [
2289
+ {
2290
+ kind: "boolean",
2291
+ key: "showButton",
2292
+ labelKey: "showButtonLabel",
2293
+ hintKey: "showButtonHint",
2294
+ defaultValue: true
2295
+ },
2296
+ {
2297
+ kind: "enum",
2298
+ key: "clockIconStyle",
2299
+ labelKey: "clockIconStyleLabel",
2300
+ hintKey: "clockIconStyleHint",
2301
+ options: ["auto", "modern", "classic"],
2302
+ defaultValue: "auto"
2303
+ },
2304
+ { kind: "number", key: "maxSchedules", labelKey: "maxSchedulesLabel", hintKey: "maxSchedulesHint", defaultValue: 100 }
2305
+ ]
2306
+ },
2307
+ {
2308
+ id: "time",
2309
+ titleKey: "sectionTime",
2310
+ layout: "grid",
2311
+ fields: [
2312
+ { kind: "time", key: "workStart", labelKey: "workStartLabel", hintKey: "smartWindowHint" },
2313
+ { kind: "time", key: "workEnd", labelKey: "workEndLabel" },
2314
+ { kind: "time", key: "lunchStart", labelKey: "lunchStartLabel" },
2315
+ { kind: "time", key: "lunchEnd", labelKey: "lunchEndLabel" },
2316
+ { kind: "time", key: "eveningEnd", labelKey: "eveningEndLabel" }
2317
+ ]
2318
+ },
2319
+ {
2320
+ id: "delivery",
2321
+ titleKey: "sectionDelivery",
2322
+ layout: "stack",
2323
+ fields: [
2324
+ {
2325
+ kind: "enum",
2326
+ key: "steerDelivery",
2327
+ labelKey: "steerDeliveryLabel",
2328
+ hintKey: "steerDeliveryHint",
2329
+ options: ["followup", "steer"],
2330
+ defaultValue: "followup"
2331
+ },
2332
+ {
2333
+ kind: "boolean",
2334
+ key: "confirmDelivery",
2335
+ labelKey: "confirmDeliveryLabel",
2336
+ hintKey: "confirmDeliveryHint",
2337
+ defaultValue: true
2338
+ },
2339
+ {
2340
+ kind: "enum",
2341
+ key: "onUnconfirmed",
2342
+ labelKey: "onUnconfirmedLabel",
2343
+ hintKey: "onUnconfirmedHint",
2344
+ options: ["keep", "discard"],
2345
+ defaultValue: "keep"
2346
+ }
2347
+ ]
2348
+ }
1836
2349
  ];
1837
- function ChevronDown({ className }) {
1838
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", className, "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("path", { d: "M3.5 5.25 7 8.75l3.5-3.5", stroke: "currentColor", strokeWidth: "1.2", strokeLinecap: "round", strokeLinejoin: "round" }) });
1839
- }
2350
+ var FIELDS = SECTIONS.flatMap((s) => s.fields);
1840
2351
  function SchedulerSettingsCard({ scope, t }) {
1841
- const [snapshot, setSnapshot] = (0, import_react9.useState)(() => scope.getSnapshot());
1842
- const [pending, setPending] = (0, import_react9.useState)({});
1843
- const [saving, setSaving] = (0, import_react9.useState)(false);
1844
- const [failed, setFailed] = (0, import_react9.useState)(false);
1845
- const [open, setOpen] = (0, import_react9.useState)(false);
1846
- (0, import_react9.useEffect)(() => {
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)(() => {
1847
2358
  const initial = scope.getSnapshot();
1848
2359
  setSnapshot(initial);
1849
2360
  setPending({});
1850
2361
  if (initial.status === "ready") setFailed(false);
1851
2362
  }, [scope]);
1852
- (0, import_react9.useEffect)(() => {
2363
+ (0, import_react8.useEffect)(() => {
1853
2364
  return scope.subscribe(() => {
1854
2365
  const snap = scope.getSnapshot();
1855
2366
  setSnapshot(snap);
@@ -1858,10 +2369,10 @@ function SchedulerSettingsCard({ scope, t }) {
1858
2369
  }
1859
2370
  });
1860
2371
  }, [scope]);
1861
- if (snapshot.status === "unavailable") return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, {});
2372
+ if (snapshot.status === "unavailable") return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, {});
1862
2373
  if (snapshot.status !== "ready") {
1863
- if (snapshot.status === "loading") return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "ss-hint", children: t("loading") });
1864
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "ss-hint", children: t("unavailable") });
2374
+ if (snapshot.status === "loading") return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ss-hint", children: t("loading") });
2375
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ss-hint", children: t("unavailable") });
1865
2376
  }
1866
2377
  const value = snapshot.value ?? {};
1867
2378
  const base = snapshot.base ?? {};
@@ -1879,6 +2390,10 @@ function SchedulerSettingsCard({ scope, t }) {
1879
2390
  const v2 = value[field.key];
1880
2391
  return v2 === false ? "false" : "true";
1881
2392
  }
2393
+ if (field.kind === "enum") {
2394
+ const v2 = value[field.key];
2395
+ return typeof v2 === "string" ? v2 : field.defaultValue;
2396
+ }
1882
2397
  const v = value[field.key];
1883
2398
  return v ?? "";
1884
2399
  };
@@ -1891,6 +2406,10 @@ function SchedulerSettingsCard({ scope, t }) {
1891
2406
  const v2 = base[field.key];
1892
2407
  return v2 === false ? "false" : "true";
1893
2408
  }
2409
+ if (field.kind === "enum") {
2410
+ const v2 = base[field.key];
2411
+ return typeof v2 === "string" ? v2 : field.defaultValue;
2412
+ }
1894
2413
  const v = base[field.key];
1895
2414
  return v ?? "";
1896
2415
  };
@@ -1903,6 +2422,7 @@ function SchedulerSettingsCard({ scope, t }) {
1903
2422
  return null;
1904
2423
  }
1905
2424
  if (field.kind === "boolean") return null;
2425
+ if (field.kind === "enum") return field.options.includes(raw) ? null : t("invalidLabel");
1906
2426
  if (raw.trim().length === 0) return null;
1907
2427
  if (!isValidHhmm(raw)) return t("invalidTimeLabel");
1908
2428
  return null;
@@ -1918,11 +2438,11 @@ function SchedulerSettingsCard({ scope, t }) {
1918
2438
  setFieldPending(field.key, baselineValue(field), true);
1919
2439
  setFailed(false);
1920
2440
  };
1921
- const handleDiscard = (0, import_react9.useCallback)(() => {
2441
+ const handleDiscard = (0, import_react8.useCallback)(() => {
1922
2442
  setPending({});
1923
2443
  setFailed(false);
1924
2444
  }, []);
1925
- const handleSave = (0, import_react9.useCallback)(async () => {
2445
+ const handleSave = (0, import_react8.useCallback)(async () => {
1926
2446
  if (!dirty || saving || !writable) return;
1927
2447
  setSaving(true);
1928
2448
  setFailed(false);
@@ -1955,66 +2475,91 @@ function SchedulerSettingsCard({ scope, t }) {
1955
2475
  };
1956
2476
  const anyInvalid = FIELDS.some((field) => invalidField(field) !== null);
1957
2477
  const saveDisabled = !dirty || saving || !writable || anyInvalid;
1958
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("li", { className: open ? "ss-card ss-cardOpen" : "ss-card", children: [
1959
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1960
- "button",
1961
- {
1962
- type: "button",
1963
- className: "ss-card-header",
1964
- "aria-expanded": open,
1965
- "aria-label": `${t(open ? "collapse" : "expand")}: ${t("title")}`,
1966
- onClick: () => setOpen(!open),
1967
- children: [
1968
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "ss-card-headText", children: [
1969
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-card-name", children: t("title") }),
1970
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-card-description", children: t("description") })
1971
- ] }),
1972
- dirty && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-card-pending", children: t("pendingBadge") }),
1973
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ChevronDown, { className: open ? "ss-card-chevron ss-card-chevronOpen" : "ss-card-chevron" })
1974
- ]
1975
- }
1976
- ),
1977
- open ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ss-card-body", children: [
1978
- !writable && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "ss-card-readOnly", role: "status", children: t("readOnly") }),
1979
- FIELDS.map((field) => {
2478
+ const confirmEnabled = (pending.confirmDelivery?.value ?? (value.confirmDelivery === false ? "false" : "true")) !== "false";
2479
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-settings-form", children: [
2480
+ !writable && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ss-hint", role: "status", children: t("readOnly") }),
2481
+ 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) }),
2483
+ /* @__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) => {
1980
2484
  const invalid = invalidField(field);
1981
2485
  const isTime = field.kind === "time";
1982
2486
  const labelKey = field.labelKey;
1983
2487
  const hintKey = field.hintKey;
1984
2488
  const userHas = isUserOverridden(field.key);
1985
2489
  const fieldId = `ss-${field.key}`;
1986
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ss-field", children: [
1987
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ss-card-fieldHead", children: [
1988
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("label", { htmlFor: fieldId, className: "ss-card-label", children: t(labelKey) }),
1989
- userHas && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "ss-card-badges", children: [
1990
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "ss-card-badge", children: t("overriddenLabel") }),
1991
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2490
+ const helpHint = hintKey !== void 0 && t(hintKey).length > 0;
2491
+ const badges = userHas ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "ss-card-badges", children: [
2492
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-card-badge", children: t("overriddenLabel") }),
2493
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2494
+ "button",
2495
+ {
2496
+ type: "button",
2497
+ className: "ss-card-reset",
2498
+ disabled: !writable || saving,
2499
+ onClick: () => handleResetField(field),
2500
+ children: t("resetLabel")
2501
+ }
2502
+ )
2503
+ ] }) : null;
2504
+ if (field.kind === "boolean") {
2505
+ const checked = displayValue(field) !== "false";
2506
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-field ss-fieldToggle", children: [
2507
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-toggle-row", children: [
2508
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ss-label-group", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { htmlFor: fieldId, className: "ss-toggle-label", children: t(labelKey) }) }),
2509
+ badges,
2510
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1992
2511
  "button",
1993
2512
  {
1994
2513
  type: "button",
1995
- className: "ss-card-reset",
2514
+ id: fieldId,
2515
+ role: "switch",
2516
+ "aria-checked": checked,
2517
+ "aria-label": t(labelKey),
2518
+ className: "ss-toggle-switch",
1996
2519
  disabled: !writable || saving,
1997
- onClick: () => handleResetField(field),
1998
- children: t("resetLabel")
2520
+ onClick: () => handleFieldEdit(field, checked ? "false" : "true")
1999
2521
  }
2000
2522
  )
2001
- ] })
2523
+ ] }),
2524
+ helpHint ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ss-toggle-description", children: t(hintKey) }) : null,
2525
+ invalid !== null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ss-card-invalid", role: "status", children: invalid }) : null
2526
+ ] }, field.key);
2527
+ }
2528
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-field", children: [
2529
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-card-fieldHead", children: [
2530
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-label-group", children: [
2531
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { htmlFor: fieldId, className: "ss-card-label", children: t(labelKey) }),
2532
+ helpHint && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2533
+ "button",
2534
+ {
2535
+ type: "button",
2536
+ className: helpOpen[field.key] === true ? "ss-help-btn ss-help-btnOpen" : "ss-help-btn",
2537
+ "aria-label": `${t(labelKey)}\u8BF4\u660E`,
2538
+ "aria-expanded": helpOpen[field.key] === true,
2539
+ "aria-controls": `ss-help-${field.key}`,
2540
+ 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
+ ] })
2546
+ }
2547
+ )
2548
+ ] }),
2549
+ badges
2002
2550
  ] }),
2003
- field.kind === "boolean" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2551
+ field.kind === "enum" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2004
2552
  "select",
2005
2553
  {
2006
2554
  id: fieldId,
2007
2555
  className: invalid !== null ? "ss-input ss-inputInvalid" : "ss-input",
2008
2556
  "aria-invalid": invalid !== null || void 0,
2009
- value: displayValue(field) === "false" ? "false" : "true",
2557
+ value: displayValue(field),
2010
2558
  disabled: !writable || saving,
2011
2559
  onChange: (event) => handleFieldEdit(field, event.target.value),
2012
- children: [
2013
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "true", children: t("optionOn") }),
2014
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("option", { value: "false", children: t("optionOff") })
2015
- ]
2560
+ children: field.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: option, children: t(`${field.key}Option_${option}`) }, option))
2016
2561
  }
2017
- ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2562
+ ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2018
2563
  "input",
2019
2564
  {
2020
2565
  id: fieldId,
@@ -2028,33 +2573,36 @@ function SchedulerSettingsCard({ scope, t }) {
2028
2573
  onChange: (event) => handleFieldEdit(field, event.target.value)
2029
2574
  }
2030
2575
  ),
2031
- invalid !== null || hintKey !== void 0 && t(hintKey).length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: invalid !== null ? "ss-card-invalid" : "ss-hint", children: invalid !== null ? invalid : t(hintKey) }) : null
2576
+ invalid !== null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ss-card-invalid", role: "status", children: invalid }) : null,
2577
+ helpOpen[field.key] === true && hintKey !== void 0 && t(hintKey).length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { id: `ss-help-${field.key}`, role: "region", "aria-label": `${t(labelKey)}\u8BF4\u660E`, className: "ss-help", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: t(hintKey) }) }) : null,
2578
+ field.key === "steerDelivery" && displayValue(field) === "steer" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ss-card-risk", role: "status", children: confirmEnabled ? t("steerRiskGuarded") : t("steerRiskUnguarded") }) : null,
2579
+ field.key === "onUnconfirmed" && displayValue(field) === "discard" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ss-card-risk", role: "status", children: t("discardRisk") }) : null
2032
2580
  ] }, field.key);
2033
- }),
2034
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ss-card-footer", children: [
2035
- failed && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "ss-card-failed", role: "status", children: t("saveFailed") }),
2036
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2037
- "button",
2038
- {
2039
- type: "button",
2040
- className: "ss-card-discard",
2041
- disabled: !dirty || saving,
2042
- onClick: handleDiscard,
2043
- children: t("discard")
2044
- }
2045
- ),
2046
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2047
- "button",
2048
- {
2049
- type: "button",
2050
- className: "ss-card-save",
2051
- disabled: saveDisabled,
2052
- onClick: () => void handleSave(),
2053
- children: saving ? t("saving") : t("save")
2054
- }
2055
- )
2056
- ] })
2057
- ] }) : null
2581
+ }) })
2582
+ ] }, section.id)),
2583
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-card-footer", children: [
2584
+ failed && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ss-card-failed", role: "status", children: t("saveFailed") }),
2585
+ dirty && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2586
+ "button",
2587
+ {
2588
+ type: "button",
2589
+ className: "ss-card-discard",
2590
+ disabled: saving,
2591
+ onClick: handleDiscard,
2592
+ children: t("discard")
2593
+ }
2594
+ ),
2595
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2596
+ "button",
2597
+ {
2598
+ type: "button",
2599
+ className: "ss-card-save",
2600
+ disabled: saveDisabled,
2601
+ onClick: () => void handleSave(),
2602
+ children: saving ? t("saving") : t("save")
2603
+ }
2604
+ )
2605
+ ] })
2058
2606
  ] });
2059
2607
  }
2060
2608
 
@@ -2062,16 +2610,57 @@ function SchedulerSettingsCard({ scope, t }) {
2062
2610
  var PRESENCE_URGENT_WINDOW_MS = 5 * 6e4;
2063
2611
  function summarizeSchedules(schedules) {
2064
2612
  let nextAt;
2613
+ let progressFrom;
2065
2614
  let count = 0;
2615
+ let pausedCount = 0;
2066
2616
  for (const item of schedules ?? []) {
2067
2617
  const raw = item.scheduled_at ?? item.scheduledAt;
2068
2618
  if (raw === void 0) continue;
2069
2619
  const epoch = Date.parse(raw);
2070
2620
  if (!Number.isFinite(epoch)) continue;
2071
2621
  count += 1;
2072
- if (nextAt === void 0 || epoch < nextAt) nextAt = epoch;
2622
+ if (item.status === "paused") {
2623
+ pausedCount += 1;
2624
+ continue;
2625
+ }
2626
+ if (nextAt === void 0 || epoch < nextAt) {
2627
+ nextAt = epoch;
2628
+ progressFrom = windowStartOf(item, epoch);
2629
+ }
2630
+ }
2631
+ if (count === 0) return { count: 0, pausedCount: 0 };
2632
+ return nextAt === void 0 ? { count, pausedCount } : { count, nextAt, pausedCount, ...progressFrom !== void 0 ? { progressFrom } : {} };
2633
+ }
2634
+ function windowStartOf(item, scheduledEpoch) {
2635
+ const explicit = toFiniteSeconds(item.window_seconds ?? item.windowSeconds);
2636
+ if (explicit !== void 0) return scheduledEpoch - explicit * 1e3;
2637
+ const afterSec = toFiniteSeconds(item.after_seconds ?? item.afterSeconds);
2638
+ const everySec = toFiniteSeconds(item.every_seconds ?? item.everySeconds);
2639
+ const span = item.kind === "every" ? everySec : afterSec ?? everySec;
2640
+ if (span !== void 0) return scheduledEpoch - span * 1e3;
2641
+ const created = toEpochMs(item.created_at) ?? toEpochMs(item.createdAt);
2642
+ if (created !== null) return created;
2643
+ return void 0;
2644
+ }
2645
+ function toFiniteSeconds(value) {
2646
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
2647
+ }
2648
+ function toEpochMs(value) {
2649
+ if (typeof value === "number") return Number.isFinite(value) ? value : null;
2650
+ if (typeof value === "string" && value.length > 0) {
2651
+ const parsed = Date.parse(value);
2652
+ return Number.isFinite(parsed) ? parsed : null;
2073
2653
  }
2074
- return nextAt === void 0 ? { count: 0 } : { count, nextAt };
2654
+ return null;
2655
+ }
2656
+ function progressOf(entry, now) {
2657
+ const { nextAt, progressFrom } = entry;
2658
+ if (nextAt === void 0 || progressFrom === void 0) return void 0;
2659
+ const span = nextAt - progressFrom;
2660
+ if (!(span > 0)) return void 0;
2661
+ const ratio = (now - progressFrom) / span;
2662
+ if (!Number.isFinite(ratio)) return void 0;
2663
+ return ratio <= 0 ? 0 : ratio >= 1 ? 1 : ratio;
2075
2664
  }
2076
2665
  function badgeStateFor(nextAt, now) {
2077
2666
  if (nextAt === void 0) return "scheduled";
@@ -2080,6 +2669,24 @@ function badgeStateFor(nextAt, now) {
2080
2669
  if (diff <= PRESENCE_URGENT_WINDOW_MS) return "urgent";
2081
2670
  return "scheduled";
2082
2671
  }
2672
+ function hoverScheduleStatus(entry, now, labels, strings, formatHhmm3, formatDate2) {
2673
+ const tone = badgeStateFor(entry.nextAt, now);
2674
+ if (entry.nextAt === void 0 && entry.pausedCount > 0) {
2675
+ const paused = strings.hoverSchedulePaused ?? strings.hoverScheduleOverdue;
2676
+ return { label: formatTemplate(paused, { n: entry.count }), tone };
2677
+ }
2678
+ if (tone === "overdue" || entry.nextAt === void 0) {
2679
+ return { label: formatTemplate(strings.hoverScheduleOverdue, { n: entry.count }), tone };
2680
+ }
2681
+ const time = relativeFireLabel(entry.nextAt, now, labels, formatHhmm3, formatDate2);
2682
+ return { label: formatTemplate(strings.hoverScheduleStatus, { n: entry.count, time }), tone };
2683
+ }
2684
+ function formatTemplate(template, params) {
2685
+ return template.replace(
2686
+ /\{(\w+)\}/g,
2687
+ (match, key) => key in params ? String(params[key]) : match
2688
+ );
2689
+ }
2083
2690
  function startOfDay(epoch) {
2084
2691
  const d = new Date(epoch);
2085
2692
  d.setHours(0, 0, 0, 0);
@@ -2099,17 +2706,26 @@ function relativeFireLabel(nextAt, now, labels, formatHhmm3, formatDate2) {
2099
2706
 
2100
2707
  // src/client/session-presence.ts
2101
2708
  var BADGE_CLASS = "ss-presence";
2709
+ var HOVER_ROW_CLASS = "ss-hover-status";
2102
2710
  var FIBER_MAX_DEPTH = 8;
2103
2711
  var SCAN_DEBOUNCE_MS = 60;
2104
2712
  var STATE_TICK_MS = 3e4;
2105
- var REFRESH_INTERVAL_MS = 6e4;
2106
- var CLOCK_SVG = '<svg width="10" height="10" viewBox="0 0 10 10" shape-rendering="crispEdges" aria-hidden="true"><g class="ss-presence-ring"><rect x="0" y="0" width="2" height="2"/><rect x="4" y="0" width="2" height="2"/><rect x="8" y="0" width="2" height="2"/><rect x="8" y="4" width="2" height="2"/><rect x="8" y="8" width="2" height="2"/><rect x="4" y="8" width="2" height="2"/><rect x="0" y="8" width="2" height="2"/><rect x="0" y="4" width="2" height="2"/></g><g class="ss-presence-hand"><rect x="4" y="2" width="2" height="2"/><rect x="6" y="4" width="2" height="2"/></g></svg>';
2713
+ var CLOCK_SVG_CLASSIC = '<svg width="10" height="10" viewBox="0 0 10 10" shape-rendering="crispEdges" aria-hidden="true"><g class="ss-presence-ring"><rect x="0" y="0" width="2" height="2"/><rect x="4" y="0" width="2" height="2"/><rect x="8" y="0" width="2" height="2"/><rect x="8" y="4" width="2" height="2"/><rect x="8" y="8" width="2" height="2"/><rect x="4" y="8" width="2" height="2"/><rect x="0" y="8" width="2" height="2"/><rect x="0" y="4" width="2" height="2"/></g><g class="ss-presence-hand"><rect x="4" y="2" width="2" height="2"/><rect x="6" y="4" width="2" height="2"/></g></svg>';
2714
+ var CLOCK_FACE_R = 9.5;
2715
+ var CLOCK_FACE_CIRCUMFERENCE = 2 * Math.PI * CLOCK_FACE_R;
2716
+ var CLOCK_SVG_MODERN = `<svg width="14" height="14" viewBox="0 0 24 24" aria-hidden="true"><circle class="ss-clock-track" cx="12" cy="12" r="${CLOCK_FACE_R}"/><circle class="ss-clock-prog" cx="12" cy="12" r="${CLOCK_FACE_R}" stroke-dasharray="${CLOCK_FACE_CIRCUMFERENCE.toFixed(3)}" stroke-dashoffset="${CLOCK_FACE_CIRCUMFERENCE.toFixed(3)}" transform="rotate(-90 12 12)"/><g class="ss-clock-hand"><line class="ss-clock-hand-h" x1="12" y1="12" x2="12" y2="6.5"/><line class="ss-clock-hand-m" x1="12" y1="12" x2="17" y2="12"/></g></svg>`;
2107
2717
  var hhmmFormatter = new Intl.DateTimeFormat(void 0, { hour: "2-digit", minute: "2-digit", hour12: false });
2108
2718
  var dateFormatter = new Intl.DateTimeFormat(void 0, { month: "short", day: "numeric" });
2109
2719
  var formatHhmm2 = (epoch) => hhmmFormatter.format(epoch);
2110
2720
  var formatDate = (epoch) => dateFormatter.format(epoch);
2111
2721
  function sessionIdOfRow(row) {
2112
- const host = row;
2722
+ return sessionIdOfNode(row);
2723
+ }
2724
+ function sessionIdOfHoverCard(card) {
2725
+ return sessionIdOfNode(card);
2726
+ }
2727
+ function sessionIdOfNode(element) {
2728
+ const host = element;
2113
2729
  const fiberKey = Object.keys(host).find((key) => key.startsWith("__reactFiber$"));
2114
2730
  if (fiberKey === void 0) return void 0;
2115
2731
  let fiber = host[fiberKey];
@@ -2120,14 +2736,9 @@ function sessionIdOfRow(row) {
2120
2736
  }
2121
2737
  return void 0;
2122
2738
  }
2123
- function buildIndex(state) {
2124
- const index = /* @__PURE__ */ new Map();
2125
- for (const [sessionId, summary] of Object.entries(state.byId)) {
2126
- const schedules = summary.projectionValues?.["userSchedules"]?.schedules;
2127
- const entry = summarizeSchedules(schedules);
2128
- if (entry.count > 0) index.set(sessionId, entry);
2129
- }
2130
- return index;
2739
+ function currentIndex(summary) {
2740
+ summary.reload();
2741
+ return summary.getSnapshot();
2131
2742
  }
2132
2743
  function findBadge(row) {
2133
2744
  for (const child of Array.from(row.children)) {
@@ -2148,23 +2759,28 @@ function labelsFor(dict) {
2148
2759
  };
2149
2760
  }
2150
2761
  function mountSessionPresence(options) {
2151
- const { sessions, locale } = options;
2762
+ const { summary, locale, getClockIconStyle } = options;
2152
2763
  if (typeof document === "undefined" || typeof MutationObserver === "undefined") {
2153
2764
  return () => void 0;
2154
2765
  }
2766
+ const getClockSvg = () => {
2767
+ const style = getClockIconStyle?.() ?? "auto";
2768
+ return style === "classic" ? CLOCK_SVG_CLASSIC : CLOCK_SVG_MODERN;
2769
+ };
2155
2770
  let index = /* @__PURE__ */ new Map();
2156
2771
  let scanTimer;
2157
2772
  let disposed = false;
2158
2773
  const dictForNow = () => dictFor(locale?.getSnapshot().active);
2159
2774
  const scan = () => {
2160
2775
  if (disposed) return;
2161
- index = buildIndex(sessions.list.getSnapshot());
2776
+ index = currentIndex(summary);
2162
2777
  const dict = dictForNow();
2163
2778
  const now = Date.now();
2164
2779
  for (const row of Array.from(document.querySelectorAll('[role="treeitem"][draggable="true"]'))) {
2165
2780
  if (row.hasAttribute("aria-expanded")) continue;
2166
2781
  applyBadge(row, now, dict);
2167
2782
  }
2783
+ applyHoverCard(now, dict);
2168
2784
  };
2169
2785
  const scheduleScan = () => {
2170
2786
  if (disposed || scanTimer !== void 0) return;
@@ -2184,12 +2800,15 @@ function mountSessionPresence(options) {
2184
2800
  }
2185
2801
  const state = badgeStateFor(entry.nextAt, now);
2186
2802
  const time = entry.nextAt === void 0 ? "" : relativeFireLabel(entry.nextAt, now, labelsFor(dict), formatHhmm2, formatDate);
2187
- const aria = state === "overdue" ? format(dict.presenceOverdueAria, { n: entry.count }) : format(dict.presenceBadgeAria, { n: entry.count, time });
2188
- const tooltip = state === "overdue" ? format(dict.presenceOverdueTooltip, { n: entry.count }) : format(dict.presenceTooltip, { n: entry.count, time });
2803
+ const allPaused = entry.nextAt === void 0 && entry.pausedCount > 0;
2804
+ const aria = allPaused ? format(dict.presencePausedAria, { n: entry.count }) : state === "overdue" ? format(dict.presenceOverdueAria, { n: entry.count }) : format(dict.presenceBadgeAria, { n: entry.count, time });
2805
+ const tooltip = allPaused ? format(dict.presencePausedTooltip, { n: entry.count }) : state === "overdue" ? format(dict.presenceOverdueTooltip, { n: entry.count }) : format(dict.presenceTooltip, { n: entry.count, time });
2806
+ const progress = progressOf(entry, now);
2189
2807
  if (existing !== null) {
2190
2808
  if (existing.dataset.state !== state) existing.dataset.state = state;
2191
2809
  if (existing.getAttribute("aria-label") !== aria) existing.setAttribute("aria-label", aria);
2192
2810
  if (existing.getAttribute("title") !== tooltip) existing.setAttribute("title", tooltip);
2811
+ applyProgress(existing, progress);
2193
2812
  return;
2194
2813
  }
2195
2814
  const slot = row.firstElementChild;
@@ -2201,66 +2820,293 @@ function mountSessionPresence(options) {
2201
2820
  badge.setAttribute("role", "img");
2202
2821
  badge.setAttribute("aria-label", aria);
2203
2822
  badge.setAttribute("title", tooltip);
2204
- badge.innerHTML = CLOCK_SVG;
2823
+ badge.innerHTML = getClockSvg();
2824
+ applyProgress(badge, progress);
2205
2825
  if (beside) slot.after(badge);
2206
2826
  else slot.append(badge);
2207
2827
  }
2208
- const unsubscribeList = sessions.list.subscribe(scheduleScan);
2828
+ function applyProgress(badge, ratio) {
2829
+ const arc = badge.querySelector(".ss-clock-prog");
2830
+ if (arc === null) return;
2831
+ if (ratio === void 0) {
2832
+ arc.style.display = "none";
2833
+ return;
2834
+ }
2835
+ if (arc.style.display === "none") arc.style.display = "";
2836
+ arc.style.strokeDashoffset = String(CLOCK_FACE_CIRCUMFERENCE * (1 - ratio));
2837
+ }
2838
+ function findHoverCard() {
2839
+ for (const card of Array.from(document.body.children)) {
2840
+ if (!(card instanceof HTMLElement)) continue;
2841
+ const statusHost = card.firstElementChild;
2842
+ if (!(statusHost instanceof HTMLElement)) continue;
2843
+ const hasStatusRow = Array.from(statusHost.children).some((child) => {
2844
+ const dot = child.firstElementChild;
2845
+ return child.children.length >= 2 && dot !== null && dot.tagName === "SPAN" && dot.getAttribute("aria-hidden") === "true";
2846
+ });
2847
+ if (!hasStatusRow) continue;
2848
+ const sessionId = sessionIdOfHoverCard(card);
2849
+ if (sessionId === void 0) continue;
2850
+ return { card, statusHost, sessionId };
2851
+ }
2852
+ return null;
2853
+ }
2854
+ function applyHoverCard(now, dict) {
2855
+ const found = findHoverCard();
2856
+ if (found === null) return;
2857
+ const { statusHost, sessionId } = found;
2858
+ const existing = statusHost.querySelector(`:scope > .${HOVER_ROW_CLASS}`);
2859
+ const entry = index.get(sessionId);
2860
+ if (entry === void 0) {
2861
+ existing?.remove();
2862
+ return;
2863
+ }
2864
+ const { label } = hoverScheduleStatus(entry, now, labelsFor(dict), dict, formatHhmm2, formatDate);
2865
+ const state = badgeStateFor(entry.nextAt, now);
2866
+ if (existing !== null) {
2867
+ const text2 = existing.lastElementChild;
2868
+ if (text2 !== null && text2.textContent !== label) text2.textContent = label;
2869
+ if (existing.dataset.state !== state) existing.dataset.state = state;
2870
+ return;
2871
+ }
2872
+ const row = document.createElement("div");
2873
+ row.className = HOVER_ROW_CLASS;
2874
+ row.dataset.state = state;
2875
+ const dot = document.createElement("span");
2876
+ dot.setAttribute("aria-hidden", "true");
2877
+ dot.className = "ss-hover-status-dot";
2878
+ const text = document.createElement("span");
2879
+ text.textContent = label;
2880
+ row.append(dot, text);
2881
+ statusHost.append(row);
2882
+ }
2883
+ const unsubscribeSummary = summary.subscribe(scheduleScan);
2209
2884
  const unsubscribeLocale = locale?.subscribe(scheduleScan);
2210
2885
  const observer = new MutationObserver(scheduleScan);
2211
2886
  observer.observe(document.body, { childList: true, subtree: true });
2212
- const refreshNow = () => {
2213
- if (disposed) return;
2214
- try {
2215
- void sessions.refresh().catch(() => void 0);
2216
- } catch {
2217
- }
2218
- };
2219
- const onVisible = () => {
2220
- if (document.visibilityState === "visible") {
2221
- refreshNow();
2222
- scheduleScan();
2223
- }
2224
- };
2225
- document.addEventListener("visibilitychange", onVisible);
2226
- window.addEventListener("online", onVisible);
2227
2887
  const stateTick = setInterval(scheduleScan, STATE_TICK_MS);
2228
- const refreshTick = setInterval(() => {
2229
- if (document.visibilityState === "visible") refreshNow();
2230
- }, REFRESH_INTERVAL_MS);
2231
- refreshNow();
2232
2888
  scheduleScan();
2233
2889
  return () => {
2234
2890
  disposed = true;
2235
2891
  if (scanTimer !== void 0) clearTimeout(scanTimer);
2236
2892
  clearInterval(stateTick);
2237
- clearInterval(refreshTick);
2238
2893
  observer.disconnect();
2239
- unsubscribeList();
2894
+ unsubscribeSummary();
2240
2895
  unsubscribeLocale?.();
2241
- document.removeEventListener("visibilitychange", onVisible);
2242
- window.removeEventListener("online", onVisible);
2243
2896
  for (const badge of Array.from(document.querySelectorAll(`.${BADGE_CLASS}`))) badge.remove();
2897
+ for (const row of Array.from(document.querySelectorAll(`.${HOVER_ROW_CLASS}`))) row.remove();
2244
2898
  };
2245
2899
  }
2246
2900
 
2901
+ // src/schedule-summary.ts
2902
+ var SCHEDULE_PROJECTION_KEY = "userSchedules";
2903
+ function schedulesOfProjection(projectionValues) {
2904
+ const value = projectionValues?.[SCHEDULE_PROJECTION_KEY];
2905
+ if (typeof value !== "object" || value === null) return void 0;
2906
+ const schedules = value.schedules;
2907
+ return Array.isArray(schedules) ? schedules : void 0;
2908
+ }
2909
+ function buildScheduleSummary(source, now) {
2910
+ const summary = /* @__PURE__ */ new Map();
2911
+ for (const [sessionId, row] of Object.entries(source.byId)) {
2912
+ if (row === void 0) continue;
2913
+ const entry = summarizeSchedules(schedulesOfProjection(row.projectionValues));
2914
+ if (entry.count === 0) continue;
2915
+ summary.set(sessionId, { ...entry, state: badgeStateFor(entry.nextAt, now) });
2916
+ }
2917
+ return summary;
2918
+ }
2919
+ function sameScheduleSummary(a, b) {
2920
+ if (a === b) return true;
2921
+ if (a.size !== b.size) return false;
2922
+ for (const [sessionId, left] of a) {
2923
+ const right = b.get(sessionId);
2924
+ if (right === void 0) return false;
2925
+ if (left.count !== right.count || left.pausedCount !== right.pausedCount || left.nextAt !== right.nextAt || left.progressFrom !== right.progressFrom || left.state !== right.state) {
2926
+ return false;
2927
+ }
2928
+ }
2929
+ return true;
2930
+ }
2931
+ var STATE_RANK = { scheduled: 0, urgent: 1, overdue: 2 };
2932
+ function summarizeScheduleGroup(summary, sessionIds) {
2933
+ let sessions = 0;
2934
+ let count = 0;
2935
+ let pausedCount = 0;
2936
+ let nextAt;
2937
+ let state;
2938
+ for (const sessionId of sessionIds) {
2939
+ const entry = summary.get(sessionId);
2940
+ if (entry === void 0) continue;
2941
+ sessions += 1;
2942
+ count += entry.count;
2943
+ pausedCount += entry.pausedCount;
2944
+ if (entry.nextAt !== void 0 && (nextAt === void 0 || entry.nextAt < nextAt)) nextAt = entry.nextAt;
2945
+ if (state === void 0 || STATE_RANK[entry.state] > STATE_RANK[state]) state = entry.state;
2946
+ }
2947
+ return nextAt === void 0 ? { sessions, count, pausedCount, state } : { sessions, count, pausedCount, nextAt, state };
2948
+ }
2949
+
2950
+ // src/schedule-summary-store.ts
2951
+ var SUMMARY_STATE_TICK_MS = 3e4;
2952
+ var SUMMARY_REFRESH_INTERVAL_MS = 6e4;
2953
+ function documentOf() {
2954
+ const doc = globalThis.document;
2955
+ return typeof doc === "object" && doc !== null ? doc : void 0;
2956
+ }
2957
+ function createScheduleSummaryStore(sessions, options = {}) {
2958
+ const now = options.now ?? Date.now;
2959
+ const stateTickMs = options.stateTickMs ?? SUMMARY_STATE_TICK_MS;
2960
+ const refreshIntervalMs = options.refreshIntervalMs ?? SUMMARY_REFRESH_INTERVAL_MS;
2961
+ const autoRefresh = options.autoRefresh ?? true;
2962
+ const canRefresh = options.canRefresh ?? (() => {
2963
+ const doc2 = documentOf();
2964
+ return doc2?.visibilityState === void 0 || doc2.visibilityState === "visible";
2965
+ });
2966
+ const listeners = /* @__PURE__ */ new Set();
2967
+ let snapshot = /* @__PURE__ */ new Map();
2968
+ let disposed = false;
2969
+ const notify = () => {
2970
+ for (const listener of [...listeners]) {
2971
+ try {
2972
+ listener();
2973
+ } catch {
2974
+ }
2975
+ }
2976
+ };
2977
+ const reload = () => {
2978
+ if (disposed) return;
2979
+ const next = buildScheduleSummary(sessions.list.getSnapshot(), now());
2980
+ if (sameScheduleSummary(snapshot, next)) return;
2981
+ snapshot = next;
2982
+ notify();
2983
+ };
2984
+ const unsubscribeList = sessions.list.subscribe(reload);
2985
+ const stateTick = setInterval(reload, stateTickMs);
2986
+ let refreshTick;
2987
+ let onVisible;
2988
+ const doc = documentOf();
2989
+ const target = globalThis;
2990
+ const refreshNow = () => {
2991
+ if (disposed || !canRefresh()) return;
2992
+ try {
2993
+ void sessions.refresh().catch(() => void 0);
2994
+ } catch {
2995
+ }
2996
+ };
2997
+ if (autoRefresh) {
2998
+ onVisible = () => {
2999
+ if (!disposed && canRefresh()) {
3000
+ refreshNow();
3001
+ reload();
3002
+ }
3003
+ };
3004
+ refreshTick = setInterval(() => {
3005
+ if (canRefresh()) refreshNow();
3006
+ }, refreshIntervalMs);
3007
+ doc?.addEventListener?.("visibilitychange", onVisible);
3008
+ target.addEventListener?.("online", onVisible);
3009
+ refreshNow();
3010
+ }
3011
+ reload();
3012
+ const dispose = () => {
3013
+ if (disposed) return;
3014
+ disposed = true;
3015
+ clearInterval(stateTick);
3016
+ if (refreshTick !== void 0) clearInterval(refreshTick);
3017
+ if (onVisible !== void 0) {
3018
+ doc?.removeEventListener?.("visibilitychange", onVisible);
3019
+ target.removeEventListener?.("online", onVisible);
3020
+ }
3021
+ unsubscribeList();
3022
+ listeners.clear();
3023
+ };
3024
+ return {
3025
+ getSnapshot: () => snapshot,
3026
+ subscribe: (listener) => {
3027
+ listeners.add(listener);
3028
+ return () => {
3029
+ listeners.delete(listener);
3030
+ };
3031
+ },
3032
+ reload,
3033
+ dispose
3034
+ };
3035
+ }
3036
+ var activeStore;
3037
+ var registryListeners = /* @__PURE__ */ new Set();
3038
+ function setActiveScheduleSummaryStore(store) {
3039
+ if (activeStore === store) return;
3040
+ activeStore = store;
3041
+ for (const listener of [...registryListeners]) {
3042
+ try {
3043
+ listener();
3044
+ } catch {
3045
+ }
3046
+ }
3047
+ }
3048
+ function getScheduleSummaryStore() {
3049
+ return activeStore;
3050
+ }
3051
+ function subscribeScheduleSummaryStore(listener) {
3052
+ registryListeners.add(listener);
3053
+ return () => {
3054
+ registryListeners.delete(listener);
3055
+ };
3056
+ }
3057
+
3058
+ // src/client/useScheduleSummary.ts
3059
+ var import_react9 = require("react");
3060
+ var EMPTY_SUMMARY = /* @__PURE__ */ new Map();
3061
+ var noopSubscribe2 = () => () => void 0;
3062
+ var emptySnapshot = () => EMPTY_SUMMARY;
3063
+ var missingSnapshot = () => void 0;
3064
+ function useScheduleSummary(store) {
3065
+ const registered = (0, import_react9.useSyncExternalStore)(subscribeScheduleSummaryStore, getScheduleSummaryStore, missingSnapshot);
3066
+ const target = store ?? registered;
3067
+ const subscribe = (0, import_react9.useMemo)(
3068
+ () => target === void 0 ? noopSubscribe2 : (listener) => target.subscribe(listener),
3069
+ [target]
3070
+ );
3071
+ const getSnapshot = (0, import_react9.useMemo)(
3072
+ () => target === void 0 ? emptySnapshot : () => target.getSnapshot(),
3073
+ [target]
3074
+ );
3075
+ return (0, import_react9.useSyncExternalStore)(subscribe, getSnapshot, emptySnapshot);
3076
+ }
3077
+
2247
3078
  // src/client/index.tsx
2248
3079
  var INPUT_RIGHT_SLOT = "conversation.input.right";
2249
- var inject = ["slots", "sessions", "conversation", "settingsScope", "locale"];
3080
+ var inject = ["slots", "sessions", "conversation", "locale"];
2250
3081
  var NS = "settings.plugins.later";
2251
3082
  var SETTINGS_NS = "dsh-later";
3083
+ var ENTRY_ID = "later";
2252
3084
  function apply(ctx) {
2253
3085
  const slots = ctx.get("slots");
2254
3086
  const sessions = ctx.get("sessions");
2255
- const settingsScope = ctx.get("settingsScope");
2256
3087
  const locale = ctx.get("locale");
2257
3088
  if (slots === void 0 || sessions === void 0) return;
2258
3089
  ctx.effect(() => injectStyles(), "dsh-later: styles");
2259
- ctx.effect(() => mountReminderToastHost(), "dsh-later: toast host");
3090
+ let detectedVersion = "classic";
3091
+ let getClockIconStyle = () => "auto";
3092
+ const summary = createScheduleSummaryStore(sessions);
3093
+ setActiveScheduleSummaryStore(summary);
3094
+ ctx.effect(
3095
+ () => () => {
3096
+ if (getScheduleSummaryStore() === summary) setActiveScheduleSummaryStore(void 0);
3097
+ summary.dispose();
3098
+ },
3099
+ "dsh-later: schedule summary"
3100
+ );
2260
3101
  ctx.effect(
2261
3102
  () => mountSessionPresence({
2262
- sessions,
2263
- ...locale === void 0 ? {} : { locale }
3103
+ summary,
3104
+ ...locale === void 0 ? {} : { locale },
3105
+ getClockIconStyle: () => {
3106
+ const style = getClockIconStyle();
3107
+ if (style === "auto") return detectedVersion;
3108
+ return style;
3109
+ }
2264
3110
  }),
2265
3111
  "dsh-later: presence"
2266
3112
  );
@@ -2273,10 +3119,11 @@ function apply(ctx) {
2273
3119
  expand: "\u5C55\u5F00\u8BBE\u7F6E",
2274
3120
  collapse: "\u6536\u8D77\u8BBE\u7F6E",
2275
3121
  readOnly: "\u672C\u90E8\u7F72\u7684\u8BBE\u7F6E\u4E3A\u53EA\u8BFB\u3002",
3122
+ sectionDisplay: "\u663E\u793A\u8BBE\u7F6E",
3123
+ sectionTime: "\u65F6\u95F4\u8BBE\u7F6E",
3124
+ sectionDelivery: "\u6295\u9012\u8BBE\u7F6E",
2276
3125
  showButtonLabel: "\u663E\u793A\u5B9A\u65F6\u6309\u94AE",
2277
3126
  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",
2278
- optionOn: "\u663E\u793A",
2279
- optionOff: "\u9690\u85CF",
2280
3127
  maxSchedulesLabel: "\u5355\u4F1A\u8BDD\u4EFB\u52A1\u4E0A\u9650",
2281
3128
  maxSchedulesHint: "\u5355\u4E2A\u4F1A\u8BDD\u5185\u5141\u8BB8\u521B\u5EFA\u7684\u6700\u5927\u5B9A\u65F6\u4EFB\u52A1\u6570\u91CF\u3002",
2282
3129
  smartWindowHint: "\u7528\u4E8E\u300C\u5DE5\u4F5C\u65F6\u95F4\u300D\u82AF\u7247\u4E0E\u667A\u80FD\u6A21\u5F0F\u81EA\u52A8\u6392\u671F\u3002",
@@ -2285,6 +3132,24 @@ function apply(ctx) {
2285
3132
  lunchStartLabel: "\u5348\u4F11\u5F00\u59CB",
2286
3133
  lunchEndLabel: "\u5348\u4F11\u7ED3\u675F",
2287
3134
  eveningEndLabel: "\u591C\u95F4\u9759\u9ED8\u8D77\u70B9",
3135
+ steerDeliveryLabel: "\u63D2\u8BDD\u6295\u9012\u65B9\u5F0F",
3136
+ steerDeliveryHint: "\u300C\u63D2\u8BDD\u53D1\u9001\u300D\u628A\u63D0\u9192\u5185\u5BB9\u63A8\u7ED9\u4F1A\u8BDD\u65F6\u8FDB\u5165\u7684\u961F\u5217\u3002",
3137
+ steerDeliveryOption_followup: "\u72EC\u7ACB\u6210\u4E00\u8F6E\uFF08\u63A8\u8350\uFF09",
3138
+ steerDeliveryOption_steer: "\u63D2\u5165\u5F53\u524D\u56DE\u5408\uFF08\u66F4\u5FEB\uFF09",
3139
+ confirmDeliveryLabel: "\u6295\u9012\u786E\u8BA4",
3140
+ confirmDeliveryHint: "\u6295\u9012\u540E\u6838\u5BF9\u4F1A\u8BDD\u65E5\u5FD7\uFF0C\u786E\u8BA4\u6D88\u606F\u771F\u6B63\u8FDB\u5165\u8BF7\u6C42\u3002\u5173\u95ED\u5219\u4E0D\u518D\u6838\u5BF9\uFF0C\u4E5F\u4E0D\u4FDD\u8BC1\u9001\u8FBE\u3002",
3141
+ onUnconfirmedLabel: "\u672A\u786E\u8BA4\u65F6",
3142
+ onUnconfirmedHint: "\u6295\u9012\u672A\u80FD\u786E\u8BA4\u65F6\u7684\u5904\u7406\u65B9\u5F0F\u3002",
3143
+ onUnconfirmedOption_keep: "\u4FDD\u7559\u6761\u76EE\u53EF\u91CD\u8BD5\uFF08\u63A8\u8350\uFF09",
3144
+ onUnconfirmedOption_discard: "\u4E22\u5F03",
3145
+ clockIconStyleLabel: "\u65F6\u949F\u56FE\u6807\u98CE\u683C",
3146
+ clockIconStyleHint: "\u4FA7\u680F\u4F1A\u8BDD\u884C\u5B9A\u65F6\u72B6\u6001\u56FE\u6807\u7684\u663E\u793A\u98CE\u683C\u3002",
3147
+ clockIconStyleOption_auto: "\u81EA\u52A8\uFF08\u63A8\u8350\uFF09",
3148
+ clockIconStyleOption_modern: "\u65B0\u7248\u63CF\u8FB9\u98CE\u683C",
3149
+ clockIconStyleOption_classic: "\u65E7\u7248\u70B9\u9635\u98CE\u683C",
3150
+ steerRiskGuarded: "\u26A0 \u649E\u4E0A\u56DE\u5408\u542F\u52A8\u65F6\u53EF\u80FD\u88AB\u541E\u6389\uFF1B\u5DF2\u5F00\u542F\u6295\u9012\u786E\u8BA4\uFF0C\u672A\u9001\u8FBE\u4F1A\u4FDD\u7559\u6761\u76EE\u5E76\u53EF\u91CD\u8BD5\u3002",
3151
+ steerRiskUnguarded: "\u26A0 \u649E\u4E0A\u56DE\u5408\u542F\u52A8\u65F6\u53EF\u80FD\u88AB\u541E\u6389\uFF0C\u4E14\u4E0D\u4F1A\u4FDD\u7559\u6761\u76EE\uFF08\u6295\u9012\u786E\u8BA4\u5DF2\u5173\u95ED\uFF09\u3002",
3152
+ discardRisk: "\u26A0 \u672A\u786E\u8BA4\u7684\u63D0\u9192\u4F1A\u88AB\u79FB\u51FA\u5217\u8868 \u2014\u2014 \u9759\u9ED8\u4E22\u5931\u5C06\u91CD\u65B0\u53D8\u5F97\u53EF\u80FD\u3002",
2288
3153
  overriddenLabel: "\u5DF2\u8986\u76D6",
2289
3154
  resetLabel: "\u91CD\u7F6E",
2290
3155
  invalidLabel: "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u6570\u5B57\u3002",
@@ -2303,10 +3168,11 @@ function apply(ctx) {
2303
3168
  expand: "Show settings",
2304
3169
  collapse: "Hide settings",
2305
3170
  readOnly: "Settings for this deployment are read-only.",
3171
+ sectionDisplay: "Display",
3172
+ sectionTime: "Time windows",
3173
+ sectionDelivery: "Delivery",
2306
3174
  showButtonLabel: "Show schedule button",
2307
3175
  showButtonHint: "Hide the clock button on the input bar. Existing reminders keep firing and stay visible in the dock below the composer.",
2308
- optionOn: "Show",
2309
- optionOff: "Hide",
2310
3176
  maxSchedulesLabel: "Max schedules per session",
2311
3177
  maxSchedulesHint: "Maximum number of scheduled reminders allowed per session.",
2312
3178
  smartWindowHint: "Used by the Work-hours chip and smart auto-scheduling.",
@@ -2315,6 +3181,24 @@ function apply(ctx) {
2315
3181
  lunchStartLabel: "Lunch break start",
2316
3182
  lunchEndLabel: "Lunch break end",
2317
3183
  eveningEndLabel: "Night quiet starts at",
3184
+ steerDeliveryLabel: "Interject delivery",
3185
+ steerDeliveryHint: 'Which queue the reminder content enters when you press "Send interjection".',
3186
+ steerDeliveryOption_followup: "Own turn (recommended)",
3187
+ steerDeliveryOption_steer: "Current turn (faster)",
3188
+ confirmDeliveryLabel: "Confirm delivery",
3189
+ confirmDeliveryHint: "After sending, check the session log to confirm the message actually entered a request. Turning this off skips the check and no longer guarantees delivery.",
3190
+ onUnconfirmedLabel: "When unconfirmed",
3191
+ onUnconfirmedHint: "What to do when delivery cannot be confirmed.",
3192
+ onUnconfirmedOption_keep: "Keep for retry (recommended)",
3193
+ onUnconfirmedOption_discard: "Discard",
3194
+ clockIconStyleLabel: "Clock icon style",
3195
+ clockIconStyleHint: "Display style of the schedule status icon in the sidebar.",
3196
+ clockIconStyleOption_auto: "Auto (recommended)",
3197
+ clockIconStyleOption_modern: "Modern stroke style",
3198
+ clockIconStyleOption_classic: "Classic dot-matrix style",
3199
+ steerRiskGuarded: "\u26A0 May be swallowed when it collides with turn start; delivery confirmation is on, so an undelivered reminder is kept and can be retried.",
3200
+ steerRiskUnguarded: "\u26A0 May be swallowed when it collides with turn start, and the reminder will NOT be kept (delivery confirmation is off).",
3201
+ discardRisk: "\u26A0 Unconfirmed reminders are removed from the list \u2014 silent loss becomes possible again.",
2318
3202
  overriddenLabel: "Overridden",
2319
3203
  resetLabel: "Reset",
2320
3204
  invalidLabel: "Please enter a valid number.",
@@ -2331,27 +3215,14 @@ function apply(ctx) {
2331
3215
  const callCommand = async (sessionId, line) => {
2332
3216
  const actx = sessions.scope(sessionId);
2333
3217
  const face = actx === void 0 ? void 0 : sessions.sessionOf(actx);
2334
- if (face === void 0) return false;
3218
+ if (face === void 0) return { matched: false };
2335
3219
  try {
2336
3220
  const result = await face.command(line);
2337
- return result?.ok === true && result.value?.matched === true;
3221
+ return { matched: result?.ok === true && result.value?.matched === true };
2338
3222
  } catch {
2339
- return false;
3223
+ return { matched: false };
2340
3224
  }
2341
3225
  };
2342
- const schedulerScope = settingsScope === void 0 ? void 0 : settingsScope.bind({ namespace: SETTINGS_NS });
2343
- ctx.slots.inject(
2344
- INPUT_RIGHT_SLOT,
2345
- () => ctx.slots.register(
2346
- {
2347
- name: INPUT_RIGHT_SLOT,
2348
- id: "later",
2349
- order: 50,
2350
- inject: () => ({ callCommand, locale, schedulerScope })
2351
- },
2352
- SchedButton
2353
- )
2354
- );
2355
3226
  ctx.slots.inject(
2356
3227
  "conversation.input.dock",
2357
3228
  () => ctx.slots.register(
@@ -2364,19 +3235,74 @@ function apply(ctx) {
2364
3235
  ScheduleDock
2365
3236
  )
2366
3237
  );
2367
- if (settingsScope !== void 0 && locale !== void 0) {
2368
- ctx.slots.inject("settings.plugin.item", function* () {
2369
- yield ctx.slots.register({
2370
- name: "settings.plugin.item",
2371
- key: SETTINGS_NS,
2372
- locale: NS,
2373
- inject: () => ({
2374
- scope: settingsScope.bind({ namespace: SETTINGS_NS }),
2375
- t: locale.bind(NS)
2376
- })
2377
- }, SchedulerSettingsCard);
2378
- });
2379
- }
3238
+ let composerMounted = false;
3239
+ const mountComposer = (scope) => {
3240
+ if (composerMounted) return;
3241
+ composerMounted = true;
3242
+ ctx.slots.inject(
3243
+ INPUT_RIGHT_SLOT,
3244
+ () => ctx.slots.register(
3245
+ {
3246
+ name: INPUT_RIGHT_SLOT,
3247
+ id: "later",
3248
+ order: 50,
3249
+ inject: () => ({ callCommand, locale, schedulerScope: scope })
3250
+ },
3251
+ SchedButton
3252
+ )
3253
+ );
3254
+ };
3255
+ const cardT = locale === void 0 ? void 0 : locale.bind(NS);
3256
+ const cardDeclaration = (slot, scope) => ({
3257
+ name: slot,
3258
+ key: SETTINGS_NS,
3259
+ locale: NS,
3260
+ inject: () => ({ scope, t: cardT })
3261
+ });
3262
+ ctx.inject(["settingsScope"], () => {
3263
+ const binder = ctx.get("settingsScope");
3264
+ if (binder === void 0) return;
3265
+ detectedVersion = "classic";
3266
+ const scope = binder.bind({ namespace: SETTINGS_NS });
3267
+ getClockIconStyle = () => {
3268
+ const snap = scope.getSnapshot();
3269
+ if (snap.status !== "ready") return "auto";
3270
+ const value = snap.value ?? {};
3271
+ const style = value["clockIconStyle"];
3272
+ return style === "modern" || style === "classic" ? style : "auto";
3273
+ };
3274
+ mountComposer(scope);
3275
+ if (cardT === void 0) return;
3276
+ ctx.slots.inject(
3277
+ "settings.plugin.item",
3278
+ () => ctx.slots.register(cardDeclaration("settings.plugin.item", scope), SchedulerSettingsCard)
3279
+ );
3280
+ });
3281
+ ctx.inject(["configForms"], () => {
3282
+ const forms = ctx.get("configForms");
3283
+ if (forms === void 0 || typeof forms.get !== "function" || typeof forms.whileServed !== "function") return;
3284
+ detectedVersion = "modern";
3285
+ const scope = forms.get(ENTRY_ID);
3286
+ getClockIconStyle = () => {
3287
+ const snap = scope.getSnapshot();
3288
+ if (snap.status !== "ready") return "auto";
3289
+ const value = snap.value ?? {};
3290
+ const style = value["clockIconStyle"];
3291
+ return style === "modern" || style === "classic" ? style : "auto";
3292
+ };
3293
+ mountComposer(scope);
3294
+ if (cardT === void 0) return;
3295
+ ctx.effect(
3296
+ () => forms.whileServed(
3297
+ [ENTRY_ID],
3298
+ () => ctx.slots.inject(
3299
+ "plugins.bundle.config",
3300
+ () => ctx.slots.register(cardDeclaration("plugins.bundle.config", scope), SchedulerSettingsCard)
3301
+ )
3302
+ ),
3303
+ "dsh-later: plugins-page card"
3304
+ );
3305
+ });
2380
3306
  }
2381
3307
 
2382
3308
  return module.exports;