dsh-later 1.0.0 → 1.1.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
@@ -131,8 +131,51 @@ var COMPONENTS = [
131
131
  ".ss-dock-bar-fill {",
132
132
  " position: relative; z-index: 1;",
133
133
  " height: 100%; border-radius: 999px; background: var(--dsw-alias-brand-primary);",
134
- " transition: width 1s linear;",
134
+ /* 活动期的推进由 CSS 动画驱动(见 ScheduleDock 的 fillStyle):
135
+ 旧实现是「每秒 tick 改一次宽度 + transition 补间」,1 分钟任务每秒跳约 8px,
136
+ 肉眼可见锯齿。改为动画后由合成器逐帧插值,真 60fps 且零重渲染。
137
+ 这里**不保留** transition: width —— 它与动画叠加会造成双重补间、反而更抖。 */
138
+ " /* \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",
139
+ " \u907F\u514D\u6682\u505C\u524D\u540E\u4FDD\u5E95\u9608\u503C\u4E0D\u4E00\u81F4\u5BFC\u81F4\u6761\u957F\u8DF3\u53D8\u3002 */",
140
+ " min-width: 10px;",
135
141
  "}",
142
+ "/* \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",
143
+ " \u53C2\u6570\u7531 JS \u6CE8\u5165 --ss-bar-duration / --ss-bar-delay\uFF1A",
144
+ " 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",
145
+ " 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",
146
+ " JS \u4FA7\u53EA\u4F20\u53D8\u91CF\u3001\u4E0D\u5199 animationName \u7B80\u5199\uFF0C\u907F\u514D\u8986\u76D6\u8FD9\u91CC\u7684\u58F0\u660E\u3002",
147
+ " \u6CE8\u610F\u6B64\u5904**\u4E0D\u5E26** :not(.ss-paused)\uFF1A\u6682\u505C\u6001\u53E6\u6709 animation: none \u8986\u76D6\u3002 */",
148
+ ".ss-dock-bar-fill {",
149
+ " animation-name: ss-dock-bar-progress;",
150
+ " animation-duration: var(--ss-bar-duration, 3600s);",
151
+ " animation-delay: var(--ss-bar-delay, 0ms);",
152
+ " animation-timing-function: linear;",
153
+ " animation-fill-mode: forwards;",
154
+ " animation-iteration-count: 1;",
155
+ "}",
156
+ "@keyframes ss-dock-bar-progress { from { width: 0%; } to { width: 100%; } }",
157
+ "@media (prefers-reduced-motion: reduce) {",
158
+ " /* \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",
159
+ " \u6545\u7531 JS \u4FA7\u6539\u8D70\u9759\u6001 width \u8DEF\u5F84\uFF08\u89C1 ScheduleDock \u7684 prefersReducedMotion\uFF09\u3002 */",
160
+ " .ss-dock-bar-fill { animation: none !important; }",
161
+ "}",
162
+ "/* \u6682\u505C\u6001\uFF08P1\uFF1A\u4E0D\u989D\u5916\u52A0\u6837\u5F0F\uFF09\u3002",
163
+ " \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",
164
+ " \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",
165
+ ' \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',
166
+ " \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",
167
+ " \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",
168
+ " \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 */",
169
+ ".ss-dock-row.ss-paused .ss-dock-bar-fill {",
170
+ " animation: none;",
171
+ "}",
172
+ "@media (prefers-reduced-motion: reduce) {",
173
+ " .ss-dock-row:not(.ss-paused) .ss-dock-bar-fill { animation: none; background: var(--dsw-alias-brand-primary); }",
174
+ "}",
175
+ ".ss-dock-row.ss-paused .ss-dock-row-countdown { color: var(--dsw-alias-label-tertiary); }",
176
+ ".ss-dock-row.ss-paused .ss-dock-row-time,",
177
+ ".ss-dock-row.ss-paused .ss-dock-row-prompt { color: var(--dsw-alias-label-secondary); }",
178
+ ".ss-dock-action.ss-paused-active { color: var(--dsw-alias-state-success-primary); }",
136
179
  "/* \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
180
  ".ss-dock-bar-divider {",
138
181
  " position: absolute; inset: 0; pointer-events: none;",
@@ -152,6 +195,29 @@ var COMPONENTS = [
152
195
  ".ss-dock-steer-err {",
153
196
  " color: var(--dsw-alias-state-warn-secondary); font-size: 12px; line-height: 16px;",
154
197
  "}",
198
+ "/*",
199
+ " * \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",
200
+ ' * \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',
201
+ " * \u8BED\u6C14\u5E94\u662F\u63D0\u793A\u800C\u975E\u62A5\u9519\uFF0C\u6545\u7ED9\u6D45\u5E95 + \u8FB9\u6846 + \u53EF\u70B9\u7684\u91CD\u8BD5\u3002",
202
+ " */",
203
+ ".ss-dock-steer-warn {",
204
+ " display: flex; align-items: center; gap: 8px; flex-wrap: wrap;",
205
+ " margin-top: 4px; padding: 4px 8px; border-radius: 6px;",
206
+ " font-size: 12px; line-height: 16px;",
207
+ " color: var(--dsw-alias-state-warn-secondary);",
208
+ " background: color-mix(in srgb, var(--dsw-alias-state-warn-secondary) 12%, transparent);",
209
+ " border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-secondary) 32%, transparent);",
210
+ "}",
211
+ ".ss-dock-steer-retry {",
212
+ " margin-left: auto; padding: 1px 8px; border-radius: 5px; cursor: pointer;",
213
+ " font: inherit; font-size: 12px;",
214
+ " color: var(--dsw-alias-state-warn-secondary);",
215
+ " background: color-mix(in srgb, var(--dsw-alias-state-warn-secondary) 18%, transparent);",
216
+ " border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-secondary) 38%, transparent);",
217
+ "}",
218
+ ".ss-dock-steer-retry:hover {",
219
+ " background: color-mix(in srgb, var(--dsw-alias-state-warn-secondary) 28%, transparent);",
220
+ "}",
155
221
  "/* \u884C\u5185\u7F16\u8F91\uFF08QueueDock .editor \u540C\u6B3E\u8F93\u5165\u6846\uFF09\u3002 */",
156
222
  ".ss-dock-edit-input {",
157
223
  " box-sizing: border-box; flex: auto; min-width: 0; height: 28px; padding: 0 8px;",
@@ -170,23 +236,6 @@ var COMPONENTS = [
170
236
  " flex-basis: 100%; color: var(--dsw-alias-state-error-secondary); font-size: 12px; line-height: 16px;",
171
237
  "}",
172
238
  ".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
239
  "",
191
240
  "/* ==================== \u9762\u677F ==================== */",
192
241
  "/* \u5BF9\u9F50\u5B98\u65B9 popover panel\uFF1Az-index 100\u3001border-inverted\u3001radius 12\u3001\u5B57\u53F7 12\u3001secondary \u6587\u5B57 */",
@@ -253,23 +302,22 @@ var COMPONENTS = [
253
302
  ".ss-tasklist-head { margin-top: 10px; }",
254
303
  "",
255
304
  "/* ==================== \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 */",
305
+ "/* \u5BF9\u9F50\u5B98\u65B9 fields.module.css\uFF1Acolumn \u5E03\u5C40\u3001label \u5728\u4E0A 13px/500\uFF0C\u5B57\u6BB5\u95F4\u65E0\u5206\u9694\u7EBF */",
257
306
  ".ss-field {",
258
307
  " display: flex; flex-direction: column; gap: 6px; padding: 12px 0;",
259
308
  "}",
260
- ".ss-field + .ss-field { border-top: 1px solid var(--dsw-alias-border-l2); }",
261
309
  ".ss-input {",
262
- " height: 34px; padding: 0 12px;",
263
- " border: 1px solid var(--dsw-alias-border-l2); border-radius: 8px;",
310
+ " min-height: 36px; padding: 0 12px;",
311
+ " border: .5px solid var(--dsw-alias-border-l4); border-radius: var(--dsw-radius-md);",
264
312
  " 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);",
313
+ " font: inherit; font-size: 13px; line-height: 1.5;",
266
314
  " flex: 1; min-width: 0; width: 100%; box-sizing: border-box;",
267
315
  "}",
268
316
  ".ss-input:focus-visible {",
269
- " border-color: var(--dsw-alias-brand-primary); outline: none;",
317
+ " outline: none; border-color: var(--dsw-alias-state-business-primary);",
270
318
  "}",
271
319
  ".ss-input:disabled { color: var(--dsw-alias-label-tertiary); cursor: default; }",
272
- ".ss-input.ss-inputInvalid { border-color: var(--dsw-alias-label-error); }",
320
+ ".ss-input.ss-inputInvalid { border-color: var(--dsw-alias-state-error-primary); }",
273
321
  "",
274
322
  "/* ==================== \u4EFB\u52A1\u5217\u8868 ==================== */",
275
323
  ".ss-tasks { max-height: 160px; overflow-y: auto; margin-bottom: 8px; }",
@@ -362,46 +410,147 @@ var COMPONENTS = [
362
410
  "/* \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
411
  ".ss-presence { display: inline-flex; flex: none; color: #8b5cf6; }",
364
412
  ".ss-presence-beside { margin-left: 4px; }",
413
+ "",
414
+ "/* \u2500\u2500 \u65E7\u7248\u70B9\u9635\u65F6\u949F\uFF08classic\uFF09 \u2500\u2500 */",
365
415
  ".ss-presence rect { fill: currentColor; }",
366
416
  ".ss-presence .ss-presence-ring { opacity: 0.8; animation: ss-presence-breathe 2.4s var(--ds-ease-in-out, ease-in-out) infinite; }",
367
417
  ".ss-presence .ss-presence-hand { opacity: 1; }",
368
- '.ss-presence[data-state="urgent"] { color: var(--dsw-alias-state-warn-secondary); }',
369
418
  '.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
419
  '.ss-presence[data-state="overdue"] .ss-presence-ring { animation: none; }',
420
+ "",
421
+ "/* \u65B0\u7248\u63CF\u8FB9\u65F6\u949F\uFF08modern\uFF09\u2014 \u5BF9\u9F50 DSH \u5B98\u65B9 spinner \u6837\u5F0F \u2500\u2500 */",
422
+ ".ss-presence .ss-clock-face {",
423
+ " fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round;",
424
+ " opacity: 0.25; animation: ss-clock-breathe 2.4s var(--ds-ease-in-out, ease-in-out) infinite;",
425
+ "}",
426
+ ".ss-presence .ss-clock-hand { stroke: currentColor; stroke-width: 2; stroke-linecap: round; }",
427
+ ".ss-presence .ss-clock-hand-h { opacity: 1; }",
428
+ ".ss-presence .ss-clock-hand-m { opacity: 0.85; }",
429
+ '.ss-presence[data-state="urgent"] .ss-clock-face { animation-name: ss-clock-pulse; animation-duration: 0.9s; }',
430
+ '.ss-presence[data-state="overdue"] .ss-clock-face { animation: none; opacity: 1; }',
431
+ "",
432
+ "/* \u2500\u2500 \u4E09\u6001\u989C\u8272 \u2500\u2500 */",
433
+ '.ss-presence[data-state="urgent"] { color: var(--dsw-alias-state-warn-secondary); }',
434
+ '.ss-presence[data-state="overdue"] { color: var(--dsw-alias-state-error-primary); }',
435
+ "",
436
+ "/* \u2500\u2500 \u52A8\u753B\u5173\u952E\u5E27 \u2500\u2500 */",
372
437
  "@keyframes ss-presence-breathe { 0%, 100% { opacity: 0.65; } 50% { opacity: 1; } }",
373
438
  "@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; } }",
439
+ "@keyframes ss-clock-breathe { 0%, 100% { opacity: 0.65; } 50% { opacity: 1; } }",
440
+ "@keyframes ss-clock-pulse { 0%, 100% { opacity: 0.5; } 50% { opacity: 1; } }",
441
+ "@media (prefers-reduced-motion: reduce) {",
442
+ " .ss-presence .ss-presence-ring { animation: none; }",
443
+ " .ss-presence .ss-clock-face { animation: none; }",
444
+ "}",
375
445
  "",
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;",
446
+ "/* ==================== \u60AC\u6D6E\u5361\u7247\u72B6\u6001\u884C\u589E\u8865\uFF08issue #4\uFF09 ==================== */",
447
+ "/* \u4E0E\u5BBF\u4E3B .hoverStatus \u884C\u4E25\u683C\u540C\u6784\u3002\u5BBF\u4E3B StateDot \u5B9E\u6D4B\u7ED3\u6784\uFF08dsh-client-ui-primitives",
448
+ " \u7684 ._dot_* \u8FD0\u884C\u65F6\u6837\u5F0F\uFF0C10\xD710 relative + ::before 10px/inset:0 + ::after 6px/inset:2px\uFF0C",
449
+ " \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",
450
+ " \u7C7B\u540D\uFF08_dot_xxxxxx_n \u4E0D\u7A33\u5B9A\uFF0C\u5BBF\u4E3B\u5347\u7EA7\u4F1A\u9759\u9ED8\u5931\u6548\uFF09\u3002",
451
+ " \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",
452
+ " \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",
453
+ "",
454
+ " \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",
455
+ " \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",
456
+ " \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/",
457
+ " \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",
458
+ " \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 */",
459
+ ".ss-hover-status {",
460
+ " display: flex; align-items: center; gap: 8px;",
461
+ " color: #adb2b8; font-size: 12px; line-height: 20px;",
462
+ "}",
463
+ "/* \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",
464
+ " \u4E0D\u662F\u5B9E\u5FC3\u5916\u73AF\uFF1B::after \u624D\u662F 6px \u5B9E\u5FC3\u6838\u5FC3\u3002\u82E5 ::before \u4E0D\u8BBE opacity\uFF0C",
465
+ " \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 */",
466
+ ".ss-hover-status-dot {",
467
+ " position: relative; display: block; flex: none;",
468
+ " width: 10px; height: 10px;",
469
+ " color: #adb2b8;",
470
+ "}",
471
+ ".ss-hover-status-dot::before,",
472
+ ".ss-hover-status-dot::after {",
473
+ ' content: ""; position: absolute; border-radius: 50%; background: currentColor;',
474
+ "}",
475
+ ".ss-hover-status-dot::before { inset: 0; opacity: 0.1; }",
476
+ ".ss-hover-status-dot::after { inset: 2px; }",
477
+ "/* \u8BED\u4E49\u6620\u5C04\uFF08\u5BF9\u9F50\u5BBF\u4E3B done/ongoing/warning/error \u56DB\u6001\u8272\u503C\uFF09\uFF1A",
478
+ " scheduled \u2192 ongoing \u7070\uFF08\u4E2D\u6027\uFF1A\u5DF2\u6392\u671F\uFF0C\u65E0\u7D27\u8FEB\u6027\uFF09",
479
+ " urgent \u2192 warning \u7425\u73C0\uFF08\u22645min \u5373\u5C06\u89E6\u53D1\uFF09",
480
+ " overdue \u2192 error \u7EA2\uFF08\u5DF2\u5230\u671F\uFF0C\u7B49\u5F85\u4F1A\u8BDD\u7A7A\u95F2\u53D1\u9001\uFF09 */",
481
+ '.ss-hover-status[data-state="urgent"] .ss-hover-status-dot { color: #f59e0b; }',
482
+ '.ss-hover-status[data-state="overdue"] .ss-hover-status-dot { color: #f25a5a; }',
483
+ "",
484
+ "/* ==================== \u8BBE\u7F6E\u9875\uFF08\u5B9A\u65F6\u63D0\u9192\u8868\u5355\uFF09 ==================== */",
485
+ "/* \u89C6\u89C9\u5BF9\u9F50\u5B98\u65B9 SettingsForm\uFF08dsh-client-ui-primitives\uFF09\uFF1A\u88F8\u8868\u5355\uFF0C\u65E0\u5361\u7247\u5BB9\u5668\uFF0C",
486
+ " \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 */",
487
+ ".ss-settings-form {",
488
+ " display: flex; flex-direction: column;",
489
+ "}",
490
+ "/* Section \u5206\u7EC4\uFF08\u5BF9\u9F50\u5B98\u65B9 AZSXYW_section \u7ED3\u6784\uFF09 */",
491
+ ".ss-section {",
492
+ " padding: 16px 0;",
493
+ "}",
494
+ ".ss-section-heading {",
495
+ " margin: 0; font-size: 13px; font-weight: 600; line-height: 1.5;",
496
+ " color: var(--dsw-alias-label-primary);",
497
+ "}",
498
+ ".ss-section-fields {",
499
+ " display: flex; flex-direction: column;",
500
+ "}",
501
+ /* 紧凑字段并排(对齐官方 hF0LTq_limits 网格:两等宽列、间距 16px) */
502
+ ".ss-section-fieldsGrid {",
503
+ " display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px;",
504
+ "}",
505
+ /* 帮助按钮(对齐官方 _helpButton_:24×24、radius 8px、12px 圆圈问号图标) */
506
+ ".ss-help-btn {",
507
+ " width: 24px; height: 24px; padding: 0; flex: none;",
508
+ " display: inline-flex; align-items: center; justify-content: center;",
509
+ " background: none; border: none; border-radius: 8px; cursor: pointer;",
510
+ " color: var(--dsw-alias-label-tertiary);",
511
+ "}",
512
+ ".ss-help-btn:hover, .ss-help-btnOpen { color: var(--dsw-alias-label-secondary); }",
513
+ ".ss-help-btn:focus-visible {",
514
+ " outline: 2px solid var(--dsw-alias-state-business-primary); outline-offset: -1px;",
515
+ "}",
516
+ /* 展开后的说明区(对齐官方 _help_:12px / 1.6 行高、顶部 10px、次级文字色) */
517
+ ".ss-help {",
518
+ " margin: 0; padding: 10px 0 0; font-size: 12px; line-height: 1.6;",
519
+ " color: var(--dsw-alias-label-secondary);",
520
+ "}",
521
+ ".ss-help p { margin: 0; }",
522
+ /* Toggle 行(对齐官方子智能体插件的开关行:label 左 + switch 右) */
523
+ ".ss-toggle-row {",
524
+ " display: flex; align-items: center; justify-content: space-between;",
525
+ " gap: 16px;",
526
+ "}",
527
+ ".ss-toggle-label {",
528
+ " flex: 1; min-width: 0; font-size: 13px; font-weight: 500; line-height: 1.5;",
529
+ " color: var(--dsw-alias-label-primary);",
530
+ "}",
531
+ ".ss-toggle-switch {",
532
+ " position: relative; width: 36px; height: 20px; flex: none;",
533
+ " background: var(--dsw-alias-bg-module-platform); border-radius: 999px;",
534
+ " cursor: pointer; transition: background var(--ds-transition-duration-fast) var(--ds-ease-in-out);",
535
+ " border: none; padding: 0;",
536
+ "}",
537
+ '.ss-toggle-switch[aria-checked="true"] { background: var(--dsw-alias-state-business-primary); }',
538
+ ".ss-toggle-switch::after {",
539
+ ' content: ""; position: absolute; top: 2px; left: 2px;',
540
+ " width: 16px; height: 16px; border-radius: 999px;",
541
+ " background: #fff; transition: transform var(--ds-transition-duration-fast) var(--ds-ease-in-out);",
542
+ "}",
543
+ '.ss-toggle-switch[aria-checked="true"]::after { transform: translateX(16px); }',
544
+ ".ss-toggle-switch:disabled { opacity: 0.4; cursor: default; }",
545
+ ".ss-toggle-switch:focus-visible {",
546
+ " outline: 2px solid var(--dsw-alias-state-business-primary); outline-offset: 2px;",
547
+ "}",
548
+ ".ss-toggle-description {",
549
+ " margin: 0; padding: 0 0 12px; font-size: 12px; line-height: 1.6;",
550
+ " color: var(--dsw-alias-label-secondary);",
551
+ "}",
552
+ ".ss-label-group {",
553
+ " display: flex; align-items: center; gap: 4px; flex: 1; min-width: 0;",
405
554
  "}",
406
555
  ".ss-card-fieldHead { align-items: center; gap: 8px; display: flex; }",
407
556
  ".ss-card-label {",
@@ -420,11 +569,21 @@ var COMPONENTS = [
420
569
  "}",
421
570
  ".ss-card-reset:hover:not(:disabled) { color: var(--dsw-alias-label-primary); }",
422
571
  ".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; }",
572
+ ".ss-card-invalid { color: var(--dsw-alias-state-error-primary); margin: 0; font-size: 12px; line-height: 1.5; }",
573
+ "/*",
574
+ " * \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",
575
+ ' * \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',
576
+ " */",
577
+ ".ss-card-risk {",
578
+ " margin: 6px 0 0; padding: 6px 9px; border-radius: 6px;",
579
+ " font-size: 12px; line-height: 1.55;",
580
+ " color: var(--dsw-alias-state-warn-secondary);",
581
+ " background: color-mix(in srgb, var(--dsw-alias-state-warn-secondary) 12%, transparent);",
582
+ " border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-secondary) 30%, transparent);",
583
+ "}",
424
584
  ".ss-card-footer {",
425
- " border-top: 1px solid var(--dsw-alias-border-l2);",
426
585
  " justify-content: flex-end; align-items: center; gap: 8px;",
427
- " padding: 12px 0 4px; display: flex;",
586
+ " padding-top: 16px; display: flex;",
428
587
  "}",
429
588
  ".ss-card-failed {",
430
589
  " min-width: 0; color: var(--dsw-alias-label-error); flex: 1; margin: 0;",
@@ -432,7 +591,7 @@ var COMPONENTS = [
432
591
  "}",
433
592
  ".ss-card-discard, .ss-card-save {",
434
593
  " appearance: none; font: inherit; cursor: pointer;",
435
- " border: 1px solid transparent; border-radius: 8px;",
594
+ " border: 1px solid transparent; border-radius: var(--dsw-radius-md);",
436
595
  " padding: 5px 14px; font-size: 13px; line-height: 1.5;",
437
596
  "}",
438
597
  ".ss-card-discard { border-color: var(--dsw-alias-border-l2); color: var(--dsw-alias-label-secondary); background: none; }",
@@ -441,7 +600,7 @@ var COMPONENTS = [
441
600
  ".ss-card-save:hover:not(:disabled) { background: var(--dsw-alias-button-primary-hover); }",
442
601
  ".ss-card-discard:disabled, .ss-card-save:disabled { opacity: 0.4; cursor: default; }",
443
602
  ".ss-card-discard:focus-visible, .ss-card-save:focus-visible {",
444
- " outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: 1px;",
603
+ " outline: var(--dsw-focus-ring-width) solid var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary)); outline-offset: 1px;",
445
604
  "}"
446
605
  ].join("\n");
447
606
  function injectStyles() {
@@ -561,6 +720,16 @@ var zh = {
561
720
  steerAlreadySent: "\u5DF2\u63D2\u8BDD",
562
721
  steerFailed: "\u63D2\u8BDD\u5931\u8D25\uFF1A{message}",
563
722
  steerUnsupportedKind: "\u5468\u671F\u63D0\u9192\u6682\u4E0D\u652F\u6301\u63D2\u8BDD",
723
+ /** 投递未确认(宿主保留条目,可重试) */
724
+ steerUnconfirmed: "\u6295\u9012\u672A\u786E\u8BA4\uFF0C\u63D0\u9192\u5DF2\u4FDD\u7559\uFF0C\u53EF\u91CD\u8BD5",
725
+ steerRetry: "\u91CD\u8BD5",
726
+ /** 暂停 / 恢复(仅 after;原地冻结进度条) */
727
+ pauseTask: "\u6682\u505C\u63D0\u9192",
728
+ resumeTask: "\u6062\u590D\u63D0\u9192",
729
+ pausedLabel: "\u5DF2\u6682\u505C",
730
+ pauseFailed: "\u6682\u505C\u5931\u8D25\uFF1A{message}",
731
+ resumeFailed: "\u6062\u590D\u5931\u8D25\uFF1A{message}",
732
+ pauseUnsupportedKind: "\u4EC5\u652F\u6301\u6682\u505C\u300C\u518D\u7B49 N \u5206\u949F\u300D\u7C7B\u63D0\u9192",
564
733
  /** dock 折叠头计数(QueueDock「N 条排队消息」样式) */
565
734
  panelCount: "{n} \u6761\u5B9A\u65F6\u63D0\u9192",
566
735
  /** 精准倒计时(dock 行 + 折叠头) */
@@ -587,6 +756,13 @@ var zh = {
587
756
  presenceOverdueAria: "\u6709 {n} \u6761\u5B9A\u65F6\u63D0\u9192\u5DF2\u5230\u671F\uFF0C\u7B49\u5F85\u53D1\u9001",
588
757
  presenceTooltip: "\u4E0B\u6B21 {time} \xB7 {n} \u6761\u4EFB\u52A1",
589
758
  presenceOverdueTooltip: "\u5DF2\u5230\u671F \xB7 {n} \u6761\u4EFB\u52A1\uFF08\u7B49\u5F85\u4F1A\u8BDD\u7A7A\u95F2\u53D1\u9001\uFF09",
759
+ /** 全部任务都处于暂停:没有排定的触发时刻,故不显示"下次"或"已到期"。 */
760
+ presencePausedAria: "\u6709 {n} \u6761\u5B9A\u65F6\u63D0\u9192\u5DF2\u6682\u505C",
761
+ presencePausedTooltip: "\u5DF2\u6682\u505C \xB7 {n} \u6761\u4EFB\u52A1",
762
+ /** 悬浮卡片状态区追加行(与宿主 hoverStatus 同构,纯追加不改写既有状态) */
763
+ hoverScheduleStatus: "\u6709 {n} \u6761\u5B9A\u65F6\u63D0\u9192\uFF0C\u4E0B\u6B21 {time}",
764
+ hoverScheduleOverdue: "\u6709 {n} \u6761\u5B9A\u65F6\u63D0\u9192\u5DF2\u5230\u671F\uFF0C\u7B49\u5F85\u53D1\u9001",
765
+ hoverSchedulePaused: "\u6709 {n} \u6761\u5B9A\u65F6\u63D0\u9192\u5DF2\u6682\u505C",
590
766
  relMinutes: "{m} \u5206\u540E",
591
767
  relHours: "{h} \u5C0F\u65F6\u540E",
592
768
  relTomorrow: "\u660E\u5929 {time}",
@@ -623,6 +799,15 @@ var en = {
623
799
  steerAlreadySent: "Steered",
624
800
  steerFailed: "Steer failed: {message}",
625
801
  steerUnsupportedKind: "Recurring reminders can't be steered",
802
+ /** Delivery unconfirmed (host kept the item; retryable) */
803
+ steerUnconfirmed: "Delivery unconfirmed \u2014 reminder kept, you can retry",
804
+ steerRetry: "Retry",
805
+ pauseTask: "Pause reminder",
806
+ resumeTask: "Resume reminder",
807
+ pausedLabel: "Paused",
808
+ pauseFailed: "Pause failed: {message}",
809
+ resumeFailed: "Resume failed: {message}",
810
+ pauseUnsupportedKind: 'Only "wait N minutes" (after) reminders can be paused',
626
811
  panelCount: "{n} scheduled reminders",
627
812
  countdownLeft: "in",
628
813
  dueAnyMoment: "Sending soon",
@@ -641,6 +826,11 @@ var en = {
641
826
  presenceOverdueAria: "{n} scheduled reminder(s) due, waiting to send",
642
827
  presenceTooltip: "Next at {time} \xB7 {n} task(s)",
643
828
  presenceOverdueTooltip: "Due \xB7 {n} task(s) (sends when the session is idle)",
829
+ presencePausedAria: "{n} paused reminder(s)",
830
+ presencePausedTooltip: "Paused \xB7 {n} task(s)",
831
+ hoverScheduleStatus: "{n} scheduled reminder(s), next {time}",
832
+ hoverScheduleOverdue: "{n} scheduled reminder(s) due, waiting to send",
833
+ hoverSchedulePaused: "{n} paused reminder(s)",
644
834
  relMinutes: "in {m} min",
645
835
  relHours: "in {h} h",
646
836
  relTomorrow: "Tomorrow {time}",
@@ -860,11 +1050,11 @@ var import_jsx_runtime = require("react/jsx-runtime");
860
1050
  function scheduleStateOf(item, now) {
861
1051
  return Date.parse(item.scheduled_at) <= now ? "overdue" : "scheduled";
862
1052
  }
863
- function TaskList({ items: items2, now, deliveredIds, cancellingIds, onDelete, timeZone, t, lang }) {
864
- if (items2.length === 0) {
1053
+ function TaskList({ items, now, deliveredIds, cancellingIds, onDelete, timeZone, t, lang }) {
1054
+ if (items.length === 0) {
865
1055
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ss-empty", "data-ss-empty": "", children: t.emptyTasks });
866
1056
  }
867
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "ss-tasks", "data-ss-tasks": "", children: items2.map((item) => {
1057
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: "ss-tasks", "data-ss-tasks": "", children: items.map((item) => {
868
1058
  const dotState = deliveredIds?.has(item.id) ? "delivered" : cancellingIds?.has(item.id) ? "cancelled" : scheduleStateOf(item, now);
869
1059
  const isCancelled = dotState === "cancelled";
870
1060
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: isCancelled ? "ss-task cancelled" : "ss-task", "data-ss-task": item.id, children: [
@@ -1237,12 +1427,12 @@ function useSchedules(inject2) {
1237
1427
  if (pendingSync.length === 0 || !sessionId) return;
1238
1428
  let cancelled = false;
1239
1429
  const syncAll = async () => {
1240
- const items2 = [...pendingSync];
1241
- for (const item of items2) {
1430
+ const items = [...pendingSync];
1431
+ for (const item of items) {
1242
1432
  if (cancelled) return;
1243
1433
  try {
1244
1434
  const accepted = await callCommand(sessionId, createLine(item.payload));
1245
- if (accepted && !cancelled) {
1435
+ if (accepted.matched && !cancelled) {
1246
1436
  removePending(item.clientSeq);
1247
1437
  setPendingSync((prev) => prev.filter((p) => p.clientSeq !== item.clientSeq));
1248
1438
  }
@@ -1268,7 +1458,7 @@ function useSchedules(inject2) {
1268
1458
  setBusy(true);
1269
1459
  try {
1270
1460
  const accepted = await callCommand(sessionId, createLine(inputPayload));
1271
- if (!accepted) {
1461
+ if (!accepted.matched) {
1272
1462
  appendPending(inputPayload);
1273
1463
  setPendingSync((prev) => [...prev, { clientSeq: Date.now(), createdAt: Date.now(), payload: inputPayload }]);
1274
1464
  throw new Error(CLIENT_ERR.NOT_ACCEPTED);
@@ -1457,65 +1647,79 @@ function SchedButton(props) {
1457
1647
  }
1458
1648
 
1459
1649
  // 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
1650
  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;
1651
+
1652
+ // src/bar-geometry.ts
1653
+ var BAR_UNIT_MS = 36e5;
1654
+ function barWindow(item, end, now, firstSeen) {
1655
+ let start;
1656
+ if (item.kind === "after") {
1657
+ const windowSec = item.window_seconds ?? item.after_seconds;
1658
+ if (windowSec !== void 0) {
1659
+ start = end - windowSec * 1e3;
1660
+ } else if (item.created_at !== void 0) {
1661
+ const parsed = Date.parse(item.created_at);
1662
+ start = Number.isNaN(parsed) ? firstSeen.get(item.id) ?? now : parsed;
1663
+ } else {
1664
+ start = firstSeen.get(item.id) ?? now;
1665
+ }
1666
+ } else if (item.kind === "every" && item.every_seconds !== void 0) {
1667
+ start = end - item.every_seconds * 1e3;
1668
+ } else if (item.created_at !== void 0) {
1669
+ const parsed = Date.parse(item.created_at);
1670
+ start = Number.isNaN(parsed) ? firstSeen.get(item.id) ?? now : parsed;
1671
+ } else {
1672
+ start = firstSeen.get(item.id) ?? now;
1673
+ }
1674
+ return { start, totalMs: Math.max(1e3, end - start) };
1675
+ }
1676
+ function ratioAt(item, at, firstSeen) {
1677
+ const end = Date.parse(item.scheduled_at);
1678
+ const { start, totalMs } = barWindow(item, end, at, firstSeen);
1679
+ const elapsedMs = Math.min(Math.max(at - start, 0), totalMs);
1680
+ return {
1681
+ totalRatio: elapsedMs / totalMs,
1682
+ count: Math.max(1, Math.ceil(totalMs / BAR_UNIT_MS))
1683
+ };
1684
+ }
1685
+ function barSegments(item, now, firstSeen) {
1686
+ return ratioAt(item, now, firstSeen);
1687
+ }
1688
+ function frozenBarSegments(item, frozenLeftMs, firstSeen, renderedAt) {
1689
+ const windowSec = item.window_seconds ?? item.after_seconds;
1690
+ if (windowSec === void 0 || windowSec <= 0) {
1691
+ const end = Date.parse(item.scheduled_at);
1692
+ const pausedAt2 = Date.parse(item.paused_at ?? "");
1693
+ const exact = Number.isNaN(pausedAt2) ? end - Math.floor(frozenLeftMs / 1e3) * 1e3 : pausedAt2;
1694
+ return ratioAt(item, Number.isNaN(exact) ? end : exact, firstSeen);
1695
+ }
1696
+ const totalMs = Math.max(1e3, windowSec * 1e3);
1697
+ let leftMs = Math.min(Math.max(frozenLeftMs, 0), totalMs);
1698
+ const pausedAt = Date.parse(item.paused_at ?? "");
1699
+ if (renderedAt !== void 0 && !Number.isNaN(pausedAt) && pausedAt > renderedAt) {
1700
+ leftMs = Math.min(leftMs + (pausedAt - renderedAt), totalMs);
1701
+ }
1702
+ const elapsedMs = Math.min(Math.max(totalMs - leftMs, 0), totalMs);
1703
+ return {
1704
+ totalRatio: elapsedMs / totalMs,
1705
+ count: Math.max(1, Math.ceil(totalMs / BAR_UNIT_MS))
1706
+ };
1707
+ }
1708
+ function planBarAnimation(totalMs, elapsedMs) {
1709
+ if (!Number.isFinite(totalMs) || totalMs <= 0) return void 0;
1710
+ const raw = Number.isFinite(elapsedMs) ? elapsedMs : 0;
1711
+ const clamped = Math.min(Math.max(raw, 0), totalMs);
1712
+ const elapsed = clamped === 0 ? 0 : clamped;
1713
+ if (elapsed >= totalMs) return void 0;
1714
+ return {
1715
+ durationMs: totalMs,
1716
+ // -0 会在 CSS 里序列化成难看的 "-0ms",故显式归零
1717
+ delayMs: elapsed === 0 ? 0 : -elapsed
1514
1718
  };
1515
1719
  }
1516
1720
 
1517
1721
  // src/client/components/ScheduleDock.tsx
1518
- var import_jsx_runtime5 = require("react/jsx-runtime");
1722
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1519
1723
  function formatCountdown(ms) {
1520
1724
  const total = Math.max(0, Math.round(ms / 1e3));
1521
1725
  const h = Math.floor(total / 3600);
@@ -1525,53 +1729,151 @@ function formatCountdown(ms) {
1525
1729
  const ss = String(s).padStart(2, "0");
1526
1730
  return h > 0 ? `${h}:${mm}:${ss}` : `${mm}:${ss}`;
1527
1731
  }
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;
1732
+ function prefersReducedMotion() {
1733
+ try {
1734
+ return globalThis.matchMedia?.("(prefers-reduced-motion: reduce)").matches === true;
1735
+ } catch {
1736
+ return false;
1541
1737
  }
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 };
1738
+ }
1739
+ function planBarAnimationFor(item, now, firstSeen) {
1740
+ const end = Date.parse(item.scheduled_at);
1741
+ if (!Number.isFinite(end)) return void 0;
1742
+ const { start, totalMs } = barWindow(item, end, now, firstSeen);
1743
+ return planBarAnimation(totalMs, now - start);
1547
1744
  }
1548
1745
  var deleteLine2 = (id) => `/user-schedule-delete ${JSON.stringify({ id })}`;
1549
1746
  var editLine = (id, prompt) => `/user-schedule-edit ${JSON.stringify({ id, prompt })}`;
1550
1747
  var steerLine = (id) => `/user-schedule-steer-now ${JSON.stringify({ id })}`;
1748
+ var STEER_CONFIRM_WINDOW_MS = 2600;
1749
+ var pauseLine = (id) => `/user-schedule-pause ${JSON.stringify({ id })}`;
1750
+ var resumeLine = (uid) => `/user-schedule-resume ${JSON.stringify({ uid })}`;
1751
+ function canPause(item, now) {
1752
+ if (item.status === "paused") return false;
1753
+ if (item.kind !== "after") return false;
1754
+ const epoch = Date.parse(item.scheduled_at);
1755
+ return Number.isFinite(epoch) && epoch > now;
1756
+ }
1551
1757
  function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
1552
1758
  const now = useNow(1e3);
1553
1759
  const { t } = useSchedT(locale);
1554
1760
  const projection = typeof useProjection === "function" ? useProjection("userSchedules") : void 0;
1555
- const schedules = (0, import_react8.useMemo)(
1556
- () => [...projection?.schedules ?? []].sort(
1761
+ const [dismissedPaused, setDismissedPaused] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
1762
+ (0, import_react7.useEffect)(() => {
1763
+ const live = projection?.schedules;
1764
+ if (live === void 0) return;
1765
+ setDismissedPaused((current) => {
1766
+ if (current.size === 0) return current;
1767
+ let changed = false;
1768
+ const nextSet = new Set(current);
1769
+ for (const item of live) {
1770
+ if (item.status !== "paused" && nextSet.delete(item.id)) changed = true;
1771
+ }
1772
+ return changed ? nextSet : current;
1773
+ });
1774
+ }, [projection]);
1775
+ const [promptOverrides, setPromptOverrides] = (0, import_react7.useState)(/* @__PURE__ */ new Map());
1776
+ (0, import_react7.useEffect)(() => {
1777
+ const live = projection?.schedules;
1778
+ if (live === void 0 || promptOverrides.size === 0) return;
1779
+ setPromptOverrides((current) => {
1780
+ if (current.size === 0) return current;
1781
+ let changed = false;
1782
+ const nextMap = new Map(current);
1783
+ for (const [id, text] of current) {
1784
+ const item = live.find((s) => s.id === id);
1785
+ if (item === void 0 || item.prompt === text) {
1786
+ nextMap.delete(id);
1787
+ changed = true;
1788
+ }
1789
+ }
1790
+ return changed ? nextMap : current;
1791
+ });
1792
+ }, [projection, promptOverrides]);
1793
+ const schedules = (0, import_react7.useMemo)(
1794
+ () => (projection?.schedules ?? []).filter((item) => !(item.status === "paused" && dismissedPaused.has(item.id))).map((item) => {
1795
+ const override = promptOverrides.get(item.id);
1796
+ return override === void 0 ? item : { ...item, prompt: override };
1797
+ }).sort(
1557
1798
  (a, b) => Date.parse(a.scheduled_at) - Date.parse(b.scheduled_at)
1558
1799
  ),
1559
- [projection]
1800
+ [projection, dismissedPaused, promptOverrides]
1560
1801
  );
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)(() => {
1802
+ const [collapsed, setCollapsed] = (0, import_react7.useState)(true);
1803
+ const [cancelling, setCancelling] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
1804
+ const [editingId, setEditingId] = (0, import_react7.useState)(null);
1805
+ const [editingText, setEditingText] = (0, import_react7.useState)("");
1806
+ const [editErr, setEditErr] = (0, import_react7.useState)(null);
1807
+ const [saving, setSaving] = (0, import_react7.useState)(false);
1808
+ const [steering, setSteering] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
1809
+ const [steerDone, setSteerDone] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
1810
+ const [steerErr, setSteerErr] = (0, import_react7.useState)(/* @__PURE__ */ new Map());
1811
+ const [steerUnconfirmed, setSteerUnconfirmed] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
1812
+ (0, import_react7.useEffect)(() => {
1813
+ const live = projection?.schedules;
1814
+ if (live === void 0) return;
1815
+ const present = new Set(live.filter((item) => item.status !== "paused").map((item) => item.id));
1816
+ setSteerDone((current) => {
1817
+ if (current.size === 0) return current;
1818
+ let changed = false;
1819
+ const next2 = new Set(current);
1820
+ for (const id of current) {
1821
+ if (!present.has(id)) {
1822
+ next2.delete(id);
1823
+ changed = true;
1824
+ }
1825
+ }
1826
+ return changed ? next2 : current;
1827
+ });
1828
+ }, [projection]);
1829
+ (0, import_react7.useEffect)(() => {
1830
+ if (steerDone.size === 0) return void 0;
1831
+ const timer = window.setTimeout(() => {
1832
+ const live = projection?.schedules;
1833
+ if (live === void 0) return;
1834
+ const present = new Set(live.filter((item) => item.status !== "paused").map((item) => item.id));
1835
+ setSteerUnconfirmed((current) => {
1836
+ let changed = false;
1837
+ const next2 = new Set(current);
1838
+ for (const id of steerDone) {
1839
+ if (present.has(id) && !next2.has(id)) {
1840
+ next2.add(id);
1841
+ changed = true;
1842
+ }
1843
+ if (!present.has(id) && next2.delete(id)) changed = true;
1844
+ }
1845
+ return changed ? next2 : current;
1846
+ });
1847
+ }, STEER_CONFIRM_WINDOW_MS);
1848
+ return () => window.clearTimeout(timer);
1849
+ }, [steerDone, projection]);
1850
+ const [pausing, setPausing] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
1851
+ const [resuming, setResuming] = (0, import_react7.useState)(/* @__PURE__ */ new Set());
1852
+ const [pauseErr, setPauseErr] = (0, import_react7.useState)(/* @__PURE__ */ new Map());
1853
+ const firstSeenRef = (0, import_react7.useRef)(/* @__PURE__ */ new Map());
1854
+ const lastActiveAtRef = (0, import_react7.useRef)(/* @__PURE__ */ new Map());
1855
+ const wallClock = Date.now();
1856
+ {
1857
+ const next2 = new Map(lastActiveAtRef.current);
1858
+ let changed = false;
1859
+ for (const item of schedules) {
1860
+ if (item.status === "paused") continue;
1861
+ const prev = next2.get(item.id);
1862
+ if (prev === void 0 || wallClock > prev) {
1863
+ next2.set(item.id, wallClock);
1864
+ changed = true;
1865
+ }
1866
+ }
1867
+ for (const id of [...next2.keys()]) {
1868
+ if (!schedules.some((item) => item.id === id)) {
1869
+ next2.delete(id);
1870
+ changed = true;
1871
+ }
1872
+ }
1873
+ if (changed) lastActiveAtRef.current = next2;
1874
+ }
1875
+ const byId = (0, import_react7.useMemo)(() => new Map(schedules.map((item) => [item.id, item])), [schedules]);
1876
+ (0, import_react7.useEffect)(() => {
1575
1877
  let changed = false;
1576
1878
  const next2 = new Map(firstSeenRef.current);
1577
1879
  for (const [id] of byId) {
@@ -1587,32 +1889,30 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
1587
1889
  }
1588
1890
  }
1589
1891
  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
1892
  }, [byId]);
1602
- const suppress = (id) => {
1603
- suppressedRef.current = new Set(suppressedRef.current).add(id);
1604
- };
1605
- (0, import_react8.useEffect)(() => {
1893
+ (0, import_react7.useEffect)(() => {
1606
1894
  if (schedules.length <= 1) setCollapsed(true);
1607
1895
  }, [schedules.length]);
1608
1896
  if (schedules.length === 0 || sessionId === void 0) return null;
1609
1897
  const next = schedules[0];
1610
1898
  if (next === void 0) return null;
1611
1899
  const expanded = schedules.length === 1 || !collapsed;
1612
- const handleCancel = (id) => {
1613
- suppress(id);
1900
+ const handleCancel = (id, status) => {
1614
1901
  setCancelling((current) => new Set(current).add(id));
1615
- void callCommand(sessionId, deleteLine2(id)).finally(() => {
1902
+ const restore = () => {
1903
+ setDismissedPaused((current) => {
1904
+ if (!current.has(id)) return current;
1905
+ const nextSet = new Set(current);
1906
+ nextSet.delete(id);
1907
+ return nextSet;
1908
+ });
1909
+ };
1910
+ if (status === "paused") {
1911
+ setDismissedPaused((current) => new Set(current).add(id));
1912
+ }
1913
+ void callCommand(sessionId, deleteLine2(id)).then((outcome) => {
1914
+ if (!outcome.matched) restore();
1915
+ }).catch(restore).finally(() => {
1616
1916
  window.setTimeout(() => {
1617
1917
  setCancelling((current) => {
1618
1918
  const nextSet = new Set(current);
@@ -1624,16 +1924,19 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
1624
1924
  };
1625
1925
  const handleSteer = (item) => {
1626
1926
  const id = item.id;
1627
- suppress(id);
1927
+ const wasPaused = item.status === "paused";
1628
1928
  setSteering((current) => new Set(current).add(id));
1629
1929
  setSteerErr((current) => {
1630
1930
  const next2 = new Map(current);
1631
1931
  next2.delete(id);
1632
1932
  return next2;
1633
1933
  });
1634
- void callCommand(sessionId, steerLine(id)).then((ok) => {
1635
- if (ok) {
1934
+ void callCommand(sessionId, steerLine(id)).then((outcome) => {
1935
+ if (outcome.matched) {
1636
1936
  setSteerDone((current) => new Set(current).add(id));
1937
+ if (wasPaused) {
1938
+ setDismissedPaused((current) => new Set(current).add(id));
1939
+ }
1637
1940
  } else {
1638
1941
  setSteerErr((current) => new Map(current).set(id, t.editErrNotAccepted));
1639
1942
  }
@@ -1647,6 +1950,67 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
1647
1950
  });
1648
1951
  });
1649
1952
  };
1953
+ const handleSteerRetry = (item) => {
1954
+ const id = item.id;
1955
+ setSteerUnconfirmed((current) => {
1956
+ if (!current.has(id)) return current;
1957
+ const next2 = new Set(current);
1958
+ next2.delete(id);
1959
+ return next2;
1960
+ });
1961
+ setSteerDone((current) => {
1962
+ if (!current.has(id)) return current;
1963
+ const next2 = new Set(current);
1964
+ next2.delete(id);
1965
+ return next2;
1966
+ });
1967
+ handleSteer(item);
1968
+ };
1969
+ const handlePause = (item) => {
1970
+ const id = item.id;
1971
+ if (!canPause(item, now)) return;
1972
+ setPausing((current) => new Set(current).add(id));
1973
+ setPauseErr((current) => {
1974
+ const next2 = new Map(current);
1975
+ next2.delete(id);
1976
+ return next2;
1977
+ });
1978
+ void callCommand(sessionId, pauseLine(id)).then((outcome) => {
1979
+ if (!outcome.matched) {
1980
+ setPauseErr((current) => new Map(current).set(id, t.editErrNotAccepted));
1981
+ }
1982
+ }).catch(() => {
1983
+ setPauseErr((current) => new Map(current).set(id, t.editErrCommandFailed));
1984
+ }).finally(() => {
1985
+ setPausing((current) => {
1986
+ const next2 = new Set(current);
1987
+ next2.delete(id);
1988
+ return next2;
1989
+ });
1990
+ });
1991
+ };
1992
+ const handleResume = (item) => {
1993
+ const uid = item.id;
1994
+ setResuming((current) => new Set(current).add(uid));
1995
+ setPauseErr((current) => {
1996
+ const next2 = new Map(current);
1997
+ next2.delete(uid);
1998
+ return next2;
1999
+ });
2000
+ void callCommand(sessionId, resumeLine(uid)).then((outcome) => {
2001
+ if (!outcome.matched) {
2002
+ setPauseErr((current) => new Map(current).set(uid, t.editErrNotAccepted));
2003
+ }
2004
+ }).catch(() => {
2005
+ setPauseErr((current) => new Map(current).set(uid, t.editErrCommandFailed));
2006
+ }).finally(() => {
2007
+ setResuming((current) => {
2008
+ const next2 = new Set(current);
2009
+ next2.delete(uid);
2010
+ return next2;
2011
+ });
2012
+ });
2013
+ };
1650
2014
  const startEdit = (item) => {
1651
2015
  setEditingId(item.id);
1652
2016
  setEditingText(item.prompt);
@@ -1663,12 +2027,15 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
1663
2027
  setEditErr(t.editErrEmpty);
1664
2028
  return;
1665
2029
  }
1666
- suppress(id);
1667
2030
  setSaving(true);
1668
2031
  setEditErr(null);
1669
- void callCommand(sessionId, editLine(id, trimmed)).then((ok) => {
1670
- if (!ok) setEditErr(format(t.editErrFailed, { message: t.editErrNotAccepted }));
1671
- else cancelEdit();
2032
+ void callCommand(sessionId, editLine(id, trimmed)).then((outcome) => {
2033
+ if (!outcome.matched) {
2034
+ setEditErr(format(t.editErrFailed, { message: t.editErrNotAccepted }));
2035
+ return;
2036
+ }
2037
+ setPromptOverrides((current) => new Map(current).set(id, trimmed));
2038
+ cancelEdit();
1672
2039
  }).catch(() => {
1673
2040
  setEditErr(format(t.editErrFailed, { message: t.editErrCommandFailed }));
1674
2041
  }).finally(() => setSaving(false));
@@ -1677,8 +2044,8 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
1677
2044
  const epoch = Date.parse(item.scheduled_at);
1678
2045
  const state = epoch <= now ? "overdue" : "scheduled";
1679
2046
  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)(
2047
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("li", { className: "ss-dock-row ss-editing", "data-ss-dock-row": item.id, children: [
2048
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1682
2049
  "input",
1683
2050
  {
1684
2051
  className: "ss-dock-edit-input",
@@ -1695,7 +2062,7 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
1695
2062
  "aria-label": `${t.editTask}: ${item.prompt}`
1696
2063
  }
1697
2064
  ),
1698
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2065
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1699
2066
  "button",
1700
2067
  {
1701
2068
  type: "button",
@@ -1705,60 +2072,98 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
1705
2072
  children: saving ? "\u2026" : t.editSave
1706
2073
  }
1707
2074
  ),
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 })
2075
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "ss-dock-action", onClick: cancelEdit, "aria-label": t.editCancel, children: "\u2715" }),
2076
+ editErr !== null && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ss-dock-edit-err", children: editErr })
1710
2077
  ] }, item.id);
1711
2078
  }
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);
2079
+ const isPaused = item.status === "paused";
2080
+ const frozenLeft = isPaused ? (item.remaining_seconds ?? 0) * 1e3 : epoch - now;
2081
+ const countdownText = isPaused ? t.pausedLabel : state === "overdue" ? t.dueAnyMoment : `${t.countdownLeft} ${formatCountdown(Math.max(0, frozenLeft))}`;
2082
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
2083
+ "li",
2084
+ {
2085
+ className: `ss-dock-row${isPaused ? " ss-paused" : ""}`,
2086
+ "data-ss-dock-row": item.id,
2087
+ children: [
2088
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ss-dock-preview", children: [
2089
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ss-dock-row-line", children: [
2090
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ss-dock-row-time", children: formatHhmm(epoch, detectTimeZone()) }),
2091
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: `ss-dock-row-countdown${!isPaused && state === "overdue" ? " ss-due" : ""}${isPaused ? " ss-paused-label" : ""}`, children: countdownText }),
2092
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ss-dock-row-prompt", title: item.prompt, children: item.prompt })
2093
+ ] }),
2094
+ /* @__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 }),
2095
+ (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) }),
2096
+ steerUnconfirmed.has(item.id) && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "ss-dock-steer-warn", role: "status", children: [
2097
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: t.steerUnconfirmed }),
2098
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "ss-dock-steer-retry", onClick: () => handleSteerRetry(item), children: t.steerRetry })
2099
+ ] })
2100
+ ] }),
2101
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ss-dock-actions", children: [
2102
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2103
+ "button",
2104
+ {
2105
+ type: "button",
2106
+ className: "ss-dock-action",
2107
+ title: t.editTask,
2108
+ "aria-label": t.editTask,
2109
+ onClick: () => startEdit(item),
2110
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueueEditIcon, {})
2111
+ }
2112
+ ),
2113
+ isPaused ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2114
+ "button",
2115
+ {
2116
+ type: "button",
2117
+ className: `ss-dock-action ss-paused-active${resuming.has(item.id) ? " ss-pending" : ""}`,
2118
+ title: t.resumeTask,
2119
+ "aria-label": t.resumeTask,
2120
+ disabled: resuming.has(item.id),
2121
+ onClick: () => handleResume(item),
2122
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueueResumeIcon, {})
2123
+ }
2124
+ ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2125
+ "button",
2126
+ {
2127
+ type: "button",
2128
+ className: `ss-dock-action${pausing.has(item.id) ? " ss-pending" : ""}`,
2129
+ title: canPause(item, now) ? t.pauseTask : t.pauseUnsupportedKind,
2130
+ "aria-label": canPause(item, now) ? t.pauseTask : t.pauseUnsupportedKind,
2131
+ disabled: !canPause(item, now) || pausing.has(item.id),
2132
+ onClick: () => handlePause(item),
2133
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueuePauseIcon, {})
2134
+ }
2135
+ ),
2136
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2137
+ "button",
2138
+ {
2139
+ type: "button",
2140
+ className: "ss-dock-action",
2141
+ title: t.deleteTask,
2142
+ "aria-label": t.deleteTask,
2143
+ onClick: () => handleCancel(item.id, isPaused ? "paused" : "active"),
2144
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueueDeleteIcon, {})
2145
+ }
2146
+ ),
2147
+ item.kind !== "every" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
2148
+ "button",
2149
+ {
2150
+ type: "button",
2151
+ className: `ss-dock-action ss-dock-action-steer${steering.has(item.id) ? " ss-pending" : ""}${steerDone.has(item.id) ? " ss-done" : ""}`,
2152
+ title: steerDone.has(item.id) ? t.steerAlreadySent : t.steerTask,
2153
+ "aria-label": steerDone.has(item.id) ? t.steerAlreadySent : t.steerTask,
2154
+ disabled: steering.has(item.id) || steerDone.has(item.id),
2155
+ onClick: () => handleSteer(item),
2156
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueueSendIcon, {})
2157
+ }
2158
+ )
2159
+ ] })
2160
+ ]
2161
+ },
2162
+ item.id
2163
+ );
1759
2164
  };
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)(
2165
+ 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: [
2166
+ schedules.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1762
2167
  "button",
1763
2168
  {
1764
2169
  type: "button",
@@ -1766,23 +2171,48 @@ function ScheduleDock({ callCommand, sessionId, useProjection, locale }) {
1766
2171
  "aria-expanded": !collapsed,
1767
2172
  onClick: () => setCollapsed((value) => !value),
1768
2173
  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, {}) })
2174
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ss-dock-lead", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(QueueClockIcon, {}) }),
2175
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "ss-dock-count", children: format(t.panelCount, { n: schedules.length }) }),
2176
+ /* @__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
2177
  ]
1773
2178
  }
1774
2179
  ),
1775
- expanded && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ul", { className: "ss-dock-list", children: schedules.map(renderRow) })
2180
+ expanded && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { className: "ss-dock-list", children: schedules.map(renderRow) })
1776
2181
  ] }) });
1777
2182
  }
1778
2183
  function MultiBar({
1779
2184
  item,
1780
2185
  now,
1781
2186
  firstSeen,
1782
- t
2187
+ t,
2188
+ frozen = false,
2189
+ frozenLeftMs,
2190
+ renderedAt
1783
2191
  }) {
1784
- const { totalRatio, count } = barSegments(item, now, firstSeen);
1785
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2192
+ const frozenSeg = frozen ? frozenBarSegments(item, frozenLeftMs ?? 0, firstSeen, renderedAt) : void 0;
2193
+ const activeSeg = frozen ? void 0 : barSegments(item, now, firstSeen);
2194
+ const { totalRatio, count } = frozenSeg ?? activeSeg ?? { totalRatio: 0, count: 1 };
2195
+ const phaseAtRef = (0, import_react7.useRef)(null);
2196
+ if (frozen || prefersReducedMotion()) {
2197
+ phaseAtRef.current = null;
2198
+ } else if (phaseAtRef.current === null) {
2199
+ phaseAtRef.current = now;
2200
+ }
2201
+ const anim = frozen || prefersReducedMotion() ? void 0 : planBarAnimationFor(item, phaseAtRef.current ?? now, firstSeen);
2202
+ const fillStyle = anim === void 0 ? { width: `${totalRatio * 100}%` } : {
2203
+ /**
2204
+ * 只注入**参数**(CSS 变量),动画的组装交给 CSS(见 styles.ts)。
2205
+ *
2206
+ * 这样做的原因:动画声明留在 CSS 里,JS 不碰 `animationName` 等简写属性
2207
+ * ——否则会整条覆盖 CSS 的声明。当前只有进度推进一个动画,但保持这个
2208
+ * 分工,将来若再加纹理/状态动效不必回头改 JS。
2209
+ */
2210
+ ["--ss-bar-duration"]: `${anim.durationMs}ms`,
2211
+ // 负 delay 把播放头定位到挂载时刻的绝对相位;此后恒定不变
2212
+ // (重算会让动画多跳——见上方 phaseAtRef 注释)。
2213
+ ["--ss-bar-delay"]: `${anim.delayMs}ms`
2214
+ };
2215
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1786
2216
  "div",
1787
2217
  {
1788
2218
  className: `ss-dock-bars${count > 4 ? " ss-dock-bars-compact" : ""}`,
@@ -1791,8 +2221,8 @@ function MultiBar({
1791
2221
  "aria-valuemax": 100,
1792
2222
  "aria-valuenow": Math.round(totalRatio * 100),
1793
2223
  "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)(
2224
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "ss-dock-bar", children: [
2225
+ count > 1 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1796
2226
  "div",
1797
2227
  {
1798
2228
  className: "ss-dock-bar-divider",
@@ -1801,55 +2231,120 @@ function MultiBar({
1801
2231
  }
1802
2232
  }
1803
2233
  ),
1804
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ss-dock-bar-fill", style: { width: `${totalRatio * 100}%` } })
2234
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "ss-dock-bar-fill", style: fillStyle })
1805
2235
  ] })
1806
2236
  }
1807
2237
  );
1808
2238
  }
1809
2239
  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" }) });
2240
+ 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
2241
  }
1812
2242
  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" }) });
2243
+ 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
2244
  }
1815
2245
  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" }) });
2246
+ 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
2247
  }
1818
2248
  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" }) });
2249
+ 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
2250
  }
1821
2251
  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" }) });
2252
+ 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" }) });
2253
+ }
2254
+ function QueuePauseIcon() {
2255
+ 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: [
2256
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "3.6", y: "2.6", width: "3.2", height: "10.8", rx: "1.1", fill: "currentColor" }),
2257
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("rect", { x: "9.2", y: "2.6", width: "3.2", height: "10.8", rx: "1.1", fill: "currentColor" })
2258
+ ] });
2259
+ }
2260
+ function QueueResumeIcon() {
2261
+ 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
2262
  }
1824
2263
 
1825
2264
  // 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" }
2265
+ var import_react8 = require("react");
2266
+ var import_jsx_runtime5 = require("react/jsx-runtime");
2267
+ var SECTIONS = [
2268
+ {
2269
+ id: "display",
2270
+ titleKey: "sectionDisplay",
2271
+ layout: "stack",
2272
+ fields: [
2273
+ {
2274
+ kind: "boolean",
2275
+ key: "showButton",
2276
+ labelKey: "showButtonLabel",
2277
+ hintKey: "showButtonHint",
2278
+ defaultValue: true
2279
+ },
2280
+ {
2281
+ kind: "enum",
2282
+ key: "clockIconStyle",
2283
+ labelKey: "clockIconStyleLabel",
2284
+ hintKey: "clockIconStyleHint",
2285
+ options: ["auto", "modern", "classic"],
2286
+ defaultValue: "auto"
2287
+ },
2288
+ { kind: "number", key: "maxSchedules", labelKey: "maxSchedulesLabel", hintKey: "maxSchedulesHint", defaultValue: 100 }
2289
+ ]
2290
+ },
2291
+ {
2292
+ id: "time",
2293
+ titleKey: "sectionTime",
2294
+ layout: "grid",
2295
+ fields: [
2296
+ { kind: "time", key: "workStart", labelKey: "workStartLabel", hintKey: "smartWindowHint" },
2297
+ { kind: "time", key: "workEnd", labelKey: "workEndLabel" },
2298
+ { kind: "time", key: "lunchStart", labelKey: "lunchStartLabel" },
2299
+ { kind: "time", key: "lunchEnd", labelKey: "lunchEndLabel" },
2300
+ { kind: "time", key: "eveningEnd", labelKey: "eveningEndLabel" }
2301
+ ]
2302
+ },
2303
+ {
2304
+ id: "delivery",
2305
+ titleKey: "sectionDelivery",
2306
+ layout: "stack",
2307
+ fields: [
2308
+ {
2309
+ kind: "enum",
2310
+ key: "steerDelivery",
2311
+ labelKey: "steerDeliveryLabel",
2312
+ hintKey: "steerDeliveryHint",
2313
+ options: ["followup", "steer"],
2314
+ defaultValue: "followup"
2315
+ },
2316
+ {
2317
+ kind: "boolean",
2318
+ key: "confirmDelivery",
2319
+ labelKey: "confirmDeliveryLabel",
2320
+ hintKey: "confirmDeliveryHint",
2321
+ defaultValue: true
2322
+ },
2323
+ {
2324
+ kind: "enum",
2325
+ key: "onUnconfirmed",
2326
+ labelKey: "onUnconfirmedLabel",
2327
+ hintKey: "onUnconfirmedHint",
2328
+ options: ["keep", "discard"],
2329
+ defaultValue: "keep"
2330
+ }
2331
+ ]
2332
+ }
1836
2333
  ];
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
- }
2334
+ var FIELDS = SECTIONS.flatMap((s) => s.fields);
1840
2335
  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)(() => {
2336
+ const [snapshot, setSnapshot] = (0, import_react8.useState)(() => scope.getSnapshot());
2337
+ const [pending, setPending] = (0, import_react8.useState)({});
2338
+ const [saving, setSaving] = (0, import_react8.useState)(false);
2339
+ const [failed, setFailed] = (0, import_react8.useState)(false);
2340
+ const [helpOpen, setHelpOpen] = (0, import_react8.useState)({});
2341
+ (0, import_react8.useEffect)(() => {
1847
2342
  const initial = scope.getSnapshot();
1848
2343
  setSnapshot(initial);
1849
2344
  setPending({});
1850
2345
  if (initial.status === "ready") setFailed(false);
1851
2346
  }, [scope]);
1852
- (0, import_react9.useEffect)(() => {
2347
+ (0, import_react8.useEffect)(() => {
1853
2348
  return scope.subscribe(() => {
1854
2349
  const snap = scope.getSnapshot();
1855
2350
  setSnapshot(snap);
@@ -1858,10 +2353,10 @@ function SchedulerSettingsCard({ scope, t }) {
1858
2353
  }
1859
2354
  });
1860
2355
  }, [scope]);
1861
- if (snapshot.status === "unavailable") return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, {});
2356
+ if (snapshot.status === "unavailable") return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_jsx_runtime5.Fragment, {});
1862
2357
  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") });
2358
+ if (snapshot.status === "loading") return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ss-hint", children: t("loading") });
2359
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "ss-hint", children: t("unavailable") });
1865
2360
  }
1866
2361
  const value = snapshot.value ?? {};
1867
2362
  const base = snapshot.base ?? {};
@@ -1879,6 +2374,10 @@ function SchedulerSettingsCard({ scope, t }) {
1879
2374
  const v2 = value[field.key];
1880
2375
  return v2 === false ? "false" : "true";
1881
2376
  }
2377
+ if (field.kind === "enum") {
2378
+ const v2 = value[field.key];
2379
+ return typeof v2 === "string" ? v2 : field.defaultValue;
2380
+ }
1882
2381
  const v = value[field.key];
1883
2382
  return v ?? "";
1884
2383
  };
@@ -1891,6 +2390,10 @@ function SchedulerSettingsCard({ scope, t }) {
1891
2390
  const v2 = base[field.key];
1892
2391
  return v2 === false ? "false" : "true";
1893
2392
  }
2393
+ if (field.kind === "enum") {
2394
+ const v2 = base[field.key];
2395
+ return typeof v2 === "string" ? v2 : field.defaultValue;
2396
+ }
1894
2397
  const v = base[field.key];
1895
2398
  return v ?? "";
1896
2399
  };
@@ -1903,6 +2406,7 @@ function SchedulerSettingsCard({ scope, t }) {
1903
2406
  return null;
1904
2407
  }
1905
2408
  if (field.kind === "boolean") return null;
2409
+ if (field.kind === "enum") return field.options.includes(raw) ? null : t("invalidLabel");
1906
2410
  if (raw.trim().length === 0) return null;
1907
2411
  if (!isValidHhmm(raw)) return t("invalidTimeLabel");
1908
2412
  return null;
@@ -1918,11 +2422,11 @@ function SchedulerSettingsCard({ scope, t }) {
1918
2422
  setFieldPending(field.key, baselineValue(field), true);
1919
2423
  setFailed(false);
1920
2424
  };
1921
- const handleDiscard = (0, import_react9.useCallback)(() => {
2425
+ const handleDiscard = (0, import_react8.useCallback)(() => {
1922
2426
  setPending({});
1923
2427
  setFailed(false);
1924
2428
  }, []);
1925
- const handleSave = (0, import_react9.useCallback)(async () => {
2429
+ const handleSave = (0, import_react8.useCallback)(async () => {
1926
2430
  if (!dirty || saving || !writable) return;
1927
2431
  setSaving(true);
1928
2432
  setFailed(false);
@@ -1955,66 +2459,91 @@ function SchedulerSettingsCard({ scope, t }) {
1955
2459
  };
1956
2460
  const anyInvalid = FIELDS.some((field) => invalidField(field) !== null);
1957
2461
  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) => {
2462
+ const confirmEnabled = (pending.confirmDelivery?.value ?? (value.confirmDelivery === false ? "false" : "true")) !== "false";
2463
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-settings-form", children: [
2464
+ !writable && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ss-hint", role: "status", children: t("readOnly") }),
2465
+ SECTIONS.map((section) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { className: "ss-section", "aria-labelledby": `ss-section-${section.id}`, children: [
2466
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { className: "ss-section-heading", id: `ss-section-${section.id}`, children: t(section.titleKey) }),
2467
+ /* @__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
2468
  const invalid = invalidField(field);
1981
2469
  const isTime = field.kind === "time";
1982
2470
  const labelKey = field.labelKey;
1983
2471
  const hintKey = field.hintKey;
1984
2472
  const userHas = isUserOverridden(field.key);
1985
2473
  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)(
2474
+ const helpHint = hintKey !== void 0 && t(hintKey).length > 0;
2475
+ const badges = userHas ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: "ss-card-badges", children: [
2476
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "ss-card-badge", children: t("overriddenLabel") }),
2477
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2478
+ "button",
2479
+ {
2480
+ type: "button",
2481
+ className: "ss-card-reset",
2482
+ disabled: !writable || saving,
2483
+ onClick: () => handleResetField(field),
2484
+ children: t("resetLabel")
2485
+ }
2486
+ )
2487
+ ] }) : null;
2488
+ if (field.kind === "boolean") {
2489
+ const checked = displayValue(field) !== "false";
2490
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-field ss-fieldToggle", children: [
2491
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-toggle-row", children: [
2492
+ /* @__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) }) }),
2493
+ badges,
2494
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1992
2495
  "button",
1993
2496
  {
1994
2497
  type: "button",
1995
- className: "ss-card-reset",
2498
+ id: fieldId,
2499
+ role: "switch",
2500
+ "aria-checked": checked,
2501
+ "aria-label": t(labelKey),
2502
+ className: "ss-toggle-switch",
1996
2503
  disabled: !writable || saving,
1997
- onClick: () => handleResetField(field),
1998
- children: t("resetLabel")
2504
+ onClick: () => handleFieldEdit(field, checked ? "false" : "true")
1999
2505
  }
2000
2506
  )
2001
- ] })
2507
+ ] }),
2508
+ helpHint ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ss-toggle-description", children: t(hintKey) }) : null,
2509
+ invalid !== null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ss-card-invalid", role: "status", children: invalid }) : null
2510
+ ] }, field.key);
2511
+ }
2512
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-field", children: [
2513
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-card-fieldHead", children: [
2514
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-label-group", children: [
2515
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("label", { htmlFor: fieldId, className: "ss-card-label", children: t(labelKey) }),
2516
+ helpHint && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2517
+ "button",
2518
+ {
2519
+ type: "button",
2520
+ className: helpOpen[field.key] === true ? "ss-help-btn ss-help-btnOpen" : "ss-help-btn",
2521
+ "aria-label": `${t(labelKey)}\u8BF4\u660E`,
2522
+ "aria-expanded": helpOpen[field.key] === true,
2523
+ "aria-controls": `ss-help-${field.key}`,
2524
+ onClick: () => setHelpOpen((prev) => ({ ...prev, [field.key]: !prev[field.key] })),
2525
+ 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: [
2526
+ /* @__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" }),
2527
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M7.6127 3.18921V4.55986H6.38735V3.18921H7.6127Z", fill: "currentColor" }),
2528
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: "M7.6127 5.68921V10.8109H6.38735V5.68921H7.6127Z", fill: "currentColor" })
2529
+ ] })
2530
+ }
2531
+ )
2532
+ ] }),
2533
+ badges
2002
2534
  ] }),
2003
- field.kind === "boolean" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2535
+ field.kind === "enum" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2004
2536
  "select",
2005
2537
  {
2006
2538
  id: fieldId,
2007
2539
  className: invalid !== null ? "ss-input ss-inputInvalid" : "ss-input",
2008
2540
  "aria-invalid": invalid !== null || void 0,
2009
- value: displayValue(field) === "false" ? "false" : "true",
2541
+ value: displayValue(field),
2010
2542
  disabled: !writable || saving,
2011
2543
  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
- ]
2544
+ children: field.options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: option, children: t(`${field.key}Option_${option}`) }, option))
2016
2545
  }
2017
- ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2546
+ ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2018
2547
  "input",
2019
2548
  {
2020
2549
  id: fieldId,
@@ -2028,33 +2557,36 @@ function SchedulerSettingsCard({ scope, t }) {
2028
2557
  onChange: (event) => handleFieldEdit(field, event.target.value)
2029
2558
  }
2030
2559
  ),
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
2560
+ invalid !== null ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ss-card-invalid", role: "status", children: invalid }) : null,
2561
+ 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,
2562
+ 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,
2563
+ field.key === "onUnconfirmed" && displayValue(field) === "discard" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ss-card-risk", role: "status", children: t("discardRisk") }) : null
2032
2564
  ] }, 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
2565
+ }) })
2566
+ ] }, section.id)),
2567
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ss-card-footer", children: [
2568
+ failed && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "ss-card-failed", role: "status", children: t("saveFailed") }),
2569
+ dirty && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2570
+ "button",
2571
+ {
2572
+ type: "button",
2573
+ className: "ss-card-discard",
2574
+ disabled: saving,
2575
+ onClick: handleDiscard,
2576
+ children: t("discard")
2577
+ }
2578
+ ),
2579
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2580
+ "button",
2581
+ {
2582
+ type: "button",
2583
+ className: "ss-card-save",
2584
+ disabled: saveDisabled,
2585
+ onClick: () => void handleSave(),
2586
+ children: saving ? t("saving") : t("save")
2587
+ }
2588
+ )
2589
+ ] })
2058
2590
  ] });
2059
2591
  }
2060
2592
 
@@ -2063,15 +2595,21 @@ var PRESENCE_URGENT_WINDOW_MS = 5 * 6e4;
2063
2595
  function summarizeSchedules(schedules) {
2064
2596
  let nextAt;
2065
2597
  let count = 0;
2598
+ let pausedCount = 0;
2066
2599
  for (const item of schedules ?? []) {
2067
2600
  const raw = item.scheduled_at ?? item.scheduledAt;
2068
2601
  if (raw === void 0) continue;
2069
2602
  const epoch = Date.parse(raw);
2070
2603
  if (!Number.isFinite(epoch)) continue;
2071
2604
  count += 1;
2605
+ if (item.status === "paused") {
2606
+ pausedCount += 1;
2607
+ continue;
2608
+ }
2072
2609
  if (nextAt === void 0 || epoch < nextAt) nextAt = epoch;
2073
2610
  }
2074
- return nextAt === void 0 ? { count: 0 } : { count, nextAt };
2611
+ if (count === 0) return { count: 0, pausedCount: 0 };
2612
+ return nextAt === void 0 ? { count, pausedCount } : { count, nextAt, pausedCount };
2075
2613
  }
2076
2614
  function badgeStateFor(nextAt, now) {
2077
2615
  if (nextAt === void 0) return "scheduled";
@@ -2080,6 +2618,24 @@ function badgeStateFor(nextAt, now) {
2080
2618
  if (diff <= PRESENCE_URGENT_WINDOW_MS) return "urgent";
2081
2619
  return "scheduled";
2082
2620
  }
2621
+ function hoverScheduleStatus(entry, now, labels, strings, formatHhmm3, formatDate2) {
2622
+ const tone = badgeStateFor(entry.nextAt, now);
2623
+ if (entry.nextAt === void 0 && entry.pausedCount > 0) {
2624
+ const paused = strings.hoverSchedulePaused ?? strings.hoverScheduleOverdue;
2625
+ return { label: formatTemplate(paused, { n: entry.count }), tone };
2626
+ }
2627
+ if (tone === "overdue" || entry.nextAt === void 0) {
2628
+ return { label: formatTemplate(strings.hoverScheduleOverdue, { n: entry.count }), tone };
2629
+ }
2630
+ const time = relativeFireLabel(entry.nextAt, now, labels, formatHhmm3, formatDate2);
2631
+ return { label: formatTemplate(strings.hoverScheduleStatus, { n: entry.count, time }), tone };
2632
+ }
2633
+ function formatTemplate(template, params) {
2634
+ return template.replace(
2635
+ /\{(\w+)\}/g,
2636
+ (match, key) => key in params ? String(params[key]) : match
2637
+ );
2638
+ }
2083
2639
  function startOfDay(epoch) {
2084
2640
  const d = new Date(epoch);
2085
2641
  d.setHours(0, 0, 0, 0);
@@ -2099,17 +2655,25 @@ function relativeFireLabel(nextAt, now, labels, formatHhmm3, formatDate2) {
2099
2655
 
2100
2656
  // src/client/session-presence.ts
2101
2657
  var BADGE_CLASS = "ss-presence";
2658
+ var HOVER_ROW_CLASS = "ss-hover-status";
2102
2659
  var FIBER_MAX_DEPTH = 8;
2103
2660
  var SCAN_DEBOUNCE_MS = 60;
2104
2661
  var STATE_TICK_MS = 3e4;
2105
2662
  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>';
2663
+ 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>';
2664
+ var CLOCK_SVG_MODERN = '<svg width="14" height="14" viewBox="0 0 24 24" aria-hidden="true"><circle class="ss-clock-face" cx="12" cy="12" r="9.5"/><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
2665
  var hhmmFormatter = new Intl.DateTimeFormat(void 0, { hour: "2-digit", minute: "2-digit", hour12: false });
2108
2666
  var dateFormatter = new Intl.DateTimeFormat(void 0, { month: "short", day: "numeric" });
2109
2667
  var formatHhmm2 = (epoch) => hhmmFormatter.format(epoch);
2110
2668
  var formatDate = (epoch) => dateFormatter.format(epoch);
2111
2669
  function sessionIdOfRow(row) {
2112
- const host = row;
2670
+ return sessionIdOfNode(row);
2671
+ }
2672
+ function sessionIdOfHoverCard(card) {
2673
+ return sessionIdOfNode(card);
2674
+ }
2675
+ function sessionIdOfNode(element) {
2676
+ const host = element;
2113
2677
  const fiberKey = Object.keys(host).find((key) => key.startsWith("__reactFiber$"));
2114
2678
  if (fiberKey === void 0) return void 0;
2115
2679
  let fiber = host[fiberKey];
@@ -2148,10 +2712,14 @@ function labelsFor(dict) {
2148
2712
  };
2149
2713
  }
2150
2714
  function mountSessionPresence(options) {
2151
- const { sessions, locale } = options;
2715
+ const { sessions, locale, getClockIconStyle } = options;
2152
2716
  if (typeof document === "undefined" || typeof MutationObserver === "undefined") {
2153
2717
  return () => void 0;
2154
2718
  }
2719
+ const getClockSvg = () => {
2720
+ const style = getClockIconStyle?.() ?? "auto";
2721
+ return style === "classic" ? CLOCK_SVG_CLASSIC : CLOCK_SVG_MODERN;
2722
+ };
2155
2723
  let index = /* @__PURE__ */ new Map();
2156
2724
  let scanTimer;
2157
2725
  let disposed = false;
@@ -2165,6 +2733,7 @@ function mountSessionPresence(options) {
2165
2733
  if (row.hasAttribute("aria-expanded")) continue;
2166
2734
  applyBadge(row, now, dict);
2167
2735
  }
2736
+ applyHoverCard(now, dict);
2168
2737
  };
2169
2738
  const scheduleScan = () => {
2170
2739
  if (disposed || scanTimer !== void 0) return;
@@ -2184,8 +2753,9 @@ function mountSessionPresence(options) {
2184
2753
  }
2185
2754
  const state = badgeStateFor(entry.nextAt, now);
2186
2755
  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 });
2756
+ const allPaused = entry.nextAt === void 0 && entry.pausedCount > 0;
2757
+ const aria = allPaused ? format(dict.presencePausedAria, { n: entry.count }) : state === "overdue" ? format(dict.presenceOverdueAria, { n: entry.count }) : format(dict.presenceBadgeAria, { n: entry.count, time });
2758
+ const tooltip = allPaused ? format(dict.presencePausedTooltip, { n: entry.count }) : state === "overdue" ? format(dict.presenceOverdueTooltip, { n: entry.count }) : format(dict.presenceTooltip, { n: entry.count, time });
2189
2759
  if (existing !== null) {
2190
2760
  if (existing.dataset.state !== state) existing.dataset.state = state;
2191
2761
  if (existing.getAttribute("aria-label") !== aria) existing.setAttribute("aria-label", aria);
@@ -2201,10 +2771,55 @@ function mountSessionPresence(options) {
2201
2771
  badge.setAttribute("role", "img");
2202
2772
  badge.setAttribute("aria-label", aria);
2203
2773
  badge.setAttribute("title", tooltip);
2204
- badge.innerHTML = CLOCK_SVG;
2774
+ badge.innerHTML = getClockSvg();
2205
2775
  if (beside) slot.after(badge);
2206
2776
  else slot.append(badge);
2207
2777
  }
2778
+ function findHoverCard() {
2779
+ for (const card of Array.from(document.body.children)) {
2780
+ if (!(card instanceof HTMLElement)) continue;
2781
+ const statusHost = card.firstElementChild;
2782
+ if (!(statusHost instanceof HTMLElement)) continue;
2783
+ const hasStatusRow = Array.from(statusHost.children).some((child) => {
2784
+ const dot = child.firstElementChild;
2785
+ return child.children.length >= 2 && dot !== null && dot.tagName === "SPAN" && dot.getAttribute("aria-hidden") === "true";
2786
+ });
2787
+ if (!hasStatusRow) continue;
2788
+ const sessionId = sessionIdOfHoverCard(card);
2789
+ if (sessionId === void 0) continue;
2790
+ return { card, statusHost, sessionId };
2791
+ }
2792
+ return null;
2793
+ }
2794
+ function applyHoverCard(now, dict) {
2795
+ const found = findHoverCard();
2796
+ if (found === null) return;
2797
+ const { statusHost, sessionId } = found;
2798
+ const existing = statusHost.querySelector(`:scope > .${HOVER_ROW_CLASS}`);
2799
+ const entry = index.get(sessionId);
2800
+ if (entry === void 0) {
2801
+ existing?.remove();
2802
+ return;
2803
+ }
2804
+ const { label } = hoverScheduleStatus(entry, now, labelsFor(dict), dict, formatHhmm2, formatDate);
2805
+ const state = badgeStateFor(entry.nextAt, now);
2806
+ if (existing !== null) {
2807
+ const text2 = existing.lastElementChild;
2808
+ if (text2 !== null && text2.textContent !== label) text2.textContent = label;
2809
+ if (existing.dataset.state !== state) existing.dataset.state = state;
2810
+ return;
2811
+ }
2812
+ const row = document.createElement("div");
2813
+ row.className = HOVER_ROW_CLASS;
2814
+ row.dataset.state = state;
2815
+ const dot = document.createElement("span");
2816
+ dot.setAttribute("aria-hidden", "true");
2817
+ dot.className = "ss-hover-status-dot";
2818
+ const text = document.createElement("span");
2819
+ text.textContent = label;
2820
+ row.append(dot, text);
2821
+ statusHost.append(row);
2822
+ }
2208
2823
  const unsubscribeList = sessions.list.subscribe(scheduleScan);
2209
2824
  const unsubscribeLocale = locale?.subscribe(scheduleScan);
2210
2825
  const observer = new MutationObserver(scheduleScan);
@@ -2241,26 +2856,33 @@ function mountSessionPresence(options) {
2241
2856
  document.removeEventListener("visibilitychange", onVisible);
2242
2857
  window.removeEventListener("online", onVisible);
2243
2858
  for (const badge of Array.from(document.querySelectorAll(`.${BADGE_CLASS}`))) badge.remove();
2859
+ for (const row of Array.from(document.querySelectorAll(`.${HOVER_ROW_CLASS}`))) row.remove();
2244
2860
  };
2245
2861
  }
2246
2862
 
2247
2863
  // src/client/index.tsx
2248
2864
  var INPUT_RIGHT_SLOT = "conversation.input.right";
2249
- var inject = ["slots", "sessions", "conversation", "settingsScope", "locale"];
2865
+ var inject = ["slots", "sessions", "conversation", "locale"];
2250
2866
  var NS = "settings.plugins.later";
2251
2867
  var SETTINGS_NS = "dsh-later";
2868
+ var ENTRY_ID = "later";
2252
2869
  function apply(ctx) {
2253
2870
  const slots = ctx.get("slots");
2254
2871
  const sessions = ctx.get("sessions");
2255
- const settingsScope = ctx.get("settingsScope");
2256
2872
  const locale = ctx.get("locale");
2257
2873
  if (slots === void 0 || sessions === void 0) return;
2258
2874
  ctx.effect(() => injectStyles(), "dsh-later: styles");
2259
- ctx.effect(() => mountReminderToastHost(), "dsh-later: toast host");
2875
+ let detectedVersion = "classic";
2876
+ let getClockIconStyle = () => "auto";
2260
2877
  ctx.effect(
2261
2878
  () => mountSessionPresence({
2262
2879
  sessions,
2263
- ...locale === void 0 ? {} : { locale }
2880
+ ...locale === void 0 ? {} : { locale },
2881
+ getClockIconStyle: () => {
2882
+ const style = getClockIconStyle();
2883
+ if (style === "auto") return detectedVersion;
2884
+ return style;
2885
+ }
2264
2886
  }),
2265
2887
  "dsh-later: presence"
2266
2888
  );
@@ -2273,10 +2895,11 @@ function apply(ctx) {
2273
2895
  expand: "\u5C55\u5F00\u8BBE\u7F6E",
2274
2896
  collapse: "\u6536\u8D77\u8BBE\u7F6E",
2275
2897
  readOnly: "\u672C\u90E8\u7F72\u7684\u8BBE\u7F6E\u4E3A\u53EA\u8BFB\u3002",
2898
+ sectionDisplay: "\u663E\u793A\u8BBE\u7F6E",
2899
+ sectionTime: "\u65F6\u95F4\u8BBE\u7F6E",
2900
+ sectionDelivery: "\u6295\u9012\u8BBE\u7F6E",
2276
2901
  showButtonLabel: "\u663E\u793A\u5B9A\u65F6\u6309\u94AE",
2277
2902
  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
2903
  maxSchedulesLabel: "\u5355\u4F1A\u8BDD\u4EFB\u52A1\u4E0A\u9650",
2281
2904
  maxSchedulesHint: "\u5355\u4E2A\u4F1A\u8BDD\u5185\u5141\u8BB8\u521B\u5EFA\u7684\u6700\u5927\u5B9A\u65F6\u4EFB\u52A1\u6570\u91CF\u3002",
2282
2905
  smartWindowHint: "\u7528\u4E8E\u300C\u5DE5\u4F5C\u65F6\u95F4\u300D\u82AF\u7247\u4E0E\u667A\u80FD\u6A21\u5F0F\u81EA\u52A8\u6392\u671F\u3002",
@@ -2285,6 +2908,24 @@ function apply(ctx) {
2285
2908
  lunchStartLabel: "\u5348\u4F11\u5F00\u59CB",
2286
2909
  lunchEndLabel: "\u5348\u4F11\u7ED3\u675F",
2287
2910
  eveningEndLabel: "\u591C\u95F4\u9759\u9ED8\u8D77\u70B9",
2911
+ steerDeliveryLabel: "\u63D2\u8BDD\u6295\u9012\u65B9\u5F0F",
2912
+ steerDeliveryHint: "\u300C\u63D2\u8BDD\u53D1\u9001\u300D\u628A\u63D0\u9192\u5185\u5BB9\u63A8\u7ED9\u4F1A\u8BDD\u65F6\u8FDB\u5165\u7684\u961F\u5217\u3002",
2913
+ steerDeliveryOption_followup: "\u72EC\u7ACB\u6210\u4E00\u8F6E\uFF08\u63A8\u8350\uFF09",
2914
+ steerDeliveryOption_steer: "\u63D2\u5165\u5F53\u524D\u56DE\u5408\uFF08\u66F4\u5FEB\uFF09",
2915
+ confirmDeliveryLabel: "\u6295\u9012\u786E\u8BA4",
2916
+ 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",
2917
+ onUnconfirmedLabel: "\u672A\u786E\u8BA4\u65F6",
2918
+ onUnconfirmedHint: "\u6295\u9012\u672A\u80FD\u786E\u8BA4\u65F6\u7684\u5904\u7406\u65B9\u5F0F\u3002",
2919
+ onUnconfirmedOption_keep: "\u4FDD\u7559\u6761\u76EE\u53EF\u91CD\u8BD5\uFF08\u63A8\u8350\uFF09",
2920
+ onUnconfirmedOption_discard: "\u4E22\u5F03",
2921
+ clockIconStyleLabel: "\u65F6\u949F\u56FE\u6807\u98CE\u683C",
2922
+ clockIconStyleHint: "\u4FA7\u680F\u4F1A\u8BDD\u884C\u5B9A\u65F6\u72B6\u6001\u56FE\u6807\u7684\u663E\u793A\u98CE\u683C\u3002",
2923
+ clockIconStyleOption_auto: "\u81EA\u52A8\uFF08\u63A8\u8350\uFF09",
2924
+ clockIconStyleOption_modern: "\u65B0\u7248\u63CF\u8FB9\u98CE\u683C",
2925
+ clockIconStyleOption_classic: "\u65E7\u7248\u70B9\u9635\u98CE\u683C",
2926
+ 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",
2927
+ 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",
2928
+ 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
2929
  overriddenLabel: "\u5DF2\u8986\u76D6",
2289
2930
  resetLabel: "\u91CD\u7F6E",
2290
2931
  invalidLabel: "\u8BF7\u8F93\u5165\u6709\u6548\u7684\u6570\u5B57\u3002",
@@ -2303,10 +2944,11 @@ function apply(ctx) {
2303
2944
  expand: "Show settings",
2304
2945
  collapse: "Hide settings",
2305
2946
  readOnly: "Settings for this deployment are read-only.",
2947
+ sectionDisplay: "Display",
2948
+ sectionTime: "Time windows",
2949
+ sectionDelivery: "Delivery",
2306
2950
  showButtonLabel: "Show schedule button",
2307
2951
  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
2952
  maxSchedulesLabel: "Max schedules per session",
2311
2953
  maxSchedulesHint: "Maximum number of scheduled reminders allowed per session.",
2312
2954
  smartWindowHint: "Used by the Work-hours chip and smart auto-scheduling.",
@@ -2315,6 +2957,24 @@ function apply(ctx) {
2315
2957
  lunchStartLabel: "Lunch break start",
2316
2958
  lunchEndLabel: "Lunch break end",
2317
2959
  eveningEndLabel: "Night quiet starts at",
2960
+ steerDeliveryLabel: "Interject delivery",
2961
+ steerDeliveryHint: 'Which queue the reminder content enters when you press "Send interjection".',
2962
+ steerDeliveryOption_followup: "Own turn (recommended)",
2963
+ steerDeliveryOption_steer: "Current turn (faster)",
2964
+ confirmDeliveryLabel: "Confirm delivery",
2965
+ 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.",
2966
+ onUnconfirmedLabel: "When unconfirmed",
2967
+ onUnconfirmedHint: "What to do when delivery cannot be confirmed.",
2968
+ onUnconfirmedOption_keep: "Keep for retry (recommended)",
2969
+ onUnconfirmedOption_discard: "Discard",
2970
+ clockIconStyleLabel: "Clock icon style",
2971
+ clockIconStyleHint: "Display style of the schedule status icon in the sidebar.",
2972
+ clockIconStyleOption_auto: "Auto (recommended)",
2973
+ clockIconStyleOption_modern: "Modern stroke style",
2974
+ clockIconStyleOption_classic: "Classic dot-matrix style",
2975
+ 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.",
2976
+ steerRiskUnguarded: "\u26A0 May be swallowed when it collides with turn start, and the reminder will NOT be kept (delivery confirmation is off).",
2977
+ discardRisk: "\u26A0 Unconfirmed reminders are removed from the list \u2014 silent loss becomes possible again.",
2318
2978
  overriddenLabel: "Overridden",
2319
2979
  resetLabel: "Reset",
2320
2980
  invalidLabel: "Please enter a valid number.",
@@ -2331,27 +2991,14 @@ function apply(ctx) {
2331
2991
  const callCommand = async (sessionId, line) => {
2332
2992
  const actx = sessions.scope(sessionId);
2333
2993
  const face = actx === void 0 ? void 0 : sessions.sessionOf(actx);
2334
- if (face === void 0) return false;
2994
+ if (face === void 0) return { matched: false };
2335
2995
  try {
2336
2996
  const result = await face.command(line);
2337
- return result?.ok === true && result.value?.matched === true;
2997
+ return { matched: result?.ok === true && result.value?.matched === true };
2338
2998
  } catch {
2339
- return false;
2999
+ return { matched: false };
2340
3000
  }
2341
3001
  };
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
3002
  ctx.slots.inject(
2356
3003
  "conversation.input.dock",
2357
3004
  () => ctx.slots.register(
@@ -2364,19 +3011,74 @@ function apply(ctx) {
2364
3011
  ScheduleDock
2365
3012
  )
2366
3013
  );
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
- }
3014
+ let composerMounted = false;
3015
+ const mountComposer = (scope) => {
3016
+ if (composerMounted) return;
3017
+ composerMounted = true;
3018
+ ctx.slots.inject(
3019
+ INPUT_RIGHT_SLOT,
3020
+ () => ctx.slots.register(
3021
+ {
3022
+ name: INPUT_RIGHT_SLOT,
3023
+ id: "later",
3024
+ order: 50,
3025
+ inject: () => ({ callCommand, locale, schedulerScope: scope })
3026
+ },
3027
+ SchedButton
3028
+ )
3029
+ );
3030
+ };
3031
+ const cardT = locale === void 0 ? void 0 : locale.bind(NS);
3032
+ const cardDeclaration = (slot, scope) => ({
3033
+ name: slot,
3034
+ key: SETTINGS_NS,
3035
+ locale: NS,
3036
+ inject: () => ({ scope, t: cardT })
3037
+ });
3038
+ ctx.inject(["settingsScope"], () => {
3039
+ const binder = ctx.get("settingsScope");
3040
+ if (binder === void 0) return;
3041
+ detectedVersion = "classic";
3042
+ const scope = binder.bind({ namespace: SETTINGS_NS });
3043
+ getClockIconStyle = () => {
3044
+ const snap = scope.getSnapshot();
3045
+ if (snap.status !== "ready") return "auto";
3046
+ const value = snap.value ?? {};
3047
+ const style = value["clockIconStyle"];
3048
+ return style === "modern" || style === "classic" ? style : "auto";
3049
+ };
3050
+ mountComposer(scope);
3051
+ if (cardT === void 0) return;
3052
+ ctx.slots.inject(
3053
+ "settings.plugin.item",
3054
+ () => ctx.slots.register(cardDeclaration("settings.plugin.item", scope), SchedulerSettingsCard)
3055
+ );
3056
+ });
3057
+ ctx.inject(["configForms"], () => {
3058
+ const forms = ctx.get("configForms");
3059
+ if (forms === void 0 || typeof forms.get !== "function" || typeof forms.whileServed !== "function") return;
3060
+ detectedVersion = "modern";
3061
+ const scope = forms.get(ENTRY_ID);
3062
+ getClockIconStyle = () => {
3063
+ const snap = scope.getSnapshot();
3064
+ if (snap.status !== "ready") return "auto";
3065
+ const value = snap.value ?? {};
3066
+ const style = value["clockIconStyle"];
3067
+ return style === "modern" || style === "classic" ? style : "auto";
3068
+ };
3069
+ mountComposer(scope);
3070
+ if (cardT === void 0) return;
3071
+ ctx.effect(
3072
+ () => forms.whileServed(
3073
+ [ENTRY_ID],
3074
+ () => ctx.slots.inject(
3075
+ "plugins.bundle.config",
3076
+ () => ctx.slots.register(cardDeclaration("plugins.bundle.config", scope), SchedulerSettingsCard)
3077
+ )
3078
+ ),
3079
+ "dsh-later: plugins-page card"
3080
+ );
3081
+ });
2380
3082
  }
2381
3083
 
2382
3084
  return module.exports;