@auto-ai/agent 2.1.90 → 2.1.92

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/dist/404/index.html +1 -1
  2. package/dist/404.html +1 -1
  3. package/dist/_next/static/{v7b7kpIIWrJ_TrI3XvYpK → IV9dkeTt0V-ZE8jl01i6B}/_buildManifest.js +1 -1
  4. package/dist/_next/static/IV9dkeTt0V-ZE8jl01i6B/_ssgManifest.js +1 -0
  5. package/dist/_next/static/chunks/091dc4a67d911a93.js +1 -0
  6. package/dist/_next/static/chunks/0b5fd45c6d5ed376.js +1 -0
  7. package/dist/_next/static/chunks/0c059f531456fce2.js +1 -0
  8. package/dist/_next/static/chunks/15734e910215c5c7.js +1 -0
  9. package/dist/_next/static/chunks/1f4af280db551c9d.js +1 -0
  10. package/dist/_next/static/chunks/2b6b9fdaaa345603.js +1 -0
  11. package/dist/_next/static/chunks/34b34d02b7d6b4cb.js +1 -0
  12. package/dist/_next/static/chunks/3740042834e8f1fa.js +1 -0
  13. package/dist/_next/static/chunks/3a17a1f5303a1c2c.js +1 -0
  14. package/dist/_next/static/chunks/40268f8e3ff0314e.js +1 -0
  15. package/dist/_next/static/chunks/4247f46093e522c6.js +1 -0
  16. package/dist/_next/static/chunks/4456351ffa1be45f.js +1 -0
  17. package/dist/_next/static/chunks/{2fa3e4168e941aef.js → 52e2164e45febae6.js} +1 -1
  18. package/dist/_next/static/chunks/620e3011cd69dfc9.js +1 -0
  19. package/dist/_next/static/chunks/67c7406790a840c1.js +1 -0
  20. package/dist/_next/static/chunks/6831f547a9403a0f.js +1 -0
  21. package/dist/_next/static/chunks/763710bf823861a8.js +1 -0
  22. package/dist/_next/static/chunks/76a71d344cc15a9f.js +1 -0
  23. package/dist/_next/static/chunks/7988d5ea63356e10.js +1 -0
  24. package/dist/_next/static/chunks/8c0da143ceae2767.js +1 -0
  25. package/dist/_next/static/chunks/8d0a29ce5f05a73d.js +1 -0
  26. package/dist/_next/static/chunks/{e99db8276524ccf5.js → 8dc694eabda7878d.js} +1 -1
  27. package/dist/_next/static/chunks/91adb7bdb9870c6a.js +1 -0
  28. package/dist/_next/static/chunks/ad4ba491cf12423f.js +5 -0
  29. package/dist/_next/static/chunks/c889d3f6eb8ab09e.css +1 -0
  30. package/dist/_next/static/chunks/ce0cac88dd992956.css +4 -0
  31. package/dist/_next/static/chunks/d9726d84bd7d40ff.js +1 -0
  32. package/dist/_next/static/chunks/e4675b3a8b7605e4.js +1 -0
  33. package/dist/_next/static/chunks/ebcd85ff4a1db0dc.js +5 -0
  34. package/dist/_next/static/chunks/{turbopack-8a0e770cd106af0c.js → turbopack-030a42d60560a927.js} +1 -1
  35. package/dist/_next/static/chunks/{turbopack-cd5b40c9e0ee1fe0.js → turbopack-3d84668fefd38b4b.js} +1 -1
  36. package/dist/_next/static/chunks/{turbopack-25a49bf58581b314.js → turbopack-8b41433c9a94981f.js} +1 -1
  37. package/dist/agent-office/accents.js +28 -0
  38. package/dist/agent-office/api.js +142 -0
  39. package/dist/agent-office/list.js +79 -0
  40. package/dist/agent-office/main.js +38 -0
  41. package/dist/agent-office/officeController.js +13 -0
  42. package/dist/agent-office/ui.js +264 -0
  43. package/dist/agent-office.html +307 -0
  44. package/dist/index.html +1 -1
  45. package/dist/index.txt +29 -19
  46. package/dist/manage/about/index.html +2 -0
  47. package/dist/manage/about/index.txt +37 -0
  48. package/dist/manage/add-account/basic/index.html +2 -0
  49. package/dist/manage/add-account/basic/index.txt +39 -0
  50. package/dist/manage/add-account/index.html +2 -1
  51. package/dist/manage/add-account/index.txt +34 -27
  52. package/dist/manage/add-account/prompt/index.html +2 -0
  53. package/dist/manage/add-account/prompt/index.txt +40 -0
  54. package/dist/manage/agent-teams/index.html +2 -2
  55. package/dist/manage/agent-teams/index.txt +34 -26
  56. package/dist/manage/env/index.html +2 -2
  57. package/dist/manage/env/index.txt +34 -26
  58. package/dist/manage/general/index.html +2 -0
  59. package/dist/manage/general/index.txt +37 -0
  60. package/dist/manage/index.html +1 -0
  61. package/dist/manage/index.txt +33 -0
  62. package/dist/manage/mcp/index.html +2 -2
  63. package/dist/manage/mcp/index.txt +34 -26
  64. package/dist/manage/permissions/index.html +2 -0
  65. package/dist/manage/permissions/index.txt +37 -0
  66. package/dist/manage/skills/index.html +2 -2
  67. package/dist/manage/skills/index.txt +34 -26
  68. package/dist/manage/task/index.html +1 -0
  69. package/dist/manage/task/index.txt +38 -0
  70. package/dist/manage/teams/index.html +1 -0
  71. package/dist/manage/teams/index.txt +37 -0
  72. package/dist/manage/tools/index.html +2 -2
  73. package/dist/manage/tools/index.txt +34 -26
  74. package/dist/ws-test.html +1151 -30
  75. package/package.json +6 -6
  76. package/dist/_next/static/chunks/01037955b0804f69.js +0 -1
  77. package/dist/_next/static/chunks/071c2b2eece424b8.js +0 -1
  78. package/dist/_next/static/chunks/19d949d5c8e7fc66.js +0 -1
  79. package/dist/_next/static/chunks/39dac725d46ff2cf.js +0 -5
  80. package/dist/_next/static/chunks/3a00f465f3afdd13.js +0 -1
  81. package/dist/_next/static/chunks/43c3e97de0c89c14.js +0 -1
  82. package/dist/_next/static/chunks/479bb32e1848b26b.js +0 -1
  83. package/dist/_next/static/chunks/573efa1cd3d0872c.js +0 -1
  84. package/dist/_next/static/chunks/6a8dfef8eb153262.js +0 -1
  85. package/dist/_next/static/chunks/6ea69f45a19b4f00.js +0 -1
  86. package/dist/_next/static/chunks/75622a4fe3b7b015.js +0 -1
  87. package/dist/_next/static/chunks/80a811d77e9d2ba6.js +0 -1
  88. package/dist/_next/static/chunks/8508beba62ed11df.js +0 -1
  89. package/dist/_next/static/chunks/8915ded29d610342.js +0 -1
  90. package/dist/_next/static/chunks/93e645e175860ad2.js +0 -1
  91. package/dist/_next/static/chunks/9597a4f1aa937100.js +0 -1
  92. package/dist/_next/static/chunks/9923762f97969b52.css +0 -4
  93. package/dist/_next/static/chunks/9c9c063cb0b2e562.js +0 -1
  94. package/dist/_next/static/chunks/a32559d6604a11fb.js +0 -5
  95. package/dist/_next/static/chunks/a6c743f3d7975ca2.css +0 -1
  96. package/dist/_next/static/chunks/ab6655809333a412.js +0 -1
  97. package/dist/_next/static/chunks/acb68dccafc14ac1.js +0 -1
  98. package/dist/_next/static/chunks/b1e8db918a2dcc7c.js +0 -1
  99. package/dist/_next/static/chunks/ca3c520aa0575c69.js +0 -1
  100. package/dist/_next/static/chunks/cdd193032944dfed.js +0 -1
  101. package/dist/_next/static/chunks/d9cb9883957b864c.js +0 -1
  102. package/dist/_next/static/v7b7kpIIWrJ_TrI3XvYpK/_ssgManifest.js +0 -1
  103. package/dist/manage/agent/index.html +0 -2
  104. package/dist/manage/agent/index.txt +0 -32
  105. /package/dist/_next/static/{v7b7kpIIWrJ_TrI3XvYpK → IV9dkeTt0V-ZE8jl01i6B}/_clientMiddlewareManifest.json +0 -0
package/dist/ws-test.html CHANGED
@@ -72,6 +72,10 @@
72
72
  justify-content: center;
73
73
  min-width: 0;
74
74
  }
75
+ .agent-switch-wrap {
76
+ position: relative;
77
+ display: inline-flex;
78
+ }
75
79
  .sidebar-avatar {
76
80
  width: 40px;
77
81
  height: 40px;
@@ -87,7 +91,140 @@
87
91
  line-height: 1;
88
92
  box-shadow: var(--ds-shadow);
89
93
  user-select: none;
90
- cursor: default;
94
+ cursor: pointer;
95
+ padding: 0;
96
+ font-family: inherit;
97
+ transition: border-color 0.15s ease, box-shadow 0.15s ease;
98
+ }
99
+ .sidebar-avatar:hover,
100
+ .agent-switch-wrap.open .sidebar-avatar {
101
+ border-color: var(--ds-accent);
102
+ box-shadow: 0 0 0 3px rgba(10, 132, 255, 0.14);
103
+ }
104
+ /* 浮层挂 body,fixed 定位,避免侧栏 overflow:hidden 裁剪 */
105
+ .agent-switch-dropdown {
106
+ display: none;
107
+ position: fixed;
108
+ z-index: 10050;
109
+ min-width: 168px;
110
+ width: max-content;
111
+ max-width: min(260px, calc(100vw - 24px));
112
+ max-height: min(360px, calc(100vh - 24px));
113
+ overflow: hidden;
114
+ background: var(--ds-bg);
115
+ border: 1px solid rgba(0, 0, 0, 0.08);
116
+ border-radius: 14px;
117
+ box-shadow:
118
+ 0 4px 6px rgba(15, 23, 42, 0.05),
119
+ 0 16px 40px rgba(15, 23, 42, 0.14);
120
+ flex-direction: column;
121
+ }
122
+ .agent-switch-dropdown.is-open {
123
+ display: flex;
124
+ }
125
+ .agent-switch-dropdown-head {
126
+ flex-shrink: 0;
127
+ padding: 10px 12px 8px;
128
+ font-size: 12px;
129
+ font-weight: 600;
130
+ color: var(--ds-muted);
131
+ letter-spacing: 0.02em;
132
+ border-bottom: 1px solid var(--ds-border);
133
+ background: #fafafa;
134
+ border-radius: 14px 14px 0 0;
135
+ }
136
+ .agent-switch-dropdown-list {
137
+ overflow-y: auto;
138
+ padding: 6px;
139
+ min-height: 0;
140
+ }
141
+ .agent-switch-item {
142
+ display: flex;
143
+ align-items: center;
144
+ justify-content: space-between;
145
+ gap: 10px;
146
+ width: 100%;
147
+ text-align: left;
148
+ padding: 8px 10px;
149
+ border: none;
150
+ border-radius: 10px;
151
+ background: transparent;
152
+ color: var(--ds-text);
153
+ font-size: 13px;
154
+ cursor: pointer;
155
+ }
156
+ .agent-switch-item:hover {
157
+ background: var(--ds-item-hover);
158
+ }
159
+ .agent-switch-item.is-current {
160
+ background: var(--ds-item-active);
161
+ color: var(--ds-accent);
162
+ }
163
+ .agent-switch-item-main {
164
+ min-width: 0;
165
+ display: flex;
166
+ flex-direction: column;
167
+ gap: 1px;
168
+ }
169
+ .agent-switch-item-name {
170
+ font-weight: 600;
171
+ line-height: 1.25;
172
+ overflow: hidden;
173
+ text-overflow: ellipsis;
174
+ white-space: nowrap;
175
+ }
176
+ .agent-switch-item-id {
177
+ font-size: 11px;
178
+ color: var(--ds-muted);
179
+ line-height: 1.2;
180
+ overflow: hidden;
181
+ text-overflow: ellipsis;
182
+ white-space: nowrap;
183
+ }
184
+ .agent-switch-item.is-current .agent-switch-item-id {
185
+ color: var(--ds-accent);
186
+ opacity: 0.85;
187
+ }
188
+ .agent-switch-item-check {
189
+ flex-shrink: 0;
190
+ width: 16px;
191
+ height: 16px;
192
+ color: var(--ds-accent);
193
+ opacity: 0;
194
+ }
195
+ .agent-switch-item.is-current .agent-switch-item-check {
196
+ opacity: 1;
197
+ }
198
+ .agent-switch-loading,
199
+ .agent-switch-empty {
200
+ padding: 14px 12px;
201
+ font-size: 13px;
202
+ color: var(--ds-muted);
203
+ }
204
+ .agent-switch-dropdown-foot {
205
+ flex-shrink: 0;
206
+ border-top: 1px solid var(--ds-border);
207
+ padding: 6px;
208
+ background: #fafafa;
209
+ border-radius: 0 0 14px 14px;
210
+ }
211
+ .agent-switch-manage-btn {
212
+ display: flex;
213
+ width: 100%;
214
+ align-items: center;
215
+ justify-content: center;
216
+ gap: 6px;
217
+ border: none;
218
+ border-radius: 10px;
219
+ background: transparent;
220
+ color: var(--ds-accent);
221
+ font-size: 13px;
222
+ font-weight: 600;
223
+ padding: 8px 10px;
224
+ cursor: pointer;
225
+ }
226
+ .agent-switch-manage-btn:hover {
227
+ background: var(--ds-item-hover);
91
228
  }
92
229
  .sidebar-brand-ws {
93
230
  margin-top: 0.45rem;
@@ -413,12 +550,17 @@
413
550
  .sidebar-icon-rail {
414
551
  align-items: center;
415
552
  gap: 8px;
416
- padding: 10px 0 10px;
417
- overflow: hidden;
553
+ padding: 10px 0 12px;
554
+ overflow-x: hidden;
555
+ overflow-y: auto;
556
+ flex: 1;
557
+ min-height: 0;
558
+ scrollbar-width: thin;
418
559
  }
419
560
  .sidebar-nav-item {
420
561
  width: 34px;
421
562
  height: 34px;
563
+ flex-shrink: 0;
422
564
  border: none;
423
565
  border-radius: 10px;
424
566
  display: inline-flex;
@@ -442,6 +584,103 @@
442
584
  height: 18px;
443
585
  display: block;
444
586
  }
587
+ .schedule-manage-table-wrap {
588
+ overflow: auto;
589
+ max-height: min(52vh, 420px);
590
+ border: 1px solid var(--ds-border);
591
+ border-radius: var(--ds-radius-sm);
592
+ background: #fff;
593
+ }
594
+ .schedule-manage-table {
595
+ width: 100%;
596
+ border-collapse: collapse;
597
+ font-size: 0.78rem;
598
+ }
599
+ .schedule-manage-table th,
600
+ .schedule-manage-table td {
601
+ padding: 0.45rem 0.55rem;
602
+ border-bottom: 1px solid var(--ds-border);
603
+ text-align: left;
604
+ vertical-align: top;
605
+ }
606
+ .schedule-manage-table th {
607
+ position: sticky;
608
+ top: 0;
609
+ background: #f8fafc;
610
+ color: var(--ds-text-soft);
611
+ font-weight: 600;
612
+ z-index: 1;
613
+ }
614
+ .schedule-manage-table tr:last-child td {
615
+ border-bottom: none;
616
+ }
617
+ .schedule-manage-prompt {
618
+ max-width: 220px;
619
+ word-break: break-word;
620
+ white-space: pre-wrap;
621
+ }
622
+ .schedule-manage-session-link {
623
+ color: var(--ds-accent);
624
+ cursor: pointer;
625
+ text-decoration: underline;
626
+ background: none;
627
+ border: none;
628
+ padding: 0;
629
+ font: inherit;
630
+ }
631
+ .schedule-create-form {
632
+ display: grid;
633
+ gap: 0.55rem;
634
+ margin-top: 0.75rem;
635
+ padding: 0.75rem;
636
+ border: 1px dashed var(--ds-border);
637
+ border-radius: var(--ds-radius-sm);
638
+ background: #fafbfc;
639
+ }
640
+ .schedule-create-form[hidden] {
641
+ display: none !important;
642
+ }
643
+ .schedule-create-row {
644
+ display: grid;
645
+ gap: 0.25rem;
646
+ }
647
+ .schedule-create-row label {
648
+ font-size: 0.75rem;
649
+ color: var(--ds-text-soft);
650
+ }
651
+ .schedule-create-row input,
652
+ .schedule-create-row select,
653
+ .schedule-create-row textarea {
654
+ width: 100%;
655
+ box-sizing: border-box;
656
+ border: 1px solid var(--ds-border);
657
+ border-radius: 6px;
658
+ padding: 0.4rem 0.5rem;
659
+ font: inherit;
660
+ background: #fff;
661
+ }
662
+ .schedule-create-row textarea {
663
+ min-height: 72px;
664
+ resize: vertical;
665
+ }
666
+ .schedule-create-actions {
667
+ display: flex;
668
+ gap: 0.5rem;
669
+ justify-content: flex-end;
670
+ margin-top: 0.25rem;
671
+ }
672
+ .schedule-manage-toolbar {
673
+ display: flex;
674
+ gap: 0.5rem;
675
+ align-items: center;
676
+ margin-bottom: 0.65rem;
677
+ }
678
+ .schedule-manage-empty {
679
+ padding: 1rem;
680
+ text-align: center;
681
+ color: var(--ds-text-soft);
682
+ font-size: 0.82rem;
683
+ }
445
684
  /* 侧栏图标悬浮说明(fixed,避免被 sidebar overflow 裁切) */
446
685
  .sidebar-hover-tip {
447
686
  position: fixed;
@@ -1815,11 +2054,16 @@
1815
2054
  }
1816
2055
  .sidebar-icon-rail {
1817
2056
  gap: 7px;
1818
- padding: var(--layout-card-gap) 0;
2057
+ padding: var(--layout-card-gap) 0 12px;
2058
+ overflow-x: hidden;
2059
+ overflow-y: auto;
2060
+ flex: 1;
2061
+ min-height: 0;
1819
2062
  }
1820
2063
  .sidebar-nav-item {
1821
2064
  width: 32px;
1822
2065
  height: 32px;
2066
+ flex-shrink: 0;
1823
2067
  border-radius: 10px;
1824
2068
  }
1825
2069
  .sidebar-brand-ws {
@@ -2241,16 +2485,34 @@
2241
2485
  <aside class="sidebar">
2242
2486
  <div class="sidebar-brand">
2243
2487
  <div class="sidebar-brand-title-row">
2244
- <div
2245
- class="sidebar-avatar"
2246
- id="brandAgentName"
2247
- title="agent: qihoo"
2248
- aria-label="agent: qihoo"
2249
- >Q</div>
2488
+ <div class="agent-switch-wrap" id="agentSwitchWrap">
2489
+ <button
2490
+ type="button"
2491
+ class="sidebar-avatar"
2492
+ id="brandAgentName"
2493
+ title="agent: qihoo"
2494
+ aria-label="agent: qihoo"
2495
+ aria-haspopup="listbox"
2496
+ aria-expanded="false"
2497
+ >Q</button>
2498
+ </div>
2250
2499
  </div>
2251
2500
  </div>
2252
2501
 
2253
2502
  <div class="sidebar-drawers sidebar-icon-rail" aria-label="左侧管理导航">
2503
+ <button
2504
+ type="button"
2505
+ class="sidebar-nav-item"
2506
+ id="btnManageAgents"
2507
+ title="返回办公室"
2508
+ aria-label="返回办公室"
2509
+ >
2510
+ <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
2511
+ <rect x="4" y="4" width="16" height="16" rx="4"/>
2512
+ <circle cx="12" cy="10" r="2.6"/>
2513
+ <path d="M7.5 17.5c.8-2.2 2.4-3.5 4.5-3.5s3.7 1.3 4.5 3.5"/>
2514
+ </svg>
2515
+ </button>
2254
2516
  <button
2255
2517
  type="button"
2256
2518
  class="sidebar-nav-item"
@@ -2300,6 +2562,19 @@
2300
2562
  <path d="M11 7h2M12 10v4"/>
2301
2563
  </svg>
2302
2564
  </button>
2565
+ <button
2566
+ type="button"
2567
+ class="sidebar-nav-item"
2568
+ id="btnManageSchedules"
2569
+ data-add="schedules"
2570
+ title="定时任务"
2571
+ aria-label="定时任务"
2572
+ >
2573
+ <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
2574
+ <circle cx="12" cy="12" r="10"/>
2575
+ <polyline points="12 6 12 12 16 14"/>
2576
+ </svg>
2577
+ </button>
2303
2578
  <button
2304
2579
  type="button"
2305
2580
  class="sidebar-nav-item"
@@ -2493,6 +2768,23 @@
2493
2768
  </div>
2494
2769
  </div>
2495
2770
 
2771
+ <div id="skillMdModal" class="agent-md-modal" aria-hidden="true">
2772
+ <div class="agent-md-modal-backdrop" id="skillMdModalBackdrop"></div>
2773
+ <div class="agent-md-modal-card" role="dialog" aria-modal="true" aria-labelledby="skillMdModalTitle">
2774
+ <div class="agent-md-modal-head">
2775
+ <h2 id="skillMdModalTitle">编辑 SKILL.md</h2>
2776
+ <button type="button" class="agent-md-modal-close" id="btnSkillMdModalClose" aria-label="关闭">
2777
+ &times;
2778
+ </button>
2779
+ </div>
2780
+ <textarea id="skillMdEditor" class="agent-md-editor" spellcheck="false" placeholder="加载中…"></textarea>
2781
+ <div class="agent-md-modal-foot">
2782
+ <button type="button" class="btn-agent-md-cancel" id="btnSkillMdCancel">取消</button>
2783
+ <button type="button" class="btn-primary" id="btnSkillMdSave">保存</button>
2784
+ </div>
2785
+ </div>
2786
+ </div>
2787
+
2496
2788
  <div id="toolFilesModal" class="agent-md-modal" aria-hidden="true">
2497
2789
  <div class="agent-md-modal-backdrop" id="toolFilesModalBackdrop"></div>
2498
2790
  <div class="agent-md-modal-card modal-unified" role="dialog" aria-modal="true" aria-labelledby="toolFilesModalTitle">
@@ -2757,11 +3049,102 @@
2757
3049
  </div>
2758
3050
  </div>
2759
3051
 
3052
+ <div id="scheduleManageModal" class="agent-md-modal" aria-hidden="true">
3053
+ <div class="agent-md-modal-backdrop" id="scheduleManageModalBackdrop"></div>
3054
+ <div id="scheduleManageModalCard" class="agent-md-modal-card modal-unified" role="dialog" aria-modal="true" aria-labelledby="scheduleManageModalTitle">
3055
+ <div class="agent-md-modal-head">
3056
+ <h2 id="scheduleManageModalTitle">定时任务</h2>
3057
+ <div class="modal-head-actions modal-head-actions--close-only">
3058
+ <button type="button" class="agent-md-modal-close" id="btnScheduleManageModalClose" aria-label="关闭">
3059
+ &times;
3060
+ </button>
3061
+ </div>
3062
+ </div>
3063
+ <div class="tool-files-body">
3064
+ <p id="scheduleManageMeta" class="tool-files-meta" style="margin: 0 0 0.5rem"></p>
3065
+ <div class="schedule-manage-toolbar">
3066
+ <button type="button" class="btn-system-settings" id="btnScheduleRefresh">刷新</button>
3067
+ <button type="button" class="btn-system-settings" id="btnScheduleCreateToggle">新建任务</button>
3068
+ <button type="button" class="btn-system-settings" id="btnScheduleGeelibPreset">Geelib 巡检</button>
3069
+ </div>
3070
+ <div id="scheduleCreateForm" class="schedule-create-form" hidden>
3071
+ <div class="schedule-create-row">
3072
+ <label for="scheduleSessionSelect">关联会话</label>
3073
+ <select id="scheduleSessionSelect"></select>
3074
+ </div>
3075
+ <div class="schedule-create-row">
3076
+ <label for="schedulePromptInput">Prompt</label>
3077
+ <textarea id="schedulePromptInput" placeholder="到期后发送给 agent 的提示词"></textarea>
3078
+ </div>
3079
+ <div class="schedule-create-row">
3080
+ <label>触发方式</label>
3081
+ <div style="display:flex;gap:0.75rem;align-items:center;font-size:0.78rem">
3082
+ <label><input type="radio" name="scheduleTriggerMode" value="delay" checked /> 相对分钟</label>
3083
+ <label><input type="radio" name="scheduleTriggerMode" value="cron" /> Cron</label>
3084
+ <label><input type="checkbox" id="scheduleRecurringInput" /> 循环</label>
3085
+ </div>
3086
+ </div>
3087
+ <div class="schedule-create-row" id="scheduleDelayRow">
3088
+ <label for="scheduleDelayMinutesInput">delayMinutes(1~10080)</label>
3089
+ <input id="scheduleDelayMinutesInput" type="number" min="1" max="10080" value="5" />
3090
+ </div>
3091
+ <div class="schedule-create-row" id="scheduleCronRow" hidden>
3092
+ <label for="scheduleCronInput">Cron(5 段,本地时区)</label>
3093
+ <input id="scheduleCronInput" type="text" placeholder="30 9 * * *" />
3094
+ </div>
3095
+ <div class="schedule-create-actions">
3096
+ <button type="button" class="btn-agent-md-cancel" id="btnScheduleCreateCancel">取消</button>
3097
+ <button type="button" class="btn-agent-md-save" id="btnScheduleCreateSubmit">创建</button>
3098
+ </div>
3099
+ </div>
3100
+ <div class="schedule-manage-table-wrap">
3101
+ <table class="schedule-manage-table">
3102
+ <thead>
3103
+ <tr>
3104
+ <th>ID</th>
3105
+ <th>会话</th>
3106
+ <th>Cron</th>
3107
+ <th>下次执行</th>
3108
+ <th>Prompt</th>
3109
+ <th>类型</th>
3110
+ <th>操作</th>
3111
+ </tr>
3112
+ </thead>
3113
+ <tbody id="scheduleTaskTableBody"></tbody>
3114
+ </table>
3115
+ <div id="scheduleManageEmpty" class="schedule-manage-empty" hidden>暂无定时任务</div>
3116
+ </div>
3117
+ </div>
3118
+ </div>
3119
+ </div>
3120
+
3121
+ </div>
3122
+
2760
3123
  <div id="sidebarHoverTip" class="sidebar-hover-tip" role="tooltip" hidden></div>
3124
+ <div
3125
+ class="agent-switch-dropdown"
3126
+ id="agentSwitchDropdown"
3127
+ role="listbox"
3128
+ aria-label="切换 agent"
3129
+ hidden
3130
+ ></div>
2761
3131
 
2762
3132
  <script src="https://cdn.jsdelivr.net/npm/marked@12.0.2/marked.min.js"></script>
2763
3133
  <script>
2764
3134
  (function () {
3135
+ /** ws-test 必须有合法 ?agent= 参数,否则回到办公室首页 */
3136
+ ;(function wsTestRequireAgentParam() {
3137
+ try {
3138
+ const ag = new URLSearchParams(window.location.search).get('agent')
3139
+ const id = ag ? String(ag).trim() : ''
3140
+ if (!id || !/^[a-zA-Z0-9_-]{1,64}$/.test(id)) {
3141
+ location.replace('/')
3142
+ }
3143
+ } catch {
3144
+ location.replace('/')
3145
+ }
3146
+ })()
3147
+
2765
3148
  const $ = (id) => document.getElementById(id)
2766
3149
  const logEl = $('log')
2767
3150
  const chatThreadEl = $('chatThread')
@@ -2785,6 +3168,14 @@
2785
3168
  const btnAgentMdModalClose = $('btnAgentMdModalClose')
2786
3169
  const btnAgentMdCancel = $('btnAgentMdCancel')
2787
3170
  const btnAgentMdSave = $('btnAgentMdSave')
3171
+ const skillMdModal = $('skillMdModal')
3172
+ const skillMdModalTitle = $('skillMdModalTitle')
3173
+ const skillMdModalBackdrop = $('skillMdModalBackdrop')
3174
+ const skillMdEditor = $('skillMdEditor')
3175
+ const btnSkillMdModalClose = $('btnSkillMdModalClose')
3176
+ const btnSkillMdCancel = $('btnSkillMdCancel')
3177
+ const btnSkillMdSave = $('btnSkillMdSave')
3178
+ let skillMdEditingName = ''
2788
3179
  const agentEnvModal = $('agentEnvModal')
2789
3180
  const agentEnvModalCard = $('agentEnvModalCard')
2790
3181
  const agentEnvModalBackdrop = $('agentEnvModalBackdrop')
@@ -2838,6 +3229,27 @@
2838
3229
  const runGroupModalTitle = $('runGroupModalTitle')
2839
3230
  const runGroupModalBody = $('runGroupModalBody')
2840
3231
  const btnRunGroupModalClose = $('btnRunGroupModalClose')
3232
+ const scheduleManageModal = $('scheduleManageModal')
3233
+ const scheduleManageModalBackdrop = $('scheduleManageModalBackdrop')
3234
+ const scheduleManageMeta = $('scheduleManageMeta')
3235
+ const scheduleTaskTableBody = $('scheduleTaskTableBody')
3236
+ const scheduleManageEmpty = $('scheduleManageEmpty')
3237
+ const btnScheduleManageModalClose = $('btnScheduleManageModalClose')
3238
+ const btnScheduleRefresh = $('btnScheduleRefresh')
3239
+ const btnScheduleCreateToggle = $('btnScheduleCreateToggle')
3240
+ const btnScheduleGeelibPreset = $('btnScheduleGeelibPreset')
3241
+ const scheduleCreateForm = $('scheduleCreateForm')
3242
+ const scheduleSessionSelect = $('scheduleSessionSelect')
3243
+ const schedulePromptInput = $('schedulePromptInput')
3244
+ const scheduleDelayMinutesInput = $('scheduleDelayMinutesInput')
3245
+ const scheduleCronInput = $('scheduleCronInput')
3246
+ const scheduleRecurringInput = $('scheduleRecurringInput')
3247
+ const scheduleDelayRow = $('scheduleDelayRow')
3248
+ const scheduleCronRow = $('scheduleCronRow')
3249
+ const btnScheduleCreateCancel = $('btnScheduleCreateCancel')
3250
+ const btnScheduleCreateSubmit = $('btnScheduleCreateSubmit')
3251
+ const btnManageAgents = $('btnManageAgents')
3252
+ const DEFAULT_AGENT_ID = 'qihoo'
2841
3253
  const mcpPackageMeta = $('mcpPackageMeta')
2842
3254
  const mcpPackageList = $('mcpPackageList')
2843
3255
  const btnMcpPackageModalClose = $('btnMcpPackageModalClose')
@@ -2852,6 +3264,9 @@
2852
3264
  const mainTitleEl = $('mainTitle')
2853
3265
  const mainSubEl = $('mainSub')
2854
3266
  const brandAgentNameEl = $('brandAgentName')
3267
+ const agentSwitchWrapEl = $('agentSwitchWrap')
3268
+ const agentSwitchDropdownEl = $('agentSwitchDropdown')
3269
+ let agentSwitchOpen = false
2855
3270
  const sidebarHoverTipEl = $('sidebarHoverTip')
2856
3271
  const sidebarAsideEl = document.querySelector('aside.sidebar')
2857
3272
  let sidebarHoverTipHideTimer = null
@@ -2907,7 +3322,7 @@
2907
3322
  }
2908
3323
  function wireSidebarHoverTips() {
2909
3324
  if (!sidebarAsideEl || !sidebarHoverTipEl) return
2910
- const nodes = sidebarAsideEl.querySelectorAll('#brandAgentName, .sidebar-nav-item')
3325
+ const nodes = sidebarAsideEl.querySelectorAll('#brandAgentName, #btnManageAgents, .sidebar-nav-item')
2911
3326
  for (let i = 0; i < nodes.length; i++) {
2912
3327
  const el = nodes[i]
2913
3328
  el.addEventListener('pointerenter', function () {
@@ -3005,7 +3420,7 @@
3005
3420
  let refreshSkillPickerRows = null
3006
3421
  let remoteMcpServers = []
3007
3422
  const WS_PERMISSION_MODE_KEY = 'WS_PERMISSION_MODE'
3008
- const ANTHROPIC_MODEL_KEY = 'ANTHROPIC_MODEL'
3423
+ const LLM_MODEL_KEY = 'LLM_MODEL'
3009
3424
  const WS_PERMISSION_MODE_ALLOWED = new Set([
3010
3425
  'acceptEdits',
3011
3426
  'plan',
@@ -3021,17 +3436,71 @@
3021
3436
  return typeof envObj[key] === 'string' ? envObj[key].trim() : ''
3022
3437
  }
3023
3438
 
3439
+ /** 项目根 .env 中的 LLM 默认值(agent.json 未配置时用于新 session 展示) */
3440
+ let projectEnvDefaults = { LLM_MODEL: '' }
3441
+
3442
+ function parseDotEnvValue(content, key) {
3443
+ if (!content || typeof content !== 'string' || !key) return ''
3444
+ const lines = content.split('\n')
3445
+ for (let i = 0; i < lines.length; i++) {
3446
+ const trimmed = lines[i].trim()
3447
+ if (!trimmed || trimmed.charAt(0) === '#') continue
3448
+ const eq = trimmed.indexOf('=')
3449
+ if (eq <= 0) continue
3450
+ if (trimmed.slice(0, eq).trim() !== key) continue
3451
+ let value = trimmed.slice(eq + 1).trim()
3452
+ if (
3453
+ (value.charAt(0) === '"' && value.charAt(value.length - 1) === '"') ||
3454
+ (value.charAt(0) === "'" && value.charAt(value.length - 1) === "'")
3455
+ ) {
3456
+ value = value.slice(1, -1)
3457
+ }
3458
+ return value
3459
+ }
3460
+ return ''
3461
+ }
3462
+
3463
+ function buildSystemEnvApiUrl() {
3464
+ const u = new URL('/api/system/env', httpOriginForApi() + '/')
3465
+ u.searchParams.set('agent', currentAgentParam())
3466
+ return u.toString()
3467
+ }
3468
+
3469
+ async function loadProjectEnvDefaults() {
3470
+ try {
3471
+ const r = await fetch(buildSystemEnvApiUrl())
3472
+ if (!r.ok) return
3473
+ const body = await r.json().catch(function () {
3474
+ return {}
3475
+ })
3476
+ const content = typeof body.content === 'string' ? body.content : ''
3477
+ projectEnvDefaults = {
3478
+ LLM_MODEL: parseDotEnvValue(content, LLM_MODEL_KEY),
3479
+ }
3480
+ } catch {
3481
+ /* 项目 .env 不可读时不阻塞 composer */
3482
+ }
3483
+ }
3484
+
3485
+ /** 新 session 默认模型:agent.json.env → agent.json.model → 项目 .env */
3486
+ function readDefaultLlmModel() {
3487
+ const fromAgentEnv = readAgentEnvString(LLM_MODEL_KEY)
3488
+ if (fromAgentEnv) return fromAgentEnv
3489
+ const fromAgentModel =
3490
+ typeof agentConfigState.model === 'string' ? agentConfigState.model.trim() : ''
3491
+ if (fromAgentModel) return fromAgentModel
3492
+ return projectEnvDefaults.LLM_MODEL || ''
3493
+ }
3494
+
3024
3495
  /**
3025
3496
  * 业务语义:三个会话级配置的初始化顺序必须稳定:
3026
- * 1) 先读取环境变量(agent.json.env);
3027
- * 2) 若未配置,再回退到产品默认值(自动/空/默认);
3497
+ * 1) 先读取 agent.json.env / agent.json.model;
3498
+ * 2) 再回退到项目 .env 的 LLM_MODEL;
3028
3499
  * 3) 将结果投影为 sessionOverrideState,保证 UI 与后端 PATCH 入参一致。
3029
3500
  */
3030
3501
  function buildDefaultSessionOverrideState() {
3031
- const model = readAgentEnvString(ANTHROPIC_MODEL_KEY)
3032
- // 新 session 产品默认权限模式为 default,不继承 agent.json 中的 plan
3033
3502
  return {
3034
- model: model,
3503
+ model: readDefaultLlmModel(),
3035
3504
  env: {
3036
3505
  [WS_PERMISSION_MODE_KEY]: 'default',
3037
3506
  },
@@ -3942,11 +4411,195 @@
3942
4411
  typeof name === 'string' && name.trim() ? name.trim() : currentAgentParam()
3943
4412
  const initial = id.charAt(0).toUpperCase() || 'A'
3944
4413
  brandAgentNameEl.textContent = initial
3945
- const tip = 'agent: ' + id
4414
+ const tip = 'agent: ' + id + '(点击切换)'
3946
4415
  brandAgentNameEl.setAttribute('title', tip)
3947
4416
  brandAgentNameEl.setAttribute('aria-label', tip)
3948
4417
  }
3949
4418
 
4419
+ /** 构建 agent 列表 API 地址,用于侧栏头像切换 workspace agent */
4420
+ function buildAgentsListUrl() {
4421
+ const u = new URL('/api/agents', httpOriginForApi() + '/')
4422
+ u.searchParams.set('agent', currentAgentParam())
4423
+ return u.toString()
4424
+ }
4425
+
4426
+ /** 构建单个 agent 的 REST 地址,用于详情/修改/删除 */
4427
+ function buildAgentItemUrl(id) {
4428
+ const u = new URL(
4429
+ '/api/agents/' + encodeURIComponent(String(id || '').trim()),
4430
+ httpOriginForApi() + '/'
4431
+ )
4432
+ u.searchParams.set('agent', currentAgentParam())
4433
+ return u.toString()
4434
+ }
4435
+
4436
+ /** 关闭 agent 切换下拉,恢复头像按钮状态 */
4437
+ function closeAgentSwitchMenu() {
4438
+ agentSwitchOpen = false
4439
+ if (agentSwitchWrapEl) agentSwitchWrapEl.classList.remove('open')
4440
+ if (agentSwitchDropdownEl) {
4441
+ agentSwitchDropdownEl.classList.remove('is-open')
4442
+ agentSwitchDropdownEl.hidden = true
4443
+ agentSwitchDropdownEl.style.left = ''
4444
+ agentSwitchDropdownEl.style.top = ''
4445
+ }
4446
+ if (brandAgentNameEl) brandAgentNameEl.setAttribute('aria-expanded', 'false')
4447
+ }
4448
+
4449
+ /** 根据头像位置计算浮层坐标,显示在侧栏右侧避免被 overflow 裁剪 */
4450
+ function positionAgentSwitchDropdown() {
4451
+ if (!brandAgentNameEl || !agentSwitchDropdownEl || !agentSwitchOpen) return
4452
+ requestAnimationFrame(function () {
4453
+ if (!agentSwitchOpen || !brandAgentNameEl || !agentSwitchDropdownEl) return
4454
+ const rect = brandAgentNameEl.getBoundingClientRect()
4455
+ const gap = 10
4456
+ const menuW = agentSwitchDropdownEl.offsetWidth
4457
+ const menuH = agentSwitchDropdownEl.offsetHeight
4458
+ let left = rect.right + gap
4459
+ let top = rect.top
4460
+ if (left + menuW > window.innerWidth - 12) {
4461
+ left = rect.left
4462
+ top = rect.bottom + gap
4463
+ }
4464
+ left = Math.max(12, Math.min(left, window.innerWidth - menuW - 12))
4465
+ top = Math.max(12, Math.min(top, window.innerHeight - menuH - 12))
4466
+ agentSwitchDropdownEl.style.left = left + 'px'
4467
+ agentSwitchDropdownEl.style.top = top + 'px'
4468
+ })
4469
+ }
4470
+
4471
+ /** 在 agent 切换下拉底部追加「管理 Agent」入口 */
4472
+ function appendAgentSwitchManageFooter() {
4473
+ if (!agentSwitchDropdownEl) return
4474
+ const foot = document.createElement('div')
4475
+ foot.className = 'agent-switch-dropdown-foot'
4476
+ const manageBtn = document.createElement('button')
4477
+ manageBtn.type = 'button'
4478
+ manageBtn.className = 'agent-switch-manage-btn'
4479
+ manageBtn.textContent = '管理 Agent…'
4480
+ manageBtn.addEventListener('click', function (ev) {
4481
+ ev.preventDefault()
4482
+ ev.stopPropagation()
4483
+ closeAgentSwitchMenu()
4484
+ const cur = currentAgentParam()
4485
+ window.location.href = cur ? '/?agent=' + encodeURIComponent(cur) : '/'
4486
+ })
4487
+ foot.appendChild(manageBtn)
4488
+ agentSwitchDropdownEl.appendChild(foot)
4489
+ }
4490
+
4491
+ /** 渲染 agent 列表项;当前 agent 高亮,点击后立即切换 workspace */
4492
+ function renderAgentSwitchList(agents) {
4493
+ if (!agentSwitchDropdownEl) return
4494
+ agentSwitchDropdownEl.innerHTML = ''
4495
+ const current = currentAgentParam()
4496
+ const head = document.createElement('div')
4497
+ head.className = 'agent-switch-dropdown-head'
4498
+ head.textContent = '切换 Agent'
4499
+ agentSwitchDropdownEl.appendChild(head)
4500
+ if (!Array.isArray(agents) || !agents.length) {
4501
+ const empty = document.createElement('div')
4502
+ empty.className = 'agent-switch-empty'
4503
+ empty.textContent = '暂无 agent'
4504
+ agentSwitchDropdownEl.appendChild(empty)
4505
+ appendAgentSwitchManageFooter()
4506
+ positionAgentSwitchDropdown()
4507
+ return
4508
+ }
4509
+ const list = document.createElement('div')
4510
+ list.className = 'agent-switch-dropdown-list'
4511
+ const frag = document.createDocumentFragment()
4512
+ for (let i = 0; i < agents.length; i++) {
4513
+ const row = agents[i]
4514
+ const id = String(row && row.id != null ? row.id : '').trim()
4515
+ if (!id) continue
4516
+ const displayName =
4517
+ row && typeof row.displayName === 'string' && row.displayName.trim()
4518
+ ? row.displayName.trim()
4519
+ : id
4520
+ const btn = document.createElement('button')
4521
+ btn.type = 'button'
4522
+ btn.className = 'agent-switch-item' + (id === current ? ' is-current' : '')
4523
+ btn.setAttribute('role', 'option')
4524
+ btn.setAttribute('aria-selected', id === current ? 'true' : 'false')
4525
+ const mainEl = document.createElement('span')
4526
+ mainEl.className = 'agent-switch-item-main'
4527
+ const nameEl = document.createElement('span')
4528
+ nameEl.className = 'agent-switch-item-name'
4529
+ nameEl.textContent = displayName
4530
+ mainEl.appendChild(nameEl)
4531
+ if (displayName !== id) {
4532
+ const idEl = document.createElement('span')
4533
+ idEl.className = 'agent-switch-item-id'
4534
+ idEl.textContent = id
4535
+ mainEl.appendChild(idEl)
4536
+ }
4537
+ btn.appendChild(mainEl)
4538
+ const checkEl = document.createElement('span')
4539
+ checkEl.className = 'agent-switch-item-check'
4540
+ checkEl.setAttribute('aria-hidden', 'true')
4541
+ checkEl.innerHTML =
4542
+ '<svg viewBox="0 0 16 16" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M3.5 8.2 6.6 11.3 12.5 4.8"/></svg>'
4543
+ btn.appendChild(checkEl)
4544
+ btn.addEventListener('click', function (ev) {
4545
+ ev.preventDefault()
4546
+ ev.stopPropagation()
4547
+ selectWorkspaceAgent(id)
4548
+ })
4549
+ frag.appendChild(btn)
4550
+ }
4551
+ list.appendChild(frag)
4552
+ agentSwitchDropdownEl.appendChild(list)
4553
+ appendAgentSwitchManageFooter()
4554
+ positionAgentSwitchDropdown()
4555
+ }
4556
+
4557
+ /** 选中目标 agent:复用 onAgentChanged 完成 WS 切换、会话刷新与配置重载 */
4558
+ function selectWorkspaceAgent(nextId) {
4559
+ const id = String(nextId || '').trim()
4560
+ if (!id || !agentIdInput) return
4561
+ closeAgentSwitchMenu()
4562
+ if (id === currentAgentParam()) return
4563
+ agentIdInput.value = id
4564
+ onAgentChanged()
4565
+ }
4566
+
4567
+ /** 打开 agent 切换下拉,按需拉取 /api/agents 列表 */
4568
+ async function openAgentSwitchMenu() {
4569
+ if (!agentSwitchWrapEl || !agentSwitchDropdownEl || !brandAgentNameEl) return
4570
+ hideSidebarHoverTip()
4571
+ agentSwitchOpen = true
4572
+ agentSwitchWrapEl.classList.add('open')
4573
+ agentSwitchDropdownEl.hidden = false
4574
+ agentSwitchDropdownEl.classList.add('is-open')
4575
+ brandAgentNameEl.setAttribute('aria-expanded', 'true')
4576
+ agentSwitchDropdownEl.innerHTML = '<div class="agent-switch-loading">加载中…</div>'
4577
+ positionAgentSwitchDropdown()
4578
+ try {
4579
+ const r = await fetch(buildAgentsListUrl())
4580
+ const body = await r.json().catch(function () {
4581
+ return {}
4582
+ })
4583
+ if (!r.ok) {
4584
+ throw new Error(body.message || body.error || r.statusText)
4585
+ }
4586
+ renderAgentSwitchList(body.agents)
4587
+ } catch (e) {
4588
+ agentSwitchDropdownEl.innerHTML =
4589
+ '<div class="agent-switch-empty">加载失败: ' + escapeHtml(String(e)) + '</div>'
4590
+ positionAgentSwitchDropdown()
4591
+ }
4592
+ }
4593
+
4594
+ /** 点击头像时切换下拉开关 */
4595
+ async function toggleAgentSwitchMenu() {
4596
+ if (agentSwitchOpen) {
4597
+ closeAgentSwitchMenu()
4598
+ return
4599
+ }
4600
+ await openAgentSwitchMenu()
4601
+ }
4602
+
3950
4603
  function rewriteSameOriginNavLinks() {
3951
4604
  const agent = currentAgentParam()
3952
4605
  const origin = window.location.origin
@@ -3988,6 +4641,244 @@
3988
4641
  return u.toString()
3989
4642
  }
3990
4643
 
4644
+ function buildSchedulesUrl() {
4645
+ const u = new URL('/api/schedules', httpOriginForApi() + '/')
4646
+ u.searchParams.set('agent', currentAgentParam())
4647
+ return u.toString()
4648
+ }
4649
+
4650
+ function buildScheduleDeleteUrl(id) {
4651
+ const u = new URL('/api/schedules', httpOriginForApi() + '/')
4652
+ u.searchParams.set('agent', currentAgentParam())
4653
+ u.searchParams.set('id', id)
4654
+ return u.toString()
4655
+ }
4656
+
4657
+ /** 从已加载 session 列表解析会话标题 */
4658
+ function scheduleSessionLabel(sessionId) {
4659
+ const sid = String(sessionId || '')
4660
+ const sessions = window.__lastSessions
4661
+ if (Array.isArray(sessions)) {
4662
+ for (let i = 0; i < sessions.length; i++) {
4663
+ const s = sessions[i]
4664
+ if (s && s.sessionId === sid) {
4665
+ return sessionTitle(s)
4666
+ }
4667
+ }
4668
+ }
4669
+ return sid.slice(0, 8) + '…'
4670
+ }
4671
+
4672
+ function formatScheduleFireAt(ms) {
4673
+ if (typeof ms !== 'number' || !Number.isFinite(ms)) return '—'
4674
+ try {
4675
+ return new Date(ms).toLocaleString()
4676
+ } catch {
4677
+ return String(ms)
4678
+ }
4679
+ }
4680
+
4681
+ /** 填充新建任务时的 session 下拉 */
4682
+ function populateScheduleSessionSelect() {
4683
+ if (!scheduleSessionSelect) return
4684
+ const sessions = Array.isArray(window.__lastSessions) ? window.__lastSessions : []
4685
+ const currentSid = sessionIdInput.value.trim()
4686
+ scheduleSessionSelect.innerHTML = ''
4687
+ if (!sessions.length) {
4688
+ const opt = document.createElement('option')
4689
+ opt.value = currentSid
4690
+ opt.textContent = currentSid ? currentSid.slice(0, 8) + '…' : '(当前会话)'
4691
+ scheduleSessionSelect.appendChild(opt)
4692
+ return
4693
+ }
4694
+ for (let i = 0; i < sessions.length; i++) {
4695
+ const s = sessions[i]
4696
+ if (!s || !s.sessionId) continue
4697
+ const opt = document.createElement('option')
4698
+ opt.value = s.sessionId
4699
+ opt.textContent = sessionTitle(s) + ' (' + s.sessionId.slice(0, 8) + '…)'
4700
+ if (s.sessionId === currentSid) opt.selected = true
4701
+ scheduleSessionSelect.appendChild(opt)
4702
+ }
4703
+ }
4704
+
4705
+ /** Geelib 定时巡检快捷模板:/geelib poll,每分钟循环 */
4706
+ function applyGeelibSchedulePreset() {
4707
+ if (scheduleCreateForm) scheduleCreateForm.hidden = false
4708
+ populateScheduleSessionSelect()
4709
+ if (schedulePromptInput) schedulePromptInput.value = '/geelib poll'
4710
+ document.querySelectorAll('input[name="scheduleTriggerMode"]').forEach(function (el) {
4711
+ el.checked = el.value === 'cron'
4712
+ })
4713
+ if (scheduleDelayRow) scheduleDelayRow.hidden = true
4714
+ if (scheduleCronRow) scheduleCronRow.hidden = false
4715
+ if (scheduleCronInput) scheduleCronInput.value = '* * * * *'
4716
+ if (scheduleRecurringInput) scheduleRecurringInput.checked = true
4717
+ }
4718
+
4719
+ /** 渲染定时任务表格 */
4720
+ function renderScheduleTaskTable(tasks, timezone) {
4721
+ if (!scheduleTaskTableBody || !scheduleManageEmpty) return
4722
+ scheduleTaskTableBody.innerHTML = ''
4723
+ const list = Array.isArray(tasks) ? tasks : []
4724
+ scheduleManageEmpty.hidden = list.length > 0
4725
+ for (let i = 0; i < list.length; i++) {
4726
+ const task = list[i]
4727
+ if (!task || !task.id) continue
4728
+ const tr = document.createElement('tr')
4729
+ const tdId = document.createElement('td')
4730
+ tdId.textContent = task.id
4731
+ const tdSession = document.createElement('td')
4732
+ const sessionBtn = document.createElement('button')
4733
+ sessionBtn.type = 'button'
4734
+ sessionBtn.className = 'schedule-manage-session-link'
4735
+ sessionBtn.textContent = scheduleSessionLabel(task.sessionId)
4736
+ sessionBtn.title = task.sessionId
4737
+ sessionBtn.addEventListener('click', function () {
4738
+ closeScheduleManageModal()
4739
+ switchToSession(task.sessionId)
4740
+ })
4741
+ tdSession.appendChild(sessionBtn)
4742
+ const tdCron = document.createElement('td')
4743
+ tdCron.textContent = task.cron || '—'
4744
+ const tdNext = document.createElement('td')
4745
+ tdNext.textContent = formatScheduleFireAt(task.nextFireAt)
4746
+ const tdPrompt = document.createElement('td')
4747
+ tdPrompt.className = 'schedule-manage-prompt'
4748
+ tdPrompt.textContent = task.prompt || ''
4749
+ const tdType = document.createElement('td')
4750
+ tdType.textContent = task.recurring ? '循环' : '一次性'
4751
+ const tdAction = document.createElement('td')
4752
+ const delBtn = document.createElement('button')
4753
+ delBtn.type = 'button'
4754
+ delBtn.className = 'btn-system-settings'
4755
+ delBtn.textContent = '删除'
4756
+ delBtn.addEventListener('click', function () {
4757
+ void deleteScheduleTask(task.id)
4758
+ })
4759
+ tdAction.appendChild(delBtn)
4760
+ tr.appendChild(tdId)
4761
+ tr.appendChild(tdSession)
4762
+ tr.appendChild(tdCron)
4763
+ tr.appendChild(tdNext)
4764
+ tr.appendChild(tdPrompt)
4765
+ tr.appendChild(tdType)
4766
+ tr.appendChild(tdAction)
4767
+ scheduleTaskTableBody.appendChild(tr)
4768
+ }
4769
+ if (scheduleManageMeta) {
4770
+ scheduleManageMeta.textContent =
4771
+ '时区: ' + (timezone || 'local') + ' · 共 ' + list.length + ' 个任务'
4772
+ }
4773
+ }
4774
+
4775
+ /** 拉取 agent 全部定时任务 */
4776
+ async function loadScheduleTasks() {
4777
+ const res = await fetch(buildSchedulesUrl())
4778
+ const body = await res.json()
4779
+ if (!res.ok) {
4780
+ throw new Error(body.message || body.error || res.statusText)
4781
+ }
4782
+ renderScheduleTaskTable(body.tasks, body.timezone)
4783
+ return body
4784
+ }
4785
+
4786
+ /** 创建定时任务 */
4787
+ async function createScheduleTask() {
4788
+ if (!scheduleSessionSelect || !schedulePromptInput) return
4789
+ const sessionId = scheduleSessionSelect.value.trim()
4790
+ const prompt = schedulePromptInput.value.trim()
4791
+ if (!sessionId) {
4792
+ window.alert('请选择关联会话')
4793
+ return
4794
+ }
4795
+ if (!prompt) {
4796
+ window.alert('请填写 Prompt')
4797
+ return
4798
+ }
4799
+ const modeEl = document.querySelector('input[name="scheduleTriggerMode"]:checked')
4800
+ const mode = modeEl ? modeEl.value : 'delay'
4801
+ const payload = {
4802
+ sessionId: sessionId,
4803
+ prompt: prompt,
4804
+ recurring: !!(scheduleRecurringInput && scheduleRecurringInput.checked),
4805
+ }
4806
+ if (mode === 'cron') {
4807
+ const cron = scheduleCronInput ? scheduleCronInput.value.trim() : ''
4808
+ if (!cron) {
4809
+ window.alert('请填写 Cron 表达式')
4810
+ return
4811
+ }
4812
+ payload.cron = cron
4813
+ } else {
4814
+ const delay = scheduleDelayMinutesInput
4815
+ ? Number(scheduleDelayMinutesInput.value)
4816
+ : NaN
4817
+ if (!Number.isFinite(delay) || delay < 1) {
4818
+ window.alert('delayMinutes 必须是 >= 1 的整数')
4819
+ return
4820
+ }
4821
+ payload.delayMinutes = Math.floor(delay)
4822
+ }
4823
+ const res = await fetch(buildSchedulesUrl(), {
4824
+ method: 'POST',
4825
+ headers: { 'Content-Type': 'application/json; charset=utf-8' },
4826
+ body: JSON.stringify(payload),
4827
+ })
4828
+ const body = await res.json()
4829
+ if (!res.ok) {
4830
+ throw new Error(body.message || body.error || res.statusText)
4831
+ }
4832
+ if (scheduleCreateForm) scheduleCreateForm.hidden = true
4833
+ if (schedulePromptInput) schedulePromptInput.value = ''
4834
+ await loadScheduleTasks()
4835
+ }
4836
+
4837
+ /** 删除定时任务 */
4838
+ async function deleteScheduleTask(id) {
4839
+ if (!window.confirm('确定删除定时任务 ' + id + '?')) return
4840
+ const res = await fetch(buildScheduleDeleteUrl(id), { method: 'DELETE' })
4841
+ const body = await res.json()
4842
+ if (!res.ok) {
4843
+ window.alert('删除失败: ' + (body.message || body.error || res.statusText))
4844
+ return
4845
+ }
4846
+ await loadScheduleTasks()
4847
+ }
4848
+
4849
+ function closeScheduleManageModal() {
4850
+ if (!scheduleManageModal) return
4851
+ scheduleManageModal.classList.remove('is-open')
4852
+ scheduleManageModal.setAttribute('aria-hidden', 'true')
4853
+ document.body.style.overflow = ''
4854
+ if (scheduleCreateForm) scheduleCreateForm.hidden = true
4855
+ }
4856
+
4857
+ /** 打开定时任务管理弹窗 */
4858
+ async function openScheduleManageModal() {
4859
+ if (!scheduleManageModal) return
4860
+ scheduleManageModal.classList.add('is-open')
4861
+ scheduleManageModal.setAttribute('aria-hidden', 'false')
4862
+ document.body.style.overflow = 'hidden'
4863
+ populateScheduleSessionSelect()
4864
+ if (scheduleTaskTableBody) {
4865
+ scheduleTaskTableBody.innerHTML =
4866
+ '<tr><td colspan="7" style="padding:1rem;text-align:center;color:#8892a8">加载中…</td></tr>'
4867
+ }
4868
+ try {
4869
+ await loadSessions()
4870
+ populateScheduleSessionSelect()
4871
+ await loadScheduleTasks()
4872
+ } catch (e) {
4873
+ if (scheduleTaskTableBody) {
4874
+ scheduleTaskTableBody.innerHTML =
4875
+ '<tr><td colspan="7" style="padding:1rem;color:#c0392b">加载失败: ' +
4876
+ String(e) +
4877
+ '</td></tr>'
4878
+ }
4879
+ }
4880
+ }
4881
+
3991
4882
  function renderPendingPromptsList(items) {
3992
4883
  if (!pendingPromptsListEl || !pendingPromptsBarEl) return
3993
4884
  pendingPromptsCache = Array.isArray(items) ? items : []
@@ -4181,6 +5072,13 @@
4181
5072
  return u.toString()
4182
5073
  }
4183
5074
 
5075
+ function buildBaseSkillMdUrl(skillName) {
5076
+ const u = new URL('/api/skills/base-skill-md', httpOriginForApi() + '/')
5077
+ u.searchParams.set('agent', currentAgentParam())
5078
+ u.searchParams.set('name', skillName)
5079
+ return u.toString()
5080
+ }
5081
+
4184
5082
  function buildSkillInstalledListUrl() {
4185
5083
  const u = new URL('/api/skills/installed-list', httpOriginForApi() + '/')
4186
5084
  u.searchParams.set('agent', currentAgentParam())
@@ -4864,10 +5762,6 @@
4864
5762
 
4865
5763
  async function deleteSessionById(sessionId) {
4866
5764
  if (!sessionId) return
4867
- const ok = window.confirm(
4868
- '确定删除该会话?将删除磁盘上的 transcript 与相关目录,不可恢复。\n\n' + sessionId,
4869
- )
4870
- if (!ok) return
4871
5765
  const delUrl = buildSessionDeleteUrl(sessionId)
4872
5766
  try {
4873
5767
  const r = await fetch(delUrl, { method: 'DELETE' })
@@ -4960,12 +5854,23 @@
4960
5854
  const nextSid = typeof id === 'string' ? id : ''
4961
5855
  sessionIdInput.value = nextSid
4962
5856
  void loadPendingPrompts()
5857
+ if (nextSid) {
5858
+ void loadSessionOverridesIntoComposer()
5859
+ } else {
5860
+ void loadProjectEnvDefaults().then(function () {
5861
+ resetSessionOverrideStateToDefault()
5862
+ })
5863
+ }
4963
5864
  // 优先走「单 WS、多子进程」路径:复用当前连接,仅让后端 kill+respawn 子进程
4964
5865
  if (socket && socket.readyState === WebSocket.OPEN) {
4965
5866
  serverReady = false
4966
5867
  resetChatUi()
4967
5868
  pendingSessionOverrides = null
4968
- resetSessionOverrideStateToDefault()
5869
+ if (nextSid) {
5870
+ /* 已在上方拉取 overrides;切换中勿清空 composer 模型 */
5871
+ } else {
5872
+ resetSessionOverrideStateToDefault()
5873
+ }
4969
5874
  if (window.__lastSessions) renderSessionList(window.__lastSessions)
4970
5875
  else updateMainHeader()
4971
5876
  const payload = {
@@ -4990,7 +5895,9 @@
4990
5895
  disconnectIfOpen()
4991
5896
  if (window.__lastSessions) renderSessionList(window.__lastSessions)
4992
5897
  else updateMainHeader()
4993
- resetSessionOverrideStateToDefault()
5898
+ if (!nextSid) {
5899
+ resetSessionOverrideStateToDefault()
5900
+ }
4994
5901
  connectWebSocket()
4995
5902
  }
4996
5903
 
@@ -5391,7 +6298,7 @@
5391
6298
  const model = typeof sessionOverrideState.model === 'string'
5392
6299
  ? sessionOverrideState.model.trim()
5393
6300
  : ''
5394
- env[ANTHROPIC_MODEL_KEY] = model
6301
+ env[LLM_MODEL_KEY] = model
5395
6302
  }
5396
6303
 
5397
6304
  function normalizePermissionMode(value) {
@@ -5549,8 +6456,8 @@
5549
6456
  : {}
5550
6457
  sessionOverrideState = {
5551
6458
  model:
5552
- typeof ovEnv[ANTHROPIC_MODEL_KEY] === 'string'
5553
- ? String(ovEnv[ANTHROPIC_MODEL_KEY]).trim()
6459
+ typeof ovEnv[LLM_MODEL_KEY] === 'string'
6460
+ ? String(ovEnv[LLM_MODEL_KEY]).trim()
5554
6461
  : defaults.model,
5555
6462
  env: {
5556
6463
  [WS_PERMISSION_MODE_KEY]:
@@ -5569,7 +6476,7 @@
5569
6476
  const env = getSessionOverrideEnv()
5570
6477
  const patchEnv = {}
5571
6478
  const defaults = buildDefaultSessionOverrideState()
5572
- patchEnv[ANTHROPIC_MODEL_KEY] =
6479
+ patchEnv[LLM_MODEL_KEY] =
5573
6480
  typeof sessionOverrideState.model === 'string'
5574
6481
  ? sessionOverrideState.model.trim()
5575
6482
  : defaults.model
@@ -5766,7 +6673,13 @@
5766
6673
  }
5767
6674
  renderBindChips()
5768
6675
  syncModelInputFromState()
5769
- void loadSessionOverridesIntoComposer()
6676
+ void loadProjectEnvDefaults().then(function () {
6677
+ if (!sessionIdInput || !sessionIdInput.value.trim()) {
6678
+ resetSessionOverrideStateToDefault()
6679
+ } else {
6680
+ void loadSessionOverridesIntoComposer()
6681
+ }
6682
+ })
5770
6683
  logLine('agent-config', 'load failed ' + (body.message || r.status))
5771
6684
  return
5772
6685
  }
@@ -5810,7 +6723,13 @@
5810
6723
  }
5811
6724
  renderBindChips()
5812
6725
  syncModelInputFromState()
5813
- void loadSessionOverridesIntoComposer()
6726
+ void loadProjectEnvDefaults().then(function () {
6727
+ if (!sessionIdInput || !sessionIdInput.value.trim()) {
6728
+ resetSessionOverrideStateToDefault()
6729
+ } else {
6730
+ void loadSessionOverridesIntoComposer()
6731
+ }
6732
+ })
5814
6733
  } catch (e) {
5815
6734
  logLine('agent-config', String(e))
5816
6735
  }
@@ -6762,6 +7681,16 @@
6762
7681
  renderSkillRows()
6763
7682
  })
6764
7683
  actions.appendChild(toggleBtn)
7684
+ if (!canDelete) {
7685
+ const editBtn = document.createElement('button')
7686
+ editBtn.type = 'button'
7687
+ editBtn.className = 'btn-picker-action'
7688
+ editBtn.textContent = '编辑'
7689
+ editBtn.addEventListener('click', function () {
7690
+ openSkillMdModal(id)
7691
+ })
7692
+ actions.appendChild(editBtn)
7693
+ }
6765
7694
  if (canDelete) {
6766
7695
  const exportBtn = document.createElement('button')
6767
7696
  exportBtn.type = 'button'
@@ -7089,6 +8018,16 @@
7089
8018
  const btn = ev.target && ev.target.closest ? ev.target.closest('[data-add]') : null
7090
8019
  if (!btn) return
7091
8020
  const k = btn.getAttribute('data-add')
8021
+ if (k === 'schedules') {
8022
+ ev.preventDefault()
8023
+ ev.stopPropagation()
8024
+ const items = sidebarDrawersEl.querySelectorAll('.sidebar-nav-item')
8025
+ for (let i = 0; i < items.length; i++) {
8026
+ items[i].classList.toggle('is-active', items[i] === btn)
8027
+ }
8028
+ void openScheduleManageModal()
8029
+ return
8030
+ }
7092
8031
  if (k === 'tools' || k === 'mcp' || k === 'skills' || k === 'agentTeams') {
7093
8032
  ev.preventDefault()
7094
8033
  ev.stopPropagation()
@@ -7197,6 +8136,59 @@
7197
8136
  })
7198
8137
  }
7199
8138
 
8139
+ if (btnScheduleManageModalClose) {
8140
+ btnScheduleManageModalClose.addEventListener('click', closeScheduleManageModal)
8141
+ }
8142
+ if (scheduleManageModalBackdrop) {
8143
+ scheduleManageModalBackdrop.addEventListener('click', closeScheduleManageModal)
8144
+ }
8145
+ if (btnScheduleRefresh) {
8146
+ btnScheduleRefresh.addEventListener('click', function () {
8147
+ void loadScheduleTasks().catch(function (e) {
8148
+ window.alert('刷新失败: ' + e)
8149
+ })
8150
+ })
8151
+ }
8152
+ if (btnScheduleCreateToggle && scheduleCreateForm) {
8153
+ btnScheduleCreateToggle.addEventListener('click', function () {
8154
+ scheduleCreateForm.hidden = !scheduleCreateForm.hidden
8155
+ if (!scheduleCreateForm.hidden) populateScheduleSessionSelect()
8156
+ })
8157
+ }
8158
+ if (btnScheduleGeelibPreset) {
8159
+ btnScheduleGeelibPreset.addEventListener('click', function () {
8160
+ applyGeelibSchedulePreset()
8161
+ })
8162
+ }
8163
+ if (btnScheduleCreateCancel && scheduleCreateForm) {
8164
+ btnScheduleCreateCancel.addEventListener('click', function () {
8165
+ scheduleCreateForm.hidden = true
8166
+ })
8167
+ }
8168
+ if (btnScheduleCreateSubmit) {
8169
+ btnScheduleCreateSubmit.addEventListener('click', function () {
8170
+ void createScheduleTask().catch(function (e) {
8171
+ window.alert('创建失败: ' + e)
8172
+ })
8173
+ })
8174
+ }
8175
+ document.querySelectorAll('input[name="scheduleTriggerMode"]').forEach(function (el) {
8176
+ el.addEventListener('change', function () {
8177
+ const useCron = el.value === 'cron' && el.checked
8178
+ if (scheduleDelayRow) scheduleDelayRow.hidden = useCron
8179
+ if (scheduleCronRow) scheduleCronRow.hidden = !useCron
8180
+ })
8181
+ })
8182
+
8183
+ if (btnManageAgents) {
8184
+ btnManageAgents.addEventListener('click', function (ev) {
8185
+ ev.preventDefault()
8186
+ ev.stopPropagation()
8187
+ const cur = currentAgentParam()
8188
+ window.location.href = cur ? '/?agent=' + encodeURIComponent(cur) : '/'
8189
+ })
8190
+ }
8191
+
7200
8192
  function closeAgentMdModal() {
7201
8193
  if (!agentMdModal) return
7202
8194
  agentMdModal.classList.remove('is-open')
@@ -7204,6 +8196,78 @@
7204
8196
  document.body.style.overflow = ''
7205
8197
  }
7206
8198
 
8199
+ function closeSkillMdModal() {
8200
+ if (!skillMdModal) return
8201
+ skillMdModal.classList.remove('is-open')
8202
+ skillMdModal.setAttribute('aria-hidden', 'true')
8203
+ document.body.style.overflow = ''
8204
+ skillMdEditingName = ''
8205
+ }
8206
+
8207
+ function openSkillMdModal(skillName) {
8208
+ if (!skillMdModal || !skillMdEditor || !skillMdModalTitle) return
8209
+ skillMdEditingName = String(skillName || '').trim()
8210
+ if (!skillMdEditingName) return
8211
+ skillMdModal.classList.add('is-open')
8212
+ skillMdModal.setAttribute('aria-hidden', 'false')
8213
+ document.body.style.overflow = 'hidden'
8214
+ skillMdEditor.value = ''
8215
+ skillMdEditor.placeholder = '加载中…'
8216
+ skillMdModalTitle.textContent = '编辑 SKILL.md · /' + skillMdEditingName
8217
+ fetch(buildBaseSkillMdUrl(skillMdEditingName))
8218
+ .then(function (r) {
8219
+ return r.json().then(function (body) {
8220
+ return { r: r, body: body }
8221
+ })
8222
+ })
8223
+ .then(function (x) {
8224
+ if (!x.r.ok) {
8225
+ skillMdEditor.placeholder = ''
8226
+ const msg = x.body.message || x.body.error || x.r.statusText || '请求失败'
8227
+ window.alert('加载 SKILL.md 失败:' + msg)
8228
+ closeSkillMdModal()
8229
+ return
8230
+ }
8231
+ skillMdEditor.value =
8232
+ typeof x.body.content === 'string' ? x.body.content : ''
8233
+ skillMdEditor.placeholder = 'Markdown 源码…'
8234
+ })
8235
+ .catch(function (e) {
8236
+ window.alert('加载 SKILL.md 失败: ' + e)
8237
+ closeSkillMdModal()
8238
+ })
8239
+ }
8240
+
8241
+ async function saveSkillMd() {
8242
+ if (!skillMdEditor || !btnSkillMdSave || !skillMdEditingName) return
8243
+ btnSkillMdSave.disabled = true
8244
+ try {
8245
+ const r = await fetch(buildBaseSkillMdUrl(skillMdEditingName), {
8246
+ method: 'PUT',
8247
+ headers: { 'Content-Type': 'application/json; charset=utf-8' },
8248
+ body: JSON.stringify({ content: String(skillMdEditor.value) }),
8249
+ })
8250
+ const body = await r.json().catch(function () {
8251
+ return {}
8252
+ })
8253
+ if (!r.ok) {
8254
+ window.alert('保存失败:' + (body.message || body.error || r.statusText))
8255
+ return
8256
+ }
8257
+ closeSkillMdModal()
8258
+ setStatus('SKILL.md 已保存', serverReady ? 'ready' : '')
8259
+ restartCurrentSessionSubprocessWithReason('save-base-skill-md')
8260
+ if (typeof refreshSkillPickerRows === 'function') {
8261
+ void refreshSkillPickerRows()
8262
+ }
8263
+ window.alert('SKILL.md 已保存,并已重启当前 session 子进程。')
8264
+ } catch (e) {
8265
+ window.alert('保存失败: ' + e)
8266
+ } finally {
8267
+ btnSkillMdSave.disabled = false
8268
+ }
8269
+ }
8270
+
7207
8271
  function closeAgentEnvModal() {
7208
8272
  if (!agentEnvModal) return
7209
8273
  agentEnvModal.classList.remove('is-open')
@@ -7942,6 +9006,20 @@
7942
9006
  void saveAgentMd()
7943
9007
  })
7944
9008
  }
9009
+ if (btnSkillMdModalClose) {
9010
+ btnSkillMdModalClose.addEventListener('click', closeSkillMdModal)
9011
+ }
9012
+ if (btnSkillMdCancel) {
9013
+ btnSkillMdCancel.addEventListener('click', closeSkillMdModal)
9014
+ }
9015
+ if (skillMdModalBackdrop) {
9016
+ skillMdModalBackdrop.addEventListener('click', closeSkillMdModal)
9017
+ }
9018
+ if (btnSkillMdSave) {
9019
+ btnSkillMdSave.addEventListener('click', function () {
9020
+ void saveSkillMd()
9021
+ })
9022
+ }
7945
9023
  if (btnToolFilesModalClose) {
7946
9024
  btnToolFilesModalClose.addEventListener('click', closeToolFilesModal)
7947
9025
  }
@@ -7959,6 +9037,10 @@
7959
9037
  }
7960
9038
  document.addEventListener('keydown', function (ev) {
7961
9039
  if (ev.key !== 'Escape') return
9040
+ if (agentSwitchOpen) {
9041
+ closeAgentSwitchMenu()
9042
+ return
9043
+ }
7962
9044
  if (agentPickerModal && agentPickerModal.classList.contains('is-open')) {
7963
9045
  closeAgentPickerModal()
7964
9046
  return
@@ -7971,10 +9053,18 @@
7971
9053
  closeAgentMdModal()
7972
9054
  return
7973
9055
  }
9056
+ if (skillMdModal && skillMdModal.classList.contains('is-open')) {
9057
+ closeSkillMdModal()
9058
+ return
9059
+ }
7974
9060
  if (agentEnvModal && agentEnvModal.classList.contains('is-open')) {
7975
9061
  closeAgentEnvModal()
7976
9062
  return
7977
9063
  }
9064
+ if (scheduleManageModal && scheduleManageModal.classList.contains('is-open')) {
9065
+ closeScheduleManageModal()
9066
+ return
9067
+ }
7978
9068
  if (toolFilesModal && toolFilesModal.classList.contains('is-open')) {
7979
9069
  closeToolFilesModal()
7980
9070
  return
@@ -8025,6 +9115,37 @@
8025
9115
  rewriteSameOriginNavLinks()
8026
9116
  })
8027
9117
  }
9118
+ if (brandAgentNameEl) {
9119
+ brandAgentNameEl.addEventListener('click', function (ev) {
9120
+ ev.preventDefault()
9121
+ ev.stopPropagation()
9122
+ void toggleAgentSwitchMenu()
9123
+ })
9124
+ }
9125
+ if (agentSwitchDropdownEl) {
9126
+ agentSwitchDropdownEl.addEventListener('click', function (ev) {
9127
+ ev.stopPropagation()
9128
+ })
9129
+ }
9130
+ document.addEventListener('click', function (ev) {
9131
+ if (!agentSwitchOpen) return
9132
+ const t = ev.target
9133
+ if (t instanceof Node) {
9134
+ if (agentSwitchWrapEl && agentSwitchWrapEl.contains(t)) return
9135
+ if (agentSwitchDropdownEl && agentSwitchDropdownEl.contains(t)) return
9136
+ }
9137
+ closeAgentSwitchMenu()
9138
+ })
9139
+ window.addEventListener('resize', function () {
9140
+ if (agentSwitchOpen) positionAgentSwitchDropdown()
9141
+ })
9142
+ window.addEventListener(
9143
+ 'scroll',
9144
+ function () {
9145
+ if (agentSwitchOpen) positionAgentSwitchDropdown()
9146
+ },
9147
+ true
9148
+ )
8028
9149
 
8029
9150
  updateBrandAgent()
8030
9151
  rewriteSameOriginNavLinks()