dsh-plugin-t-expert 0.3.90 → 0.3.92

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
@@ -39,7 +39,7 @@ __export(index_exports, {
39
39
  inject: () => inject
40
40
  });
41
41
  module.exports = __toCommonJS(index_exports);
42
- var import_react8 = __toESM(require("react"), 1);
42
+ var import_react7 = __toESM(require("react"), 1);
43
43
 
44
44
  // src/client/attention.jsx
45
45
  var import_react2 = __toESM(require("react"), 1);
@@ -103,8 +103,8 @@ function subscribePopoverClaims(listener) {
103
103
  // src/client/state.js
104
104
  var import_react = __toESM(require("react"), 1);
105
105
  var NS = "t-team";
106
- var CLIENT_BUILD_VERSION = "0.3.90";
107
- var uiPrefs = { showScheduleButton: true, showActivePulse: true };
106
+ var CLIENT_BUILD_VERSION = "0.3.92";
107
+ var uiPrefs = { showActivePulse: true };
108
108
  var UI_PREF_KEYS = Object.keys(uiPrefs);
109
109
  var uiPrefsListeners = /* @__PURE__ */ new Set();
110
110
  function setUiPrefs(next) {
@@ -118,13 +118,6 @@ function setUiPrefs(next) {
118
118
  if (!changed) return;
119
119
  for (const listener of uiPrefsListeners) listener();
120
120
  }
121
- function subscribeUiPrefs(listener) {
122
- uiPrefsListeners.add(listener);
123
- return () => uiPrefsListeners.delete(listener);
124
- }
125
- function scheduleEntryVisible() {
126
- return uiPrefs.showScheduleButton !== false;
127
- }
128
121
  function useUiPref(key, fallback = true) {
129
122
  return import_react.default.useSyncExternalStore(
130
123
  (onChange) => {
@@ -135,9 +128,6 @@ function useUiPref(key, fallback = true) {
135
128
  () => fallback
136
129
  );
137
130
  }
138
- function useShowScheduleButton() {
139
- return useUiPref("showScheduleButton", true);
140
- }
141
131
  function useShowActivePulse() {
142
132
  return useUiPref("showActivePulse", true);
143
133
  }
@@ -484,51 +474,6 @@ function displayDescription(expert, active) {
484
474
  function divisionLabel(expert, active) {
485
475
  return active === "en" ? expert.divisionEn || expert.division : expert.divisionZh || expert.division;
486
476
  }
487
- function matchExpertAtHead(text, experts, active) {
488
- if (!text.startsWith("@")) return void 0;
489
- let matched;
490
- for (const expert of experts ?? []) {
491
- const names = [displayName(expert, active), expert?.name, expert?.nameEn, expert?.slug].filter((name) => typeof name === "string" && name !== "");
492
- for (const name of names) {
493
- if (!text.startsWith(`@${name}`)) continue;
494
- if (matched === void 0 || name.length > matched.name.length) {
495
- matched = { name, display: displayName(expert, active) };
496
- }
497
- }
498
- }
499
- return matched;
500
- }
501
- function tokenizePrompt(text, experts, active) {
502
- const raw = String(text ?? "");
503
- const tokens = [];
504
- let buffer = "";
505
- let rest = raw;
506
- const flush = () => {
507
- if (buffer === "") return;
508
- tokens.push({ type: "text", text: buffer });
509
- buffer = "";
510
- };
511
- while (rest !== "") {
512
- const hit = rest.startsWith("@") ? matchExpertAtHead(rest, experts, active) : void 0;
513
- if (hit === void 0) {
514
- buffer += rest[0];
515
- rest = rest.slice(1);
516
- continue;
517
- }
518
- flush();
519
- tokens.push({ type: "expert", name: hit.display });
520
- rest = rest.slice(hit.name.length + 1);
521
- }
522
- flush();
523
- return tokens;
524
- }
525
- function collectExpertMentions(text, experts, active) {
526
- const names = [];
527
- for (const token of tokenizePrompt(text, experts, active)) {
528
- if (token.type === "expert" && !names.includes(token.name)) names.push(token.name);
529
- }
530
- return names;
531
- }
532
477
  function matchExpert(expert, active, query) {
533
478
  if (query === "") return true;
534
479
  const haystack = `${expert.name} ${expert.nameEn} ${expert.description} ${expert.descriptionEn} ${expert.slug}`.toLowerCase();
@@ -662,9 +607,16 @@ var CSS = `
662
607
  .t-team-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:10px 12px}
663
608
  .t-team-group{margin-top:6px}
664
609
  .t-team-division{font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary);margin:2px 0 6px}
665
- .t-team-card{position:relative;display:grid;min-width:0;min-height:132px;overflow:hidden;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-layer-2)}
666
- .t-team-card[data-enabled="true"]{border-color:var(--dsw-alias-button-primary-fill)}
667
- .t-team-card:hover{background:var(--dsw-alias-interactive-bg-hover)}
610
+ /* \u5361\u7247\u8FB9\u6846\uFF082026-09-26 \u7528\u6237\u53CD\u9988\u300C\u8FB9\u6846\u592A\u660E\u663E\u4E86\uFF0C\u4E0D\u534F\u8C03\u300D\uFF09\uFF1A
611
+ \u539F\u5148\u300C\u5DF2\u542F\u7528\u300D\u7684\u5361\u7247\u7528 button-primary-fill \u63CF\u8FB9\uFF0C\u4F46\u9010\u4E13\u5BB6\u542F\u505C\u5F00\u5173\u65E9\u5DF2\u4E0B\u7EBF
612
+ \uFF08\u89C1 settings.jsx \u91CC\u90A3\u6BB5\u6CE8\u91CA\uFF09\uFF0C\u540D\u5355\u9ED8\u8BA4\u5168\u90E8\u542F\u7528 \u2014\u2014 \u4E8E\u662F 323 \u5F20\u5361\u65E0\u4E00\u4F8B\u5916\u90FD\u6302\u4E0A
613
+ \u8FD1\u767D\u4E3B\u8272\u63CF\u8FB9\uFF08\u6DF1\u8272\u4E3B\u9898\u4E0B\u5C31\u662F --dsw-static-neutral-bluish-50 = #f9fafb\uFF09\uFF0C
614
+ \u5728 #2c2c2e \u7684\u5361\u7247\u5E95\u4E0A\u4EAE\u6210\u4E00\u6761\u6761\u767D\u6846\uFF0C\u65E2\u6CA1\u6709\u533A\u5206\u610F\u4E49\u53C8\u5F88\u624E\u773C\u3002
615
+ \u73B0\u5728\uFF1A\u5E38\u6001\u7528\u6700\u6DE1\u7684 border-l1\uFF0C\u60AC\u505C\u624D\u62AC\u5230 border-l2\uFF1B\u5361\u7247\u4E0E\u9875\u9762\u7684\u5C42\u6B21\u4EA4\u7ED9
616
+ bg-layer-2 \u672C\u8EAB\u53BB\u8868\u8FBE\u3002\u82E5\u4EE5\u540E\u6062\u590D\u300C\u6309\u4E13\u5BB6\u542F\u505C\u300D\uFF0C\u518D\u6309\u9700\u7ED9\u505C\u7528\u7684\u5361\u7247\u52A0\u533A\u5206
617
+ \uFF08\u522B\u518D\u7528\u4E3B\u8272\u63CF\u8FB9\uFF0C\u5B83\u662F\u7ED9\u6309\u94AE\u7528\u7684\uFF09\u3002 */
618
+ .t-team-card{position:relative;display:grid;min-width:0;min-height:132px;overflow:hidden;border:1px solid var(--dsw-alias-border-l1);border-radius:8px;background:var(--dsw-alias-bg-layer-2)}
619
+ .t-team-card:hover{background:var(--dsw-alias-interactive-bg-hover);border-color:var(--dsw-alias-border-l2)}
668
620
  /* \u53F3\u4E0A\u89D2\u5DE5\u5177\u4F4D\uFF1A\u67E5\u770B\u63D0\u793A\u8BCD + \u542F\u505C\u5F00\u5173 */
669
621
  .t-team-card-tools{position:absolute;top:8px;right:8px;display:flex;align-items:center;gap:6px;z-index:1}
670
622
  .t-team-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;padding:0;border-radius:6px;border:1px solid transparent;background:transparent;color:var(--dsw-alias-label-tertiary);font:inherit;font-size:13px;line-height:1;cursor:pointer}
@@ -721,9 +673,12 @@ var CSS = `
721
673
  .t-team-pop .t-team-input \u4E24\u6761\u89C4\u5219\u4E00\u8D77\u541E\u6389\uFF0C\u5F39\u7A97\u9000\u5316\u6210\u65E0\u6837\u5F0F\u5757\u7EA7\u5143\u7D20\uFF081265\xD712420\uFF09\uFF0C
722
674
  \u5173\u95ED\u6309\u94AE\u88AB\u9876\u51FA\u5C4F\u5E55\u3002CSS \u6CE8\u91CA\u4E0D\u53EF\u5D4C\u5957\uFF0C\u4E22\u4E86\u7ED3\u5C3E\u5C31\u4F1A\u4E00\u8DEF\u541E\u5230\u4E0B\u4E00\u4E2A\u7ED3\u675F\u7B26\u3002
723
675
  2026-09-23 \u7528\u6237\u53CD\u9988\u300C\u5F39\u7A97\u8FB9\u7EBF\u592A\u660E\u663E\u4E86\uFF0C\u592A\u7C97\u4E86\u300D\uFF1A\u8FB9\u6846\u4ECE 1px + border-l2 \u6539\u4E3A
724
- .5px + border-l1\uFF08\u6D45\u8272\u4E0B alpha 10% \u2192 4%\uFF09\uFF0C\u8FB9\u6846\u4E0D\u518D\u62A2\u773C\uFF0C\u5C42\u6B21\u6539\u7531 box-shadow \u627F\u62C5\u3002
725
- Retina \u4E0A .5px \u6B63\u597D\u662F\u4E00\u4E2A\u7269\u7406\u50CF\u7D20\uFF1B\u5BBF\u4E3B\u81EA\u5DF1\u7684\u6309\u94AE\uFF08\u540C\u6587\u4EF6\u4E0B\u65B9 schedule-glyph \u90A3\u6761\uFF09\u4E5F\u7528 .5px\u3002 */
726
- .t-team-pop{position:fixed;z-index:60;width:var(--t-team-pop-w, 720px);max-width:calc(100vw - 16px);max-height:min(600px, calc(100vh - 16px));overflow:hidden;box-sizing:border-box;display:flex;flex-direction:column;gap:8px;padding:10px 0 10px 10px;border-radius:12px;border:.5px solid var(--dsw-alias-border-l1);background:var(--dsw-specific-menu, var(--dsw-alias-bg-layer-3));backdrop-filter:var(--dsw-menu-backdrop-filter,blur(20px) saturate(1.4));box-shadow:var(--dsw-shadow-lv3);color:var(--dsw-alias-label-primary)}
676
+ .5px + border-l1\uFF08\u6D45\u8272\u4E0B alpha 10% \u2192 4%\uFF09\uFF0C\u8FB9\u6846\u4E0D\u518D\u62A2\u773C\u3002
677
+ \u5F39\u7A97\u9634\u5F71\u539F\u7528 var(--dsw-shadow-lv3)\uFF0C\u5B83\u662F\u4E09\u5C42\u53E0\u52A0\uFF1A0 0 1px \u5747\u5300\u63CF\u8FB9\u30010 0 4px \u5747\u5300\u67D4\u5149\u3001
678
+ 0 12px 32px \u5411\u4E0B\u504F\u79FB\u7684\u5927\u6295\u5F71\u3002\u7528\u6237\u8981\u6C42\u53BB\u6389\u300C\u5E95\u90E8\u300D\u7684\u6295\u5F71\u2014\u2014\u5373\u7B2C\u4E09\u5C42\u5411\u4E0B 12px \u90A3\u9053
679
+ \uFF08\u843D\u5728\u8F93\u5165\u6846\u4E0A\u5F88\u660E\u663E\uFF09\uFF0C\u6545\u8FD9\u91CC\u53EA\u4FDD\u7559\u524D\u4E24\u5C42\u5747\u5300\u63CF\u8FB9/\u67D4\u5149\uFF08\u5199\u6B7B\u6570\u503C\uFF0C\u5BBF\u4E3B\u6CA1\u6709\u53EA\u542B\u524D\u4E24\u5C42\u7684\u53D8\u91CF\uFF09\u3002
680
+ Retina \u4E0A .5px \u6B63\u597D\u662F\u4E00\u4E2A\u7269\u7406\u50CF\u7D20\uFF1B\u5BBF\u4E3B\u81EA\u5DF1\u7684\u6309\u94AE\u4E5F\u7528 .5px\u3002 */
681
+ .t-team-pop{position:fixed;z-index:60;width:var(--t-team-pop-w, 720px);max-width:calc(100vw - 16px);max-height:min(600px, calc(100vh - 16px));overflow:hidden;box-sizing:border-box;display:flex;flex-direction:column;gap:8px;padding:10px 0 10px 10px;border-radius:12px;border:.5px solid var(--dsw-alias-border-l1);background:var(--dsw-specific-menu, var(--dsw-alias-bg-layer-3));backdrop-filter:var(--dsw-menu-backdrop-filter,blur(20px) saturate(1.4));box-shadow:0 0 1px 0 #0003, 0 0 4px 0 #00000005;color:var(--dsw-alias-label-primary)}
727
682
  /* \u4E0D\u5199 width:100%\uFF1A\u5B83\u91CF\u7684\u662F\u5BB9\u5668 content \u5BBD\uFF0C\u518D\u53E0\u4E0A\u300C> *\u300D\u7684 margin-right \u5C31\u4F1A\u6A2A\u5411\u6EA2\u51FA\uFF1B
728
683
  \u9760 flex \u5BB9\u5668\u9ED8\u8BA4\u7684 align-items:stretch \u81EA\u52A8\u6491\u6EE1\u51CF\u6389 margin \u540E\u7684\u5BBD\u5EA6\u3002 */
729
684
  .t-team-pop .t-team-input{flex:0 0 auto;min-width:0}
@@ -782,100 +737,108 @@ var CSS = `
782
737
  .t-team-pop-desc{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;min-height:36px;font-size:12px;line-height:1.5;color:var(--dsw-alias-label-secondary)}
783
738
  .t-team-pop-empty{font-size:12px;color:var(--dsw-alias-label-tertiary);padding:6px 2px}
784
739
  .t-team-pop-head{display:flex;align-items:center;justify-content:space-between;font-size:12px;font-weight:600;color:var(--dsw-alias-label-secondary)}
785
- /* ---- \u5B9A\u65F6\u4EFB\u52A1\uFF1A\u4FA7\u680F\u5165\u53E3\uFF08\u6CE8\u518C\u4E3A sidebar.panellist \u7684\u4E00\u884C\uFF0C\u4F4D\u4E8E\u300C\u65B0\u4F1A\u8BDD\u300D\u6309\u94AE\u4E0B\u65B9\uFF09 ---- */
786
- /*
787
- * \u90A3\u4E00\u884C\u672C\u8EAB\uFF08\u6309\u94AE\u3001\u6587\u5B57\u3001\u9009\u4E2D\u6001\u3001\u70B9\u51FB\u884C\u4E3A\uFF09\u7531\u5BBF\u4E3B sidebar \u6E32\u67D3\uFF0Cclass \u662F CSS Modules \u54C8\u5E0C\u5316\u7684\u3001
788
- * \u6307\u4E0D\u4E0A\uFF1B\u6240\u4EE5\u62FF\u6211\u4EEC\u81EA\u5DF1\u7684\u56FE\u6807\u7C7B\u5F53\u951A\u70B9\uFF08:has\uFF09\u628A\u8FD9\u4E00\u884C\u8C03\u6210\u300C\u65B0\u4F1A\u8BDD\u300D\u6309\u94AE\u7684\u89C2\u611F\uFF1A
789
- * \u540C\u9AD8 38px\u3001\u540C 12px \u5706\u89D2\u3001\u540C\u8FB9\u6846\u4E0E\u62AC\u5347\u586B\u5145\u3001\u540C\u5C45\u4E2D\u6392\u5E03\u3002
790
- *
791
- * \u26A0\uFE0F \u5BBD\u5EA6\u5FC5\u987B\u662F width:auto + align-self:stretch\uFF0C\u4E0D\u80FD\u6CBF\u7528\u5BBF\u4E3B panelRow \u7684 width:100%\uFF1A
792
- * \u300C\u65B0\u4F1A\u8BDD\u300D\u7684\u5BBD\u5EA6\u662F flex \u62C9\u4F38\u51FA\u6765\u7684\uFF08\u5BB9\u5668\u5BBD \u2212 \u5DE6\u53F3\u5404 2px \u7684 margin\uFF09\uFF0C\u800C width:100% \u662F
793
- * **\u5BB9\u5668\u5168\u5BBD\u518D\u53E0\u52A0\u90A3 2px margin** \u2014\u2014 \u4E24\u8FB9\u7684 margin \u65E0\u5904\u53EF\u53BB\uFF0C\u4E8E\u662F\u90A3\u4E00\u884C\u6BD4\u300C\u65B0\u4F1A\u8BDD\u300D\u5BBD\u51FA 4px\u3002
794
- * \u4FA7\u680F\u6536\u8D77\u65F6\u518D\u663E\u5F0F\u56DE\u5230 36px \u56FE\u6807\u4F4D\uFF0C\u5426\u5219 stretch \u4F1A\u8BA9\u5B83\u6491\u6EE1\u6574\u6761\u8FB9\u680F\u3002
795
- */
796
- .t-team-schedule-glyph{display:block}
797
- button:has(.t-team-schedule-glyph){box-sizing:border-box;width:auto;align-self:stretch;height:38px;min-height:38px;margin:0 2px 8px;padding:8px 16px;border:.5px solid var(--dsw-alias-border-l3);border-radius:12px;background:var(--dsw-alias-button-elevated-fill);color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px;justify-content:center;gap:6px}
798
- button:has(.t-team-schedule-glyph):hover{background:var(--dsw-alias-button-floating-hover)}
799
- [data-sidebar-collapsed] button:has(.t-team-schedule-glyph){width:36px;align-self:flex-start;height:36px;min-height:36px;margin:0;padding:0;border-color:transparent;background:transparent}
800
- [data-sidebar-collapsed] button:has(.t-team-schedule-glyph):hover{background:var(--dsw-alias-interactive-bg-hover)}
801
- /* ---- \u5B9A\u65F6\u4EFB\u52A1\uFF1A\u53F3\u4FA7\u4E3B\u533A\u57DF\u7BA1\u7406\u9875\uFF08\u6CE8\u518C\u5728 main \u69FD\u7684 keyed \u9762\u677F\uFF09 ---- */
802
- .t-team-sched{box-sizing:border-box;display:flex;flex-direction:column;flex:1 1 auto;gap:12px;width:100%;height:100%;min-height:0;padding:18px 22px 28px;overflow:auto;color:var(--dsw-alias-label-primary)}
803
- .t-team-sched-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;flex:none}
804
- .t-team-sched-title{font-size:18px;font-weight:600;margin:0}
805
- .t-team-sched-actions{display:flex;gap:8px;flex:none}
806
- .t-team-sched-intro{font-size:13px;color:var(--dsw-alias-label-secondary);margin:0;max-width:760px}
807
- .t-team-sched-tip{font-size:12px;color:var(--dsw-alias-label-secondary);margin:0;max-width:760px}
808
- .t-team-sched-note{font-size:13px;color:var(--dsw-alias-state-warn-primary);margin:0}
809
- .t-team-sched-error{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--dsw-alias-state-error-primary);margin:0}
810
- .t-team-sched-rowNote{font-size:12px;color:var(--dsw-alias-label-tertiary);font-style:italic}
811
- .t-team-sched-file{font-size:11px;color:var(--dsw-alias-label-tertiary);font-family:var(--ds-font-family-code, monospace);word-break:break-all}
812
- .t-team-sched-body{display:flex;flex-direction:column;gap:12px;max-width:820px;width:100%}
813
- .t-team-sched-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:8px}
814
- .t-team-sched-row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 14px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-layer-2)}
815
- .t-team-sched-rowMain{display:flex;flex-direction:column;gap:3px;min-width:0}
816
- .t-team-sched-rowTitle{font-size:14px;font-weight:600}
817
- .t-team-sched-rowCron{font-size:12px;color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums}
818
- .t-team-sched-rowMeta{font-size:12px;color:var(--dsw-alias-label-secondary)}
819
- .t-team-sched-rowActions{display:flex;gap:8px;flex:none}
820
- .t-team-sched-runsToggle{align-self:flex-start;margin-top:2px;padding:0;border:none;background:transparent;color:var(--dsw-alias-brand-primary, var(--dsw-alias-label-primary));font-size:12px;cursor:pointer}
821
- .t-team-sched-runsToggle:hover{text-decoration:underline}
822
- .t-team-sched-runs{list-style:none;margin:6px 0 0;padding:8px 0 0;border-top:1px solid var(--dsw-alias-border-l2);display:flex;flex-direction:column;gap:3px}
823
- .t-team-sched-run{display:flex;gap:8px;align-items:baseline;font-size:12px;color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums}
824
- .t-team-sched-runFail{color:var(--dsw-alias-state-error-primary);word-break:break-word}
825
- .t-team-sched-runSession{font-size:11px;color:var(--dsw-alias-label-tertiary)}
826
- .t-team-sched-btn{font-size:13px;padding:5px 10px;border-radius:7px;border:1px solid var(--dsw-alias-border-l2);background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;cursor:pointer}
827
- .t-team-sched-btn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
828
- .t-team-sched-btn:disabled{opacity:.5;cursor:default}
829
- .t-team-sched-btn-primary{border-color:transparent;background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-base);font-weight:600}
830
- .t-team-sched-btn-primary:hover:not(:disabled){background:color-mix(in srgb, var(--dsw-alias-bg-base) 14%, var(--dsw-alias-label-primary))}
831
- .t-team-sched-btn-danger{color:var(--dsw-alias-state-error-primary);border-color:color-mix(in srgb, var(--dsw-alias-state-error-primary) 32%, var(--dsw-alias-border-l2))}
832
- .t-team-sched-btn-danger:hover:not(:disabled){background:color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent)}
833
- .t-team-sched-form{display:flex;flex-direction:column;gap:12px;padding:16px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-layer-2)}
834
- .t-team-sched-formTitle{font-size:15px;font-weight:600;margin:0}
835
- .t-team-sched-field{display:flex;flex-direction:column;gap:5px;font-size:13px;color:var(--dsw-alias-label-secondary)}
836
- .t-team-sched-field input,.t-team-sched-field textarea,.t-team-sched-field select{padding:8px 10px;border-radius:8px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font-size:13px;font-family:inherit}
837
- .t-team-sched-field input:focus,.t-team-sched-field textarea:focus,.t-team-sched-field select:focus{outline:none;border-color:var(--dsw-alias-brand-primary, var(--dsw-alias-label-primary))}
838
- .t-team-sched-field textarea{resize:vertical;min-height:72px}
839
- .t-team-sched-hint{font-size:12px;color:var(--dsw-alias-label-secondary)}
840
- .t-team-sched-checkbox{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--dsw-alias-label-secondary)}
841
- .t-team-sched-formActions{display:flex;gap:8px}
842
- /* cron \u9009\u62E9\u5668\uFF1A\u6A21\u677F chips + \u9891\u7387\u5206\u6BB5 + \u5404\u6A21\u5F0F\u5B57\u6BB5 + \u6458\u8981 + \u6700\u8FD1\u51E0\u6B21\u9884\u89C8 */
843
- .t-team-sched-cron{display:flex;flex-direction:column;gap:9px;width:100%}
844
- .t-team-sched-chips{display:flex;flex-wrap:wrap;gap:6px}
845
- .t-team-sched-chip{font-size:12px;padding:4px 11px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);font:inherit;font-size:12px;cursor:pointer}
846
- .t-team-sched-chip:hover:not(:disabled){border-color:var(--dsw-alias-label-primary);color:var(--dsw-alias-label-primary)}
847
- .t-team-sched-seg{display:inline-flex;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;overflow:hidden;align-self:flex-start}
848
- .t-team-sched-seg button{border:none;border-right:1px solid var(--dsw-alias-border-l2);background:transparent;color:var(--dsw-alias-label-secondary);padding:5px 14px;font:inherit;font-size:12px;cursor:pointer}
849
- .t-team-sched-seg button:last-child{border-right:none}
850
- .t-team-sched-seg button[data-on="true"]{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-base)}
851
- .t-team-sched-cronRow{display:flex;flex-wrap:wrap;gap:10px;align-items:center;font-size:13px;color:var(--dsw-alias-label-secondary)}
852
- .t-team-sched-cronRow select,.t-team-sched-cronRow input{padding:6px 8px;border-radius:8px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;font-variant-numeric:tabular-nums}
853
- .t-team-sched-days{display:flex;gap:5px;flex-wrap:wrap}
854
- .t-team-sched-day{min-width:32px;height:30px;padding:0 6px;border-radius:8px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);font:inherit;font-size:12px;cursor:pointer}
855
- .t-team-sched-day[data-on="true"]{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-base);border-color:transparent}
856
- .t-team-sched-sum{font-size:12px;color:var(--dsw-alias-label-secondary)}
857
- .t-team-sched-next{display:flex;flex-direction:column;gap:4px}
858
- .t-team-sched-nextLabel{font-size:12px;color:var(--dsw-alias-label-secondary)}
859
- .t-team-sched-nextList{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;gap:6px}
860
- .t-team-sched-nextList li{font-size:12px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);border-radius:6px;padding:2px 8px;font-variant-numeric:tabular-nums}
861
- /* \u63D0\u793A\u8BCD\u8F93\u5165\u533A\uFF1A\u6846\u5185\u7B2C\u4E00\u884C\u662F\u4E13\u5BB6\u82AF\u7247\uFF08\u6807\u7B7E\u89C2\u611F\uFF0C\u4E0E\u5BF9\u8BDD\u8F93\u5165\u6846\u4E00\u81F4\uFF09\uFF0C\u4E0B\u9762\u662F\u6B63\u6587 */
862
- .t-team-sched-promptbox{box-sizing:border-box;display:flex;flex-direction:column;padding:8px 10px;border-radius:8px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-1);transition:border-color .16s}
863
- .t-team-sched-promptbox:focus-within{border-color:var(--dsw-alias-brand-primary, var(--dsw-alias-label-primary))}
740
+ /* \u952E\u76D8\u7126\u70B9\u73AF\uFF1A\u5B98\u65B9\u7ED9\u6574\u9875\u4E00\u6761\u7EDF\u4E00\u89C4\u5219\uFF08.t-XoWW_page :focus-visible{outline:2px solid \u2026;offset:2px}\uFF09\uFF0C
741
+ \u53EA\u6709\u5927\u6807\u9898\u8F93\u5165\u6846\u4E0E\u63D0\u793A\u8BCD\u8F93\u5165\u533A\u4F8B\u5916\u2014\u2014\u5B83\u4EEC\u81EA\u5DF1\u6709 focus \u8868\u73B0\uFF08\u4E0B\u5212\u7EBF / \u5916\u6846\u53D8\u84DD\uFF09\u3002
742
+ \u7167\u6284\uFF0C\u514D\u5F97\u5404\u5904\u6309\u94AE\u4E0E\u8F93\u5165\u6846\u7684\u7126\u70B9\u6837\u5F0F\u5404\u5199\u5404\u7684\u3002 */
743
+ /* \u5DE6\u680F\uFF08\u5217\u8868\uFF09\uFF1Aflex:1 \u6491\u6EE1\uFF0C\u53F3\u4FA7\u6709\u8BE6\u60C5\u65F6\u81EA\u7136\u8BA9\u51FA\u4E00\u534A\uFF1B\u81EA\u5DF1\u4E0D\u5206\u680F\u6EDA\u52A8\uFF0C\u6EDA\u52A8\u4EA4\u7ED9\u91CC\u9762\u7684 pageScroll\u3002
744
+ 2026-09-25 \u7528\u6237\u53E3\u5F84\uFF1A\u65B0\u5EFA/\u7F16\u8F91\u6539\u6210\u5B98\u65B9\u90A3\u79CD\u300C\u5DE6\u5217\u8868 + \u53F3\u8BE6\u60C5\u300D\u7684\u53CC\u680F\u3002 */
745
+ /* \u26A0\uFE0F \u6EDA\u52A8\u5BB9\u5668\u5FC5\u987B\u662F\u5DE6\u680F\u91CC**\u5168\u5BBD**\u7684\u8FD9\u4E00\u5C42\uFF0C\u5185\u5BB9\u5217\uFF08.t-team-sched-page\uFF09\u53EA\u8D1F\u8D23\u5C45\u4E2D\u3002
746
+ * 2026-09-25 \u7528\u6237\u53D1\u73B0\u300C\u6EDA\u52A8\u6761\u4E0D\u5728\u6700\u53F3\u8FB9\u300D\uFF1A\u6B64\u524D\u6EDA\u52A8\u6302\u5728 960px \u7684\u5C45\u4E2D\u5217\u4E0A\uFF0C\u6EDA\u52A8\u6761\u5C31\u957F\u5728
747
+ * \u90A3\u4E00\u5217\u7684\u53F3\u8FB9\u7F18\u3001\u79BB\u7A97\u53E3\u53F3\u8FB9\u8FD8\u6709\u4E00\u5927\u622A\u7A7A\u767D\u3002\u5B98\u65B9\u90A3\u4E00\u9875\u4E5F\u662F\u8FD9\u4E48\u5206\u7684\uFF1A
748
+ * .t-XoWW_pageScroll\uFF08flex:1 + overflow:auto + scrollbar-gutter:stable\uFF09\u5957 .t-XoWW_pageContent
749
+ * \uFF08max-width + margin auto\uFF09\u3002scrollbar-gutter:stable \u8BA9\u6709/\u65E0\u6EDA\u52A8\u6761\u65F6\u5185\u5BB9\u4E0D\u5DE6\u53F3\u8DF3\uFF1B
750
+ * 9px \u5BBD\u4E0E 2px \u5185\u7F29\u4E5F\u662F\u5B98\u65B9\u90A3\u4E24\u4E2A\u503C\uFF08\u6EDA\u52A8\u6761\u914D\u8272\u8D70\u5BBF\u4E3B\u7684 --dsh-scrollbar-* \u53D8\u91CF\uFF09\u3002
751
+ * \u26A0\uFE0F \u8FD9\u4E00\u5C42\u662F**\u5757\u7EA7**\u5BB9\u5668\uFF08\u4E0D\u52A0 display:flex\uFF09\uFF1A\u5B98\u65B9\u7684 pageScroll \u4E5F\u6CA1\u6709 display\uFF0C\u5185\u5BB9\u5217\u56E0\u6B64
752
+ * \u8D70\u5757\u7EA7\u7684 width:auto + max-width \u89C4\u5219\u3002\u7ED9\u5B83\u52A0 flex \u4F1A\u8BA9\u5B50\u9879\u7684\u81EA\u52A8\u5916\u8FB9\u8DDD\u6539\u53D8\u5BBD\u5EA6\u7B97\u6CD5\u3002 */
753
+ /* \u26A0\uFE0F \u5185\u5BB9\u5217\u4E0E\u5B98\u65B9 .t-XoWW_pageContent **\u9010\u5B57\u4E00\u81F4**\uFF1Amax-width:960px + padding\uFF0C\u5757\u7EA7\uFF08\u4E0D\u52A0 display:flex\uFF09\u3001
754
+ * **\u4E0D\u8981** box-sizing:border-box \u4E0E width:100%\uFF082026-09-25 \u7528\u6237\u62A5\u300C\u533A\u57DF\u5BBD\u548C\u5B98\u65B9\u4E0D\u4E00\u6837\u300D\u5C31\u662F\u90A3\u4E24\u6761\u6765\u7684\uFF09\uFF1A
755
+ * \xB7 \u5B98\u65B9 max-width \u9650\u7684\u662F**\u5185\u5BB9\u76D2** \u2192 \u6574\u5217\u6700\u5BBD 960 + 2\xD7padding\uFF08\u6700\u5927 1056\uFF09\uFF1B
756
+ * \xB7 \u52A0\u4E86 border-box + width:100% \u5C31\u53D8\u6210\u300C\u5185\u5BB9 + padding \u4E00\u5171 960\u300D\u2192 \u5185\u5BB9\u53EA\u6709 864\uFF0C\u7A84\u4E86 96px\u3002
757
+ * \u5757\u7EA7\u6D41\u91CC\u5404\u6BB5\u7684\u95F4\u8DDD\u7531\u5143\u7D20\u81EA\u5DF1\u7684 margin \u63D0\u4F9B\uFF08heading 24 / filters 14 / search 16\uFF09\uFF0C\u4E0E\u5B98\u65B9\u540C\u6B3E\uFF1B
758
+ * \u8FD9\u91CC\u4E0D\u7528 flex + gap \u2014\u2014 \u90A3\u4F1A\u8BA9\u540C\u4E00\u5904\u95F4\u8DDD\u7531\u4E24\u5957\u673A\u5236\u53E0\u52A0\uFF0C\u5B9E\u6D4B\u5C31\u4E0E\u5B98\u65B9\u5DEE 2px\u3002 */
759
+ /* \u53F3\u680F\uFF08\u8BE6\u60C5 / \u65B0\u5EFA / \u7F16\u8F91\uFF09\uFF1A\u5B98\u65B9 detail \u90A3\u5957 \u2014\u2014 47% \u5BBD\u3001\u5DE6\u4FA7 .5px \u5206\u9694\u7EBF\u3001\u9876\u90E8 tab \u884C\u3001
760
+ \u4E2D\u95F4\u6EDA\u52A8\u533A\u3001\u5E95\u90E8\u56FA\u5B9A\u52A8\u4F5C\u6761\u3002\u5DE6\u53F3\u7559\u767D\u7EDF\u4E00\u8D70\u5B98\u65B9\u7684 --detail-gutter\uFF0824 / 20 / 16 \u4E09\u6863\u65AD\u70B9\uFF09\uFF0C
761
+ \u7A84\u5C4F\uFF08<=760px\uFF09\u65F6\u53F3\u680F\u72EC\u5360\u6574\u9875\u3001\u5217\u8868\u8BA9\u4F4D\uFF08\u5B98\u65B9\u540C\u6B3E\u65AD\u70B9\uFF09\u3002 */
762
+ /* \u5E95\u90E8\u52A8\u4F5C\u6761\uFF1A\u5B98\u65B9 saveFooter \u7684 20px \u5185\u8FB9\u8DDD + \u6700\u540E\u4E00\u4E2A\u6309\u94AE\u53F3\u79FB 8px\uFF08\u89C6\u89C9\u53F3\u8FB9\u7F18\u4E0E\u5185\u5BB9\u5BF9\u9F50\uFF09\u3002 */
763
+ /* \u6807\u9898\u884C\uFF1A\u4E0E\u5B98\u65B9 .t-XoWW_pageHeading \u540C\u6B3E\uFF08padding-top 28 / margin-bottom 24 / gap 16\uFF09\u3002
764
+ \u5185\u5BB9\u5217\u6539\u6210\u5757\u7EA7\u6D41\u4E4B\u540E\uFF0C24px \u7531\u5B83\u81EA\u5DF1\u7ED9\uFF0C\u4E0D\u518D\u4E0E page \u7684 gap \u53E0\u52A0\u3002 */
765
+ /* \u63D0\u793A\u6587\u5B57\uFF08\u52A0\u8F7D\u4E2D\uFF09\uFF1A\u5B98\u65B9\u90A3\u9875\u6CA1\u6709\u8FD9\u4E00\u53E5\uFF0C\u7ED9\u5B83\u4E00\u4E2A\u4E0D\u8D34\u4F4F\u4E0B\u4E00\u6BB5\u7684\u4E0B\u8FB9\u8DDD\u3002 */
766
+ /* \u7A7A\u6001 / \u65E0\u5339\u914D\uFF1A\u5B98\u65B9 .t-XoWW_empty \u662F**\u5C45\u4E2D**\u7684\u4E00\u5757\uFF08flex column + \u5C45\u4E2D + 48px 20px \u5185\u8FB9\u8DDD\uFF09\u3002 */
767
+ /* \u9875\u5C3E\u4E0D\u518D\u6302\u300C\u5B89\u5168\u63D0\u793A\u300D\u4E0E\u300C\u6570\u636E\u6587\u4EF6\u8DEF\u5F84\u300D\u4E24\u884C\uFF082026-09-25 \u7528\u6237\u53E3\u5F84\uFF09\uFF1A
768
+ tip \u632A\u5230\u63D0\u793A\u8BCD\u8F93\u5165\u6846\u4E0B\u9762\uFF0C\u7528 .t-team-sched-hint\uFF1B\u8DEF\u5F84\u90A3\u884C\u6574\u4E2A\u5220\u6389\u3002 */
769
+ /* \u5217\u8868\u533A\u5BB9\u5668\uFF1A\u5B98\u65B9 pageContent \u91CC\u6CA1\u6709\u8FD9\u4E00\u5C42\uFF08heading/filters/search/list \u76F4\u63A5\u662F\u5144\u5F1F\uFF09\uFF0C
770
+ \u6240\u4EE5\u8FD9\u91CC**\u4E0D\u7ED9\u4EFB\u4F55\u95F4\u8DDD**\u2014\u2014\u95F4\u8DDD\u7531\u5404\u5143\u7D20\u81EA\u5DF1\u7684 margin \u63D0\u4F9B\uFF0C\u8DDF\u5B98\u65B9\u4E00\u6A21\u4E00\u6837\uFF0C\u907F\u514D\u4E24\u5957\u673A\u5236\u53E0\u52A0\u3002 */
771
+ /* \u8FC7\u6EE4\u6807\u7B7E\u884C + \u641C\u7D22\u6846\uFF1A\u5B98\u65B9\u9875\u9762\u7684\u90A3\u4E24\u884C\uFF0C\u6570\u503C\u7167\u6284\uFF0828px \u80F6\u56CA / 36px \u5706\u89D2 12px \u8F93\u5165\u6846\uFF09\uFF0C
772
+ * \u8FDE\u95F4\u8DDD\u7684**\u6765\u6E90**\u4E5F\u7167\u6284\uFF1Afilters{margin-bottom:14px}\u3001searchField{margin:0 0 16px}\u3002 */
773
+ /* \u26A0\uFE0F \u641C\u7D22\u6846\u9010\u6761\u5BF9\u9F50\u5B98\u65B9 .t-XoWW_searchField\uFF1A**content-box**\uFF08\u5B98\u65B9\u6CA1\u5199 box-sizing\uFF0C\u52A0\u4E86 border-box
774
+ * \u4F1A\u8BA9\u5916\u9AD8\u4ECE 37 \u53D8 36\uFF09\u3001**\u4E0D\u8BBE gap**\uFF08\u56FE\u6807\u4E0E\u8F93\u5165\u6846\u4E4B\u95F4\u90A3 6px \u5C5E\u4E8E\u5B98\u65B9\u7684 Input \u7EC4\u4EF6\uFF0C
775
+ * \u7531\u56FE\u6807\u76D2\u81EA\u5DF1\u7684 margin-right \u7ED9\uFF09\u3001margin 0 0 16px\u3002 */
776
+ /* \u56FE\u6807\u76D2\uFF1A\u5B98\u65B9 Input \u7684 .icon \u662F 16\xD716 \u7684 inline-flex \u5C45\u4E2D\u76D2\uFF08\u91CC\u9762\u7684 svg 14px\uFF09\uFF0C
777
+ \u56FE\u6807\u76D2\u4E0E\u8F93\u5165\u6846\u4E4B\u95F4 6px \u2014\u2014 \u7167\u6284\uFF0C\u5426\u5219\u6587\u5B57\u8D77\u59CB\u4F4D\u7F6E\u4F1A\u5DEE 2~4px\u3002 */
778
+ /* \u8F93\u5165\u5143\u7D20\uFF1A\u5B98\u65B9 .input \u53EA\u91CD\u7F6E\u4E86 border/outline/background\uFF0C**\u4FDD\u7559\u4E86 UA \u9ED8\u8BA4\u7684 padding:1px 2px**
779
+ * \uFF08\u6240\u4EE5\u5360\u4F4D\u6587\u5B57\u7684\u8D77\u59CB\u4F4D\u7F6E\u6BD4\u6211\u4EEC\u6309\u4F4F padding \u65F6\u591A 2px\uFF09\u3002\u7167\u6284\uFF1Apadding \u7528 UA \u9ED8\u8BA4\u503C\uFF0C\u522B\u6E05\u96F6\u3002 */
780
+ /* \u6E05\u7A7A\u6309\u94AE\uFF1A\u5B98\u65B9 .t-XoWW_searchClear \u662F 28\xD728\u3001\u53F3\u79FB 6px\uFF08\u56FE\u6807 14px\uFF09\u3002 */
781
+ /* \u4EFB\u52A1\u884C\uFF1A\u5B98\u65B9 .t-XoWW_row \u7684\u89C2\u611F \u2014\u2014 \u65E0\u8FB9\u6846\u3001\u60AC\u505C\u6D45\u7070\u3001\u56FE\u6807 + \u4E3B\u526F\u4E24\u884C\uFF1B\u64CD\u4F5C\u6309\u94AE\u56FA\u5B9A\u5728\u884C\u5C3E\u3002
782
+ * \u5B98\u65B9\u90A3\u884C\u662F content-box + width:100% + padding 8px\uFF08\u5BBF\u4E3B\u6CA1\u6709\u5168\u5C40 box-sizing reset\uFF1A\u5B98\u65B9\u5728
783
+ * instruction / zoneSearch / confirmDialog \u56DB\u5904\u90FD**\u663E\u5F0F**\u8865\u4E86 border-box\uFF0C\u6B63\u8BF4\u660E\u9ED8\u8BA4\u662F content-box\uFF09\u3002
784
+ * \u4E8E\u662F\u8FD9\u4E00\u884C\u7684 border box \u6BD4\u5185\u5BB9\u5217**\u53F3\u51FA\u8840 16px** \u2014\u2014 \u90A3 16px \u843D\u5728\u5185\u5BB9\u5217\u7684 padding\uFF08\u226524px\uFF09\u91CC\uFF0C
785
+ * \u4E0D\u4F1A\u6EA2\u51FA\u5230\u6EDA\u52A8\u5C42\uFF0C\u6240\u4EE5\u7167\u6284\u4E0D\u4F1A\u6709\u6A2A\u5411\u6EDA\u52A8\u6761\u3002\u522B\u6539\u56DE border-box\uFF0C\u90A3\u6837\u884C\u4F1A\u6BD4\u5B98\u65B9\u7A84 16px\u3002 */
786
+ /* \u56FE\u6807\u69FD\uFF1A\u5B98\u65B9\u53EA\u6709 width/height/margin-top\uFF08svg \u662F inline\uFF09\uFF0C\u8FD9\u91CC\u4E5F\u4E0D\u52A0 flex \u2014\u2014
787
+ \u52A0\u4E86\u4F1A\u8BA9\u56FE\u6807\u76F8\u5BF9\u884C\u6807\u9898\u7684\u5782\u76F4\u4F4D\u7F6E\u5DEE 1~2px\u3002 */
788
+ /* \u884C\u6807\u9898\u524D\u7684\u72B6\u6001\u56FE\u6807\uFF0814px\uFF0C\u4E0E 23px \u884C\u9AD8\u7684\u6587\u5B57\u5BF9\u9F50\uFF09\uFF1A
789
+ \u542F\u7528 = \u7EFF\uFF08state-success-primary\uFF09\uFF0C\u505C\u7528 = **\u6DE1\u7EA2**\uFF08state-error-secondary\uFF0C\u7528\u6237\u53E3\u5F84\u300C\u6DE1\u7EA2\u624D\u660E\u663E\u300D\uFF09\u3002
790
+ \u989C\u8272\u56FA\u5B9A\u3001\u4E0D\u968F\u884C\u7684\u60AC\u505C\u6001\u53D8\u5316 \u2014\u2014 \u60AC\u505C\u65F6\u6807\u9898\u62AC\u56DE\u6B63\u5E38\u8272\uFF0C\u56FE\u6807\u7EE7\u7EED\u8868\u793A\u8FD9\u6761\u4EFB\u52A1\u7684\u72B6\u6001\u3002 */
791
+ /* \u5DF2\u505C\u7528\u7684\u884C\u6309\u5B98\u65B9\u300C\u5DF2\u7ED3\u675F\u300D\u7684\u5904\u7406\u65B9\u5F0F\u538B\u6697\u6807\u9898\u4E0E\u6458\u8981\uFF08\u60AC\u505C\u65F6\u518D\u62AC\u56DE\u6765\uFF0C\u4FDD\u8BC1\u53EF\u8BFB\uFF09\u3002 */
792
+ /* ---- \u6267\u884C\u8BB0\u5F55\u9875\uFF08\u53F3\u680F\u7B2C\u4E8C\u4E2A tab\uFF09\uFF1A\u5B98\u65B9\u300C\u4EFB\u52A1\u8FD0\u884C\u8BB0\u5F55\u300D\u90A3\u5957\u65F6\u95F4\u7EBF ----
793
+ * \u5EA6\u91CF\u7167\u6284 .t-XoWW_delivery*\uFF1A\u6BCF\u6761 = \u56FE\u6807 + \u65F6\u95F4\uFF0814/500\uFF09+ \u7ED3\u679C\uFF0C\u5DE6\u4FA7\u4E00\u6761 .5px \u7AD6\u7EBF\u628A\u5404\u6761\u4E32\u8D77\u6765
794
+ * \uFF08left:15.75px \u662F\u56FE\u6807\u4E2D\u5FC3\uFF1A\u884C margin -8 + padding 8 \u2192 \u56FE\u6807\u4E2D\u5FC3 16\uFF09\u3002 */
795
+ /* \u72B6\u6001\u8DDF\u5728\u65F6\u95F4\u540E\u9762\uFF082026-09-25 \u7528\u6237\u53E3\u5F84\uFF09\uFF1A\u5C0F\u56FE\u6807 + \u6587\u5B57\uFF0C\u6210\u529F\u7EFF\u3001\u5931\u8D25\u7EA2\u3002
796
+ \u56FE\u6807\u7528 14px\uFF08\u5BBF\u4E3B\u90A3\u4E9B\u56FE\u6807\u672C\u8EAB\u662F 16px \u7684 viewBox\uFF0C\u8FD9\u91CC\u7F29\u653E\u4E00\u4E0B\u4E0E 14px \u7684\u65F6\u95F4\u5B57\u53F7\u66F4\u8D34\uFF09\u3002 */
797
+ /* \u5931\u8D25\u539F\u56E0\u5355\u72EC\u4E00\u884C\uFF08\u522B\u628A"\u65F6\u95F4 + \u72B6\u6001"\u90A3\u4E00\u884C\u6491\u957F\uFF09\u3002 */
798
+ /* \u4F1A\u8BDD\u884C\uFF1Aid + \u540E\u9762\u90A3\u679A\u300C\u5173\u8054\u4F1A\u8BDD \u203A\u300D\u6309\u94AE\uFF08\u5E76\u6392\uFF0C\u7A84\u4E86\u81EA\u52A8\u6362\u884C\uFF09\u3002 */
799
+ /* \u300C\u8FD9\u4E2A\u4F1A\u8BDD\u6253\u4E0D\u5F00\u300D\u7684\u63D0\u793A\u884C\uFF1A\u5F52\u6863\u8D70 warn \u8272\uFF08\u65C1\u8FB9\u8FD8\u6709\u4E00\u679A\u300C\u6062\u590D\u5E76\u6253\u5F00\u300D\uFF09\uFF0C\u5DF2\u5220\u8D70\u9519\u8BEF\u8272\u3002 */
800
+ /* \u90A3\u4E00\u6B21\u63D0\u4EA4\u7684\u63D0\u793A\u8BCD\uFF1A\u5B98\u65B9 savedPrompt \u90A3\u5957 \u2014\u2014 \u4E24\u884C\u622A\u65AD\uFF08line-clamp:2\uFF09\uFF0C\u70B9\u300C\u5C55\u5F00\u300D\u770B\u5168\u6587\u3002 */
801
+ /* \u672B\u5C3E\u4E00\u884C\uFF1A\u8BF4\u660E\u53EA\u7559\u6700\u8FD1\u591A\u5C11\u6B21\uFF08\u5B98\u65B9\u7684 retentionEnd \u540C\u6B3E\u5C0F\u5B57\uFF09\u3002 */
802
+ /* \u6309\u94AE\uFF1A\u5B98\u65B9\u90A3\u4E24\u6863 \u2014\u2014 \u6B21\u7EA7\u662F\u900F\u660E\u80F6\u56CA\uFF08h28 / r14\uFF09\uFF0C\u4E3B\u6309\u94AE\u6309\u5B98\u65B9 Button + newButton \u7684\u89C4\u683C\uFF1A
803
+ * \u80CC\u666F\u8D70 --dsw-alias-button-primary-fill\u3001\u6587\u5B57\u8D70 --dsw-alias-label-primary-foreground\uFF08\u4E0D\u662F\u6211\u4EEC\u81EA\u5DF1
804
+ * \u62FC\u7684 label-primary/bg-base \u2014\u2014 \u6362\u4E86\u54C1\u724C\u8272\u5C31\u4F1A\u770B\u51FA\u5DEE\u522B\uFF09\u3001h32 / r16 / padding 0 12px / gap 4px\u3002 */
805
+ /* \u53F3\u680F\u8868\u5355\u91CC\u7684\u5B57\u6BB5\u7EC4\u4E0E\u63A7\u4EF6\uFF1A\u5B98\u65B9\u8BE6\u60C5\u9875\u90A3\u5957\uFF08.5px \u63CF\u8FB9 + 12px \u5706\u89D2\u8F93\u5165\u6846\u300136px \u9AD8\u3001
806
+ \u805A\u7126\u6362\u6210\u4E3B\u9898\u84DD\uFF09\uFF1B\u5206\u7EC4\u6807\u9898\u662F\u5B98\u65B9 ruleCard h3 \u90A3\u4E2A 13px \u5C0F\u6807\u9898\u3002 */
807
+ /* cron \u9009\u62E9\u5668\uFF1A\u8FD0\u884C\u65F6\u95F4\u5361\u7247\uFF08\u5B98\u65B9 ruleRows \u90A3\u5957\uFF09+ \u5361\u7247\u4E0B\u65B9\u7684\u5E38\u7528\u6A21\u677F + \u6458\u8981 + \u6700\u8FD1\u51E0\u6B21\u9884\u89C8 */
808
+ /* \u8FD0\u884C\u65F6\u95F4\u5361\u7247\uFF1A\u5EA6\u91CF\u7167\u6284\u5B98\u65B9 .t-XoWW_ruleRows / ruleRow / ruleLabel / ruleValue / ruleInput \u2014\u2014
809
+ * .5px \u63CF\u8FB9 + 16px \u5706\u89D2\u5BB9\u5668\u3001\u6BCF\u884C min-height 48px\u3001\u884C\u95F4\u4E00\u6761 .5px \u5206\u9694\u7EBF\uFF08\u6700\u540E\u4E00\u884C\u4E0D\u8981\uFF09\uFF0C
810
+ * \u5DE6\u8FB9\u6807\u7B7E 14px\u3001\u53F3\u8FB9\u53D6\u503C\uFF08\u539F\u751F select / input \u505A\u6210\u65E0\u8FB9\u6846\u3001hover \u624D\u6D6E\u51FA\u6D45\u7070\u5706\u89D2\u5E95\uFF09\u3002 */
811
+ /* \u53D6\u503C\u9762\uFF08\u5B98\u65B9 ruleValue / ruleValueFace / pickerTrigger / pickerIcon \u7684\u5F62\u6001\uFF09\uFF1A\u4E00\u884C\u53F3\u4FA7\u662F
812
+ * \u300C\u5F53\u524D\u503C + \u4E00\u4E2A\u6307\u793A\u56FE\u6807\u300D\u7684\u53EF\u70B9\u9762\uFF0Chover \u65F6\u6574\u9762\u6D6E\u6D45\u7070\uFF0C\u70B9\u5F00\u4E00\u4E2A\u540C\u6E90\u5C0F\u9762\u677F\u3002
813
+ * \u26A0\uFE0F \u523B\u610F\u4E0D\u7528\u539F\u751F select\uFF1A\u5B83\u7684\u7BAD\u5934\u4E0E\u4E0B\u62C9\u5F39\u5C42\u7531\u6D4F\u89C8\u5668\u753B\uFF0C\u6DF1\u6D45\u4E3B\u9898\u4E0B\u90FD\u6CA1\u6CD5\u4E0E\u5B98\u65B9\u4E00\u81F4\u3002 */
814
+ /* \u70B9\u5F00\u7684\u5C0F\u9762\u677F\uFF1A\u4E0E ExpertPicker \u540C\u6E90\uFF08\u83DC\u5355\u5E95\u8272 + \u80CC\u666F\u6A21\u7CCA\uFF0C\u523B\u610F\u4E0D\u5E26\u6295\u5F71\uFF09\u3002
815
+ * \u5355\u5217\u7528 .t-team-sched-pickerList\uFF08\u7AD6\u6392\uFF09\uFF0C\u53CC\u5217\uFF08\u65F6/\u5206\uFF09\u76F4\u63A5\u662F\u4E24\u4E2A .t-team-sched-pickerCol \u5E76\u6392\u3002 */
816
+ /* \u81EA\u5B9A\u4E49\u8868\u8FBE\u5F0F\u7684\u8F93\u5165\u6846\uFF1A\u5B98\u65B9 ruleInput\uFF08\u65E0\u6846\u3001\u53F3\u5BF9\u9F50\u3001hover \u6D6E\u6D45\u7070\uFF09 */
817
+ /* \u5E38\u7528\u6A21\u677F\uFF1A\u5361\u7247\u4E0B\u65B9\u7684\u5C0F\u80F6\u56CA\uFF08\u4E0E\u5217\u8868\u9875\u7684\u8FC7\u6EE4\u6807\u7B7E\u540C\u6B3E\uFF09\u3002
818
+ * \u26A0\uFE0F \u7C7B\u540D\u5FC5\u987B\u662F .t-team-sched-preset\uFF1A.t-team-sched-chip \u5F52\u63D0\u793A\u8BCD\u91CC\u7684\u4E13\u5BB6\u82AF\u7247\uFF0C
819
+ * \u4E24\u8FB9\u540C\u540D\u65F6\u540E\u5B9A\u4E49\u7684\u90A3\u6761\u4F1A\u628A\u524D\u9762\u7684\u8986\u76D6\u6389\uFF08\u8E29\u8FC7\uFF1A\u6A21\u677F\u6309\u94AE\u957F\u6210\u84DD\u8272\u82AF\u7247\uFF09\u3002 */
820
+ /* \u63D0\u793A\u8BCD\u8F93\u5165\u533A\uFF1A\u6846\u5185\u7B2C\u4E00\u884C\u662F\u4E13\u5BB6\u82AF\u7247\uFF08\u6807\u7B7E\u89C2\u611F\uFF0C\u4E0E\u5BF9\u8BDD\u8F93\u5165\u6846\u4E00\u81F4\uFF09\uFF0C\u4E0B\u9762\u662F\u6B63\u6587\u3002
821
+ * \u5916\u6846\u5BF9\u9F50\u5B98\u65B9\u8BE6\u60C5\u9875\u7684\u63D0\u793A\u8BCD\u8F93\u5165\u6846\uFF1A\u5706\u89D2 16px\u3001.5px \u63CF\u8FB9\u3001\u805A\u7126\u65F6\u6362\u6210\u4E3B\u9898\u84DD\u3002 */
864
822
  /* \u82AF\u7247\u89C2\u611F\u5BF9\u9F50\u5BF9\u8BDD\u8F93\u5165\u6846\u91CC\u7684\u5F15\u7528\u82AF\u7247\uFF1A\u6D45\u7070\u5E95\u3001\u5706\u89D2\u77E9\u5F62\uFF08\u4E0D\u662F\u5168\u80F6\u56CA\uFF09\u3001\u84DD\u8272\u6587\u5B57\u3001
865
823
  * \u5DE6\u4FA7\u4E00\u4E2A\u5706\u5F62\u7EBF\u6761\u5C0F\u56FE\u6807\uFF1B\xD7 \u5E73\u65F6\u4E0D\u663E\u793A\uFF0C\u60AC\u505C\u624D\u6D6E\u51FA\u6765\uFF08\u622A\u56FE\u91CC\u5C31\u662F\u6CA1\u6709 \xD7 \u7684\u6837\u5B50\uFF09\u3002 */
866
- .t-team-sched-chip{box-sizing:border-box;display:inline-flex;align-items:center;gap:3px;max-width:100%;margin:0 2px;padding:0 4px;border:1px solid transparent;border-radius:6px;background:color-mix(in srgb, var(--dsw-alias-label-primary) 10%, transparent);color:var(--dsw-alias-brand-primary, #1677ff);font-size:12px;line-height:18px;vertical-align:middle;user-select:none}
867
824
  /* \u60AC\u505C\u7ED9\u4E00\u5708\u6DE1\u63CF\u8FB9\uFF1A\u8BA9"\u9F20\u6807\u5728\u8FD9\u679A\u82AF\u7247\u4E0A"\u8FD9\u4EF6\u4E8B\u6709\u786E\u5B9A\u7684\u89C6\u89C9\u53CD\u9988\uFF08\u522B\u9760\u6D4F\u89C8\u5668\u9ED8\u8BA4\uFF09\u3002 */
868
- .t-team-sched-chip:hover{border-color:color-mix(in srgb, var(--dsw-alias-brand-primary, #1677ff) 35%, transparent)}
869
- .t-team-sched-chip-icon{flex:none;display:block}
870
- .t-team-sched-chip-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
871
- .t-team-sched-chip-remove{padding:0 1px;border:0;background:transparent;color:inherit;font:inherit;font-size:12px;line-height:1;cursor:pointer;opacity:.6;transition:opacity .12s}
872
- .t-team-sched-chip-remove:hover{opacity:1}
873
825
  /* \u63D0\u793A\u8BCD\u7F16\u8F91\u533A\uFF1Acontenteditable \u7684\u5BCC\u6587\u672C\u6D41\uFF08\u7EAF\u6587\u5B57 + \u82AF\u7247\uFF09\uFF0C\u82AF\u7247\u56E0\u6B64\u80FD\u63D2\u5728\u6B63\u6587\u4EFB\u610F\u4F4D\u7F6E\u3002
874
- * \u26A0\uFE0F \u7C7B\u540D\u5FC5\u987B\u5E26 .t-team-sched-field \u524D\u7F00\uFF1A\u5426\u5219\u7279\u5F02\u6027\u4F4E\u4E8E\u901A\u7528\u7684 ".t-team-sched-field textarea"
875
- * \u90A3\u7C7B\u89C4\u5219\uFF0C\u7F16\u8F91\u533A\u4F1A\u81EA\u5E26\u4E00\u5708\u8FB9\u6846\uFF08\u8E29\u8FC7\uFF1A\u6846\u91CC\u5957\u6846\uFF09\u3002 */
876
- .t-team-sched-field .t-team-sched-prompt-input{box-sizing:border-box;width:100%;min-height:72px;max-height:320px;overflow-y:auto;padding:0;border:0;border-radius:0;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;line-height:22px;white-space:pre-wrap;word-break:break-word;cursor:text;resize:none}
877
- .t-team-sched-field .t-team-sched-prompt-input:focus{outline:none;border:0}
878
- .t-team-sched-field .t-team-sched-prompt-input[data-empty="true"]::before{content:attr(data-placeholder);color:var(--dsw-alias-label-tertiary);pointer-events:none}
826
+ * \u26A0\uFE0F \u9009\u62E9\u5668\u8981\u5E26 .t-team-sched-promptbox \u524D\u7F00\uFF08\u539F\u6765\u662F .t-team-sched-field\uFF09\uFF1A\u5426\u5219\u7279\u5F02\u6027\u4F4E\u4E8E
827
+ * \u901A\u7528\u7684 ".t-team-sched-group textarea/input" \u90A3\u7C7B\u89C4\u5219\uFF0C\u7F16\u8F91\u533A\u4F1A\u81EA\u5E26\u4E00\u5708\u8FB9\u6846\uFF08\u8E29\u8FC7\uFF1A\u6846\u91CC\u5957\u6846\uFF09\u3002 */
828
+ /* \u7A84\u5C4F\uFF08\u4E0E\u5B98\u65B9\u540C\u6B3E\u65AD\u70B9\uFF09\uFF1A\u8BE6\u60C5/\u8868\u5355\u72EC\u5360\u6574\u9875\uFF0C\u5217\u8868\u8BA9\u4F4D \u2014\u2014 \u6324\u6210\u4E24\u680F\u4E24\u8FB9\u90FD\u6CA1\u6CD5\u7528\u3002 */
829
+ /* \u5B98\u65B9\u7684\u4E09\u6863\u65AD\u70B9\uFF08\u6570\u503C\u7167\u6284\uFF09\uFF1A\u53F3\u680F\u5DE6\u53F3\u7559\u767D 24 \u2192 20 \u2192 16\uFF1B<=760 \u65F6\u53F3\u680F\u72EC\u5360\u6574\u9875\u3002 */
830
+ @media (width<=1100px){
831
+ .t-team-sched-detailForm{--detail-gutter:20px}
832
+ }
833
+ @media (width<=760px){
834
+ .t-team-sched-listPane[data-detail="true"]{display:none}
835
+ .t-team-sched-detailForm{flex-basis:100%;border-left:0}
836
+ .t-team-sched-detailScroll{padding-top:20px}
837
+ }
838
+ @media (width<=400px){
839
+ .t-team-sched-detailForm{--detail-gutter:16px}
840
+ .t-team-sched-detailTabsBar{gap:16px}
841
+ }
879
842
  /* \u63D0\u793A\u8BCD\u6846\u4E0B\u65B9\u7684\u300CT\u4E13\u5BB6\u300D\u6311\u9009\u5668\uFF1A\u6309\u94AE + \u53EA\u542B\u4E13\u5BB6\u5217\u8868\u7684\u6D6E\u5C42\uFF08\u7C7B\u540D\u72EC\u7ACB\uFF0C\u907F\u514D\u4E0E\u65E2\u6709\u7C7B\u4E92\u76F8\u8986\u76D6\uFF09 */
880
843
  .t-team-expert-pick{position:relative;display:flex;align-items:center;gap:8px;margin-top:2px}
881
844
  .t-team-expert-pick-hint{font-size:12px;color:var(--dsw-alias-label-secondary)}
@@ -993,97 +956,11 @@ var zh = {
993
956
  "custom.deleteHint": "\u5220\u9664\u300C{name}\u300D\uFF1F\u53EA\u5220\u8FD9\u4E2A\u81EA\u5EFA\u4E13\u5BB6\u6587\u4EF6\uFF0C\u4E0D\u53EF\u64A4\u9500\u3002",
994
957
  "custom.badge": "\u81EA\u5EFA",
995
958
  "custom.loadingBody": "\u6B63\u5728\u8BFB\u53D6\u4EBA\u683C\u6B63\u6587\u2026",
996
- "pop.title": "T\u4E13\u5BB6",
997
- // ---- 定时任务:侧栏按钮 + 右侧管理页 ----
998
- "settings.showScheduleButton": "\u663E\u793A\u5B9A\u65F6\u4EFB\u52A1\u6309\u94AE",
999
- "settings.showScheduleButtonHint": "\u5173\u95ED\u540E\u4FA7\u680F\u4E0D\u518D\u663E\u793A\u300C\u5B9A\u65F6\u4EFB\u52A1\u300D\u6309\u94AE\uFF0C\u5E76\u505C\u6B62\u5168\u90E8\u5B9A\u65F6\u89E6\u53D1\uFF08\u4EFB\u52A1\u4E0E\u6267\u884C\u8BB0\u5F55\u4FDD\u7559\uFF0C\u91CD\u65B0\u6253\u5F00\u5373\u6062\u590D\uFF09",
1000
- "sched.nav": "\u5B9A\u65F6\u4EFB\u52A1",
1001
- "sched.title": "\u5B9A\u65F6\u4EFB\u52A1",
1002
- "sched.intro": "\u7528 cron \u5B9A\u65F6\u5668\u628A\u63D0\u793A\u8BCD\u4EA4\u7ED9\u4E00\u4E2A\u5168\u65B0\u7684\u4F1A\u8BDD\u6267\u884C\u2014\u2014\u4E5F\u53EF\u4EE5\u7ACB\u5373\u6267\u884C\u3002\u6267\u884C\u4EA7\u751F\u7684\u4F1A\u8BDD\u51FA\u73B0\u5728\u5DE6\u4FA7\u5BF9\u5E94\u5DE5\u4F5C\u533A\u4E0B\u3002",
1003
- "sched.tip": "\u542F\u7528\u7684\u4E8B\u9879\u4F1A\u5728\u540E\u53F0\u81EA\u52A8\u65B0\u5EFA\u4F1A\u8BDD\u5E76\u63D0\u4EA4\u63D0\u793A\u8BCD\uFF08\u7B49\u4E8E\u8BA9 agent \u81EA\u5DF1\u52A8\u624B\uFF09\uFF0C\u8BF7\u53EA\u5199\u4F60\u4FE1\u4EFB\u7684\u63D0\u793A\u8BCD\u3002",
1004
- "sched.back": "\u8FD4\u56DE\u4F1A\u8BDD",
1005
- "sched.refresh": "\u5237\u65B0",
1006
- "sched.loading": "\u6B63\u5728\u52A0\u8F7D\u5B9A\u65F6\u4EFB\u52A1\u2026",
1007
- "sched.error": "\u5B9A\u65F6\u4EFB\u52A1\u670D\u52A1\u6682\u65F6\u4E0D\u53EF\u7528\u3002",
1008
- "sched.empty": "\u8FD8\u6CA1\u6709\u5B9A\u65F6\u4EFB\u52A1\uFF0C\u5148\u65B0\u5EFA\u4E00\u4E2A\u5427\u3002",
1009
- "sched.retry": "\u91CD\u8BD5",
1010
- "sched.new": "\u65B0\u5EFA\u5B9A\u65F6\u4EFB\u52A1",
1011
- "sched.edit": "\u7F16\u8F91\u5B9A\u65F6\u4EFB\u52A1",
1012
- "sched.save": "\u4FDD\u5B58",
1013
- "sched.saving": "\u4FDD\u5B58\u4E2D\u2026",
1014
- "sched.cancel": "\u53D6\u6D88",
1015
- "sched.delete": "\u5220\u9664",
1016
- "sched.deleteConfirm": "\u786E\u5B9A\u5220\u9664\u8FD9\u4E2A\u5B9A\u65F6\u4EFB\u52A1\uFF1F",
1017
- "sched.runNow": "\u7ACB\u5373\u6267\u884C",
1018
- "sched.running": "\u6267\u884C\u4E2D\u2026",
1019
- "sched.runHistory": "\u6267\u884C\u8BB0\u5F55\uFF08{count}\uFF09",
1020
- "sched.runOk": "\u6210\u529F",
1021
- "sched.runFail": "\u5931\u8D25",
1022
- "sched.lastRun": "\u4E0A\u6B21\u6267\u884C",
1023
- "sched.neverRun": "\u4ECE\u672A\u6267\u884C",
1024
- "sched.failed": "\u5931\u8D25",
1025
- "sched.disabledTag": "\u5DF2\u505C\u7528",
1026
- "sched.workspace": "\u5DE5\u4F5C\u533A",
1027
- "sched.workspaceNone": "\u4E0D\u7ED1\u5B9A\u5DE5\u4F5C\u533A\uFF08\u9ED8\u8BA4\u76EE\u5F55\uFF09",
1028
- "sched.workspaceHint": "\u6267\u884C\u65F6\u4F1A\u5728\u8FD9\u4E2A\u5DE5\u4F5C\u533A\u4E0B\u65B0\u5EFA\u4F1A\u8BDD\uFF0C\u5E76\u663E\u793A\u5728\u5DE5\u4F5C\u533A\u5206\u7EC4\u91CC\u3002",
1029
- "sched.workspacePath": "\u76EE\u5F55\uFF1A{path}",
1030
- "sched.workspaceCustom": "\uFF0B \u81EA\u5B9A\u4E49\u76EE\u5F55\u2026",
1031
- "sched.workspaceCustomPlaceholder": "\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u4F8B\u5982 /Users/\u4F60/tasks",
1032
- "sched.workspaceCustomHint": "\u76EE\u5F55\u4E0D\u5B58\u5728\u65F6\u4F1A\u81EA\u52A8\u521B\u5EFA\uFF0C\u5E76\u6CE8\u518C\u6210\u4E00\u4E2A\u5DE5\u4F5C\u533A\u3002",
1033
- "sched.workspaceCustomEmpty": "\u8BF7\u5148\u586B\u5199\u81EA\u5B9A\u4E49\u76EE\u5F55\u7684\u7EDD\u5BF9\u8DEF\u5F84\u3002",
1034
- "sched.workspaceAutoRecoverHint": "\u5DE5\u4F5C\u533A\u4E0D\u89C1\u4E86\uFF0C{path} \u4E0B\u6B21\u6267\u884C\u65F6\u4F1A\u81EA\u52A8\u5EFA\u56DE\u6765\u3002",
1035
- "sched.workspaceMissingHintNoPath": "\u5DE5\u4F5C\u533A\u4E0D\u89C1\u4E86\uFF0C\u4E14\u4EFB\u52A1\u91CC\u6CA1\u8BB0\u76EE\u5F55\u2014\u2014\u4E0B\u6B21\u6267\u884C\u81EA\u52A8\u6062\u590D\u4E0D\u4E86\uFF0C\u8BF7\u53BB\u5DE6\u4FA7\u5DE5\u4F5C\u533A\u5217\u8868\u65B0\u5EFA\u4E00\u4E2A\u540C\u540D/\u540C\u8DEF\u5F84\u7684\u5DE5\u4F5C\u533A\u3002",
1036
- "sched.cronLabel": "cron \u5B9A\u65F6\u5668",
1037
- "sched.cronHint": "\u4E94\u6BB5 croner \u8868\u8FBE\u5F0F\uFF08\u5206 \u65F6 \u65E5 \u6708 \u5468\uFF09\uFF0C\u4F8B\u5982 \u201C0 9 * * *\u201D \u8868\u793A\u6BCF\u5929 09:00\u3002",
1038
- "sched.cronHourly": "\u6BCF\u5C0F\u65F6",
1039
- "sched.cronDaily": "\u6BCF\u5929",
1040
- "sched.cronWeekly": "\u6BCF\u5468",
1041
- "sched.cronCustom": "\u81EA\u5B9A\u4E49",
1042
- "sched.cronEvery": "\u6BCF\u9694",
1043
- "sched.cronAtMinute": "\u6BCF\u5C0F\u65F6\u7684\u7B2C",
1044
- "sched.cronMinuteUnit": "\u5206",
1045
- "sched.cronMinutesUnit": "\u5206\u949F",
1046
- "sched.hourField": "\u5C0F\u65F6",
1047
- "sched.minuteField": "\u5206\u949F",
1048
- "sched.presetHourly": "\u6BCF\u5C0F\u65F6\u6574\u70B9",
1049
- "sched.presetMin30": "\u6BCF 30 \u5206\u949F",
1050
- "sched.presetDaily9": "\u6BCF\u5929 9:00",
1051
- "sched.presetWeekday830": "\u5DE5\u4F5C\u65E5 8:30",
1052
- "sched.presetMon10": "\u6BCF\u5468\u4E00 10:00",
959
+ "pop.title": "T\u4E13\u5BB6"
960
+ // 列表过滤与搜索(与官方「自动化任务」页同一套:标签行 + 搜索框)
961
+ // 三档:全部 / 已启用 / 已停用 —— 停用 ≠ 删除(停用的任务保留数据、只是不触发)。
962
+ // 运行时间卡片(对齐官方详情页的「运行时间」:重复 / 时间 / 星期 三行)
1053
963
  // 周几:键必须**逐行**写、并且在代码里以字面量引用(字典无人引用自检会盯着这一点)。
1054
- "sched.wd1": "\u4E00",
1055
- "sched.wd2": "\u4E8C",
1056
- "sched.wd3": "\u4E09",
1057
- "sched.wd4": "\u56DB",
1058
- "sched.wd5": "\u4E94",
1059
- "sched.wd6": "\u516D",
1060
- "sched.wd0": "\u65E5",
1061
- "sched.listSep": "\u3001",
1062
- "sched.sumMin": "\u6BCF {n} \u5206\u949F\u6267\u884C\u4E00\u6B21",
1063
- "sched.sumHour": "\u6BCF\u5C0F\u65F6\u7B2C {m} \u5206\u6267\u884C",
1064
- "sched.sumDaily": "\u6BCF\u5929 {t} \u6267\u884C",
1065
- "sched.sumWeekly": "\u6BCF\u5468{w} {t} \u6267\u884C",
1066
- "sched.sumWeeklyWorkday": "\u5DE5\u4F5C\u65E5 {t} \u6267\u884C",
1067
- "sched.sumCustom": "\u81EA\u5B9A\u4E49\u8868\u8FBE\u5F0F\uFF1A{raw}",
1068
- "sched.sumEmpty": "\u9009\u62E9\u6216\u586B\u5199\u4E00\u4E2A\u6267\u884C\u65F6\u95F4",
1069
- "sched.nextRuns": "\u6700\u8FD1 {n} \u6B21\u6267\u884C",
1070
- "sched.titleLabel": "\u6807\u9898",
1071
- "sched.titlePlaceholder": "\u4F8B\u5982\uFF1A\u6668\u4F1A\u7EAA\u8981",
1072
- "sched.promptLabel": "\u63D0\u793A\u8BCD",
1073
- "sched.promptPlaceholder": "\u5230\u70B9\u65F6\uFF0C\u8BA9 agent \u505A\u4EC0\u4E48\uFF1F",
1074
- "sched.expertPick": "T\u4E13\u5BB6",
1075
- "sched.expertPickHint": "\u70B9\u8FD9\u4E2A\u6309\u94AE\u4ECE\u5DF2\u542F\u7528\u4E13\u5BB6\u91CC\u6311\u4E00\u4F4D\uFF0C\u628A @\u4E13\u5BB6\u540D \u586B\u8FDB\u63D0\u793A\u8BCD\u3002",
1076
- "sched.expertPickSearch": "\u641C\u7D22\u4E13\u5BB6\u540D\u6216 slug",
1077
- "sched.expertPickEmpty": "\u6CA1\u6709\u5339\u914D\u7684\u5DF2\u542F\u7528\u4E13\u5BB6\u3002\u5148\u53BB \u8BBE\u7F6E \u2192 T\u4E13\u5BB6 \u542F\u7528\u3002",
1078
- "sched.expertInvokeHint": "\u5230\u70B9\u6267\u884C\u65F6\u4F1A\u53EC\u5524\u300C{name}\u300D\u6765\u5B8C\u6210\u8FD9\u6BB5\u63D0\u793A\u8BCD\u3002",
1079
- "sched.expertInvokeManyHint": "\u5230\u70B9\u6267\u884C\u65F6\u4F1A\u540C\u65F6\u53EC\u5524\u300C{names}\u300D\u6765\u5B8C\u6210\u8FD9\u6BB5\u63D0\u793A\u8BCD\u3002",
1080
- "sched.expertRemove": "\u79FB\u9664 {name}",
1081
- "sched.enabledLabel": "\u542F\u7528",
1082
- "sched.enabledHint": "\u505C\u7528\u7684\u4E8B\u9879\u4FDD\u7559\u6570\u636E\uFF0C\u4F46\u4E0D\u4F1A\u5B9A\u65F6\u89E6\u53D1\u3002",
1083
- "sched.invalidForm": "\u6807\u9898\u3001\u63D0\u793A\u8BCD\u548C cron \u5B9A\u65F6\u5668\u90FD\u662F\u5FC5\u586B\u9879\u3002",
1084
- "sched.off": "\u5B9A\u65F6\u4EFB\u52A1\u5DF2\u5728 \u8BBE\u7F6E \u2192 T\u4E13\u5BB6 \u91CC\u5173\u95ED\uFF1A\u73B0\u5728\u4E0D\u4F1A\u5B9A\u65F6\u89E6\u53D1\uFF0C\u4E5F\u4E0D\u80FD\u7ACB\u5373\u6267\u884C\u3002\u91CD\u65B0\u6253\u5F00\u300C\u663E\u793A\u5B9A\u65F6\u4EFB\u52A1\u6309\u94AE\u300D\u5373\u6062\u590D\u3002",
1085
- "sched.noAgents": "\u5BBF\u4E3B\u6CA1\u6709\u53EF\u7528\u7684 agents \u670D\u52A1\uFF0C\u521B\u5EFA\u4F1A\u8BDD\u4F1A\u5931\u8D25\uFF1A\u8BF7\u68C0\u67E5\u5BBF\u4E3B\u88C5\u914D\u3002",
1086
- "sched.file": "\u6570\u636E\u6587\u4EF6\uFF1A{path}"
1087
964
  };
1088
965
  var en = {
1089
966
  "settings.title": "T Expert",
@@ -1185,96 +1062,10 @@ var en = {
1185
1062
  "custom.deleteHint": "Delete \u201C{name}\u201D? Only this custom expert file is removed; this cannot be undone.",
1186
1063
  "custom.badge": "Custom",
1187
1064
  "custom.loadingBody": "Loading persona body\u2026",
1188
- "pop.title": "T Expert",
1189
- // ---- Scheduled tasks: sidebar entry + right-hand management surface ----
1190
- "settings.showScheduleButton": "Show scheduled tasks button",
1191
- "settings.showScheduleButtonHint": "When off, the sidebar no longer shows the Scheduled tasks button and every cron trigger stops (tasks and run history are kept; turning it back on restores the schedule)",
1192
- "sched.nav": "Scheduled tasks",
1193
- "sched.title": "Scheduled tasks",
1194
- "sched.intro": "Send a prompt to a fresh agent session on a cron schedule \u2014 or run it right now. Each run appears under its workspace in the sidebar.",
1195
- "sched.tip": "An enabled item creates a session and submits its prompt in the background (the agent acts on its own), so only write prompts you trust.",
1196
- "sched.back": "Back to conversation",
1197
- "sched.refresh": "Refresh",
1198
- "sched.loading": "Loading scheduled tasks\u2026",
1199
- "sched.error": "The scheduled tasks service is unavailable.",
1200
- "sched.empty": "No scheduled tasks yet \u2014 create the first one.",
1201
- "sched.retry": "Retry",
1202
- "sched.new": "New scheduled task",
1203
- "sched.edit": "Edit scheduled task",
1204
- "sched.save": "Save",
1205
- "sched.saving": "Saving\u2026",
1206
- "sched.cancel": "Cancel",
1207
- "sched.delete": "Delete",
1208
- "sched.deleteConfirm": "Delete this scheduled task?",
1209
- "sched.runNow": "Run now",
1210
- "sched.running": "Running\u2026",
1211
- "sched.runHistory": "Run history ({count})",
1212
- "sched.runOk": "OK",
1213
- "sched.runFail": "Failed",
1214
- "sched.lastRun": "Last run",
1215
- "sched.neverRun": "Never",
1216
- "sched.failed": "failed",
1217
- "sched.disabledTag": "Disabled",
1218
- "sched.workspace": "Workspace",
1219
- "sched.workspaceNone": "None (default directory)",
1220
- "sched.workspaceHint": "Each run starts a new session in this workspace; sessions appear grouped under it in the sidebar.",
1221
- "sched.workspacePath": "Directory: {path}",
1222
- "sched.workspaceCustom": "+ Custom directory\u2026",
1223
- "sched.workspaceCustomPlaceholder": "Absolute path, e.g. /Users/you/tasks",
1224
- "sched.workspaceCustomHint": "The directory is created when missing, then registered as a workspace.",
1225
- "sched.workspaceCustomEmpty": "Enter an absolute path for the custom directory first.",
1226
- "sched.workspaceAutoRecoverHint": "Workspace gone \u2014 {path} will be recreated automatically on the next run.",
1227
- "sched.workspaceMissingHintNoPath": "Workspace gone and no directory recorded \u2014 automatic recovery is not possible. Please create the workspace again in the sidebar workspace list.",
1228
- "sched.cronLabel": "Cron schedule",
1229
- "sched.cronHint": 'Five-field cron expression (minute hour day month weekday), e.g. "0 9 * * *" runs daily at 09:00.',
1230
- "sched.cronHourly": "Hourly",
1231
- "sched.cronDaily": "Daily",
1232
- "sched.cronWeekly": "Weekly",
1233
- "sched.cronCustom": "Custom",
1234
- "sched.cronEvery": "Every",
1235
- "sched.cronAtMinute": "hour at minute",
1236
- "sched.cronMinuteUnit": "",
1237
- "sched.cronMinutesUnit": "minutes",
1238
- "sched.hourField": "Hour",
1239
- "sched.minuteField": "Minute",
1240
- "sched.presetHourly": "Every hour",
1241
- "sched.presetMin30": "Every 30 min",
1242
- "sched.presetDaily9": "Daily at 9:00",
1243
- "sched.presetWeekday830": "Weekdays at 8:30",
1244
- "sched.presetMon10": "Mondays at 10:00",
1245
- "sched.wd1": "Mon",
1246
- "sched.wd2": "Tue",
1247
- "sched.wd3": "Wed",
1248
- "sched.wd4": "Thu",
1249
- "sched.wd5": "Fri",
1250
- "sched.wd6": "Sat",
1251
- "sched.wd0": "Sun",
1252
- "sched.listSep": ", ",
1253
- "sched.sumMin": "Every {n} minutes",
1254
- "sched.sumHour": "Every hour at minute {m}",
1255
- "sched.sumDaily": "Daily at {t}",
1256
- "sched.sumWeekly": "Weekly on {w} at {t}",
1257
- "sched.sumWeeklyWorkday": "Weekdays at {t}",
1258
- "sched.sumCustom": "Custom: {raw}",
1259
- "sched.sumEmpty": "Pick or type a schedule",
1260
- "sched.nextRuns": "Next {n} runs",
1261
- "sched.titleLabel": "Title",
1262
- "sched.titlePlaceholder": "e.g. Morning standup notes",
1263
- "sched.promptLabel": "Prompt",
1264
- "sched.promptPlaceholder": "What should the agent do when this item runs?",
1265
- "sched.expertPick": "T Expert",
1266
- "sched.expertPickHint": "Pick one of the enabled experts here and its @name lands in the prompt.",
1267
- "sched.expertPickSearch": "Search expert name or slug",
1268
- "sched.expertPickEmpty": "No matching enabled expert. Enable some in Settings \u2192 T Expert.",
1269
- "sched.expertInvokeHint": 'This run will summon "{name}" to carry out this prompt.',
1270
- "sched.expertInvokeManyHint": 'This run will summon "{names}" together to carry out this prompt.',
1271
- "sched.expertRemove": "Remove {name}",
1272
- "sched.enabledLabel": "Enabled",
1273
- "sched.enabledHint": "Disabled items keep their data but never run on schedule.",
1274
- "sched.invalidForm": "Title, prompt, and cron schedule are required.",
1275
- "sched.off": 'Scheduled tasks are turned off in Settings \u2192 T Expert: nothing triggers and nothing can be run by hand. Re-enable "Show scheduled tasks button" to restore it.',
1276
- "sched.noAgents": "The host has no usable agents service, so creating a session will fail \u2014 check the host composition.",
1277
- "sched.file": "Data file: {path}"
1065
+ "pop.title": "T Expert"
1066
+ // List filter and search (same shape as the built-in Automation page: tab row + search field).
1067
+ // Three lanes: All / Active / Disabled — disabled keeps its data and simply never fires.
1068
+ // Run-time card (mirrors the built-in page's "Run time": repeat / time / weekday rows)
1278
1069
  };
1279
1070
 
1280
1071
  // src/client/insert.js
@@ -21051,64 +20842,13 @@ var enabledStateSchema = external_exports.object({
21051
20842
  revision: external_exports.number().int().min(0)
21052
20843
  });
21053
20844
  var uiPrefsSchema = external_exports.object({
21054
- showScheduleButton: external_exports.boolean(),
21055
20845
  // 窗口右上角「活跃指示」是否显示。宿主**总是**返回布尔(缺省按 true 算),所以这里必填。
21056
20846
  showActivePulse: external_exports.boolean()
21057
20847
  });
21058
20848
  var uiPrefsPatchSchema = external_exports.object({
21059
- showScheduleButton: external_exports.boolean().optional(),
21060
20849
  showActivePulse: external_exports.boolean().optional()
21061
20850
  });
21062
20851
  var promptSchema = external_exports.object({ prompt: external_exports.string() });
21063
- var scheduleRunSchema = external_exports.object({
21064
- at: external_exports.string(),
21065
- ok: external_exports.boolean(),
21066
- sessionId: external_exports.string().optional(),
21067
- error: external_exports.string().optional()
21068
- });
21069
- var scheduleItemSchema = external_exports.object({
21070
- id: external_exports.string(),
21071
- title: external_exports.string(),
21072
- prompt: external_exports.string(),
21073
- cron: external_exports.string(),
21074
- enabled: external_exports.boolean(),
21075
- workspaceId: external_exports.string().optional(),
21076
- /** 绑定时记下的工作区目录:工作区被删后凭它「重建」回到原路径。面板也会在编辑表单里显示它。 */
21077
- workspacePath: external_exports.string().optional(),
21078
- createdAt: external_exports.string(),
21079
- updatedAt: external_exports.string(),
21080
- lastRunAt: external_exports.string().optional(),
21081
- lastRunError: external_exports.string().optional(),
21082
- runs: external_exports.array(scheduleRunSchema)
21083
- });
21084
- var scheduleSnapshotSchema = external_exports.object({
21085
- items: external_exports.array(scheduleItemSchema),
21086
- /** 定时事项功能是否启用(= 设置页那个开关的当前值)。 */
21087
- armed: external_exports.boolean(),
21088
- /** 数据文件绝对路径(面板把它显示在说明里,便于用户备份)。 */
21089
- file: external_exports.string(),
21090
- /** 正在执行中的事项 id(面板据此显示「执行中…」)。 */
21091
- running: external_exports.array(external_exports.string()),
21092
- capabilities: external_exports.object({ agents: external_exports.boolean(), presets: external_exports.boolean() }),
21093
- /** 可选工作区(下拉选项);path 是目录,面板显示给用户看落地位置。 */
21094
- workspaces: external_exports.array(external_exports.object({ id: external_exports.string(), title: external_exports.string(), path: external_exports.string().optional() }))
21095
- });
21096
- var scheduleInputSchema = external_exports.object({
21097
- title: external_exports.string().min(1).max(200),
21098
- prompt: external_exports.string().min(1).max(2e4),
21099
- cron: external_exports.string().min(1).max(120),
21100
- enabled: external_exports.boolean(),
21101
- /** 空串 = 不绑定工作区(显式解绑也走这个值)。 */
21102
- workspaceId: external_exports.string().max(200).optional(),
21103
- /** 绑定时记下的工作区目录;老数据可缺省,按当前选中的 workspace 自动补。 */
21104
- workspacePath: external_exports.string().max(1024).optional()
21105
- });
21106
- var schedulePatchSchema = scheduleInputSchema.partial();
21107
- var schedulePreviewSchema = external_exports.object({ fires: external_exports.array(external_exports.string()) });
21108
- var scheduleArmedSchema = external_exports.object({ armed: external_exports.boolean() });
21109
- var scheduleWorkspaceSchema = external_exports.object({
21110
- workspace: external_exports.object({ id: external_exports.string(), title: external_exports.string(), path: external_exports.string() })
21111
- });
21112
20852
 
21113
20853
  // src/client/remote.js
21114
20854
  function direct(method, parameters, typeSymbol, schema) {
@@ -21140,27 +20880,6 @@ var TYPERT_REMOTE = {
21140
20880
  direct("setUiPrefs", [
21141
20881
  { name: "patch", wire: "patch", source: "json", codec: { mode: "strict", typeSymbol: "TTeamUiPrefsPatch", schema: uiPrefsPatchSchema, create: () => uiPrefsPatchSchema } }
21142
20882
  ], "TTeamUiPrefs", uiPrefsSchema),
21143
- // 定时任务:读一份快照;写操作全部回传刷新后的整份快照,面板拿到直接重绘。
21144
- direct("getSchedule", [], "TTeamSchedule", scheduleSnapshotSchema),
21145
- direct("createScheduleItem", [
21146
- { name: "input", wire: "input", source: "json", codec: { mode: "strict", typeSymbol: "TTeamScheduleInput", schema: scheduleInputSchema, create: () => scheduleInputSchema } }
21147
- ], "TTeamSchedule", scheduleSnapshotSchema),
21148
- direct("updateScheduleItem", [
21149
- { name: "id", wire: "id", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(128), create: () => external_exports.string().min(1).max(128) } },
21150
- { name: "patch", wire: "patch", source: "json", codec: { mode: "strict", typeSymbol: "TTeamSchedulePatch", schema: schedulePatchSchema, create: () => schedulePatchSchema } }
21151
- ], "TTeamSchedule", scheduleSnapshotSchema),
21152
- direct("deleteScheduleItem", [
21153
- { name: "id", wire: "id", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(128), create: () => external_exports.string().min(1).max(128) } }
21154
- ], "TTeamSchedule", scheduleSnapshotSchema),
21155
- direct("runScheduleItem", [
21156
- { name: "id", wire: "id", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(128), create: () => external_exports.string().min(1).max(128) } }
21157
- ], "TTeamSchedule", scheduleSnapshotSchema),
21158
- direct("ensureScheduleWorkspace", [
21159
- { name: "path", wire: "path", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().max(1024), create: () => external_exports.string().max(1024) } }
21160
- ], "TTeamScheduleWorkspace", scheduleWorkspaceSchema),
21161
- direct("previewSchedule", [
21162
- { name: "cron", wire: "cron", source: "json", codec: { mode: "strict", typeSymbol: "string", schema: external_exports.string().min(1).max(120), create: () => external_exports.string().min(1).max(120) } }
21163
- ], "TTeamSchedulePreview", schedulePreviewSchema),
21164
20883
  direct("createExpert", [
21165
20884
  { name: "expert", wire: "expert", source: "json", codec: { mode: "strict", typeSymbol: "TTeamCustomExpertInput", schema: customExpertInputSchema, create: () => customExpertInputSchema } }
21166
20885
  ], "TTeamCatalog", catalogSnapshotSchema),
@@ -21187,916 +20906,18 @@ var TYPERT_REMOTE = {
21187
20906
  ]
21188
20907
  };
21189
20908
 
21190
- // src/client/schedule.jsx
21191
- var import_react4 = __toESM(require("react"), 1);
21192
-
21193
- // src/schedule-cron.js
21194
- var WEEKDAY_KEYS = [1, 2, 3, 4, 5, 6, 0];
21195
- var CRON_PRESETS = [
21196
- { id: "hourly", cron: "0 * * * *" },
21197
- { id: "min30", cron: "*/30 * * * *" },
21198
- { id: "daily9", cron: "0 9 * * *" },
21199
- { id: "weekday830", cron: "30 8 * * 1-5" },
21200
- { id: "mon10", cron: "0 10 * * 1" }
21201
- ];
21202
- var HOURLY_STEPS = [60, 30, 15, 10, 5];
21203
- function int2(value, min, max) {
21204
- if (!/^\d+$/.test(value)) return null;
21205
- const n = Number(value);
21206
- return n >= min && n <= max ? n : null;
21207
- }
21208
- function parseDow(field) {
21209
- if (field === "*") return null;
21210
- const days = /* @__PURE__ */ new Set();
21211
- for (const token of field.split(",")) {
21212
- const range = token.match(/^(\d+)-(\d+)$/);
21213
- let lo;
21214
- let hi;
21215
- if (range) {
21216
- lo = Number(range[1]);
21217
- hi = Number(range[2]);
21218
- if (lo > hi) return null;
21219
- } else {
21220
- lo = hi = Number(token);
21221
- }
21222
- for (let atom = lo; atom <= hi; atom++) {
21223
- if (!Number.isInteger(atom)) return null;
21224
- if (atom < 0 || atom > 7) return null;
21225
- days.add(atom === 7 ? 0 : atom);
21226
- }
21227
- }
21228
- if (days.size === 0) return null;
21229
- return WEEKDAY_KEYS.filter((key) => days.has(key));
21230
- }
21231
- function parseCron(str) {
21232
- const raw = typeof str === "string" ? str.trim() : "";
21233
- const custom2 = { mode: "custom", raw };
21234
- const fields = raw.split(/\s+/);
21235
- if (fields.length !== 5) return raw === "" ? { mode: "daily", minute: 0, hour: 9 } : custom2;
21236
- const [mf, hf, domf, monf, dowf] = fields;
21237
- if (domf !== "*" || monf !== "*") return custom2;
21238
- if (hf === "*" && dowf === "*") {
21239
- const step = mf.match(/^\*\/(\d+)$/);
21240
- if (step) {
21241
- const n = Number(step[1]);
21242
- return HOURLY_STEPS.includes(n) ? { mode: "hourly", step: n } : custom2;
21243
- }
21244
- const minute2 = int2(mf, 0, 59);
21245
- return minute2 === null ? custom2 : { mode: "hourly", step: 60, minute: minute2 };
21246
- }
21247
- const hour = int2(hf, 0, 23);
21248
- const minute = int2(mf, 0, 59);
21249
- if (hour === null || minute === null) return custom2;
21250
- const days = parseDow(dowf);
21251
- if (days === null) return dowf === "*" ? { mode: "daily", hour, minute } : custom2;
21252
- return { mode: "weekly", hour, minute, days };
21253
- }
21254
- function formatDow(days) {
21255
- const week = days.filter((d) => d >= 1 && d <= 6).sort((a, b) => a - b);
21256
- const tokens = [];
21257
- let start = null;
21258
- let prev = null;
21259
- const flush = () => {
21260
- if (start === null) return;
21261
- tokens.push(start === prev ? String(start) : `${start}-${prev}`);
21262
- start = null;
21263
- };
21264
- for (const d of week) {
21265
- if (start === null) {
21266
- start = d;
21267
- prev = d;
21268
- } else if (d === prev + 1) {
21269
- prev = d;
21270
- } else {
21271
- flush();
21272
- start = d;
21273
- prev = d;
21274
- }
21275
- }
21276
- flush();
21277
- if (days.includes(0)) tokens.push("0");
21278
- return tokens.join(",");
21279
- }
21280
- function buildCron(model) {
21281
- if (!model || model.mode === "custom") return (model?.raw || "").trim();
21282
- const minute = model.minute ?? 0;
21283
- if (model.mode === "hourly") {
21284
- return model.step && model.step < 60 ? `*/${model.step} * * * *` : `${minute} * * * *`;
21285
- }
21286
- const hour = model.hour ?? 9;
21287
- if (model.mode === "daily") return `${minute} ${hour} * * *`;
21288
- if (model.mode === "weekly") {
21289
- const days = model.days && model.days.length ? model.days : [1];
21290
- return `${minute} ${hour} * * ${formatDow(days)}`;
21291
- }
21292
- return "";
21293
- }
21294
-
21295
- // src/client/schedule.jsx
21296
- var CUSTOM_WORKSPACE = "__custom__";
21297
- var SCHEDULE_PANEL_KEY = `${NS}-schedule`;
21298
- var SCHEDULE_PRESET_LABELS = {
21299
- hourly: "sched.presetHourly",
21300
- min30: "sched.presetMin30",
21301
- daily9: "sched.presetDaily9",
21302
- weekday830: "sched.presetWeekday830",
21303
- mon10: "sched.presetMon10"
21304
- };
21305
- var SCHEDULE_WEEKDAY_LABELS = {
21306
- 1: "sched.wd1",
21307
- 2: "sched.wd2",
21308
- 3: "sched.wd3",
21309
- 4: "sched.wd4",
21310
- 5: "sched.wd5",
21311
- 6: "sched.wd6",
21312
- 0: "sched.wd0"
21313
- };
21314
- function errorText(cause) {
21315
- return cause instanceof Error ? cause.message : String(cause);
21316
- }
21317
- function CronPicker({ t, remote, value, onChange, disabled }) {
21318
- const [model, setModel] = import_react4.default.useState(() => parseCron(value));
21319
- const [fires, setFires] = import_react4.default.useState([]);
21320
- const [hint, setHint] = import_react4.default.useState("");
21321
- import_react4.default.useEffect(() => {
21322
- const next = parseCron(value);
21323
- if (next.mode === "custom" && typeof value === "string") {
21324
- setModel({ mode: "custom", raw: value });
21325
- return;
21326
- }
21327
- setModel(next);
21328
- }, [value]);
21329
- import_react4.default.useEffect(() => {
21330
- const cron = String(value ?? "").trim();
21331
- if (cron === "") {
21332
- setFires([]);
21333
- setHint("");
21334
- return void 0;
21335
- }
21336
- let cancelled = false;
21337
- const timer = setTimeout(() => {
21338
- void (async () => {
21339
- try {
21340
- const payload = unwrap(await remote.previewSchedule(cron), "previewSchedule");
21341
- if (cancelled) return;
21342
- setFires(Array.isArray(payload?.fires) ? payload.fires : []);
21343
- setHint("");
21344
- } catch (cause) {
21345
- if (cancelled) return;
21346
- setFires([]);
21347
- setHint(errorText(cause));
21348
- }
21349
- })();
21350
- }, 250);
21351
- return () => {
21352
- cancelled = true;
21353
- clearTimeout(timer);
21354
- };
21355
- }, [value, remote]);
21356
- import_react4.default.useEffect(() => {
21357
- if (!value || String(value).trim() === "") onChange(buildCron(parseCron("")));
21358
- }, []);
21359
- const emit = (next) => {
21360
- setModel(next);
21361
- const cron = buildCron(next);
21362
- if (cron !== "") onChange(cron);
21363
- };
21364
- const setMode = (mode) => {
21365
- if (mode === model.mode) return;
21366
- if (mode === "hourly") emit({ mode, step: 60, minute: model.minute ?? 0 });
21367
- else if (mode === "daily") emit({ mode, hour: model.hour ?? 9, minute: model.minute ?? 0 });
21368
- else if (mode === "weekly") emit({ mode, hour: model.hour ?? 9, minute: model.minute ?? 0, days: model.days && model.days.length ? model.days : [1, 2, 3, 4, 5] });
21369
- else {
21370
- const raw = buildCron(model) || "0 9 * * *";
21371
- setModel({ mode, raw });
21372
- onChange(raw);
21373
- }
21374
- };
21375
- const toggleDay = (day) => {
21376
- const current = model.days || [];
21377
- const next = current.includes(day) ? current.filter((item) => item !== day) : WEEKDAY_KEYS.filter((item) => current.includes(item) || item === day);
21378
- if (next.length === 0) return;
21379
- emit({ ...model, days: next });
21380
- };
21381
- const pad2 = (n) => String(n).padStart(2, "0");
21382
- const hours = Array.from({ length: 24 }, (_, i) => i);
21383
- const minutes = Array.from({ length: 60 }, (_, i) => i);
21384
- const time3 = `${pad2(model.hour ?? 9)}:${pad2(model.minute ?? 0)}`;
21385
- let summary;
21386
- if (model.mode === "hourly") {
21387
- summary = model.step && model.step < 60 ? t("sched.sumMin", { n: model.step }) : t("sched.sumHour", { m: pad2(model.minute ?? 0) });
21388
- } else if (model.mode === "daily") {
21389
- summary = t("sched.sumDaily", { t: time3 });
21390
- } else if (model.mode === "weekly") {
21391
- const days = model.days || [];
21392
- const isWorkday = days.length === 5 && [1, 2, 3, 4, 5].every((day) => days.includes(day));
21393
- const week = isWorkday ? "" : days.map((day) => t(SCHEDULE_WEEKDAY_LABELS[day])).join(t("sched.listSep"));
21394
- summary = t(isWorkday ? "sched.sumWeeklyWorkday" : "sched.sumWeekly", { w: week, t: time3 });
21395
- } else {
21396
- summary = model.raw ? t("sched.sumCustom", { raw: model.raw }) : t("sched.sumEmpty");
21397
- }
21398
- const timeSelects = /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement("select", { "aria-label": t("sched.hourField"), value: model.hour ?? 9, disabled, onChange: (event) => emit({ ...model, hour: Number(event.target.value) }) }, hours.map((n) => /* @__PURE__ */ import_react4.default.createElement("option", { key: n, value: n }, pad2(n)))), /* @__PURE__ */ import_react4.default.createElement("span", null, ":"), /* @__PURE__ */ import_react4.default.createElement("select", { "aria-label": t("sched.minuteField"), value: model.minute ?? 0, disabled, onChange: (event) => emit({ ...model, minute: Number(event.target.value) }) }, minutes.map((n) => /* @__PURE__ */ import_react4.default.createElement("option", { key: n, value: n }, pad2(n)))));
21399
- return /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-sched-cron" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-sched-chips" }, CRON_PRESETS.map((preset) => /* @__PURE__ */ import_react4.default.createElement(
21400
- "button",
21401
- {
21402
- key: preset.id,
21403
- type: "button",
21404
- className: "t-team-sched-chip",
21405
- disabled,
21406
- onClick: () => onChange(preset.cron)
21407
- },
21408
- t(SCHEDULE_PRESET_LABELS[preset.id])
21409
- ))), /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-sched-seg", role: "tablist" }, [["hourly", "sched.cronHourly"], ["daily", "sched.cronDaily"], ["weekly", "sched.cronWeekly"], ["custom", "sched.cronCustom"]].map(([mode, key]) => /* @__PURE__ */ import_react4.default.createElement(
21410
- "button",
21411
- {
21412
- key: mode,
21413
- type: "button",
21414
- role: "tab",
21415
- "aria-selected": model.mode === mode,
21416
- "data-on": model.mode === mode,
21417
- disabled,
21418
- onClick: () => setMode(mode)
21419
- },
21420
- t(key)
21421
- ))), model.mode === "hourly" && /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-sched-cronRow" }, /* @__PURE__ */ import_react4.default.createElement("span", null, t("sched.cronEvery")), /* @__PURE__ */ import_react4.default.createElement(
21422
- "select",
21423
- {
21424
- value: model.step ?? 60,
21425
- disabled,
21426
- onChange: (event) => {
21427
- const step = Number(event.target.value);
21428
- emit(step === 60 ? { mode: "hourly", step, minute: model.minute ?? 0 } : { mode: "hourly", step });
21429
- }
21430
- },
21431
- HOURLY_STEPS.map((step) => /* @__PURE__ */ import_react4.default.createElement("option", { key: step, value: step }, step === 60 ? "1" : String(step)))
21432
- ), (model.step ?? 60) === 60 ? /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement("span", null, t("sched.cronAtMinute")), /* @__PURE__ */ import_react4.default.createElement(
21433
- "select",
21434
- {
21435
- value: model.minute ?? 0,
21436
- disabled,
21437
- onChange: (event) => emit({ ...model, minute: Number(event.target.value) })
21438
- },
21439
- minutes.map((n) => /* @__PURE__ */ import_react4.default.createElement("option", { key: n, value: n }, pad2(n)))
21440
- ), /* @__PURE__ */ import_react4.default.createElement("span", null, t("sched.cronMinuteUnit"))) : /* @__PURE__ */ import_react4.default.createElement("span", null, t("sched.cronMinutesUnit"))), (model.mode === "daily" || model.mode === "weekly") && /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-sched-cronRow" }, model.mode === "weekly" && /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-sched-days" }, WEEKDAY_KEYS.map((day) => /* @__PURE__ */ import_react4.default.createElement(
21441
- "button",
21442
- {
21443
- key: day,
21444
- type: "button",
21445
- className: "t-team-sched-day",
21446
- "data-on": (model.days || []).includes(day),
21447
- "aria-pressed": (model.days || []).includes(day),
21448
- disabled,
21449
- onClick: () => toggleDay(day)
21450
- },
21451
- t(SCHEDULE_WEEKDAY_LABELS[day])
21452
- ))), timeSelects), model.mode === "custom" && /* @__PURE__ */ import_react4.default.createElement(
21453
- "input",
21454
- {
21455
- value: model.raw || "",
21456
- disabled,
21457
- placeholder: "0 9 * * *",
21458
- spellCheck: false,
21459
- onChange: (event) => {
21460
- const raw = event.target.value;
21461
- setModel({ mode: "custom", raw });
21462
- onChange(raw);
21463
- }
21464
- }
21465
- ), /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-sched-sum" }, hint === "" ? summary : hint), fires.length > 0 && /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-sched-next" }, /* @__PURE__ */ import_react4.default.createElement("span", { className: "t-team-sched-nextLabel" }, t("sched.nextRuns", { n: fires.length })), /* @__PURE__ */ import_react4.default.createElement("ul", { className: "t-team-sched-nextList" }, fires.map((iso, index) => /* @__PURE__ */ import_react4.default.createElement("li", { key: index }, new Date(iso).toLocaleString(void 0, { weekday: "short", month: "numeric", day: "numeric", hour: "2-digit", minute: "2-digit" }))))));
21466
- }
21467
- function emptyScheduleForm() {
21468
- return { editingId: null, title: "", prompt: "", cron: "", enabled: true, workspaceId: "", customDir: "", workspacePath: "" };
21469
- }
21470
- function scheduleLastRun(t, item) {
21471
- if (!item.lastRunAt) return t("sched.neverRun");
21472
- const time3 = new Date(item.lastRunAt).toLocaleString();
21473
- return item.lastRunError === void 0 ? time3 : `${time3}\uFF08${t("sched.failed")}: ${item.lastRunError}\uFF09`;
21474
- }
21475
- function PromptEditor({ editorRef, t, active, experts, value, disabled, onChange }) {
21476
- const boxRef = import_react4.default.useRef(null);
21477
- const lastWritten = import_react4.default.useRef(null);
21478
- const savedRange = import_react4.default.useRef(null);
21479
- const buildChipIcon = () => {
21480
- const NS2 = "http://www.w3.org/2000/svg";
21481
- const svg = document.createElementNS(NS2, "svg");
21482
- svg.setAttribute("class", "t-team-sched-chip-icon");
21483
- svg.setAttribute("viewBox", "0 0 16 16");
21484
- svg.setAttribute("width", "13");
21485
- svg.setAttribute("height", "13");
21486
- svg.setAttribute("fill", "none");
21487
- svg.setAttribute("stroke", "currentColor");
21488
- svg.setAttribute("stroke-width", "1.4");
21489
- svg.setAttribute("stroke-linecap", "round");
21490
- svg.setAttribute("aria-hidden", "true");
21491
- const circle = document.createElementNS(NS2, "circle");
21492
- circle.setAttribute("cx", "8");
21493
- circle.setAttribute("cy", "8");
21494
- circle.setAttribute("r", "6");
21495
- const line1 = document.createElementNS(NS2, "line");
21496
- line1.setAttribute("x1", "5.4");
21497
- line1.setAttribute("y1", "6.6");
21498
- line1.setAttribute("x2", "10.6");
21499
- line1.setAttribute("y2", "6.6");
21500
- const line2 = document.createElementNS(NS2, "line");
21501
- line2.setAttribute("x1", "5.4");
21502
- line2.setAttribute("y1", "9.4");
21503
- line2.setAttribute("x2", "9");
21504
- line2.setAttribute("y2", "9.4");
21505
- svg.append(circle, line1, line2);
21506
- return svg;
21507
- };
21508
- const buildChip = (name) => {
21509
- const chip = document.createElement("span");
21510
- chip.className = "t-team-sched-chip";
21511
- chip.contentEditable = "false";
21512
- chip.dataset.expert = name;
21513
- const label = document.createElement("span");
21514
- label.className = "t-team-sched-chip-name";
21515
- label.textContent = name;
21516
- const remove = document.createElement("button");
21517
- remove.type = "button";
21518
- remove.className = "t-team-sched-chip-remove";
21519
- remove.dataset.remove = name;
21520
- remove.textContent = "\xD7";
21521
- remove.title = t("sched.expertRemove", { name });
21522
- chip.append(buildChipIcon(), label, remove);
21523
- return chip;
21524
- };
21525
- const serialize = () => {
21526
- const box = boxRef.current;
21527
- if (box === null) return "";
21528
- let out = "";
21529
- for (const node2 of box.childNodes) {
21530
- if (node2.nodeType === 3) {
21531
- out += node2.textContent ?? "";
21532
- continue;
21533
- }
21534
- if (node2.nodeType !== 1) continue;
21535
- const el = (
21536
- /** @type {HTMLElement} */
21537
- node2
21538
- );
21539
- if (el.dataset?.expert !== void 0) {
21540
- out += `@${el.dataset.expert}`;
21541
- continue;
21542
- }
21543
- if (el.tagName === "BR") {
21544
- out += "\n";
21545
- continue;
21546
- }
21547
- out += el.textContent ?? "";
21548
- }
21549
- return out;
21550
- };
21551
- const refreshEmpty = () => {
21552
- const box = boxRef.current;
21553
- if (box !== null) box.dataset.empty = box.textContent === "" ? "true" : "false";
21554
- };
21555
- const pushOut = () => {
21556
- const text = serialize();
21557
- lastWritten.current = text;
21558
- refreshEmpty();
21559
- onChange(text);
21560
- };
21561
- const rebuild = () => {
21562
- const box = boxRef.current;
21563
- if (box === null) return;
21564
- box.textContent = "";
21565
- for (const token of tokenizePrompt(value, experts, active)) {
21566
- box.append(token.type === "text" ? document.createTextNode(token.text ?? "") : buildChip(token.name ?? ""));
21567
- }
21568
- refreshEmpty();
21569
- };
21570
- const removeExpert = (name) => {
21571
- const box = boxRef.current;
21572
- if (box === null) return;
21573
- for (const el of box.querySelectorAll("[data-expert]")) {
21574
- if (
21575
- /** @type {HTMLElement} */
21576
- el.dataset.expert === name
21577
- ) {
21578
- el.remove();
21579
- break;
21580
- }
21581
- }
21582
- pushOut();
21583
- };
21584
- const insertExpert = (name) => {
21585
- const box = boxRef.current;
21586
- if (box === null || disabled) return;
21587
- const chip = buildChip(name);
21588
- const space = document.createTextNode(" ");
21589
- box.focus();
21590
- const selection = window.getSelection();
21591
- if (selection !== null && savedRange.current !== null && box.contains(savedRange.current.commonAncestorContainer)) {
21592
- selection.removeAllRanges();
21593
- selection.addRange(savedRange.current);
21594
- }
21595
- const inside = selection !== null && selection.rangeCount > 0 && box.contains(selection.anchorNode);
21596
- if (inside) {
21597
- const range = selection.getRangeAt(0);
21598
- range.deleteContents();
21599
- range.insertNode(chip);
21600
- chip.after(space);
21601
- range.setStartAfter(space);
21602
- range.collapse(true);
21603
- selection.removeAllRanges();
21604
- selection.addRange(range);
21605
- savedRange.current = range.cloneRange();
21606
- } else {
21607
- box.append(chip, space);
21608
- }
21609
- pushOut();
21610
- };
21611
- import_react4.default.useEffect(() => {
21612
- if (editorRef === void 0) return void 0;
21613
- editorRef.current = { insertExpert, removeExpert, focus: () => boxRef.current?.focus() };
21614
- return () => {
21615
- editorRef.current = null;
21616
- };
21617
- });
21618
- import_react4.default.useEffect(() => {
21619
- if (lastWritten.current === value) return;
21620
- rebuild();
21621
- }, [value, experts, active]);
21622
- import_react4.default.useEffect(() => {
21623
- const onSelectionChange = () => {
21624
- const box = boxRef.current;
21625
- if (box === null) return;
21626
- const selection = window.getSelection();
21627
- if (selection === null || selection.rangeCount === 0) return;
21628
- const range = selection.getRangeAt(0);
21629
- if (box.contains(range.commonAncestorContainer)) savedRange.current = range.cloneRange();
21630
- };
21631
- document.addEventListener("selectionchange", onSelectionChange);
21632
- return () => document.removeEventListener("selectionchange", onSelectionChange);
21633
- }, []);
21634
- const onPaste = (event) => {
21635
- const text = event.clipboardData?.getData("text/plain") ?? "";
21636
- if (text === "") return;
21637
- event.preventDefault();
21638
- const selection = window.getSelection();
21639
- if (selection === null || selection.rangeCount === 0) return;
21640
- const range = selection.getRangeAt(0);
21641
- range.deleteContents();
21642
- const node2 = document.createTextNode(text);
21643
- range.insertNode(node2);
21644
- range.setStartAfter(node2);
21645
- range.collapse(true);
21646
- selection.removeAllRanges();
21647
- selection.addRange(range);
21648
- pushOut();
21649
- };
21650
- return /* @__PURE__ */ import_react4.default.createElement(
21651
- "div",
21652
- {
21653
- ref: boxRef,
21654
- className: "t-team-sched-prompt-input",
21655
- contentEditable: !disabled,
21656
- suppressContentEditableWarning: true,
21657
- role: "textbox",
21658
- "aria-multiline": "true",
21659
- "aria-label": t("sched.promptLabel"),
21660
- "data-placeholder": t("sched.promptPlaceholder"),
21661
- "data-empty": "true",
21662
- onInput: () => {
21663
- if (!disabled) pushOut();
21664
- },
21665
- onPaste,
21666
- onBlur: () => {
21667
- if (!disabled) pushOut();
21668
- },
21669
- onMouseDownCapture: (event) => {
21670
- const target = (
21671
- /** @type {HTMLElement} */
21672
- event.target
21673
- );
21674
- const name = target?.dataset?.remove;
21675
- if (name === void 0 || disabled) return;
21676
- event.preventDefault();
21677
- removeExpert(name);
21678
- }
21679
- }
21680
- );
21681
- }
21682
- function ExpertPicker({ t, active, experts, disabled, selected, onPick }) {
21683
- const [open2, setOpen] = import_react4.default.useState(false);
21684
- const [query, setQuery] = import_react4.default.useState("");
21685
- const [index, setIndex] = import_react4.default.useState(0);
21686
- const wrapRef = import_react4.default.useRef(null);
21687
- const picked = selected ?? [];
21688
- import_react4.default.useEffect(() => {
21689
- if (!open2) return void 0;
21690
- const onDown = (event) => {
21691
- const node2 = wrapRef.current;
21692
- if (node2 !== null && !node2.contains(event.target)) setOpen(false);
21693
- };
21694
- document.addEventListener("pointerdown", onDown, true);
21695
- return () => document.removeEventListener("pointerdown", onDown, true);
21696
- }, [open2]);
21697
- const needle = query.trim().toLowerCase();
21698
- const candidates = (experts ?? []).filter((expert) => matchExpert(expert, active, needle)).slice(0, 50);
21699
- const pick2 = (expert) => {
21700
- if (expert === void 0) return;
21701
- onPick(expert);
21702
- setOpen(false);
21703
- setQuery("");
21704
- setIndex(0);
21705
- };
21706
- const onKeyDown = (event) => {
21707
- if (event.key === "Escape") {
21708
- event.preventDefault();
21709
- setOpen(false);
21710
- return;
21711
- }
21712
- if (candidates.length === 0) return;
21713
- if (event.key === "ArrowDown") {
21714
- event.preventDefault();
21715
- setIndex((current) => (current + 1) % candidates.length);
21716
- } else if (event.key === "ArrowUp") {
21717
- event.preventDefault();
21718
- setIndex((current) => (current - 1 + candidates.length) % candidates.length);
21719
- } else if (event.key === "Enter") {
21720
- event.preventDefault();
21721
- pick2(candidates[Math.min(index, candidates.length - 1)]);
21722
- }
21723
- };
21724
- return /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-expert-pick", ref: wrapRef }, /* @__PURE__ */ import_react4.default.createElement(
21725
- "button",
21726
- {
21727
- type: "button",
21728
- className: "t-team-chip",
21729
- "data-active": open2,
21730
- disabled,
21731
- "aria-expanded": open2,
21732
- onClick: () => {
21733
- setOpen(!open2);
21734
- setQuery("");
21735
- setIndex(0);
21736
- }
21737
- },
21738
- "\u{1F9E9} ",
21739
- t("sched.expertPick")
21740
- ), /* @__PURE__ */ import_react4.default.createElement("span", { className: "t-team-expert-pick-hint" }, t("sched.expertPickHint")), open2 && /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-expert-pick-panel" }, /* @__PURE__ */ import_react4.default.createElement(
21741
- "input",
21742
- {
21743
- className: "t-team-expert-pick-search",
21744
- value: query,
21745
- autoFocus: true,
21746
- spellCheck: false,
21747
- placeholder: t("sched.expertPickSearch"),
21748
- "aria-label": t("sched.expertPickSearch"),
21749
- onChange: (event) => {
21750
- setQuery(event.target.value);
21751
- setIndex(0);
21752
- },
21753
- onKeyDown
21754
- }
21755
- ), candidates.length === 0 ? /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-expert-pick-empty" }, t("sched.expertPickEmpty")) : /* @__PURE__ */ import_react4.default.createElement("ul", { className: "t-team-expert-pick-list", role: "listbox" }, candidates.map((expert, position) => /* @__PURE__ */ import_react4.default.createElement("li", { key: expert.slug }, /* @__PURE__ */ import_react4.default.createElement(
21756
- "button",
21757
- {
21758
- type: "button",
21759
- role: "option",
21760
- "aria-selected": position === index,
21761
- "data-active": position === index,
21762
- "data-picked": picked.includes(displayName(expert, active)),
21763
- className: "t-team-expert-pick-item",
21764
- onMouseEnter: () => setIndex(position),
21765
- onMouseDown: (event) => event.preventDefault(),
21766
- onClick: () => pick2(expert)
21767
- },
21768
- /* @__PURE__ */ import_react4.default.createElement("span", { className: "t-team-expert-pick-name" }, picked.includes(displayName(expert, active)) ? "\u2713 " : "", expert.emoji, " ", displayName(expert, active)),
21769
- /* @__PURE__ */ import_react4.default.createElement("span", { className: "t-team-expert-pick-meta" }, divisionLabel(expert, active))
21770
- ))))));
21771
- }
21772
- function SchedulePanel({ t, ctx: hostCtx, remote, getActive }) {
21773
- const showButton = useShowScheduleButton();
21774
- const [snapshot, setSnapshot] = import_react4.default.useState(null);
21775
- const [error62, setError] = import_react4.default.useState("");
21776
- const [loading, setLoading] = import_react4.default.useState(true);
21777
- const [busy, setBusy] = import_react4.default.useState(false);
21778
- const [form, setForm] = import_react4.default.useState(null);
21779
- const [historyId, setHistoryId] = import_react4.default.useState(null);
21780
- const [confirmingId, setConfirmingId] = import_react4.default.useState("");
21781
- const [runningId, setRunningId] = import_react4.default.useState(null);
21782
- const [experts, setExperts] = import_react4.default.useState([]);
21783
- const promptEditorRef = import_react4.default.useRef(null);
21784
- const [extraWorkspaces, setExtraWorkspaces] = import_react4.default.useState([]);
21785
- const layout = () => hostCtx?.get?.("layout") ?? hostCtx?.layout;
21786
- const backToConversation = () => layout()?.selectPanel?.(null);
21787
- const load = import_react4.default.useCallback(async () => {
21788
- setLoading(true);
21789
- try {
21790
- setSnapshot(unwrap(await remote.getSchedule(), "getSchedule"));
21791
- setError("");
21792
- } catch (cause) {
21793
- setError(errorText(cause));
21794
- } finally {
21795
- setLoading(false);
21796
- }
21797
- }, [remote]);
21798
- import_react4.default.useEffect(() => {
21799
- void load();
21800
- }, [load]);
21801
- import_react4.default.useEffect(() => {
21802
- let alive = true;
21803
- const sync = () => {
21804
- const current = snapshotOf(remote);
21805
- if (current === void 0 || !alive) return;
21806
- setExperts(current.experts.filter((expert) => expert.conflict !== true && current.enabledSet.has(expert.slug)));
21807
- };
21808
- const stop = onCatalogLoaded(sync);
21809
- void (async () => {
21810
- try {
21811
- await refresh(remote);
21812
- sync();
21813
- } catch (cause) {
21814
- console.warn("[t-team] \u5B9A\u65F6\u4EFB\u52A1\uFF1A\u8BFB\u53D6\u4E13\u5BB6\u540D\u518C\u5931\u8D25\uFF0C\u300CT\u4E13\u5BB6\u300D\u6311\u9009\u5668\u6682\u4E0D\u53EF\u7528\uFF1A", cause);
21815
- }
21816
- })();
21817
- return () => {
21818
- alive = false;
21819
- stop();
21820
- };
21821
- }, [remote]);
21822
- const active = getActive();
21823
- import_react4.default.useEffect(() => {
21824
- if (showButton) return;
21825
- layout()?.selectPanel?.(null);
21826
- }, [showButton]);
21827
- const applySnapshot = (next) => {
21828
- setSnapshot(next);
21829
- setError("");
21830
- };
21831
- function fillExpert(expert) {
21832
- const editor = promptEditorRef.current;
21833
- if (editor === null) return;
21834
- const name = displayName(expert, active);
21835
- if (mentioned.includes(name)) editor.removeExpert(name);
21836
- else editor.insertExpert(name);
21837
- }
21838
- function rememberWorkspace(workspace) {
21839
- if (workspace === void 0 || workspace === null) return "";
21840
- setExtraWorkspaces((current) => current.some((item) => item.id === workspace.id) ? current : [...current, workspace]);
21841
- return workspace.id;
21842
- }
21843
- async function openNewForm() {
21844
- setBusy(true);
21845
- let workspaceId = "";
21846
- try {
21847
- workspaceId = rememberWorkspace(unwrap(await remote.ensureScheduleWorkspace(""), "ensureScheduleWorkspace")?.workspace);
21848
- } catch (cause) {
21849
- setError(errorText(cause));
21850
- } finally {
21851
- setBusy(false);
21852
- }
21853
- setForm({ ...emptyScheduleForm(), workspaceId });
21854
- }
21855
- async function submitForm() {
21856
- if (form === null || busy) return;
21857
- setError("");
21858
- if (form.title.trim() === "" || form.prompt.trim() === "" || form.cron.trim() === "") {
21859
- setError(t("sched.invalidForm"));
21860
- return;
21861
- }
21862
- setBusy(true);
21863
- try {
21864
- let workspaceId = form.workspaceId;
21865
- if (workspaceId === CUSTOM_WORKSPACE) {
21866
- const dir = form.customDir.trim();
21867
- if (dir === "") {
21868
- setError(t("sched.workspaceCustomEmpty"));
21869
- return;
21870
- }
21871
- workspaceId = rememberWorkspace(unwrap(await remote.ensureScheduleWorkspace(dir), "ensureScheduleWorkspace")?.workspace);
21872
- }
21873
- const payload = {
21874
- title: form.title.trim(),
21875
- prompt: form.prompt,
21876
- cron: form.cron.trim(),
21877
- enabled: form.enabled,
21878
- // 空串 = 不绑定工作区(显式解绑也走这个值,宿主认得)。
21879
- workspaceId: workspaceId === void 0 || workspaceId === null ? "" : workspaceId,
21880
- // 把当前绑定的目录也一起带上:将来工作区被删时,面板行内的「重建工作区」才能按这个路径
21881
- // 把任务拉回来(老数据没有这个字段时由宿主用空串兜底)。
21882
- workspacePath: selectedWorkspacePath
21883
- };
21884
- const next = form.editingId === null ? unwrap(await remote.createScheduleItem(payload), "createScheduleItem") : unwrap(await remote.updateScheduleItem(form.editingId, payload), "updateScheduleItem");
21885
- applySnapshot(next);
21886
- setForm(null);
21887
- } catch (cause) {
21888
- setError(errorText(cause));
21889
- } finally {
21890
- setBusy(false);
21891
- }
21892
- }
21893
- async function removeItem(id) {
21894
- if (confirmingId !== id) {
21895
- setConfirmingId(id);
21896
- return;
21897
- }
21898
- setConfirmingId("");
21899
- setBusy(true);
21900
- try {
21901
- applySnapshot(unwrap(await remote.deleteScheduleItem(id), "deleteScheduleItem"));
21902
- } catch (cause) {
21903
- setError(errorText(cause));
21904
- } finally {
21905
- setBusy(false);
21906
- }
21907
- }
21908
- async function runItem(id) {
21909
- setRunningId(id);
21910
- try {
21911
- applySnapshot(unwrap(await remote.runScheduleItem(id), "runScheduleItem"));
21912
- const startedAt = Date.now();
21913
- while (Date.now() - startedAt < 6e3) {
21914
- await new Promise((r) => setTimeout(r, 600));
21915
- try {
21916
- const next = unwrap(await remote.getSchedule(), "getSchedule");
21917
- if (next?.items?.find?.((it) => it.id === id) === void 0) break;
21918
- applySnapshot(next);
21919
- const live = next?.running ?? [];
21920
- if (!live.includes(id)) break;
21921
- } catch {
21922
- }
21923
- }
21924
- } catch (cause) {
21925
- setError(errorText(cause));
21926
- } finally {
21927
- setRunningId(null);
21928
- }
21929
- }
21930
- const items = snapshot?.items ?? [];
21931
- const workspaces = snapshot?.workspaces ?? [];
21932
- const allWorkspaces = [...workspaces];
21933
- for (const workspace of extraWorkspaces) {
21934
- if (!allWorkspaces.some((item) => item.id === workspace.id)) allWorkspaces.push(workspace);
21935
- }
21936
- const workspaceTitle = (id) => allWorkspaces.find((workspace) => workspace.id === id)?.title ?? id;
21937
- const isWorkspaceMissing = (item) => {
21938
- if (item.workspaceId === void 0 || item.workspaceId === "") return false;
21939
- return !allWorkspaces.some((workspace) => workspace.id === item.workspaceId);
21940
- };
21941
- const rowMeta = (item) => {
21942
- const parts = [];
21943
- if (item.workspaceId !== void 0) parts.push(`${t("sched.workspace")}: ${workspaceTitle(item.workspaceId)}`);
21944
- if (item.enabled !== true) parts.push(t("sched.disabledTag"));
21945
- parts.push(`${t("sched.lastRun")}: ${scheduleLastRun(t, item)}`);
21946
- return parts.join(" \xB7 ");
21947
- };
21948
- const disabled = busy || loading || !showButton;
21949
- const mentioned = form === null ? [] : collectExpertMentions(form.prompt, experts, active);
21950
- const selectedWorkspacePath = form === null ? "" : allWorkspaces.find((workspace) => workspace.id === form.workspaceId)?.path ?? "";
21951
- return /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-sched" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-sched-head" }, /* @__PURE__ */ import_react4.default.createElement("div", null, /* @__PURE__ */ import_react4.default.createElement("h2", { className: "t-team-sched-title" }, t("sched.title")), /* @__PURE__ */ import_react4.default.createElement("p", { className: "t-team-sched-intro" }, t("sched.intro"))), /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-sched-actions" }, /* @__PURE__ */ import_react4.default.createElement("button", { type: "button", className: "t-team-sched-btn", disabled: loading, onClick: () => void load() }, t("sched.refresh")), /* @__PURE__ */ import_react4.default.createElement("button", { type: "button", className: "t-team-sched-btn", onClick: backToConversation }, t("sched.back")))), !showButton && /* @__PURE__ */ import_react4.default.createElement("p", { className: "t-team-sched-note" }, t("sched.off")), snapshot !== null && snapshot.capabilities?.agents !== true && /* @__PURE__ */ import_react4.default.createElement("p", { className: "t-team-sched-note" }, t("sched.noAgents")), error62 !== "" && /* @__PURE__ */ import_react4.default.createElement("p", { className: "t-team-sched-error", role: "alert" }, t("sched.error"), " ", error62, /* @__PURE__ */ import_react4.default.createElement("button", { type: "button", className: "t-team-sched-btn", onClick: () => void load() }, t("sched.retry"))), loading && /* @__PURE__ */ import_react4.default.createElement("p", { className: "t-team-sched-intro" }, t("sched.loading")), /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-sched-body" }, !loading && items.length === 0 && error62 === "" && /* @__PURE__ */ import_react4.default.createElement("p", { className: "t-team-sched-intro" }, t("sched.empty")), /* @__PURE__ */ import_react4.default.createElement("ul", { className: "t-team-sched-list" }, items.map((item) => /* @__PURE__ */ import_react4.default.createElement("li", { key: item.id, className: "t-team-sched-row" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-sched-rowMain" }, /* @__PURE__ */ import_react4.default.createElement("span", { className: "t-team-sched-rowTitle" }, item.title), /* @__PURE__ */ import_react4.default.createElement("span", { className: "t-team-sched-rowCron" }, item.cron), /* @__PURE__ */ import_react4.default.createElement("span", { className: "t-team-sched-rowMeta" }, rowMeta(item)), isWorkspaceMissing(item) && // 任务绑的工作区在 registry 查不到:执行路径会按 task.workspacePath 自动
21952
- // mkdir + create 兜底,面板这里只挂一行轻量提示——不要按钮、不要输入框,
21953
- // 不替用户做决定,恢复就是自动的。
21954
- /* @__PURE__ */ import_react4.default.createElement("small", { className: "t-team-sched-rowNote" }, typeof item.workspacePath === "string" && item.workspacePath !== "" ? t("sched.workspaceAutoRecoverHint", { path: item.workspacePath }) : t("sched.workspaceMissingHintNoPath")), item.runs?.length > 0 && /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement(
21955
- "button",
21956
- {
21957
- type: "button",
21958
- className: "t-team-sched-runsToggle",
21959
- "aria-expanded": historyId === item.id,
21960
- onClick: () => setHistoryId(historyId === item.id ? null : item.id)
21961
- },
21962
- t("sched.runHistory", { count: item.runs?.length ?? 0 })
21963
- ), historyId === item.id && /* @__PURE__ */ import_react4.default.createElement("ul", { className: "t-team-sched-runs" }, [...item.runs ?? []].reverse().map((run, index) => /* @__PURE__ */ import_react4.default.createElement("li", { key: index, className: "t-team-sched-run" }, /* @__PURE__ */ import_react4.default.createElement("span", null, new Date(run.at).toLocaleString()), run.ok === true ? /* @__PURE__ */ import_react4.default.createElement("span", null, t("sched.runOk")) : /* @__PURE__ */ import_react4.default.createElement("span", { className: "t-team-sched-runFail" }, t("sched.runFail"), ": ", run.error ?? ""), run.sessionId !== void 0 && /* @__PURE__ */ import_react4.default.createElement("span", { className: "t-team-sched-runSession" }, run.sessionId)))))), /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-sched-rowActions" }, /* @__PURE__ */ import_react4.default.createElement(
21964
- "button",
21965
- {
21966
- type: "button",
21967
- className: "t-team-sched-btn",
21968
- disabled: disabled || runningId === item.id || (snapshot?.running ?? []).includes(item.id),
21969
- onClick: () => void runItem(item.id)
21970
- },
21971
- runningId === item.id || (snapshot?.running ?? []).includes(item.id) ? t("sched.running") : t("sched.runNow")
21972
- ), /* @__PURE__ */ import_react4.default.createElement(
21973
- "button",
21974
- {
21975
- type: "button",
21976
- className: "t-team-sched-btn",
21977
- disabled,
21978
- onClick: () => setForm({
21979
- editingId: item.id,
21980
- title: item.title,
21981
- prompt: item.prompt,
21982
- cron: item.cron,
21983
- enabled: item.enabled === true,
21984
- workspaceId: item.workspaceId ?? "",
21985
- customDir: "",
21986
- // 编辑时把记录的目录带进来:跟 workspaceId 一对,没手动改过就不会丢。
21987
- workspacePath: item.workspacePath ?? ""
21988
- })
21989
- },
21990
- t("sched.edit")
21991
- ), /* @__PURE__ */ import_react4.default.createElement("button", { type: "button", className: confirmingId === item.id ? "t-team-sched-btn t-team-sched-btn-danger" : "t-team-sched-btn t-team-sched-btn-danger", disabled, onClick: () => void removeItem(item.id) }, confirmingId === item.id ? t("sched.deleteConfirm") : t("sched.delete")))))), form === null ? /* @__PURE__ */ import_react4.default.createElement("button", { type: "button", className: "t-team-sched-btn t-team-sched-btn-primary", disabled, onClick: () => void openNewForm() }, t("sched.new")) : /* @__PURE__ */ import_react4.default.createElement(
21992
- "form",
21993
- {
21994
- className: "t-team-sched-form",
21995
- onSubmit: (event) => {
21996
- event.preventDefault();
21997
- void submitForm();
21998
- }
21999
- },
22000
- /* @__PURE__ */ import_react4.default.createElement("h3", { className: "t-team-sched-formTitle" }, form.editingId === null ? t("sched.new") : t("sched.edit")),
22001
- /* @__PURE__ */ import_react4.default.createElement("label", { className: "t-team-sched-field" }, /* @__PURE__ */ import_react4.default.createElement("span", null, t("sched.titleLabel")), /* @__PURE__ */ import_react4.default.createElement(
22002
- "input",
22003
- {
22004
- value: form.title,
22005
- disabled: busy,
22006
- placeholder: t("sched.titlePlaceholder"),
22007
- onChange: (event) => setForm({ ...form, title: event.target.value })
22008
- }
22009
- )),
22010
- /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-sched-field" }, /* @__PURE__ */ import_react4.default.createElement("span", null, t("sched.promptLabel")), /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-sched-promptbox" }, /* @__PURE__ */ import_react4.default.createElement(
22011
- PromptEditor,
22012
- {
22013
- editorRef: promptEditorRef,
22014
- t,
22015
- active,
22016
- experts,
22017
- value: form.prompt,
22018
- disabled: busy,
22019
- onChange: (prompt) => setForm((current) => current === null ? current : { ...current, prompt })
22020
- }
22021
- )), /* @__PURE__ */ import_react4.default.createElement(
22022
- ExpertPicker,
22023
- {
22024
- t,
22025
- active,
22026
- experts,
22027
- disabled: busy,
22028
- selected: mentioned,
22029
- onPick: fillExpert
22030
- }
22031
- ), mentioned.length > 0 && /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-expert-pick-hint" }, mentioned.length === 1 ? t("sched.expertInvokeHint", { name: mentioned[0] }) : t("sched.expertInvokeManyHint", { names: mentioned.join(t("sched.listSep")) }))),
22032
- /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-sched-field" }, /* @__PURE__ */ import_react4.default.createElement("span", null, t("sched.cronLabel")), /* @__PURE__ */ import_react4.default.createElement(CronPicker, { t, remote, value: form.cron, disabled: busy, onChange: (cron) => setForm((current) => current === null ? current : { ...current, cron }) }), /* @__PURE__ */ import_react4.default.createElement("small", { className: "t-team-sched-hint" }, t("sched.cronHint"))),
22033
- /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-sched-field" }, /* @__PURE__ */ import_react4.default.createElement("span", null, t("sched.workspace")), /* @__PURE__ */ import_react4.default.createElement(
22034
- "select",
22035
- {
22036
- value: form.workspaceId,
22037
- disabled: busy,
22038
- onChange: (event) => setForm({ ...form, workspaceId: event.target.value })
22039
- },
22040
- /* @__PURE__ */ import_react4.default.createElement("option", { value: "" }, t("sched.workspaceNone")),
22041
- allWorkspaces.map((workspace) => /* @__PURE__ */ import_react4.default.createElement("option", { key: workspace.id, value: workspace.id }, workspace.title)),
22042
- form.workspaceId !== "" && form.workspaceId !== CUSTOM_WORKSPACE && !allWorkspaces.some((workspace) => workspace.id === form.workspaceId) && /* @__PURE__ */ import_react4.default.createElement("option", { value: form.workspaceId }, form.workspaceId),
22043
- /* @__PURE__ */ import_react4.default.createElement("option", { value: CUSTOM_WORKSPACE }, t("sched.workspaceCustom"))
22044
- ), form.workspaceId === CUSTOM_WORKSPACE ? /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement(
22045
- "input",
22046
- {
22047
- value: form.customDir,
22048
- disabled: busy,
22049
- placeholder: t("sched.workspaceCustomPlaceholder"),
22050
- onChange: (event) => setForm({ ...form, customDir: event.target.value })
22051
- }
22052
- ), /* @__PURE__ */ import_react4.default.createElement("small", { className: "t-team-sched-hint" }, t("sched.workspaceCustomHint"))) : /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement("small", { className: "t-team-sched-hint" }, t("sched.workspaceHint")), selectedWorkspacePath !== "" && /* @__PURE__ */ import_react4.default.createElement("small", { className: "t-team-sched-hint" }, t("sched.workspacePath", { path: selectedWorkspacePath })))),
22053
- /* @__PURE__ */ import_react4.default.createElement("label", { className: "t-team-sched-checkbox" }, /* @__PURE__ */ import_react4.default.createElement(
22054
- "input",
22055
- {
22056
- type: "checkbox",
22057
- checked: form.enabled,
22058
- disabled: busy,
22059
- onChange: (event) => setForm({ ...form, enabled: event.target.checked })
22060
- }
22061
- ), /* @__PURE__ */ import_react4.default.createElement("span", null, t("sched.enabledLabel")), /* @__PURE__ */ import_react4.default.createElement("small", { className: "t-team-sched-hint" }, t("sched.enabledHint"))),
22062
- /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-sched-formActions" }, /* @__PURE__ */ import_react4.default.createElement("button", { type: "submit", className: "t-team-sched-btn t-team-sched-btn-primary", disabled: busy }, busy ? t("sched.saving") : t("sched.save")), /* @__PURE__ */ import_react4.default.createElement("button", { type: "button", className: "t-team-sched-btn", disabled: busy, onClick: () => setForm(null) }, t("sched.cancel")))
22063
- ), /* @__PURE__ */ import_react4.default.createElement("p", { className: "t-team-sched-tip" }, t("sched.tip")), snapshot !== null && snapshot.file !== "" && /* @__PURE__ */ import_react4.default.createElement("p", { className: "t-team-sched-file" }, t("sched.file", { path: snapshot.file }))));
22064
- }
22065
- function ScheduleGlyph({ size = 16 }) {
22066
- return /* @__PURE__ */ import_react4.default.createElement(
22067
- "svg",
22068
- {
22069
- className: "t-team-schedule-glyph",
22070
- width: size,
22071
- height: size,
22072
- viewBox: "0 0 16 16",
22073
- fill: "none",
22074
- stroke: "currentColor",
22075
- strokeWidth: "1.4",
22076
- strokeLinecap: "round",
22077
- strokeLinejoin: "round",
22078
- "aria-hidden": "true",
22079
- focusable: "false"
22080
- },
22081
- /* @__PURE__ */ import_react4.default.createElement("rect", { x: "2.2", y: "3.4", width: "11.6", height: "10.4", rx: "2.4" }),
22082
- /* @__PURE__ */ import_react4.default.createElement("path", { d: "M2.2 6.6h11.6" }),
22083
- /* @__PURE__ */ import_react4.default.createElement("path", { d: "M5.6 2.2v2.4M10.4 2.2v2.4" }),
22084
- /* @__PURE__ */ import_react4.default.createElement("path", { d: "M6.1 9.7l1.3 1.3 2.5-2.7" })
22085
- );
22086
- }
22087
-
22088
20909
  // src/client/settings.jsx
22089
- var import_react6 = __toESM(require("react"), 1);
20910
+ var import_react5 = __toESM(require("react"), 1);
22090
20911
 
22091
20912
  // src/client/tabs.jsx
22092
- var import_react5 = __toESM(require("react"), 1);
20913
+ var import_react4 = __toESM(require("react"), 1);
22093
20914
  function CategoriesTab({ t, remote, categories, onChanged }) {
22094
- const [key, setKey] = import_react5.default.useState("");
22095
- const [label, setLabel] = import_react5.default.useState("");
22096
- const [editing, setEditing] = import_react5.default.useState(null);
22097
- const [pendingDelete, setPendingDelete] = import_react5.default.useState("");
22098
- const [error62, setError] = import_react5.default.useState("");
22099
- const [busy, setBusy] = import_react5.default.useState(false);
20915
+ const [key, setKey] = import_react4.default.useState("");
20916
+ const [label, setLabel] = import_react4.default.useState("");
20917
+ const [editing, setEditing] = import_react4.default.useState(null);
20918
+ const [pendingDelete, setPendingDelete] = import_react4.default.useState("");
20919
+ const [error62, setError] = import_react4.default.useState("");
20920
+ const [busy, setBusy] = import_react4.default.useState(false);
22100
20921
  const list = categories ?? [];
22101
20922
  const mine = list.filter((item) => !item.official);
22102
20923
  const official = list.filter((item) => item.official);
@@ -22116,7 +20937,7 @@ function CategoriesTab({ t, remote, categories, onChanged }) {
22116
20937
  setBusy(false);
22117
20938
  }
22118
20939
  }
22119
- const row = (item) => /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-cat-row", key: item.key }, /* @__PURE__ */ import_react5.default.createElement("span", { className: "t-team-cat-name", title: item.label }, item.label), /* @__PURE__ */ import_react5.default.createElement("span", { className: "t-team-badge", "data-tone": item.official ? void 0 : "custom" }, item.official ? t("cat.officialBadge") : t("cat.customBadge")), /* @__PURE__ */ import_react5.default.createElement("span", { className: "t-team-cat-key", title: item.key }, item.key), /* @__PURE__ */ import_react5.default.createElement("span", { className: "t-team-cat-count" }, t("cat.count", { count: item.count, custom: item.customCount })), !item.official && /* @__PURE__ */ import_react5.default.createElement("span", { className: "t-team-cat-actions" }, editing !== null && editing.key === item.key ? /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement(
20940
+ const row = (item) => /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-cat-row", key: item.key }, /* @__PURE__ */ import_react4.default.createElement("span", { className: "t-team-cat-name", title: item.label }, item.label), /* @__PURE__ */ import_react4.default.createElement("span", { className: "t-team-badge", "data-tone": item.official ? void 0 : "custom" }, item.official ? t("cat.officialBadge") : t("cat.customBadge")), /* @__PURE__ */ import_react4.default.createElement("span", { className: "t-team-cat-key", title: item.key }, item.key), /* @__PURE__ */ import_react4.default.createElement("span", { className: "t-team-cat-count" }, t("cat.count", { count: item.count, custom: item.customCount })), !item.official && /* @__PURE__ */ import_react4.default.createElement("span", { className: "t-team-cat-actions" }, editing !== null && editing.key === item.key ? /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement(
22120
20941
  "input",
22121
20942
  {
22122
20943
  className: "t-team-input",
@@ -22124,7 +20945,7 @@ function CategoriesTab({ t, remote, categories, onChanged }) {
22124
20945
  placeholder: t("cat.label"),
22125
20946
  onChange: (event) => setEditing({ key: item.key, label: event.target.value })
22126
20947
  }
22127
- ), /* @__PURE__ */ import_react5.default.createElement(
20948
+ ), /* @__PURE__ */ import_react4.default.createElement(
22128
20949
  "button",
22129
20950
  {
22130
20951
  className: "t-team-chip",
@@ -22133,7 +20954,7 @@ function CategoriesTab({ t, remote, categories, onChanged }) {
22133
20954
  onClick: () => void run(() => remote.updateCategory(item.key, editing.label.trim()))
22134
20955
  },
22135
20956
  t("cat.save")
22136
- ), /* @__PURE__ */ import_react5.default.createElement("button", { className: "t-team-chip", type: "button", disabled: busy, onClick: () => setEditing(null) }, t("custom.cancel"))) : /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement(
20957
+ ), /* @__PURE__ */ import_react4.default.createElement("button", { className: "t-team-chip", type: "button", disabled: busy, onClick: () => setEditing(null) }, t("custom.cancel"))) : /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement(
22137
20958
  "button",
22138
20959
  {
22139
20960
  className: "t-team-chip",
@@ -22142,7 +20963,7 @@ function CategoriesTab({ t, remote, categories, onChanged }) {
22142
20963
  onClick: () => setEditing({ key: item.key, label: item.label })
22143
20964
  },
22144
20965
  t("cat.rename")
22145
- ), pendingDelete === item.key ? /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement(
20966
+ ), pendingDelete === item.key ? /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement(
22146
20967
  "button",
22147
20968
  {
22148
20969
  className: "t-team-chip",
@@ -22152,8 +20973,8 @@ function CategoriesTab({ t, remote, categories, onChanged }) {
22152
20973
  onClick: () => void run(() => remote.deleteCategory(item.key))
22153
20974
  },
22154
20975
  t("cat.confirmDelete")
22155
- ), /* @__PURE__ */ import_react5.default.createElement("button", { className: "t-team-chip", type: "button", disabled: busy, onClick: () => setPendingDelete("") }, t("custom.cancel"))) : /* @__PURE__ */ import_react5.default.createElement("button", { className: "t-team-chip", type: "button", disabled: busy, onClick: () => setPendingDelete(item.key) }, t("cat.delete")))));
22156
- return /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-tabbody" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-note" }, t("cat.hint")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-bar" }, /* @__PURE__ */ import_react5.default.createElement(
20976
+ ), /* @__PURE__ */ import_react4.default.createElement("button", { className: "t-team-chip", type: "button", disabled: busy, onClick: () => setPendingDelete("") }, t("custom.cancel"))) : /* @__PURE__ */ import_react4.default.createElement("button", { className: "t-team-chip", type: "button", disabled: busy, onClick: () => setPendingDelete(item.key) }, t("cat.delete")))));
20977
+ return /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-tabbody" }, /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-note" }, t("cat.hint")), /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-bar" }, /* @__PURE__ */ import_react4.default.createElement(
22157
20978
  "input",
22158
20979
  {
22159
20980
  className: "t-team-input",
@@ -22162,7 +20983,7 @@ function CategoriesTab({ t, remote, categories, onChanged }) {
22162
20983
  value: key,
22163
20984
  onChange: (event) => setKey(event.target.value)
22164
20985
  }
22165
- ), /* @__PURE__ */ import_react5.default.createElement(
20986
+ ), /* @__PURE__ */ import_react4.default.createElement(
22166
20987
  "input",
22167
20988
  {
22168
20989
  className: "t-team-input",
@@ -22170,7 +20991,7 @@ function CategoriesTab({ t, remote, categories, onChanged }) {
22170
20991
  value: label,
22171
20992
  onChange: (event) => setLabel(event.target.value)
22172
20993
  }
22173
- ), /* @__PURE__ */ import_react5.default.createElement(
20994
+ ), /* @__PURE__ */ import_react4.default.createElement(
22174
20995
  "button",
22175
20996
  {
22176
20997
  className: "t-team-chip",
@@ -22180,22 +21001,22 @@ function CategoriesTab({ t, remote, categories, onChanged }) {
22180
21001
  onClick: () => void run(() => remote.createCategory(key.trim(), label.trim()))
22181
21002
  },
22182
21003
  t("cat.create")
22183
- )), error62 !== "" && /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-error" }, error62), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-section-head" }, t("cat.mine")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-cat-list" }, mine.length === 0 ? /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-cat-empty" }, t("cat.empty")) : mine.map(row)), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-section-head" }, t("cat.official")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-meta" }, t("cat.officialNote")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-cat-list", "data-scroll": "true" }, official.map(row)));
21004
+ )), error62 !== "" && /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-error" }, error62), /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-section-head" }, t("cat.mine")), /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-cat-list" }, mine.length === 0 ? /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-cat-empty" }, t("cat.empty")) : mine.map(row)), /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-section-head" }, t("cat.official")), /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-meta" }, t("cat.officialNote")), /* @__PURE__ */ import_react4.default.createElement("div", { className: "t-team-cat-list", "data-scroll": "true" }, official.map(row)));
22184
21005
  }
22185
21006
 
22186
21007
  // src/client/settings.jsx
22187
21008
  function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22188
- const [snapshot, setSnapshot] = import_react6.default.useState(() => snapshotOf(remote) ?? null);
22189
- const [query, setQuery] = import_react6.default.useState("");
22190
- const [division, setDivision] = import_react6.default.useState("");
22191
- const [status, setStatus] = import_react6.default.useState("");
22192
- const [error62, setError] = import_react6.default.useState("");
22193
- const [busy, setBusy] = import_react6.default.useState(false);
22194
- const [promptView, setPromptView] = import_react6.default.useState(null);
22195
- const [editor, setEditor] = import_react6.default.useState(null);
22196
- const [pendingDelete, setPendingDelete] = import_react6.default.useState("");
22197
- const [tab, setTab] = import_react6.default.useState(initialTab ?? "experts");
22198
- const reload = import_react6.default.useCallback(async (force) => {
21009
+ const [snapshot, setSnapshot] = import_react5.default.useState(() => snapshotOf(remote) ?? null);
21010
+ const [query, setQuery] = import_react5.default.useState("");
21011
+ const [division, setDivision] = import_react5.default.useState("");
21012
+ const [status, setStatus] = import_react5.default.useState("");
21013
+ const [error62, setError] = import_react5.default.useState("");
21014
+ const [busy, setBusy] = import_react5.default.useState(false);
21015
+ const [promptView, setPromptView] = import_react5.default.useState(null);
21016
+ const [editor, setEditor] = import_react5.default.useState(null);
21017
+ const [pendingDelete, setPendingDelete] = import_react5.default.useState("");
21018
+ const [tab, setTab] = import_react5.default.useState(initialTab ?? "experts");
21019
+ const reload = import_react5.default.useCallback(async (force) => {
22199
21020
  try {
22200
21021
  const next = await refresh(remote, force);
22201
21022
  setSnapshot({ ...next });
@@ -22206,7 +21027,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22206
21027
  return void 0;
22207
21028
  }
22208
21029
  }, [remote]);
22209
- import_react6.default.useEffect(() => {
21030
+ import_react5.default.useEffect(() => {
22210
21031
  let alive = true;
22211
21032
  (async () => {
22212
21033
  const next = await reload(false);
@@ -22231,7 +21052,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22231
21052
  });
22232
21053
  }
22233
21054
  }
22234
- import_react6.default.useEffect(() => {
21055
+ import_react5.default.useEffect(() => {
22235
21056
  if (promptView === null) return void 0;
22236
21057
  const onKey = (event) => {
22237
21058
  if (event.key === "Escape") setPromptView(null);
@@ -22387,25 +21208,23 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22387
21208
  setBusy(false);
22388
21209
  }
22389
21210
  }
22390
- const [showScheduleButton, setShowScheduleButtonState] = import_react6.default.useState(true);
22391
- const [showActivePulse, setShowActivePulseState] = import_react6.default.useState(true);
22392
- const [uiPrefsError, setUiPrefsError] = import_react6.default.useState("");
22393
- const [uiPrefsWriteError, setUiPrefsWriteError] = import_react6.default.useState("");
22394
- const uiPrefQueue = import_react6.default.useRef(Promise.resolve());
22395
- import_react6.default.useEffect(() => {
21211
+ const [showActivePulse, setShowActivePulseState] = import_react5.default.useState(true);
21212
+ const [uiPrefsError, setUiPrefsError] = import_react5.default.useState("");
21213
+ const [uiPrefsWriteError, setUiPrefsWriteError] = import_react5.default.useState("");
21214
+ const uiPrefQueue = import_react5.default.useRef(Promise.resolve());
21215
+ import_react5.default.useEffect(() => {
22396
21216
  let alive = true;
22397
21217
  void (async () => {
22398
21218
  try {
22399
21219
  const data = unwrap(await remote.getUiPrefs(), "getUiPrefs");
22400
21220
  if (!alive) return;
22401
- if (typeof data?.showScheduleButton !== "boolean" || typeof data?.showActivePulse !== "boolean") {
21221
+ if (typeof data?.showActivePulse !== "boolean") {
22402
21222
  setUiPrefsError(t("settings.uiPrefsUnreadable"));
22403
21223
  return;
22404
21224
  }
22405
21225
  setUiPrefsError("");
22406
- setShowScheduleButtonState(data.showScheduleButton);
22407
21226
  setShowActivePulseState(data.showActivePulse);
22408
- setUiPrefs({ showScheduleButton: data.showScheduleButton, showActivePulse: data.showActivePulse });
21227
+ setUiPrefs({ showActivePulse: data.showActivePulse });
22409
21228
  } catch (cause) {
22410
21229
  console.error("[t-team] \u754C\u9762\u504F\u597D\u8BFB\u53D6\u5931\u8D25\uFF0C\u6682\u6309\u9ED8\u8BA4\u503C\u5904\u7406\uFF1A", cause);
22411
21230
  if (alive) setUiPrefsError(cause instanceof Error ? cause.message : String(cause));
@@ -22416,7 +21235,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22416
21235
  };
22417
21236
  }, [remote]);
22418
21237
  if (snapshot === null) {
22419
- return /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-settings" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-title" }, t("settings.title")), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-meta" }, t("settings.loading")), error62 !== "" && /* @__PURE__ */ import_react6.default.createElement(import_react6.default.Fragment, null, /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-error" }, t("settings.loadFailed", { detail: error62 })), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-row" }, /* @__PURE__ */ import_react6.default.createElement("button", { className: "t-team-chip", type: "button", onClick: () => void reload(true) }, t("settings.retry")))));
21238
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-settings" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-title" }, t("settings.title")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-meta" }, t("settings.loading")), error62 !== "" && /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-error" }, t("settings.loadFailed", { detail: error62 })), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-row" }, /* @__PURE__ */ import_react5.default.createElement("button", { className: "t-team-chip", type: "button", onClick: () => void reload(true) }, t("settings.retry")))));
22420
21239
  }
22421
21240
  async function writeUiPref(patch, rollback) {
22422
21241
  setUiPrefs(patch);
@@ -22424,12 +21243,10 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22424
21243
  try {
22425
21244
  const next = unwrap(await remote.setUiPrefs(patch), "setUiPrefs");
22426
21245
  setUiPrefs(next);
22427
- setShowScheduleButtonState(next.showScheduleButton);
22428
21246
  setShowActivePulseState(next.showActivePulse);
22429
21247
  setUiPrefsWriteError("");
22430
21248
  } catch (cause) {
22431
21249
  setUiPrefs(rollback);
22432
- setShowScheduleButtonState(rollback.showScheduleButton ?? showScheduleButton);
22433
21250
  setShowActivePulseState(rollback.showActivePulse ?? showActivePulse);
22434
21251
  setUiPrefsWriteError(cause instanceof Error ? cause.message : String(cause));
22435
21252
  }
@@ -22438,27 +21255,12 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22438
21255
  });
22439
21256
  await run;
22440
21257
  }
22441
- async function setShowScheduleButton(next) {
22442
- setShowScheduleButtonState(next);
22443
- await writeUiPref({ showScheduleButton: next }, { showScheduleButton: !next });
22444
- }
22445
21258
  async function setShowActivePulse(next) {
22446
21259
  setShowActivePulseState(next);
22447
21260
  await writeUiPref({ showActivePulse: next }, { showActivePulse: !next });
22448
21261
  }
22449
21262
  const enabledCount = snapshot.enabled.length;
22450
- return /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-settings" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-head" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-title" }, t("settings.title")), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-meta" }, t("settings.enabledCount", { enabled: enabledCount, total: experts.length }), " \xB7 v", CLIENT_BUILD_VERSION)), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-setting-row" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-setting-head" }, /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-setting-name" }, t("settings.showScheduleButton")), /* @__PURE__ */ import_react6.default.createElement(
22451
- "button",
22452
- {
22453
- className: "t-team-switch",
22454
- type: "button",
22455
- role: "switch",
22456
- "aria-checked": showScheduleButton,
22457
- "data-on": showScheduleButton,
22458
- onClick: () => void setShowScheduleButton(!showScheduleButton)
22459
- },
22460
- /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-switch-knob" })
22461
- )), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-setting-hint" }, t("settings.showScheduleButtonHint")), uiPrefsError !== "" && /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-error" }, t("settings.uiPrefsUnreadable"), "\uFF1A", uiPrefsError), uiPrefsWriteError !== "" && /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-error" }, t("settings.uiPrefsWriteFailed"), "\uFF1A", uiPrefsWriteError)), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-setting-row" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-setting-head" }, /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-setting-name" }, t("settings.showActivePulse")), /* @__PURE__ */ import_react6.default.createElement(
21263
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-settings" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-head" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-title" }, t("settings.title")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-meta" }, t("settings.enabledCount", { enabled: enabledCount, total: experts.length }), " \xB7 v", CLIENT_BUILD_VERSION)), (uiPrefsError !== "" || uiPrefsWriteError !== "") && /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-setting-row" }, uiPrefsError !== "" && /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-error" }, t("settings.uiPrefsUnreadable"), "\uFF1A", uiPrefsError), uiPrefsWriteError !== "" && /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-error" }, t("settings.uiPrefsWriteFailed"), "\uFF1A", uiPrefsWriteError)), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-setting-row" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-setting-head" }, /* @__PURE__ */ import_react5.default.createElement("span", { className: "t-team-setting-name" }, t("settings.showActivePulse")), /* @__PURE__ */ import_react5.default.createElement(
22462
21264
  "button",
22463
21265
  {
22464
21266
  className: "t-team-switch",
@@ -22468,8 +21270,8 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22468
21270
  "data-on": showActivePulse,
22469
21271
  onClick: () => void setShowActivePulse(!showActivePulse)
22470
21272
  },
22471
- /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-switch-knob" })
22472
- )), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-setting-hint" }, t("settings.showActivePulseHint"))), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-tabs", role: "tablist" }, [["experts", "tab.experts"], ["categories", "tab.categories"]].map(([key, label]) => /* @__PURE__ */ import_react6.default.createElement(
21273
+ /* @__PURE__ */ import_react5.default.createElement("span", { className: "t-team-switch-knob" })
21274
+ )), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-setting-hint" }, t("settings.showActivePulseHint"))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-tabs", role: "tablist" }, [["experts", "tab.experts"], ["categories", "tab.categories"]].map(([key, label]) => /* @__PURE__ */ import_react5.default.createElement(
22473
21275
  "button",
22474
21276
  {
22475
21277
  className: "t-team-tab",
@@ -22481,7 +21283,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22481
21283
  onClick: () => setTab(key)
22482
21284
  },
22483
21285
  t(label)
22484
- ))), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-tabbody", hidden: tab !== "categories" }, /* @__PURE__ */ import_react6.default.createElement(SectionBoundary, { t, reloadKey: tab }, /* @__PURE__ */ import_react6.default.createElement(CategoriesTab, { t, remote, categories, onChanged: () => reload(true) }))), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-tabbody", hidden: tab !== "experts" }, /* @__PURE__ */ import_react6.default.createElement(SectionBoundary, { t, reloadKey: tab }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-note" }, t("roster.expertsHint")), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-bar" }, /* @__PURE__ */ import_react6.default.createElement(
21286
+ ))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-tabbody", hidden: tab !== "categories" }, /* @__PURE__ */ import_react5.default.createElement(SectionBoundary, { t, reloadKey: tab }, /* @__PURE__ */ import_react5.default.createElement(CategoriesTab, { t, remote, categories, onChanged: () => reload(true) }))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-tabbody", hidden: tab !== "experts" }, /* @__PURE__ */ import_react5.default.createElement(SectionBoundary, { t, reloadKey: tab }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-note" }, t("roster.expertsHint")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-bar" }, /* @__PURE__ */ import_react5.default.createElement(
22485
21287
  "input",
22486
21288
  {
22487
21289
  className: "t-team-input",
@@ -22489,7 +21291,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22489
21291
  value: query,
22490
21292
  onChange: (event) => setQuery(event.target.value)
22491
21293
  }
22492
- ), /* @__PURE__ */ import_react6.default.createElement(
21294
+ ), /* @__PURE__ */ import_react5.default.createElement(
22493
21295
  "select",
22494
21296
  {
22495
21297
  className: "t-team-select",
@@ -22498,12 +21300,12 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22498
21300
  value: division,
22499
21301
  onChange: (event) => setDivision(event.target.value)
22500
21302
  },
22501
- /* @__PURE__ */ import_react6.default.createElement("option", { value: "" }, t("filter.allDivisions")),
21303
+ /* @__PURE__ */ import_react5.default.createElement("option", { value: "" }, t("filter.allDivisions")),
22502
21304
  divisions.map((item) => {
22503
21305
  const count = experts.filter((expert) => expert.division === item).length;
22504
- return /* @__PURE__ */ import_react6.default.createElement("option", { key: item, value: item }, `${labelOf(item)} (${count})`);
21306
+ return /* @__PURE__ */ import_react5.default.createElement("option", { key: item, value: item }, `${labelOf(item)} (${count})`);
22505
21307
  })
22506
- ), filtered && /* @__PURE__ */ import_react6.default.createElement(
21308
+ ), filtered && /* @__PURE__ */ import_react5.default.createElement(
22507
21309
  "button",
22508
21310
  {
22509
21311
  className: "t-team-chip",
@@ -22515,9 +21317,9 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22515
21317
  }
22516
21318
  },
22517
21319
  t("filter.clear")
22518
- ), /* @__PURE__ */ import_react6.default.createElement("button", { className: "t-team-chip", type: "button", onClick: openEditorNew }, t("custom.new"))), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-meta" }, t("filter.summary", { shown: visible.length, total: experts.length, enabled: enabledSet.size })), error62 !== "" && /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-error" }, error62 === "CONFLICT" ? t("settings.conflictRetry") : t("settings.saveFailed", { detail: error62 })), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-groups" }, grouped.map((group) => /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-group", key: group.division }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-division" }, divisionLabel(group.items[0], active), " \xB7 ", group.items.length), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-grid" }, group.items.map((expert) => {
21320
+ ), /* @__PURE__ */ import_react5.default.createElement("button", { className: "t-team-chip", type: "button", onClick: openEditorNew }, t("custom.new"))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-meta" }, t("filter.summary", { shown: visible.length, total: experts.length, enabled: enabledSet.size })), error62 !== "" && /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-error" }, error62 === "CONFLICT" ? t("settings.conflictRetry") : t("settings.saveFailed", { detail: error62 })), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-groups" }, grouped.map((group) => /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-group", key: group.division }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-division" }, divisionLabel(group.items[0], active), " \xB7 ", group.items.length), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-grid" }, group.items.map((expert) => {
22519
21321
  const on = enabledSet.has(expert.slug);
22520
- return /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-card", "data-enabled": on, key: expert.slug }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-card-body" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-avatar" }, expert.emoji || "\u{1F9E9}"), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-identity" }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-card-name" }, displayName(expert, active), expert.custom === true && /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-badge-custom" }, t("custom.badge"))), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-card-division" }, divisionLabel(expert, active)), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-card-slug" }, expert.slug)), /* @__PURE__ */ import_react6.default.createElement("p", { className: "t-team-card-desc" }, displayDescription(expert, active)), expert.conflict === true && /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-conflict", style: { gridColumn: "1/-1" } }, t("settings.conflict"))), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-card-tools" }, /* @__PURE__ */ import_react6.default.createElement(
21322
+ return /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-card", "data-enabled": on, key: expert.slug }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-card-body" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-avatar" }, expert.emoji || "\u{1F9E9}"), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-identity" }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-card-name" }, displayName(expert, active), expert.custom === true && /* @__PURE__ */ import_react5.default.createElement("span", { className: "t-team-badge-custom" }, t("custom.badge"))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-card-division" }, divisionLabel(expert, active)), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-card-slug" }, expert.slug)), /* @__PURE__ */ import_react5.default.createElement("p", { className: "t-team-card-desc" }, displayDescription(expert, active)), expert.conflict === true && /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-conflict", style: { gridColumn: "1/-1" } }, t("settings.conflict"))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-card-tools" }, /* @__PURE__ */ import_react5.default.createElement(
22521
21323
  "button",
22522
21324
  {
22523
21325
  className: "t-team-icon-btn",
@@ -22527,7 +21329,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22527
21329
  onClick: () => void openPrompt(expert)
22528
21330
  },
22529
21331
  "\u{1F4C4}"
22530
- ), expert.custom === true && /* @__PURE__ */ import_react6.default.createElement(
21332
+ ), expert.custom === true && /* @__PURE__ */ import_react5.default.createElement(
22531
21333
  "button",
22532
21334
  {
22533
21335
  className: "t-team-icon-btn",
@@ -22537,7 +21339,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22537
21339
  onClick: () => void openEditorEdit(expert)
22538
21340
  },
22539
21341
  "\u270F\uFE0F"
22540
- ), expert.custom === true && (pendingDelete === expert.slug ? /* @__PURE__ */ import_react6.default.createElement(
21342
+ ), expert.custom === true && (pendingDelete === expert.slug ? /* @__PURE__ */ import_react5.default.createElement(
22541
21343
  "button",
22542
21344
  {
22543
21345
  className: "t-team-chip t-team-danger",
@@ -22546,7 +21348,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22546
21348
  onClick: () => void removeExpert(expert)
22547
21349
  },
22548
21350
  t("custom.confirmDelete")
22549
- ) : /* @__PURE__ */ import_react6.default.createElement(
21351
+ ) : /* @__PURE__ */ import_react5.default.createElement(
22550
21352
  "button",
22551
21353
  {
22552
21354
  className: "t-team-icon-btn",
@@ -22557,7 +21359,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22557
21359
  },
22558
21360
  "\u{1F5D1}"
22559
21361
  ))));
22560
- })))), visible.length === 0 && /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-meta" }, t("settings.empty"))))), promptView !== null && /* @__PURE__ */ import_react6.default.createElement(
21362
+ })))), visible.length === 0 && /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-meta" }, t("settings.empty"))))), promptView !== null && /* @__PURE__ */ import_react5.default.createElement(
22561
21363
  "div",
22562
21364
  {
22563
21365
  className: "t-team-mask",
@@ -22565,8 +21367,8 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22565
21367
  if (event.target === event.currentTarget) setPromptView(null);
22566
21368
  }
22567
21369
  },
22568
- /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-modal", role: "dialog", "aria-modal": "true", "aria-label": t("card.promptTitle", { name: promptView.name }) }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-modal-head" }, /* @__PURE__ */ import_react6.default.createElement("span", null, t("card.promptTitle", { name: promptView.name })), /* @__PURE__ */ import_react6.default.createElement("button", { className: "t-team-chip", type: "button", onClick: () => setPromptView(null) }, t("card.close"))), /* @__PURE__ */ import_react6.default.createElement("pre", { className: "t-team-modal-body" }, promptView.loading ? t("card.promptLoading") : promptView.error !== "" ? t("card.promptFailed", { detail: promptView.error }) : promptView.text === "" ? t("card.promptEmpty") : promptView.text))
22569
- ), editor !== null && /* @__PURE__ */ import_react6.default.createElement(
21370
+ /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-modal", role: "dialog", "aria-modal": "true", "aria-label": t("card.promptTitle", { name: promptView.name }) }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-modal-head" }, /* @__PURE__ */ import_react5.default.createElement("span", null, t("card.promptTitle", { name: promptView.name })), /* @__PURE__ */ import_react5.default.createElement("button", { className: "t-team-chip", type: "button", onClick: () => setPromptView(null) }, t("card.close"))), /* @__PURE__ */ import_react5.default.createElement("pre", { className: "t-team-modal-body" }, promptView.loading ? t("card.promptLoading") : promptView.error !== "" ? t("card.promptFailed", { detail: promptView.error }) : promptView.text === "" ? t("card.promptEmpty") : promptView.text))
21371
+ ), editor !== null && /* @__PURE__ */ import_react5.default.createElement(
22570
21372
  "div",
22571
21373
  {
22572
21374
  className: "t-team-mask",
@@ -22574,7 +21376,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22574
21376
  if (event.target === event.currentTarget && !editor.saving) setEditor(null);
22575
21377
  }
22576
21378
  },
22577
- /* @__PURE__ */ import_react6.default.createElement(
21379
+ /* @__PURE__ */ import_react5.default.createElement(
22578
21380
  "div",
22579
21381
  {
22580
21382
  className: "t-team-modal",
@@ -22582,8 +21384,8 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22582
21384
  "aria-modal": "true",
22583
21385
  "aria-label": editor.mode === "new" ? t("custom.titleNew") : t("custom.titleEdit", { name: editor.name || editor.slug })
22584
21386
  },
22585
- /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-modal-head" }, /* @__PURE__ */ import_react6.default.createElement("span", null, editor.mode === "new" ? t("custom.titleNew") : t("custom.titleEdit", { name: editor.name || editor.slug })), /* @__PURE__ */ import_react6.default.createElement("button", { className: "t-team-chip", type: "button", disabled: editor.saving, onClick: () => setEditor(null) }, t("custom.cancel"))),
22586
- /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-editor", style: { padding: 14, overflow: "auto" } }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-note" }, t("custom.hint")), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-field" }, /* @__PURE__ */ import_react6.default.createElement("span", null, t("custom.division")), /* @__PURE__ */ import_react6.default.createElement(
21387
+ /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-modal-head" }, /* @__PURE__ */ import_react5.default.createElement("span", null, editor.mode === "new" ? t("custom.titleNew") : t("custom.titleEdit", { name: editor.name || editor.slug })), /* @__PURE__ */ import_react5.default.createElement("button", { className: "t-team-chip", type: "button", disabled: editor.saving, onClick: () => setEditor(null) }, t("custom.cancel"))),
21388
+ /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-editor", style: { padding: 14, overflow: "auto" } }, /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-note" }, t("custom.hint")), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-field" }, /* @__PURE__ */ import_react5.default.createElement("span", null, t("custom.division")), /* @__PURE__ */ import_react5.default.createElement(
22587
21389
  "select",
22588
21390
  {
22589
21391
  className: "t-team-select",
@@ -22594,9 +21396,9 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22594
21396
  else patchEditor({ divisionNew: false, division: value });
22595
21397
  }
22596
21398
  },
22597
- editorDivisionOptions.map((item) => /* @__PURE__ */ import_react6.default.createElement("option", { key: item.key, value: item.key }, `${item.label} \xB7 ${item.key}`)),
22598
- /* @__PURE__ */ import_react6.default.createElement("option", { value: NEW_DIVISION }, t("custom.divisionNew"))
22599
- ), editor.divisionNew && /* @__PURE__ */ import_react6.default.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 6 } }, /* @__PURE__ */ import_react6.default.createElement(
21399
+ editorDivisionOptions.map((item) => /* @__PURE__ */ import_react5.default.createElement("option", { key: item.key, value: item.key }, `${item.label} \xB7 ${item.key}`)),
21400
+ /* @__PURE__ */ import_react5.default.createElement("option", { value: NEW_DIVISION }, t("custom.divisionNew"))
21401
+ ), editor.divisionNew && /* @__PURE__ */ import_react5.default.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 6 } }, /* @__PURE__ */ import_react5.default.createElement(
22600
21402
  "input",
22601
21403
  {
22602
21404
  className: "t-team-input",
@@ -22605,7 +21407,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22605
21407
  value: editor.divisionKey,
22606
21408
  onChange: (event) => patchEditor({ divisionKey: event.target.value })
22607
21409
  }
22608
- ), /* @__PURE__ */ import_react6.default.createElement(
21410
+ ), /* @__PURE__ */ import_react5.default.createElement(
22609
21411
  "input",
22610
21412
  {
22611
21413
  className: "t-team-input",
@@ -22613,7 +21415,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22613
21415
  value: editor.divisionLabel,
22614
21416
  onChange: (event) => patchEditor({ divisionLabel: event.target.value })
22615
21417
  }
22616
- ))), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-field" }, /* @__PURE__ */ import_react6.default.createElement("span", null, t("custom.slug")), /* @__PURE__ */ import_react6.default.createElement(
21418
+ ))), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-field" }, /* @__PURE__ */ import_react5.default.createElement("span", null, t("custom.slug")), /* @__PURE__ */ import_react5.default.createElement(
22617
21419
  "input",
22618
21420
  {
22619
21421
  className: "t-team-input",
@@ -22622,7 +21424,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22622
21424
  spellCheck: false,
22623
21425
  onChange: (event) => patchEditor({ slug: event.target.value })
22624
21426
  }
22625
- )), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-field" }, /* @__PURE__ */ import_react6.default.createElement("span", null, t("custom.name")), /* @__PURE__ */ import_react6.default.createElement("input", { className: "t-team-input", value: editor.name, onChange: (event) => patchEditor({ name: event.target.value }) })), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-field" }, /* @__PURE__ */ import_react6.default.createElement("span", null, t("custom.nameEn")), /* @__PURE__ */ import_react6.default.createElement("input", { className: "t-team-input", value: editor.nameEn, onChange: (event) => patchEditor({ nameEn: event.target.value }) })), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-field" }, /* @__PURE__ */ import_react6.default.createElement("span", null, t("custom.emoji")), /* @__PURE__ */ import_react6.default.createElement("input", { className: "t-team-input", maxLength: 8, value: editor.emoji, onChange: (event) => patchEditor({ emoji: event.target.value }) })), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-field" }, /* @__PURE__ */ import_react6.default.createElement("span", null, t("custom.description")), /* @__PURE__ */ import_react6.default.createElement("input", { className: "t-team-input", value: editor.description, onChange: (event) => patchEditor({ description: event.target.value }) })), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-field" }, /* @__PURE__ */ import_react6.default.createElement("span", null, t("custom.body")), /* @__PURE__ */ import_react6.default.createElement(
21427
+ )), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-field" }, /* @__PURE__ */ import_react5.default.createElement("span", null, t("custom.name")), /* @__PURE__ */ import_react5.default.createElement("input", { className: "t-team-input", value: editor.name, onChange: (event) => patchEditor({ name: event.target.value }) })), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-field" }, /* @__PURE__ */ import_react5.default.createElement("span", null, t("custom.nameEn")), /* @__PURE__ */ import_react5.default.createElement("input", { className: "t-team-input", value: editor.nameEn, onChange: (event) => patchEditor({ nameEn: event.target.value }) })), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-field" }, /* @__PURE__ */ import_react5.default.createElement("span", null, t("custom.emoji")), /* @__PURE__ */ import_react5.default.createElement("input", { className: "t-team-input", maxLength: 8, value: editor.emoji, onChange: (event) => patchEditor({ emoji: event.target.value }) })), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-field" }, /* @__PURE__ */ import_react5.default.createElement("span", null, t("custom.description")), /* @__PURE__ */ import_react5.default.createElement("input", { className: "t-team-input", value: editor.description, onChange: (event) => patchEditor({ description: event.target.value }) })), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-field" }, /* @__PURE__ */ import_react5.default.createElement("span", null, t("custom.body")), /* @__PURE__ */ import_react5.default.createElement(
22626
21428
  "textarea",
22627
21429
  {
22628
21430
  className: "t-team-input",
@@ -22630,7 +21432,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22630
21432
  disabled: editor.loading,
22631
21433
  onChange: (event) => patchEditor({ body: event.target.value })
22632
21434
  }
22633
- )), editor.loading && /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-meta" }, t("custom.loadingBody")), editor.error !== "" && /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-error" }, editor.error), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-editor-actions" }, /* @__PURE__ */ import_react6.default.createElement("button", { className: "t-team-chip", type: "button", disabled: editor.saving, onClick: () => setEditor(null) }, t("custom.cancel")), /* @__PURE__ */ import_react6.default.createElement(
21435
+ )), editor.loading && /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-meta" }, t("custom.loadingBody")), editor.error !== "" && /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-error" }, editor.error), /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-editor-actions" }, /* @__PURE__ */ import_react5.default.createElement("button", { className: "t-team-chip", type: "button", disabled: editor.saving, onClick: () => setEditor(null) }, t("custom.cancel")), /* @__PURE__ */ import_react5.default.createElement(
22634
21436
  "button",
22635
21437
  {
22636
21438
  className: "t-team-chip",
@@ -22646,14 +21448,14 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22646
21448
  }
22647
21449
 
22648
21450
  // src/client/summon.jsx
22649
- var import_react7 = __toESM(require("react"), 1);
21451
+ var import_react6 = __toESM(require("react"), 1);
22650
21452
  function SummonButton({ t, ctx, remote, getActive, insertReference, insertSkillHint: insertSkillHint2, sessionId, preview, rootRemote }) {
22651
- const [open2, setOpen] = import_react7.default.useState(preview?.open === true);
22652
- const [popTab, setPopTab] = import_react7.default.useState(preview?.tab ?? "experts");
22653
- const [skills, setSkills] = import_react7.default.useState(null);
22654
- const [skillQuery, setSkillQuery] = import_react7.default.useState("");
22655
- const [skillsDiag, setSkillsDiag] = import_react7.default.useState("");
22656
- import_react7.default.useEffect(() => {
21453
+ const [open2, setOpen] = import_react6.default.useState(preview?.open === true);
21454
+ const [popTab, setPopTab] = import_react6.default.useState(preview?.tab ?? "experts");
21455
+ const [skills, setSkills] = import_react6.default.useState(null);
21456
+ const [skillQuery, setSkillQuery] = import_react6.default.useState("");
21457
+ const [skillsDiag, setSkillsDiag] = import_react6.default.useState("");
21458
+ import_react6.default.useEffect(() => {
22657
21459
  if (!open2) return void 0;
22658
21460
  const cached2 = skillsCache.get(sessionId);
22659
21461
  if (cached2 !== void 0) setSkills(cached2);
@@ -22701,12 +21503,12 @@ function SummonButton({ t, ctx, remote, getActive, insertReference, insertSkillH
22701
21503
  alive = false;
22702
21504
  };
22703
21505
  }, [open2, sessionId, rootRemote]);
22704
- const [popNote, setPopNote] = import_react7.default.useState("");
22705
- const [query, setQuery] = import_react7.default.useState("");
22706
- const [failed, setFailed] = import_react7.default.useState("");
22707
- const [position, setPosition] = import_react7.default.useState(void 0);
22708
- const rootRef = import_react7.default.useRef(null);
22709
- const popRef = import_react7.default.useRef(null);
21506
+ const [popNote, setPopNote] = import_react6.default.useState("");
21507
+ const [query, setQuery] = import_react6.default.useState("");
21508
+ const [failed, setFailed] = import_react6.default.useState("");
21509
+ const [position, setPosition] = import_react6.default.useState(void 0);
21510
+ const rootRef = import_react6.default.useRef(null);
21511
+ const popRef = import_react6.default.useRef(null);
22710
21512
  const snap = snapshotOf(remote);
22711
21513
  function anchorInput() {
22712
21514
  let node2 = rootRef.current?.parentElement ?? null;
@@ -22733,13 +21535,30 @@ function SummonButton({ t, ctx, remote, getActive, insertReference, insertSkillH
22733
21535
  const laidOut = measured > 0 ? measured : width;
22734
21536
  const maxLeft = laidOut === 0 ? Number.POSITIVE_INFINITY : Math.max(8, window.innerWidth - laidOut - 8);
22735
21537
  const wantedLeft = hasInput ? inputRect.left : rect.left;
22736
- setPosition({
21538
+ const refTop = hasInput ? inputRect.top : rect.top;
21539
+ const refBottom = hasInput ? inputRect.bottom : rect.bottom;
21540
+ const EDGE = 8;
21541
+ const OFFSET = 6;
21542
+ const IDEAL = 600;
21543
+ const cap = Math.max(0, Math.min(IDEAL, window.innerHeight - EDGE * 2));
21544
+ const spaceAbove = refTop - EDGE;
21545
+ const spaceBelow = window.innerHeight - refBottom - EDGE;
21546
+ const up = spaceAbove >= spaceBelow;
21547
+ const maxHeight = Math.max(0, Math.min(cap, up ? spaceAbove : spaceBelow));
21548
+ const pos = {
22737
21549
  left: Math.min(Math.max(8, wantedLeft), maxLeft),
22738
- bottom: Math.max(8, window.innerHeight - (hasInput ? inputRect.top : rect.top) + 6),
22739
21550
  "--t-team-pop-w": width > 0 ? `${width}px` : void 0
22740
- });
21551
+ };
21552
+ if (up) {
21553
+ pos.bottom = Math.max(EDGE, window.innerHeight - refTop + OFFSET);
21554
+ pos.maxHeight = `${maxHeight}px`;
21555
+ } else {
21556
+ pos.top = Math.max(EDGE, refBottom + OFFSET);
21557
+ pos.maxHeight = `${maxHeight}px`;
21558
+ }
21559
+ setPosition(pos);
22741
21560
  }
22742
- import_react7.default.useEffect(() => {
21561
+ import_react6.default.useEffect(() => {
22743
21562
  if (!open2) return void 0;
22744
21563
  const onDown = (event) => {
22745
21564
  if (rootRef.current !== null && !rootRef.current.contains(event.target)) setOpen(false);
@@ -22808,7 +21627,7 @@ function SummonButton({ t, ctx, remote, getActive, insertReference, insertSkillH
22808
21627
  setFailed(t("button.insertFailed"));
22809
21628
  }
22810
21629
  }
22811
- return /* @__PURE__ */ import_react7.default.createElement("span", { ref: rootRef, className: "t-team-btn-wrap" }, /* @__PURE__ */ import_react7.default.createElement("button", { className: "t-team-btn", type: "button", title: t("button.title"), onClick: () => void toggle() }, "\u{1F9E9} ", t("button.label")), open2 && /* @__PURE__ */ import_react7.default.createElement("div", { className: "t-team-pop", "data-tab": popTab, ref: popRef, style: position }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "t-team-pop-head" }, /* @__PURE__ */ import_react7.default.createElement("span", null, t("pop.title")), /* @__PURE__ */ import_react7.default.createElement("button", { className: "t-team-chip", type: "button", onClick: () => setOpen(false) }, t("button.close"))), /* @__PURE__ */ import_react7.default.createElement("div", { className: "t-team-tabs", role: "tablist" }, popTabs.map(([key, label]) => /* @__PURE__ */ import_react7.default.createElement(
21630
+ return /* @__PURE__ */ import_react6.default.createElement("span", { ref: rootRef, className: "t-team-btn-wrap" }, /* @__PURE__ */ import_react6.default.createElement("button", { className: "t-team-btn", type: "button", title: t("button.title"), onClick: () => void toggle() }, "\u{1F9E9} ", t("button.label")), open2 && /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-pop", "data-tab": popTab, ref: popRef, style: position }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-pop-head" }, /* @__PURE__ */ import_react6.default.createElement("span", null, t("pop.title")), /* @__PURE__ */ import_react6.default.createElement("button", { className: "t-team-chip", type: "button", onClick: () => setOpen(false) }, t("button.close"))), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-tabs", role: "tablist" }, popTabs.map(([key, label]) => /* @__PURE__ */ import_react6.default.createElement(
22812
21631
  "button",
22813
21632
  {
22814
21633
  className: "t-team-tab",
@@ -22823,8 +21642,8 @@ function SummonButton({ t, ctx, remote, getActive, insertReference, insertSkillH
22823
21642
  }
22824
21643
  },
22825
21644
  t(label),
22826
- tabCounts[key] === void 0 ? null : /* @__PURE__ */ import_react7.default.createElement("span", { className: "t-team-tab-count" }, t("tab.count", { count: tabCounts[key] }))
22827
- ))), popNote !== "" && /* @__PURE__ */ import_react7.default.createElement("div", { className: "t-team-ok" }, popNote), failed !== "" && /* @__PURE__ */ import_react7.default.createElement("div", { className: "t-team-error" }, failed), popTab === "experts" && /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, null, /* @__PURE__ */ import_react7.default.createElement(
21645
+ tabCounts[key] === void 0 ? null : /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-tab-count" }, t("tab.count", { count: tabCounts[key] }))
21646
+ ))), popNote !== "" && /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-ok" }, popNote), failed !== "" && /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-error" }, failed), popTab === "experts" && /* @__PURE__ */ import_react6.default.createElement(import_react6.default.Fragment, null, /* @__PURE__ */ import_react6.default.createElement(
22828
21647
  "input",
22829
21648
  {
22830
21649
  className: "t-team-input",
@@ -22833,10 +21652,10 @@ function SummonButton({ t, ctx, remote, getActive, insertReference, insertSkillH
22833
21652
  value: query,
22834
21653
  onChange: (event) => setQuery(event.target.value)
22835
21654
  }
22836
- ), /* @__PURE__ */ import_react7.default.createElement("div", { className: "t-team-pop-list" }, grouped.map((group) => /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, { key: group.division }, /* @__PURE__ */ import_react7.default.createElement("div", { className: "t-team-division" }, divisionLabel(group.items[0], active)), group.items.map((expert) => {
21655
+ ), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-pop-list" }, grouped.map((group) => /* @__PURE__ */ import_react6.default.createElement(import_react6.default.Fragment, { key: group.division }, /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-division" }, divisionLabel(group.items[0], active)), group.items.map((expert) => {
22837
21656
  const alt = active === "en" ? expert.name : expert.nameEn;
22838
- return /* @__PURE__ */ import_react7.default.createElement("button", { className: "t-team-pop-item", type: "button", key: expert.slug, onClick: () => pick2(expert) }, /* @__PURE__ */ import_react7.default.createElement("span", { className: "t-team-pop-head" }, /* @__PURE__ */ import_react7.default.createElement("span", { className: "t-team-pop-avatar" }, expert.emoji || "\u{1F9E9}"), /* @__PURE__ */ import_react7.default.createElement("span", { className: "t-team-pop-title" }, /* @__PURE__ */ import_react7.default.createElement("span", { className: "t-team-pop-name" }, displayName(expert, active)), alt !== void 0 && alt !== "" && /* @__PURE__ */ import_react7.default.createElement("span", { className: "t-team-pop-sub" }, alt))), /* @__PURE__ */ import_react7.default.createElement("span", { className: "t-team-pop-desc" }, displayDescription(expert, active)));
22839
- }))), experts.length === 0 && /* @__PURE__ */ import_react7.default.createElement("div", { className: "t-team-pop-empty" }, t("button.empty")), experts.length > 0 && visible.length === 0 && /* @__PURE__ */ import_react7.default.createElement("div", { className: "t-team-pop-empty" }, t("button.noMatch")))), popTab === "skills" && /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, null, /* @__PURE__ */ import_react7.default.createElement(
21657
+ return /* @__PURE__ */ import_react6.default.createElement("button", { className: "t-team-pop-item", type: "button", key: expert.slug, onClick: () => pick2(expert) }, /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-head" }, /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-avatar" }, expert.emoji || "\u{1F9E9}"), /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-title" }, /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-name" }, displayName(expert, active)), alt !== void 0 && alt !== "" && /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-sub" }, alt))), /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-desc" }, displayDescription(expert, active)));
21658
+ }))), experts.length === 0 && /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-pop-empty" }, t("button.empty")), experts.length > 0 && visible.length === 0 && /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-pop-empty" }, t("button.noMatch")))), popTab === "skills" && /* @__PURE__ */ import_react6.default.createElement(import_react6.default.Fragment, null, /* @__PURE__ */ import_react6.default.createElement(
22840
21659
  "input",
22841
21660
  {
22842
21661
  className: "t-team-input",
@@ -22845,7 +21664,7 @@ function SummonButton({ t, ctx, remote, getActive, insertReference, insertSkillH
22845
21664
  value: skillQuery,
22846
21665
  onChange: (event) => setSkillQuery(event.target.value)
22847
21666
  }
22848
- ), /* @__PURE__ */ import_react7.default.createElement("div", { className: "t-team-pop-list" }, visibleSkills.map((skill) => /* @__PURE__ */ import_react7.default.createElement("button", { className: "t-team-pop-item", type: "button", key: skill.name, onClick: () => pickSkill(skill) }, /* @__PURE__ */ import_react7.default.createElement("span", { className: "t-team-pop-head" }, /* @__PURE__ */ import_react7.default.createElement("span", { className: "t-team-pop-avatar" }, "\u{1F9F0}"), /* @__PURE__ */ import_react7.default.createElement("span", { className: "t-team-pop-title" }, /* @__PURE__ */ import_react7.default.createElement("span", { className: "t-team-pop-name" }, skill.name), skill.modelInvocable === false && /* @__PURE__ */ import_react7.default.createElement("span", { className: "t-team-pop-sub" }, t("pop.skillUserOnly")))), /* @__PURE__ */ import_react7.default.createElement("span", { className: "t-team-pop-desc" }, skill.description ?? ""))), visibleSkills.length === 0 && /* @__PURE__ */ import_react7.default.createElement("div", { className: "t-team-pop-empty" }, skills === null ? t("pop.skillEmpty") : t("pop.skillNoMatch")), skillsDiag !== "" && /* @__PURE__ */ import_react7.default.createElement("div", { className: "t-team-error", style: { fontSize: "11px", whiteSpace: "pre-wrap" } }, "\u8BCA\u65AD\uFF1A", skillsDiag)))));
21667
+ ), /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-pop-list" }, visibleSkills.map((skill) => /* @__PURE__ */ import_react6.default.createElement("button", { className: "t-team-pop-item", type: "button", key: skill.name, onClick: () => pickSkill(skill) }, /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-head" }, /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-avatar" }, "\u{1F9F0}"), /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-title" }, /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-name" }, skill.name), skill.modelInvocable === false && /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-sub" }, t("pop.skillUserOnly")))), /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-pop-desc" }, skill.description ?? ""))), visibleSkills.length === 0 && /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-pop-empty" }, skills === null ? t("pop.skillEmpty") : t("pop.skillNoMatch")), skillsDiag !== "" && /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-error", style: { fontSize: "11px", whiteSpace: "pre-wrap" } }, "\u8BCA\u65AD\uFF1A", skillsDiag)))));
22849
21668
  }
22850
21669
 
22851
21670
  // src/client/index.jsx
@@ -22912,61 +21731,14 @@ async function apply(ctx) {
22912
21731
  label: () => ctx.locale.bind(NS)("settings.title"),
22913
21732
  locale: NS,
22914
21733
  icon: "expert"
22915
- }, (props) => import_react8.default.createElement(SettingsPanel, { ...props, t: ctx.locale.bind(NS), remote, getActive })));
22916
- ctx.slots.inject("sidebar.panellist", () => {
22917
- let disposeEntry;
22918
- const sync = () => {
22919
- const want = scheduleEntryVisible();
22920
- if (want === (disposeEntry !== void 0)) return;
22921
- if (!want) {
22922
- disposeEntry?.();
22923
- disposeEntry = void 0;
22924
- return;
22925
- }
22926
- try {
22927
- disposeEntry = ctx.slots.register({
22928
- name: "sidebar.panellist",
22929
- id: SCHEDULE_PANEL_KEY,
22930
- // order 取最小:侧栏那一组里它排在最前,紧贴「新会话」按钮。
22931
- order: 1,
22932
- label: () => ctx.locale.bind(NS)("sched.nav"),
22933
- locale: NS
22934
- }, (props) => import_react8.default.createElement(ScheduleGlyph, { size: props?.size ?? 16 }));
22935
- } catch (cause) {
22936
- console.warn("[t-team] \u4FA7\u680F\u5B9A\u65F6\u4EFB\u52A1\u5165\u53E3\u6CE8\u518C\u5931\u8D25\uFF1A", cause);
22937
- disposeEntry = void 0;
22938
- }
22939
- };
22940
- const unsubscribe = subscribeUiPrefs(sync);
22941
- sync();
22942
- return () => {
22943
- unsubscribe();
22944
- disposeEntry?.();
22945
- disposeEntry = void 0;
22946
- };
22947
- });
22948
- ctx.slots.inject("main", () => ctx.slots.register({
22949
- name: "main",
22950
- key: SCHEDULE_PANEL_KEY,
22951
- locale: NS
22952
- }, (props) => import_react8.default.createElement(
22953
- SectionBoundary,
22954
- { t: ctx.locale.bind(NS), reloadKey: "schedule" },
22955
- import_react8.default.createElement(SchedulePanel, {
22956
- ...props,
22957
- t: ctx.locale.bind(NS),
22958
- remote,
22959
- getActive,
22960
- ctx: props?.ctx ?? ctx
22961
- })
22962
- )));
21734
+ }, (props) => import_react7.default.createElement(SettingsPanel, { ...props, t: ctx.locale.bind(NS), remote, getActive })));
22963
21735
  ctx.slots.inject("conversation.session.header.utilities", () => ctx.slots.register({
22964
21736
  name: "conversation.session.header.utilities",
22965
21737
  id: `${NS}-pulse`,
22966
21738
  order: 1,
22967
21739
  label: () => ctx.locale.bind(NS)("pulse.on"),
22968
21740
  locale: NS
22969
- }, (props) => import_react8.default.createElement(ActivePulse, {
21741
+ }, (props) => import_react7.default.createElement(ActivePulse, {
22970
21742
  ...props,
22971
21743
  t: ctx.locale.bind(NS),
22972
21744
  ctx: props?.ctx ?? ctx,
@@ -22985,7 +21757,7 @@ async function apply(ctx) {
22985
21757
  insertSkillHint: (text) => insertSkillHint(target(), text)
22986
21758
  };
22987
21759
  }
22988
- }, (props) => import_react8.default.createElement(SummonButton, { ...props, t: ctx.locale.bind(NS), remote, getActive, rootRemote: ctx.remote })));
21760
+ }, (props) => import_react7.default.createElement(SummonButton, { ...props, t: ctx.locale.bind(NS), remote, getActive, rootRemote: ctx.remote })));
22989
21761
  const registerSources = (active, divisions) => {
22990
21762
  const disposers = [];
22991
21763
  try {