dsh-plugin-t-expert 0.3.90 → 0.3.91

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.91";
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();
@@ -721,9 +666,12 @@ var CSS = `
721
666
  .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
667
  \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
668
  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)}
669
+ .5px + border-l1\uFF08\u6D45\u8272\u4E0B alpha 10% \u2192 4%\uFF09\uFF0C\u8FB9\u6846\u4E0D\u518D\u62A2\u773C\u3002
670
+ \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
671
+ 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
672
+ \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
673
+ Retina \u4E0A .5px \u6B63\u597D\u662F\u4E00\u4E2A\u7269\u7406\u50CF\u7D20\uFF1B\u5BBF\u4E3B\u81EA\u5DF1\u7684\u6309\u94AE\u4E5F\u7528 .5px\u3002 */
674
+ .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
675
  /* \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
676
  \u9760 flex \u5BB9\u5668\u9ED8\u8BA4\u7684 align-items:stretch \u81EA\u52A8\u6491\u6EE1\u51CF\u6389 margin \u540E\u7684\u5BBD\u5EA6\u3002 */
729
677
  .t-team-pop .t-team-input{flex:0 0 auto;min-width:0}
@@ -782,100 +730,108 @@ var CSS = `
782
730
  .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
731
  .t-team-pop-empty{font-size:12px;color:var(--dsw-alias-label-tertiary);padding:6px 2px}
784
732
  .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))}
733
+ /* \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
734
+ \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
735
+ \u7167\u6284\uFF0C\u514D\u5F97\u5404\u5904\u6309\u94AE\u4E0E\u8F93\u5165\u6846\u7684\u7126\u70B9\u6837\u5F0F\u5404\u5199\u5404\u7684\u3002 */
736
+ /* \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
737
+ 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 */
738
+ /* \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
739
+ * 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
740
+ * \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
741
+ * .t-XoWW_pageScroll\uFF08flex:1 + overflow:auto + scrollbar-gutter:stable\uFF09\u5957 .t-XoWW_pageContent
742
+ * \uFF08max-width + margin auto\uFF09\u3002scrollbar-gutter:stable \u8BA9\u6709/\u65E0\u6EDA\u52A8\u6761\u65F6\u5185\u5BB9\u4E0D\u5DE6\u53F3\u8DF3\uFF1B
743
+ * 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
744
+ * \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
745
+ * \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 */
746
+ /* \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
747
+ * **\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
748
+ * \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
749
+ * \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
750
+ * \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
751
+ * \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 */
752
+ /* \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
753
+ \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
754
+ \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 */
755
+ /* \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 */
756
+ /* \u6807\u9898\u884C\uFF1A\u4E0E\u5B98\u65B9 .t-XoWW_pageHeading \u540C\u6B3E\uFF08padding-top 28 / margin-bottom 24 / gap 16\uFF09\u3002
757
+ \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 */
758
+ /* \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 */
759
+ /* \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 */
760
+ /* \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
761
+ 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 */
762
+ /* \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
763
+ \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 */
764
+ /* \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
765
+ * \u8FDE\u95F4\u8DDD\u7684**\u6765\u6E90**\u4E5F\u7167\u6284\uFF1Afilters{margin-bottom:14px}\u3001searchField{margin:0 0 16px}\u3002 */
766
+ /* \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
767
+ * \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
768
+ * \u7531\u56FE\u6807\u76D2\u81EA\u5DF1\u7684 margin-right \u7ED9\uFF09\u3001margin 0 0 16px\u3002 */
769
+ /* \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
770
+ \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 */
771
+ /* \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**
772
+ * \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 */
773
+ /* \u6E05\u7A7A\u6309\u94AE\uFF1A\u5B98\u65B9 .t-XoWW_searchClear \u662F 28\xD728\u3001\u53F3\u79FB 6px\uFF08\u56FE\u6807 14px\uFF09\u3002 */
774
+ /* \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
775
+ * \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
776
+ * instruction / zoneSearch / confirmDialog \u56DB\u5904\u90FD**\u663E\u5F0F**\u8865\u4E86 border-box\uFF0C\u6B63\u8BF4\u660E\u9ED8\u8BA4\u662F content-box\uFF09\u3002
777
+ * \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
778
+ * \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 */
779
+ /* \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
780
+ \u52A0\u4E86\u4F1A\u8BA9\u56FE\u6807\u76F8\u5BF9\u884C\u6807\u9898\u7684\u5782\u76F4\u4F4D\u7F6E\u5DEE 1~2px\u3002 */
781
+ /* \u884C\u6807\u9898\u524D\u7684\u72B6\u6001\u56FE\u6807\uFF0814px\uFF0C\u4E0E 23px \u884C\u9AD8\u7684\u6587\u5B57\u5BF9\u9F50\uFF09\uFF1A
782
+ \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
783
+ \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 */
784
+ /* \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 */
785
+ /* ---- \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 ----
786
+ * \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
787
+ * \uFF08left:15.75px \u662F\u56FE\u6807\u4E2D\u5FC3\uFF1A\u884C margin -8 + padding 8 \u2192 \u56FE\u6807\u4E2D\u5FC3 16\uFF09\u3002 */
788
+ /* \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
789
+ \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 */
790
+ /* \u5931\u8D25\u539F\u56E0\u5355\u72EC\u4E00\u884C\uFF08\u522B\u628A"\u65F6\u95F4 + \u72B6\u6001"\u90A3\u4E00\u884C\u6491\u957F\uFF09\u3002 */
791
+ /* \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 */
792
+ /* \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 */
793
+ /* \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 */
794
+ /* \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 */
795
+ /* \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
796
+ * \u80CC\u666F\u8D70 --dsw-alias-button-primary-fill\u3001\u6587\u5B57\u8D70 --dsw-alias-label-primary-foreground\uFF08\u4E0D\u662F\u6211\u4EEC\u81EA\u5DF1
797
+ * \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 */
798
+ /* \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
799
+ \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 */
800
+ /* 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 */
801
+ /* \u8FD0\u884C\u65F6\u95F4\u5361\u7247\uFF1A\u5EA6\u91CF\u7167\u6284\u5B98\u65B9 .t-XoWW_ruleRows / ruleRow / ruleLabel / ruleValue / ruleInput \u2014\u2014
802
+ * .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
803
+ * \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 */
804
+ /* \u53D6\u503C\u9762\uFF08\u5B98\u65B9 ruleValue / ruleValueFace / pickerTrigger / pickerIcon \u7684\u5F62\u6001\uFF09\uFF1A\u4E00\u884C\u53F3\u4FA7\u662F
805
+ * \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
806
+ * \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 */
807
+ /* \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
808
+ * \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 */
809
+ /* \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 */
810
+ /* \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
811
+ * \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
812
+ * \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 */
813
+ /* \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
814
+ * \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
815
  /* \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
816
  * \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
817
  /* \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
818
  /* \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}
819
+ * \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
820
+ * \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 */
821
+ /* \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 */
822
+ /* \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 */
823
+ @media (width<=1100px){
824
+ .t-team-sched-detailForm{--detail-gutter:20px}
825
+ }
826
+ @media (width<=760px){
827
+ .t-team-sched-listPane[data-detail="true"]{display:none}
828
+ .t-team-sched-detailForm{flex-basis:100%;border-left:0}
829
+ .t-team-sched-detailScroll{padding-top:20px}
830
+ }
831
+ @media (width<=400px){
832
+ .t-team-sched-detailForm{--detail-gutter:16px}
833
+ .t-team-sched-detailTabsBar{gap:16px}
834
+ }
879
835
  /* \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
836
  .t-team-expert-pick{position:relative;display:flex;align-items:center;gap:8px;margin-top:2px}
881
837
  .t-team-expert-pick-hint{font-size:12px;color:var(--dsw-alias-label-secondary)}
@@ -993,97 +949,11 @@ var zh = {
993
949
  "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
950
  "custom.badge": "\u81EA\u5EFA",
995
951
  "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",
952
+ "pop.title": "T\u4E13\u5BB6"
953
+ // 列表过滤与搜索(与官方「自动化任务」页同一套:标签行 + 搜索框)
954
+ // 三档:全部 / 已启用 / 已停用 —— 停用 ≠ 删除(停用的任务保留数据、只是不触发)。
955
+ // 运行时间卡片(对齐官方详情页的「运行时间」:重复 / 时间 / 星期 三行)
1053
956
  // 周几:键必须**逐行**写、并且在代码里以字面量引用(字典无人引用自检会盯着这一点)。
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
957
  };
1088
958
  var en = {
1089
959
  "settings.title": "T Expert",
@@ -1185,96 +1055,10 @@ var en = {
1185
1055
  "custom.deleteHint": "Delete \u201C{name}\u201D? Only this custom expert file is removed; this cannot be undone.",
1186
1056
  "custom.badge": "Custom",
1187
1057
  "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}"
1058
+ "pop.title": "T Expert"
1059
+ // List filter and search (same shape as the built-in Automation page: tab row + search field).
1060
+ // Three lanes: All / Active / Disabled — disabled keeps its data and simply never fires.
1061
+ // Run-time card (mirrors the built-in page's "Run time": repeat / time / weekday rows)
1278
1062
  };
1279
1063
 
1280
1064
  // src/client/insert.js
@@ -21051,64 +20835,13 @@ var enabledStateSchema = external_exports.object({
21051
20835
  revision: external_exports.number().int().min(0)
21052
20836
  });
21053
20837
  var uiPrefsSchema = external_exports.object({
21054
- showScheduleButton: external_exports.boolean(),
21055
20838
  // 窗口右上角「活跃指示」是否显示。宿主**总是**返回布尔(缺省按 true 算),所以这里必填。
21056
20839
  showActivePulse: external_exports.boolean()
21057
20840
  });
21058
20841
  var uiPrefsPatchSchema = external_exports.object({
21059
- showScheduleButton: external_exports.boolean().optional(),
21060
20842
  showActivePulse: external_exports.boolean().optional()
21061
20843
  });
21062
20844
  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
20845
 
21113
20846
  // src/client/remote.js
21114
20847
  function direct(method, parameters, typeSymbol, schema) {
@@ -21140,27 +20873,6 @@ var TYPERT_REMOTE = {
21140
20873
  direct("setUiPrefs", [
21141
20874
  { name: "patch", wire: "patch", source: "json", codec: { mode: "strict", typeSymbol: "TTeamUiPrefsPatch", schema: uiPrefsPatchSchema, create: () => uiPrefsPatchSchema } }
21142
20875
  ], "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
20876
  direct("createExpert", [
21165
20877
  { name: "expert", wire: "expert", source: "json", codec: { mode: "strict", typeSymbol: "TTeamCustomExpertInput", schema: customExpertInputSchema, create: () => customExpertInputSchema } }
21166
20878
  ], "TTeamCatalog", catalogSnapshotSchema),
@@ -21187,916 +20899,18 @@ var TYPERT_REMOTE = {
21187
20899
  ]
21188
20900
  };
21189
20901
 
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
20902
  // src/client/settings.jsx
22089
- var import_react6 = __toESM(require("react"), 1);
20903
+ var import_react5 = __toESM(require("react"), 1);
22090
20904
 
22091
20905
  // src/client/tabs.jsx
22092
- var import_react5 = __toESM(require("react"), 1);
20906
+ var import_react4 = __toESM(require("react"), 1);
22093
20907
  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);
20908
+ const [key, setKey] = import_react4.default.useState("");
20909
+ const [label, setLabel] = import_react4.default.useState("");
20910
+ const [editing, setEditing] = import_react4.default.useState(null);
20911
+ const [pendingDelete, setPendingDelete] = import_react4.default.useState("");
20912
+ const [error62, setError] = import_react4.default.useState("");
20913
+ const [busy, setBusy] = import_react4.default.useState(false);
22100
20914
  const list = categories ?? [];
22101
20915
  const mine = list.filter((item) => !item.official);
22102
20916
  const official = list.filter((item) => item.official);
@@ -22116,7 +20930,7 @@ function CategoriesTab({ t, remote, categories, onChanged }) {
22116
20930
  setBusy(false);
22117
20931
  }
22118
20932
  }
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(
20933
+ 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
20934
  "input",
22121
20935
  {
22122
20936
  className: "t-team-input",
@@ -22124,7 +20938,7 @@ function CategoriesTab({ t, remote, categories, onChanged }) {
22124
20938
  placeholder: t("cat.label"),
22125
20939
  onChange: (event) => setEditing({ key: item.key, label: event.target.value })
22126
20940
  }
22127
- ), /* @__PURE__ */ import_react5.default.createElement(
20941
+ ), /* @__PURE__ */ import_react4.default.createElement(
22128
20942
  "button",
22129
20943
  {
22130
20944
  className: "t-team-chip",
@@ -22133,7 +20947,7 @@ function CategoriesTab({ t, remote, categories, onChanged }) {
22133
20947
  onClick: () => void run(() => remote.updateCategory(item.key, editing.label.trim()))
22134
20948
  },
22135
20949
  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(
20950
+ ), /* @__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
20951
  "button",
22138
20952
  {
22139
20953
  className: "t-team-chip",
@@ -22142,7 +20956,7 @@ function CategoriesTab({ t, remote, categories, onChanged }) {
22142
20956
  onClick: () => setEditing({ key: item.key, label: item.label })
22143
20957
  },
22144
20958
  t("cat.rename")
22145
- ), pendingDelete === item.key ? /* @__PURE__ */ import_react5.default.createElement(import_react5.default.Fragment, null, /* @__PURE__ */ import_react5.default.createElement(
20959
+ ), pendingDelete === item.key ? /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement(
22146
20960
  "button",
22147
20961
  {
22148
20962
  className: "t-team-chip",
@@ -22152,8 +20966,8 @@ function CategoriesTab({ t, remote, categories, onChanged }) {
22152
20966
  onClick: () => void run(() => remote.deleteCategory(item.key))
22153
20967
  },
22154
20968
  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(
20969
+ ), /* @__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")))));
20970
+ 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
20971
  "input",
22158
20972
  {
22159
20973
  className: "t-team-input",
@@ -22162,7 +20976,7 @@ function CategoriesTab({ t, remote, categories, onChanged }) {
22162
20976
  value: key,
22163
20977
  onChange: (event) => setKey(event.target.value)
22164
20978
  }
22165
- ), /* @__PURE__ */ import_react5.default.createElement(
20979
+ ), /* @__PURE__ */ import_react4.default.createElement(
22166
20980
  "input",
22167
20981
  {
22168
20982
  className: "t-team-input",
@@ -22170,7 +20984,7 @@ function CategoriesTab({ t, remote, categories, onChanged }) {
22170
20984
  value: label,
22171
20985
  onChange: (event) => setLabel(event.target.value)
22172
20986
  }
22173
- ), /* @__PURE__ */ import_react5.default.createElement(
20987
+ ), /* @__PURE__ */ import_react4.default.createElement(
22174
20988
  "button",
22175
20989
  {
22176
20990
  className: "t-team-chip",
@@ -22180,22 +20994,22 @@ function CategoriesTab({ t, remote, categories, onChanged }) {
22180
20994
  onClick: () => void run(() => remote.createCategory(key.trim(), label.trim()))
22181
20995
  },
22182
20996
  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)));
20997
+ )), 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
20998
  }
22185
20999
 
22186
21000
  // src/client/settings.jsx
22187
21001
  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) => {
21002
+ const [snapshot, setSnapshot] = import_react5.default.useState(() => snapshotOf(remote) ?? null);
21003
+ const [query, setQuery] = import_react5.default.useState("");
21004
+ const [division, setDivision] = import_react5.default.useState("");
21005
+ const [status, setStatus] = import_react5.default.useState("");
21006
+ const [error62, setError] = import_react5.default.useState("");
21007
+ const [busy, setBusy] = import_react5.default.useState(false);
21008
+ const [promptView, setPromptView] = import_react5.default.useState(null);
21009
+ const [editor, setEditor] = import_react5.default.useState(null);
21010
+ const [pendingDelete, setPendingDelete] = import_react5.default.useState("");
21011
+ const [tab, setTab] = import_react5.default.useState(initialTab ?? "experts");
21012
+ const reload = import_react5.default.useCallback(async (force) => {
22199
21013
  try {
22200
21014
  const next = await refresh(remote, force);
22201
21015
  setSnapshot({ ...next });
@@ -22206,7 +21020,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22206
21020
  return void 0;
22207
21021
  }
22208
21022
  }, [remote]);
22209
- import_react6.default.useEffect(() => {
21023
+ import_react5.default.useEffect(() => {
22210
21024
  let alive = true;
22211
21025
  (async () => {
22212
21026
  const next = await reload(false);
@@ -22231,7 +21045,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22231
21045
  });
22232
21046
  }
22233
21047
  }
22234
- import_react6.default.useEffect(() => {
21048
+ import_react5.default.useEffect(() => {
22235
21049
  if (promptView === null) return void 0;
22236
21050
  const onKey = (event) => {
22237
21051
  if (event.key === "Escape") setPromptView(null);
@@ -22387,25 +21201,23 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22387
21201
  setBusy(false);
22388
21202
  }
22389
21203
  }
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(() => {
21204
+ const [showActivePulse, setShowActivePulseState] = import_react5.default.useState(true);
21205
+ const [uiPrefsError, setUiPrefsError] = import_react5.default.useState("");
21206
+ const [uiPrefsWriteError, setUiPrefsWriteError] = import_react5.default.useState("");
21207
+ const uiPrefQueue = import_react5.default.useRef(Promise.resolve());
21208
+ import_react5.default.useEffect(() => {
22396
21209
  let alive = true;
22397
21210
  void (async () => {
22398
21211
  try {
22399
21212
  const data = unwrap(await remote.getUiPrefs(), "getUiPrefs");
22400
21213
  if (!alive) return;
22401
- if (typeof data?.showScheduleButton !== "boolean" || typeof data?.showActivePulse !== "boolean") {
21214
+ if (typeof data?.showActivePulse !== "boolean") {
22402
21215
  setUiPrefsError(t("settings.uiPrefsUnreadable"));
22403
21216
  return;
22404
21217
  }
22405
21218
  setUiPrefsError("");
22406
- setShowScheduleButtonState(data.showScheduleButton);
22407
21219
  setShowActivePulseState(data.showActivePulse);
22408
- setUiPrefs({ showScheduleButton: data.showScheduleButton, showActivePulse: data.showActivePulse });
21220
+ setUiPrefs({ showActivePulse: data.showActivePulse });
22409
21221
  } catch (cause) {
22410
21222
  console.error("[t-team] \u754C\u9762\u504F\u597D\u8BFB\u53D6\u5931\u8D25\uFF0C\u6682\u6309\u9ED8\u8BA4\u503C\u5904\u7406\uFF1A", cause);
22411
21223
  if (alive) setUiPrefsError(cause instanceof Error ? cause.message : String(cause));
@@ -22416,7 +21228,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22416
21228
  };
22417
21229
  }, [remote]);
22418
21230
  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")))));
21231
+ 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
21232
  }
22421
21233
  async function writeUiPref(patch, rollback) {
22422
21234
  setUiPrefs(patch);
@@ -22424,12 +21236,10 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22424
21236
  try {
22425
21237
  const next = unwrap(await remote.setUiPrefs(patch), "setUiPrefs");
22426
21238
  setUiPrefs(next);
22427
- setShowScheduleButtonState(next.showScheduleButton);
22428
21239
  setShowActivePulseState(next.showActivePulse);
22429
21240
  setUiPrefsWriteError("");
22430
21241
  } catch (cause) {
22431
21242
  setUiPrefs(rollback);
22432
- setShowScheduleButtonState(rollback.showScheduleButton ?? showScheduleButton);
22433
21243
  setShowActivePulseState(rollback.showActivePulse ?? showActivePulse);
22434
21244
  setUiPrefsWriteError(cause instanceof Error ? cause.message : String(cause));
22435
21245
  }
@@ -22438,27 +21248,12 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22438
21248
  });
22439
21249
  await run;
22440
21250
  }
22441
- async function setShowScheduleButton(next) {
22442
- setShowScheduleButtonState(next);
22443
- await writeUiPref({ showScheduleButton: next }, { showScheduleButton: !next });
22444
- }
22445
21251
  async function setShowActivePulse(next) {
22446
21252
  setShowActivePulseState(next);
22447
21253
  await writeUiPref({ showActivePulse: next }, { showActivePulse: !next });
22448
21254
  }
22449
21255
  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(
21256
+ 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
21257
  "button",
22463
21258
  {
22464
21259
  className: "t-team-switch",
@@ -22468,8 +21263,8 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22468
21263
  "data-on": showActivePulse,
22469
21264
  onClick: () => void setShowActivePulse(!showActivePulse)
22470
21265
  },
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(
21266
+ /* @__PURE__ */ import_react5.default.createElement("span", { className: "t-team-switch-knob" })
21267
+ )), /* @__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
21268
  "button",
22474
21269
  {
22475
21270
  className: "t-team-tab",
@@ -22481,7 +21276,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22481
21276
  onClick: () => setTab(key)
22482
21277
  },
22483
21278
  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(
21279
+ ))), /* @__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
21280
  "input",
22486
21281
  {
22487
21282
  className: "t-team-input",
@@ -22489,7 +21284,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22489
21284
  value: query,
22490
21285
  onChange: (event) => setQuery(event.target.value)
22491
21286
  }
22492
- ), /* @__PURE__ */ import_react6.default.createElement(
21287
+ ), /* @__PURE__ */ import_react5.default.createElement(
22493
21288
  "select",
22494
21289
  {
22495
21290
  className: "t-team-select",
@@ -22498,12 +21293,12 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22498
21293
  value: division,
22499
21294
  onChange: (event) => setDivision(event.target.value)
22500
21295
  },
22501
- /* @__PURE__ */ import_react6.default.createElement("option", { value: "" }, t("filter.allDivisions")),
21296
+ /* @__PURE__ */ import_react5.default.createElement("option", { value: "" }, t("filter.allDivisions")),
22502
21297
  divisions.map((item) => {
22503
21298
  const count = experts.filter((expert) => expert.division === item).length;
22504
- return /* @__PURE__ */ import_react6.default.createElement("option", { key: item, value: item }, `${labelOf(item)} (${count})`);
21299
+ return /* @__PURE__ */ import_react5.default.createElement("option", { key: item, value: item }, `${labelOf(item)} (${count})`);
22505
21300
  })
22506
- ), filtered && /* @__PURE__ */ import_react6.default.createElement(
21301
+ ), filtered && /* @__PURE__ */ import_react5.default.createElement(
22507
21302
  "button",
22508
21303
  {
22509
21304
  className: "t-team-chip",
@@ -22515,9 +21310,9 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22515
21310
  }
22516
21311
  },
22517
21312
  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) => {
21313
+ ), /* @__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
21314
  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(
21315
+ 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
21316
  "button",
22522
21317
  {
22523
21318
  className: "t-team-icon-btn",
@@ -22527,7 +21322,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22527
21322
  onClick: () => void openPrompt(expert)
22528
21323
  },
22529
21324
  "\u{1F4C4}"
22530
- ), expert.custom === true && /* @__PURE__ */ import_react6.default.createElement(
21325
+ ), expert.custom === true && /* @__PURE__ */ import_react5.default.createElement(
22531
21326
  "button",
22532
21327
  {
22533
21328
  className: "t-team-icon-btn",
@@ -22537,7 +21332,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22537
21332
  onClick: () => void openEditorEdit(expert)
22538
21333
  },
22539
21334
  "\u270F\uFE0F"
22540
- ), expert.custom === true && (pendingDelete === expert.slug ? /* @__PURE__ */ import_react6.default.createElement(
21335
+ ), expert.custom === true && (pendingDelete === expert.slug ? /* @__PURE__ */ import_react5.default.createElement(
22541
21336
  "button",
22542
21337
  {
22543
21338
  className: "t-team-chip t-team-danger",
@@ -22546,7 +21341,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22546
21341
  onClick: () => void removeExpert(expert)
22547
21342
  },
22548
21343
  t("custom.confirmDelete")
22549
- ) : /* @__PURE__ */ import_react6.default.createElement(
21344
+ ) : /* @__PURE__ */ import_react5.default.createElement(
22550
21345
  "button",
22551
21346
  {
22552
21347
  className: "t-team-icon-btn",
@@ -22557,7 +21352,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22557
21352
  },
22558
21353
  "\u{1F5D1}"
22559
21354
  ))));
22560
- })))), visible.length === 0 && /* @__PURE__ */ import_react6.default.createElement("div", { className: "t-team-meta" }, t("settings.empty"))))), promptView !== null && /* @__PURE__ */ import_react6.default.createElement(
21355
+ })))), visible.length === 0 && /* @__PURE__ */ import_react5.default.createElement("div", { className: "t-team-meta" }, t("settings.empty"))))), promptView !== null && /* @__PURE__ */ import_react5.default.createElement(
22561
21356
  "div",
22562
21357
  {
22563
21358
  className: "t-team-mask",
@@ -22565,8 +21360,8 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22565
21360
  if (event.target === event.currentTarget) setPromptView(null);
22566
21361
  }
22567
21362
  },
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(
21363
+ /* @__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))
21364
+ ), editor !== null && /* @__PURE__ */ import_react5.default.createElement(
22570
21365
  "div",
22571
21366
  {
22572
21367
  className: "t-team-mask",
@@ -22574,7 +21369,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22574
21369
  if (event.target === event.currentTarget && !editor.saving) setEditor(null);
22575
21370
  }
22576
21371
  },
22577
- /* @__PURE__ */ import_react6.default.createElement(
21372
+ /* @__PURE__ */ import_react5.default.createElement(
22578
21373
  "div",
22579
21374
  {
22580
21375
  className: "t-team-modal",
@@ -22582,8 +21377,8 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22582
21377
  "aria-modal": "true",
22583
21378
  "aria-label": editor.mode === "new" ? t("custom.titleNew") : t("custom.titleEdit", { name: editor.name || editor.slug })
22584
21379
  },
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(
21380
+ /* @__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"))),
21381
+ /* @__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
21382
  "select",
22588
21383
  {
22589
21384
  className: "t-team-select",
@@ -22594,9 +21389,9 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22594
21389
  else patchEditor({ divisionNew: false, division: value });
22595
21390
  }
22596
21391
  },
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(
21392
+ editorDivisionOptions.map((item) => /* @__PURE__ */ import_react5.default.createElement("option", { key: item.key, value: item.key }, `${item.label} \xB7 ${item.key}`)),
21393
+ /* @__PURE__ */ import_react5.default.createElement("option", { value: NEW_DIVISION }, t("custom.divisionNew"))
21394
+ ), editor.divisionNew && /* @__PURE__ */ import_react5.default.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 6 } }, /* @__PURE__ */ import_react5.default.createElement(
22600
21395
  "input",
22601
21396
  {
22602
21397
  className: "t-team-input",
@@ -22605,7 +21400,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22605
21400
  value: editor.divisionKey,
22606
21401
  onChange: (event) => patchEditor({ divisionKey: event.target.value })
22607
21402
  }
22608
- ), /* @__PURE__ */ import_react6.default.createElement(
21403
+ ), /* @__PURE__ */ import_react5.default.createElement(
22609
21404
  "input",
22610
21405
  {
22611
21406
  className: "t-team-input",
@@ -22613,7 +21408,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22613
21408
  value: editor.divisionLabel,
22614
21409
  onChange: (event) => patchEditor({ divisionLabel: event.target.value })
22615
21410
  }
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(
21411
+ ))), /* @__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
21412
  "input",
22618
21413
  {
22619
21414
  className: "t-team-input",
@@ -22622,7 +21417,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22622
21417
  spellCheck: false,
22623
21418
  onChange: (event) => patchEditor({ slug: event.target.value })
22624
21419
  }
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(
21420
+ )), /* @__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
21421
  "textarea",
22627
21422
  {
22628
21423
  className: "t-team-input",
@@ -22630,7 +21425,7 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22630
21425
  disabled: editor.loading,
22631
21426
  onChange: (event) => patchEditor({ body: event.target.value })
22632
21427
  }
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(
21428
+ )), 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
21429
  "button",
22635
21430
  {
22636
21431
  className: "t-team-chip",
@@ -22646,14 +21441,14 @@ function SettingsPanel({ t, ctx, remote, getActive, initialTab }) {
22646
21441
  }
22647
21442
 
22648
21443
  // src/client/summon.jsx
22649
- var import_react7 = __toESM(require("react"), 1);
21444
+ var import_react6 = __toESM(require("react"), 1);
22650
21445
  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(() => {
21446
+ const [open2, setOpen] = import_react6.default.useState(preview?.open === true);
21447
+ const [popTab, setPopTab] = import_react6.default.useState(preview?.tab ?? "experts");
21448
+ const [skills, setSkills] = import_react6.default.useState(null);
21449
+ const [skillQuery, setSkillQuery] = import_react6.default.useState("");
21450
+ const [skillsDiag, setSkillsDiag] = import_react6.default.useState("");
21451
+ import_react6.default.useEffect(() => {
22657
21452
  if (!open2) return void 0;
22658
21453
  const cached2 = skillsCache.get(sessionId);
22659
21454
  if (cached2 !== void 0) setSkills(cached2);
@@ -22701,12 +21496,12 @@ function SummonButton({ t, ctx, remote, getActive, insertReference, insertSkillH
22701
21496
  alive = false;
22702
21497
  };
22703
21498
  }, [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);
21499
+ const [popNote, setPopNote] = import_react6.default.useState("");
21500
+ const [query, setQuery] = import_react6.default.useState("");
21501
+ const [failed, setFailed] = import_react6.default.useState("");
21502
+ const [position, setPosition] = import_react6.default.useState(void 0);
21503
+ const rootRef = import_react6.default.useRef(null);
21504
+ const popRef = import_react6.default.useRef(null);
22710
21505
  const snap = snapshotOf(remote);
22711
21506
  function anchorInput() {
22712
21507
  let node2 = rootRef.current?.parentElement ?? null;
@@ -22733,13 +21528,30 @@ function SummonButton({ t, ctx, remote, getActive, insertReference, insertSkillH
22733
21528
  const laidOut = measured > 0 ? measured : width;
22734
21529
  const maxLeft = laidOut === 0 ? Number.POSITIVE_INFINITY : Math.max(8, window.innerWidth - laidOut - 8);
22735
21530
  const wantedLeft = hasInput ? inputRect.left : rect.left;
22736
- setPosition({
21531
+ const refTop = hasInput ? inputRect.top : rect.top;
21532
+ const refBottom = hasInput ? inputRect.bottom : rect.bottom;
21533
+ const EDGE = 8;
21534
+ const OFFSET = 6;
21535
+ const IDEAL = 600;
21536
+ const cap = Math.max(0, Math.min(IDEAL, window.innerHeight - EDGE * 2));
21537
+ const spaceAbove = refTop - EDGE;
21538
+ const spaceBelow = window.innerHeight - refBottom - EDGE;
21539
+ const up = spaceAbove >= spaceBelow;
21540
+ const maxHeight = Math.max(0, Math.min(cap, up ? spaceAbove : spaceBelow));
21541
+ const pos = {
22737
21542
  left: Math.min(Math.max(8, wantedLeft), maxLeft),
22738
- bottom: Math.max(8, window.innerHeight - (hasInput ? inputRect.top : rect.top) + 6),
22739
21543
  "--t-team-pop-w": width > 0 ? `${width}px` : void 0
22740
- });
21544
+ };
21545
+ if (up) {
21546
+ pos.bottom = Math.max(EDGE, window.innerHeight - refTop + OFFSET);
21547
+ pos.maxHeight = `${maxHeight}px`;
21548
+ } else {
21549
+ pos.top = Math.max(EDGE, refBottom + OFFSET);
21550
+ pos.maxHeight = `${maxHeight}px`;
21551
+ }
21552
+ setPosition(pos);
22741
21553
  }
22742
- import_react7.default.useEffect(() => {
21554
+ import_react6.default.useEffect(() => {
22743
21555
  if (!open2) return void 0;
22744
21556
  const onDown = (event) => {
22745
21557
  if (rootRef.current !== null && !rootRef.current.contains(event.target)) setOpen(false);
@@ -22808,7 +21620,7 @@ function SummonButton({ t, ctx, remote, getActive, insertReference, insertSkillH
22808
21620
  setFailed(t("button.insertFailed"));
22809
21621
  }
22810
21622
  }
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(
21623
+ 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
21624
  "button",
22813
21625
  {
22814
21626
  className: "t-team-tab",
@@ -22823,8 +21635,8 @@ function SummonButton({ t, ctx, remote, getActive, insertReference, insertSkillH
22823
21635
  }
22824
21636
  },
22825
21637
  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(
21638
+ tabCounts[key] === void 0 ? null : /* @__PURE__ */ import_react6.default.createElement("span", { className: "t-team-tab-count" }, t("tab.count", { count: tabCounts[key] }))
21639
+ ))), 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
21640
  "input",
22829
21641
  {
22830
21642
  className: "t-team-input",
@@ -22833,10 +21645,10 @@ function SummonButton({ t, ctx, remote, getActive, insertReference, insertSkillH
22833
21645
  value: query,
22834
21646
  onChange: (event) => setQuery(event.target.value)
22835
21647
  }
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) => {
21648
+ ), /* @__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
21649
  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(
21650
+ 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)));
21651
+ }))), 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
21652
  "input",
22841
21653
  {
22842
21654
  className: "t-team-input",
@@ -22845,7 +21657,7 @@ function SummonButton({ t, ctx, remote, getActive, insertReference, insertSkillH
22845
21657
  value: skillQuery,
22846
21658
  onChange: (event) => setSkillQuery(event.target.value)
22847
21659
  }
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)))));
21660
+ ), /* @__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
21661
  }
22850
21662
 
22851
21663
  // src/client/index.jsx
@@ -22912,61 +21724,14 @@ async function apply(ctx) {
22912
21724
  label: () => ctx.locale.bind(NS)("settings.title"),
22913
21725
  locale: NS,
22914
21726
  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
- )));
21727
+ }, (props) => import_react7.default.createElement(SettingsPanel, { ...props, t: ctx.locale.bind(NS), remote, getActive })));
22963
21728
  ctx.slots.inject("conversation.session.header.utilities", () => ctx.slots.register({
22964
21729
  name: "conversation.session.header.utilities",
22965
21730
  id: `${NS}-pulse`,
22966
21731
  order: 1,
22967
21732
  label: () => ctx.locale.bind(NS)("pulse.on"),
22968
21733
  locale: NS
22969
- }, (props) => import_react8.default.createElement(ActivePulse, {
21734
+ }, (props) => import_react7.default.createElement(ActivePulse, {
22970
21735
  ...props,
22971
21736
  t: ctx.locale.bind(NS),
22972
21737
  ctx: props?.ctx ?? ctx,
@@ -22985,7 +21750,7 @@ async function apply(ctx) {
22985
21750
  insertSkillHint: (text) => insertSkillHint(target(), text)
22986
21751
  };
22987
21752
  }
22988
- }, (props) => import_react8.default.createElement(SummonButton, { ...props, t: ctx.locale.bind(NS), remote, getActive, rootRemote: ctx.remote })));
21753
+ }, (props) => import_react7.default.createElement(SummonButton, { ...props, t: ctx.locale.bind(NS), remote, getActive, rootRemote: ctx.remote })));
22989
21754
  const registerSources = (active, divisions) => {
22990
21755
  const disposers = [];
22991
21756
  try {