@auto-ai/agent 2.1.90 → 2.1.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/dist/ws-test.html CHANGED
@@ -413,12 +413,17 @@
413
413
  .sidebar-icon-rail {
414
414
  align-items: center;
415
415
  gap: 8px;
416
- padding: 10px 0 10px;
417
- overflow: hidden;
416
+ padding: 10px 0 12px;
417
+ overflow-x: hidden;
418
+ overflow-y: auto;
419
+ flex: 1;
420
+ min-height: 0;
421
+ scrollbar-width: thin;
418
422
  }
419
423
  .sidebar-nav-item {
420
424
  width: 34px;
421
425
  height: 34px;
426
+ flex-shrink: 0;
422
427
  border: none;
423
428
  border-radius: 10px;
424
429
  display: inline-flex;
@@ -442,6 +447,103 @@
442
447
  height: 18px;
443
448
  display: block;
444
449
  }
450
+ .schedule-manage-table-wrap {
451
+ overflow: auto;
452
+ max-height: min(52vh, 420px);
453
+ border: 1px solid var(--ds-border);
454
+ border-radius: var(--ds-radius-sm);
455
+ background: #fff;
456
+ }
457
+ .schedule-manage-table {
458
+ width: 100%;
459
+ border-collapse: collapse;
460
+ font-size: 0.78rem;
461
+ }
462
+ .schedule-manage-table th,
463
+ .schedule-manage-table td {
464
+ padding: 0.45rem 0.55rem;
465
+ border-bottom: 1px solid var(--ds-border);
466
+ text-align: left;
467
+ vertical-align: top;
468
+ }
469
+ .schedule-manage-table th {
470
+ position: sticky;
471
+ top: 0;
472
+ background: #f8fafc;
473
+ color: var(--ds-text-soft);
474
+ font-weight: 600;
475
+ z-index: 1;
476
+ }
477
+ .schedule-manage-table tr:last-child td {
478
+ border-bottom: none;
479
+ }
480
+ .schedule-manage-prompt {
481
+ max-width: 220px;
482
+ word-break: break-word;
483
+ white-space: pre-wrap;
484
+ }
485
+ .schedule-manage-session-link {
486
+ color: var(--ds-accent);
487
+ cursor: pointer;
488
+ text-decoration: underline;
489
+ background: none;
490
+ border: none;
491
+ padding: 0;
492
+ font: inherit;
493
+ }
494
+ .schedule-create-form {
495
+ display: grid;
496
+ gap: 0.55rem;
497
+ margin-top: 0.75rem;
498
+ padding: 0.75rem;
499
+ border: 1px dashed var(--ds-border);
500
+ border-radius: var(--ds-radius-sm);
501
+ background: #fafbfc;
502
+ }
503
+ .schedule-create-form[hidden] {
504
+ display: none !important;
505
+ }
506
+ .schedule-create-row {
507
+ display: grid;
508
+ gap: 0.25rem;
509
+ }
510
+ .schedule-create-row label {
511
+ font-size: 0.75rem;
512
+ color: var(--ds-text-soft);
513
+ }
514
+ .schedule-create-row input,
515
+ .schedule-create-row select,
516
+ .schedule-create-row textarea {
517
+ width: 100%;
518
+ box-sizing: border-box;
519
+ border: 1px solid var(--ds-border);
520
+ border-radius: 6px;
521
+ padding: 0.4rem 0.5rem;
522
+ font: inherit;
523
+ background: #fff;
524
+ }
525
+ .schedule-create-row textarea {
526
+ min-height: 72px;
527
+ resize: vertical;
528
+ }
529
+ .schedule-create-actions {
530
+ display: flex;
531
+ gap: 0.5rem;
532
+ justify-content: flex-end;
533
+ margin-top: 0.25rem;
534
+ }
535
+ .schedule-manage-toolbar {
536
+ display: flex;
537
+ gap: 0.5rem;
538
+ align-items: center;
539
+ margin-bottom: 0.65rem;
540
+ }
541
+ .schedule-manage-empty {
542
+ padding: 1rem;
543
+ text-align: center;
544
+ color: var(--ds-text-soft);
545
+ font-size: 0.82rem;
546
+ }
445
547
  /* 侧栏图标悬浮说明(fixed,避免被 sidebar overflow 裁切) */
446
548
  .sidebar-hover-tip {
447
549
  position: fixed;
@@ -1815,11 +1917,16 @@
1815
1917
  }
1816
1918
  .sidebar-icon-rail {
1817
1919
  gap: 7px;
1818
- padding: var(--layout-card-gap) 0;
1920
+ padding: var(--layout-card-gap) 0 12px;
1921
+ overflow-x: hidden;
1922
+ overflow-y: auto;
1923
+ flex: 1;
1924
+ min-height: 0;
1819
1925
  }
1820
1926
  .sidebar-nav-item {
1821
1927
  width: 32px;
1822
1928
  height: 32px;
1929
+ flex-shrink: 0;
1823
1930
  border-radius: 10px;
1824
1931
  }
1825
1932
  .sidebar-brand-ws {
@@ -2300,6 +2407,19 @@
2300
2407
  <path d="M11 7h2M12 10v4"/>
2301
2408
  </svg>
2302
2409
  </button>
2410
+ <button
2411
+ type="button"
2412
+ class="sidebar-nav-item"
2413
+ id="btnManageSchedules"
2414
+ data-add="schedules"
2415
+ title="定时任务"
2416
+ aria-label="定时任务"
2417
+ >
2418
+ <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">
2419
+ <circle cx="12" cy="12" r="10"/>
2420
+ <polyline points="12 6 12 12 16 14"/>
2421
+ </svg>
2422
+ </button>
2303
2423
  <button
2304
2424
  type="button"
2305
2425
  class="sidebar-nav-item"
@@ -2493,6 +2613,23 @@
2493
2613
  </div>
2494
2614
  </div>
2495
2615
 
2616
+ <div id="skillMdModal" class="agent-md-modal" aria-hidden="true">
2617
+ <div class="agent-md-modal-backdrop" id="skillMdModalBackdrop"></div>
2618
+ <div class="agent-md-modal-card" role="dialog" aria-modal="true" aria-labelledby="skillMdModalTitle">
2619
+ <div class="agent-md-modal-head">
2620
+ <h2 id="skillMdModalTitle">编辑 SKILL.md</h2>
2621
+ <button type="button" class="agent-md-modal-close" id="btnSkillMdModalClose" aria-label="关闭">
2622
+ &times;
2623
+ </button>
2624
+ </div>
2625
+ <textarea id="skillMdEditor" class="agent-md-editor" spellcheck="false" placeholder="加载中…"></textarea>
2626
+ <div class="agent-md-modal-foot">
2627
+ <button type="button" class="btn-agent-md-cancel" id="btnSkillMdCancel">取消</button>
2628
+ <button type="button" class="btn-primary" id="btnSkillMdSave">保存</button>
2629
+ </div>
2630
+ </div>
2631
+ </div>
2632
+
2496
2633
  <div id="toolFilesModal" class="agent-md-modal" aria-hidden="true">
2497
2634
  <div class="agent-md-modal-backdrop" id="toolFilesModalBackdrop"></div>
2498
2635
  <div class="agent-md-modal-card modal-unified" role="dialog" aria-modal="true" aria-labelledby="toolFilesModalTitle">
@@ -2757,6 +2894,75 @@
2757
2894
  </div>
2758
2895
  </div>
2759
2896
 
2897
+ <div id="scheduleManageModal" class="agent-md-modal" aria-hidden="true">
2898
+ <div class="agent-md-modal-backdrop" id="scheduleManageModalBackdrop"></div>
2899
+ <div id="scheduleManageModalCard" class="agent-md-modal-card modal-unified" role="dialog" aria-modal="true" aria-labelledby="scheduleManageModalTitle">
2900
+ <div class="agent-md-modal-head">
2901
+ <h2 id="scheduleManageModalTitle">定时任务</h2>
2902
+ <div class="modal-head-actions modal-head-actions--close-only">
2903
+ <button type="button" class="agent-md-modal-close" id="btnScheduleManageModalClose" aria-label="关闭">
2904
+ &times;
2905
+ </button>
2906
+ </div>
2907
+ </div>
2908
+ <div class="tool-files-body">
2909
+ <p id="scheduleManageMeta" class="tool-files-meta" style="margin: 0 0 0.5rem"></p>
2910
+ <div class="schedule-manage-toolbar">
2911
+ <button type="button" class="btn-system-settings" id="btnScheduleRefresh">刷新</button>
2912
+ <button type="button" class="btn-system-settings" id="btnScheduleCreateToggle">新建任务</button>
2913
+ <button type="button" class="btn-system-settings" id="btnScheduleGeelibPreset">Geelib 巡检</button>
2914
+ </div>
2915
+ <div id="scheduleCreateForm" class="schedule-create-form" hidden>
2916
+ <div class="schedule-create-row">
2917
+ <label for="scheduleSessionSelect">关联会话</label>
2918
+ <select id="scheduleSessionSelect"></select>
2919
+ </div>
2920
+ <div class="schedule-create-row">
2921
+ <label for="schedulePromptInput">Prompt</label>
2922
+ <textarea id="schedulePromptInput" placeholder="到期后发送给 agent 的提示词"></textarea>
2923
+ </div>
2924
+ <div class="schedule-create-row">
2925
+ <label>触发方式</label>
2926
+ <div style="display:flex;gap:0.75rem;align-items:center;font-size:0.78rem">
2927
+ <label><input type="radio" name="scheduleTriggerMode" value="delay" checked /> 相对分钟</label>
2928
+ <label><input type="radio" name="scheduleTriggerMode" value="cron" /> Cron</label>
2929
+ <label><input type="checkbox" id="scheduleRecurringInput" /> 循环</label>
2930
+ </div>
2931
+ </div>
2932
+ <div class="schedule-create-row" id="scheduleDelayRow">
2933
+ <label for="scheduleDelayMinutesInput">delayMinutes(1~10080)</label>
2934
+ <input id="scheduleDelayMinutesInput" type="number" min="1" max="10080" value="5" />
2935
+ </div>
2936
+ <div class="schedule-create-row" id="scheduleCronRow" hidden>
2937
+ <label for="scheduleCronInput">Cron(5 段,本地时区)</label>
2938
+ <input id="scheduleCronInput" type="text" placeholder="30 9 * * *" />
2939
+ </div>
2940
+ <div class="schedule-create-actions">
2941
+ <button type="button" class="btn-agent-md-cancel" id="btnScheduleCreateCancel">取消</button>
2942
+ <button type="button" class="btn-agent-md-save" id="btnScheduleCreateSubmit">创建</button>
2943
+ </div>
2944
+ </div>
2945
+ <div class="schedule-manage-table-wrap">
2946
+ <table class="schedule-manage-table">
2947
+ <thead>
2948
+ <tr>
2949
+ <th>ID</th>
2950
+ <th>会话</th>
2951
+ <th>Cron</th>
2952
+ <th>下次执行</th>
2953
+ <th>Prompt</th>
2954
+ <th>类型</th>
2955
+ <th>操作</th>
2956
+ </tr>
2957
+ </thead>
2958
+ <tbody id="scheduleTaskTableBody"></tbody>
2959
+ </table>
2960
+ <div id="scheduleManageEmpty" class="schedule-manage-empty" hidden>暂无定时任务</div>
2961
+ </div>
2962
+ </div>
2963
+ </div>
2964
+ </div>
2965
+
2760
2966
  <div id="sidebarHoverTip" class="sidebar-hover-tip" role="tooltip" hidden></div>
2761
2967
 
2762
2968
  <script src="https://cdn.jsdelivr.net/npm/marked@12.0.2/marked.min.js"></script>
@@ -2785,6 +2991,14 @@
2785
2991
  const btnAgentMdModalClose = $('btnAgentMdModalClose')
2786
2992
  const btnAgentMdCancel = $('btnAgentMdCancel')
2787
2993
  const btnAgentMdSave = $('btnAgentMdSave')
2994
+ const skillMdModal = $('skillMdModal')
2995
+ const skillMdModalTitle = $('skillMdModalTitle')
2996
+ const skillMdModalBackdrop = $('skillMdModalBackdrop')
2997
+ const skillMdEditor = $('skillMdEditor')
2998
+ const btnSkillMdModalClose = $('btnSkillMdModalClose')
2999
+ const btnSkillMdCancel = $('btnSkillMdCancel')
3000
+ const btnSkillMdSave = $('btnSkillMdSave')
3001
+ let skillMdEditingName = ''
2788
3002
  const agentEnvModal = $('agentEnvModal')
2789
3003
  const agentEnvModalCard = $('agentEnvModalCard')
2790
3004
  const agentEnvModalBackdrop = $('agentEnvModalBackdrop')
@@ -2838,6 +3052,25 @@
2838
3052
  const runGroupModalTitle = $('runGroupModalTitle')
2839
3053
  const runGroupModalBody = $('runGroupModalBody')
2840
3054
  const btnRunGroupModalClose = $('btnRunGroupModalClose')
3055
+ const scheduleManageModal = $('scheduleManageModal')
3056
+ const scheduleManageModalBackdrop = $('scheduleManageModalBackdrop')
3057
+ const scheduleManageMeta = $('scheduleManageMeta')
3058
+ const scheduleTaskTableBody = $('scheduleTaskTableBody')
3059
+ const scheduleManageEmpty = $('scheduleManageEmpty')
3060
+ const btnScheduleManageModalClose = $('btnScheduleManageModalClose')
3061
+ const btnScheduleRefresh = $('btnScheduleRefresh')
3062
+ const btnScheduleCreateToggle = $('btnScheduleCreateToggle')
3063
+ const btnScheduleGeelibPreset = $('btnScheduleGeelibPreset')
3064
+ const scheduleCreateForm = $('scheduleCreateForm')
3065
+ const scheduleSessionSelect = $('scheduleSessionSelect')
3066
+ const schedulePromptInput = $('schedulePromptInput')
3067
+ const scheduleDelayMinutesInput = $('scheduleDelayMinutesInput')
3068
+ const scheduleCronInput = $('scheduleCronInput')
3069
+ const scheduleRecurringInput = $('scheduleRecurringInput')
3070
+ const scheduleDelayRow = $('scheduleDelayRow')
3071
+ const scheduleCronRow = $('scheduleCronRow')
3072
+ const btnScheduleCreateCancel = $('btnScheduleCreateCancel')
3073
+ const btnScheduleCreateSubmit = $('btnScheduleCreateSubmit')
2841
3074
  const mcpPackageMeta = $('mcpPackageMeta')
2842
3075
  const mcpPackageList = $('mcpPackageList')
2843
3076
  const btnMcpPackageModalClose = $('btnMcpPackageModalClose')
@@ -3988,6 +4221,244 @@
3988
4221
  return u.toString()
3989
4222
  }
3990
4223
 
4224
+ function buildSchedulesUrl() {
4225
+ const u = new URL('/api/schedules', httpOriginForApi() + '/')
4226
+ u.searchParams.set('agent', currentAgentParam())
4227
+ return u.toString()
4228
+ }
4229
+
4230
+ function buildScheduleDeleteUrl(id) {
4231
+ const u = new URL('/api/schedules', httpOriginForApi() + '/')
4232
+ u.searchParams.set('agent', currentAgentParam())
4233
+ u.searchParams.set('id', id)
4234
+ return u.toString()
4235
+ }
4236
+
4237
+ /** 从已加载 session 列表解析会话标题 */
4238
+ function scheduleSessionLabel(sessionId) {
4239
+ const sid = String(sessionId || '')
4240
+ const sessions = window.__lastSessions
4241
+ if (Array.isArray(sessions)) {
4242
+ for (let i = 0; i < sessions.length; i++) {
4243
+ const s = sessions[i]
4244
+ if (s && s.sessionId === sid) {
4245
+ return sessionTitle(s)
4246
+ }
4247
+ }
4248
+ }
4249
+ return sid.slice(0, 8) + '…'
4250
+ }
4251
+
4252
+ function formatScheduleFireAt(ms) {
4253
+ if (typeof ms !== 'number' || !Number.isFinite(ms)) return '—'
4254
+ try {
4255
+ return new Date(ms).toLocaleString()
4256
+ } catch {
4257
+ return String(ms)
4258
+ }
4259
+ }
4260
+
4261
+ /** 填充新建任务时的 session 下拉 */
4262
+ function populateScheduleSessionSelect() {
4263
+ if (!scheduleSessionSelect) return
4264
+ const sessions = Array.isArray(window.__lastSessions) ? window.__lastSessions : []
4265
+ const currentSid = sessionIdInput.value.trim()
4266
+ scheduleSessionSelect.innerHTML = ''
4267
+ if (!sessions.length) {
4268
+ const opt = document.createElement('option')
4269
+ opt.value = currentSid
4270
+ opt.textContent = currentSid ? currentSid.slice(0, 8) + '…' : '(当前会话)'
4271
+ scheduleSessionSelect.appendChild(opt)
4272
+ return
4273
+ }
4274
+ for (let i = 0; i < sessions.length; i++) {
4275
+ const s = sessions[i]
4276
+ if (!s || !s.sessionId) continue
4277
+ const opt = document.createElement('option')
4278
+ opt.value = s.sessionId
4279
+ opt.textContent = sessionTitle(s) + ' (' + s.sessionId.slice(0, 8) + '…)'
4280
+ if (s.sessionId === currentSid) opt.selected = true
4281
+ scheduleSessionSelect.appendChild(opt)
4282
+ }
4283
+ }
4284
+
4285
+ /** Geelib 定时巡检快捷模板:/geelib poll,每分钟循环 */
4286
+ function applyGeelibSchedulePreset() {
4287
+ if (scheduleCreateForm) scheduleCreateForm.hidden = false
4288
+ populateScheduleSessionSelect()
4289
+ if (schedulePromptInput) schedulePromptInput.value = '/geelib poll'
4290
+ document.querySelectorAll('input[name="scheduleTriggerMode"]').forEach(function (el) {
4291
+ el.checked = el.value === 'cron'
4292
+ })
4293
+ if (scheduleDelayRow) scheduleDelayRow.hidden = true
4294
+ if (scheduleCronRow) scheduleCronRow.hidden = false
4295
+ if (scheduleCronInput) scheduleCronInput.value = '* * * * *'
4296
+ if (scheduleRecurringInput) scheduleRecurringInput.checked = true
4297
+ }
4298
+
4299
+ /** 渲染定时任务表格 */
4300
+ function renderScheduleTaskTable(tasks, timezone) {
4301
+ if (!scheduleTaskTableBody || !scheduleManageEmpty) return
4302
+ scheduleTaskTableBody.innerHTML = ''
4303
+ const list = Array.isArray(tasks) ? tasks : []
4304
+ scheduleManageEmpty.hidden = list.length > 0
4305
+ for (let i = 0; i < list.length; i++) {
4306
+ const task = list[i]
4307
+ if (!task || !task.id) continue
4308
+ const tr = document.createElement('tr')
4309
+ const tdId = document.createElement('td')
4310
+ tdId.textContent = task.id
4311
+ const tdSession = document.createElement('td')
4312
+ const sessionBtn = document.createElement('button')
4313
+ sessionBtn.type = 'button'
4314
+ sessionBtn.className = 'schedule-manage-session-link'
4315
+ sessionBtn.textContent = scheduleSessionLabel(task.sessionId)
4316
+ sessionBtn.title = task.sessionId
4317
+ sessionBtn.addEventListener('click', function () {
4318
+ closeScheduleManageModal()
4319
+ switchToSession(task.sessionId)
4320
+ })
4321
+ tdSession.appendChild(sessionBtn)
4322
+ const tdCron = document.createElement('td')
4323
+ tdCron.textContent = task.cron || '—'
4324
+ const tdNext = document.createElement('td')
4325
+ tdNext.textContent = formatScheduleFireAt(task.nextFireAt)
4326
+ const tdPrompt = document.createElement('td')
4327
+ tdPrompt.className = 'schedule-manage-prompt'
4328
+ tdPrompt.textContent = task.prompt || ''
4329
+ const tdType = document.createElement('td')
4330
+ tdType.textContent = task.recurring ? '循环' : '一次性'
4331
+ const tdAction = document.createElement('td')
4332
+ const delBtn = document.createElement('button')
4333
+ delBtn.type = 'button'
4334
+ delBtn.className = 'btn-system-settings'
4335
+ delBtn.textContent = '删除'
4336
+ delBtn.addEventListener('click', function () {
4337
+ void deleteScheduleTask(task.id)
4338
+ })
4339
+ tdAction.appendChild(delBtn)
4340
+ tr.appendChild(tdId)
4341
+ tr.appendChild(tdSession)
4342
+ tr.appendChild(tdCron)
4343
+ tr.appendChild(tdNext)
4344
+ tr.appendChild(tdPrompt)
4345
+ tr.appendChild(tdType)
4346
+ tr.appendChild(tdAction)
4347
+ scheduleTaskTableBody.appendChild(tr)
4348
+ }
4349
+ if (scheduleManageMeta) {
4350
+ scheduleManageMeta.textContent =
4351
+ '时区: ' + (timezone || 'local') + ' · 共 ' + list.length + ' 个任务'
4352
+ }
4353
+ }
4354
+
4355
+ /** 拉取 agent 全部定时任务 */
4356
+ async function loadScheduleTasks() {
4357
+ const res = await fetch(buildSchedulesUrl())
4358
+ const body = await res.json()
4359
+ if (!res.ok) {
4360
+ throw new Error(body.message || body.error || res.statusText)
4361
+ }
4362
+ renderScheduleTaskTable(body.tasks, body.timezone)
4363
+ return body
4364
+ }
4365
+
4366
+ /** 创建定时任务 */
4367
+ async function createScheduleTask() {
4368
+ if (!scheduleSessionSelect || !schedulePromptInput) return
4369
+ const sessionId = scheduleSessionSelect.value.trim()
4370
+ const prompt = schedulePromptInput.value.trim()
4371
+ if (!sessionId) {
4372
+ window.alert('请选择关联会话')
4373
+ return
4374
+ }
4375
+ if (!prompt) {
4376
+ window.alert('请填写 Prompt')
4377
+ return
4378
+ }
4379
+ const modeEl = document.querySelector('input[name="scheduleTriggerMode"]:checked')
4380
+ const mode = modeEl ? modeEl.value : 'delay'
4381
+ const payload = {
4382
+ sessionId: sessionId,
4383
+ prompt: prompt,
4384
+ recurring: !!(scheduleRecurringInput && scheduleRecurringInput.checked),
4385
+ }
4386
+ if (mode === 'cron') {
4387
+ const cron = scheduleCronInput ? scheduleCronInput.value.trim() : ''
4388
+ if (!cron) {
4389
+ window.alert('请填写 Cron 表达式')
4390
+ return
4391
+ }
4392
+ payload.cron = cron
4393
+ } else {
4394
+ const delay = scheduleDelayMinutesInput
4395
+ ? Number(scheduleDelayMinutesInput.value)
4396
+ : NaN
4397
+ if (!Number.isFinite(delay) || delay < 1) {
4398
+ window.alert('delayMinutes 必须是 >= 1 的整数')
4399
+ return
4400
+ }
4401
+ payload.delayMinutes = Math.floor(delay)
4402
+ }
4403
+ const res = await fetch(buildSchedulesUrl(), {
4404
+ method: 'POST',
4405
+ headers: { 'Content-Type': 'application/json; charset=utf-8' },
4406
+ body: JSON.stringify(payload),
4407
+ })
4408
+ const body = await res.json()
4409
+ if (!res.ok) {
4410
+ throw new Error(body.message || body.error || res.statusText)
4411
+ }
4412
+ if (scheduleCreateForm) scheduleCreateForm.hidden = true
4413
+ if (schedulePromptInput) schedulePromptInput.value = ''
4414
+ await loadScheduleTasks()
4415
+ }
4416
+
4417
+ /** 删除定时任务 */
4418
+ async function deleteScheduleTask(id) {
4419
+ if (!window.confirm('确定删除定时任务 ' + id + '?')) return
4420
+ const res = await fetch(buildScheduleDeleteUrl(id), { method: 'DELETE' })
4421
+ const body = await res.json()
4422
+ if (!res.ok) {
4423
+ window.alert('删除失败: ' + (body.message || body.error || res.statusText))
4424
+ return
4425
+ }
4426
+ await loadScheduleTasks()
4427
+ }
4428
+
4429
+ function closeScheduleManageModal() {
4430
+ if (!scheduleManageModal) return
4431
+ scheduleManageModal.classList.remove('is-open')
4432
+ scheduleManageModal.setAttribute('aria-hidden', 'true')
4433
+ document.body.style.overflow = ''
4434
+ if (scheduleCreateForm) scheduleCreateForm.hidden = true
4435
+ }
4436
+
4437
+ /** 打开定时任务管理弹窗 */
4438
+ async function openScheduleManageModal() {
4439
+ if (!scheduleManageModal) return
4440
+ scheduleManageModal.classList.add('is-open')
4441
+ scheduleManageModal.setAttribute('aria-hidden', 'false')
4442
+ document.body.style.overflow = 'hidden'
4443
+ populateScheduleSessionSelect()
4444
+ if (scheduleTaskTableBody) {
4445
+ scheduleTaskTableBody.innerHTML =
4446
+ '<tr><td colspan="7" style="padding:1rem;text-align:center;color:#8892a8">加载中…</td></tr>'
4447
+ }
4448
+ try {
4449
+ await loadSessions()
4450
+ populateScheduleSessionSelect()
4451
+ await loadScheduleTasks()
4452
+ } catch (e) {
4453
+ if (scheduleTaskTableBody) {
4454
+ scheduleTaskTableBody.innerHTML =
4455
+ '<tr><td colspan="7" style="padding:1rem;color:#c0392b">加载失败: ' +
4456
+ String(e) +
4457
+ '</td></tr>'
4458
+ }
4459
+ }
4460
+ }
4461
+
3991
4462
  function renderPendingPromptsList(items) {
3992
4463
  if (!pendingPromptsListEl || !pendingPromptsBarEl) return
3993
4464
  pendingPromptsCache = Array.isArray(items) ? items : []
@@ -4181,6 +4652,13 @@
4181
4652
  return u.toString()
4182
4653
  }
4183
4654
 
4655
+ function buildBaseSkillMdUrl(skillName) {
4656
+ const u = new URL('/api/skills/base-skill-md', httpOriginForApi() + '/')
4657
+ u.searchParams.set('agent', currentAgentParam())
4658
+ u.searchParams.set('name', skillName)
4659
+ return u.toString()
4660
+ }
4661
+
4184
4662
  function buildSkillInstalledListUrl() {
4185
4663
  const u = new URL('/api/skills/installed-list', httpOriginForApi() + '/')
4186
4664
  u.searchParams.set('agent', currentAgentParam())
@@ -6762,6 +7240,16 @@
6762
7240
  renderSkillRows()
6763
7241
  })
6764
7242
  actions.appendChild(toggleBtn)
7243
+ if (!canDelete) {
7244
+ const editBtn = document.createElement('button')
7245
+ editBtn.type = 'button'
7246
+ editBtn.className = 'btn-picker-action'
7247
+ editBtn.textContent = '编辑'
7248
+ editBtn.addEventListener('click', function () {
7249
+ openSkillMdModal(id)
7250
+ })
7251
+ actions.appendChild(editBtn)
7252
+ }
6765
7253
  if (canDelete) {
6766
7254
  const exportBtn = document.createElement('button')
6767
7255
  exportBtn.type = 'button'
@@ -7089,6 +7577,16 @@
7089
7577
  const btn = ev.target && ev.target.closest ? ev.target.closest('[data-add]') : null
7090
7578
  if (!btn) return
7091
7579
  const k = btn.getAttribute('data-add')
7580
+ if (k === 'schedules') {
7581
+ ev.preventDefault()
7582
+ ev.stopPropagation()
7583
+ const items = sidebarDrawersEl.querySelectorAll('.sidebar-nav-item')
7584
+ for (let i = 0; i < items.length; i++) {
7585
+ items[i].classList.toggle('is-active', items[i] === btn)
7586
+ }
7587
+ void openScheduleManageModal()
7588
+ return
7589
+ }
7092
7590
  if (k === 'tools' || k === 'mcp' || k === 'skills' || k === 'agentTeams') {
7093
7591
  ev.preventDefault()
7094
7592
  ev.stopPropagation()
@@ -7197,6 +7695,50 @@
7197
7695
  })
7198
7696
  }
7199
7697
 
7698
+ if (btnScheduleManageModalClose) {
7699
+ btnScheduleManageModalClose.addEventListener('click', closeScheduleManageModal)
7700
+ }
7701
+ if (scheduleManageModalBackdrop) {
7702
+ scheduleManageModalBackdrop.addEventListener('click', closeScheduleManageModal)
7703
+ }
7704
+ if (btnScheduleRefresh) {
7705
+ btnScheduleRefresh.addEventListener('click', function () {
7706
+ void loadScheduleTasks().catch(function (e) {
7707
+ window.alert('刷新失败: ' + e)
7708
+ })
7709
+ })
7710
+ }
7711
+ if (btnScheduleCreateToggle && scheduleCreateForm) {
7712
+ btnScheduleCreateToggle.addEventListener('click', function () {
7713
+ scheduleCreateForm.hidden = !scheduleCreateForm.hidden
7714
+ if (!scheduleCreateForm.hidden) populateScheduleSessionSelect()
7715
+ })
7716
+ }
7717
+ if (btnScheduleGeelibPreset) {
7718
+ btnScheduleGeelibPreset.addEventListener('click', function () {
7719
+ applyGeelibSchedulePreset()
7720
+ })
7721
+ }
7722
+ if (btnScheduleCreateCancel && scheduleCreateForm) {
7723
+ btnScheduleCreateCancel.addEventListener('click', function () {
7724
+ scheduleCreateForm.hidden = true
7725
+ })
7726
+ }
7727
+ if (btnScheduleCreateSubmit) {
7728
+ btnScheduleCreateSubmit.addEventListener('click', function () {
7729
+ void createScheduleTask().catch(function (e) {
7730
+ window.alert('创建失败: ' + e)
7731
+ })
7732
+ })
7733
+ }
7734
+ document.querySelectorAll('input[name="scheduleTriggerMode"]').forEach(function (el) {
7735
+ el.addEventListener('change', function () {
7736
+ const useCron = el.value === 'cron' && el.checked
7737
+ if (scheduleDelayRow) scheduleDelayRow.hidden = useCron
7738
+ if (scheduleCronRow) scheduleCronRow.hidden = !useCron
7739
+ })
7740
+ })
7741
+
7200
7742
  function closeAgentMdModal() {
7201
7743
  if (!agentMdModal) return
7202
7744
  agentMdModal.classList.remove('is-open')
@@ -7204,6 +7746,78 @@
7204
7746
  document.body.style.overflow = ''
7205
7747
  }
7206
7748
 
7749
+ function closeSkillMdModal() {
7750
+ if (!skillMdModal) return
7751
+ skillMdModal.classList.remove('is-open')
7752
+ skillMdModal.setAttribute('aria-hidden', 'true')
7753
+ document.body.style.overflow = ''
7754
+ skillMdEditingName = ''
7755
+ }
7756
+
7757
+ function openSkillMdModal(skillName) {
7758
+ if (!skillMdModal || !skillMdEditor || !skillMdModalTitle) return
7759
+ skillMdEditingName = String(skillName || '').trim()
7760
+ if (!skillMdEditingName) return
7761
+ skillMdModal.classList.add('is-open')
7762
+ skillMdModal.setAttribute('aria-hidden', 'false')
7763
+ document.body.style.overflow = 'hidden'
7764
+ skillMdEditor.value = ''
7765
+ skillMdEditor.placeholder = '加载中…'
7766
+ skillMdModalTitle.textContent = '编辑 SKILL.md · /' + skillMdEditingName
7767
+ fetch(buildBaseSkillMdUrl(skillMdEditingName))
7768
+ .then(function (r) {
7769
+ return r.json().then(function (body) {
7770
+ return { r: r, body: body }
7771
+ })
7772
+ })
7773
+ .then(function (x) {
7774
+ if (!x.r.ok) {
7775
+ skillMdEditor.placeholder = ''
7776
+ const msg = x.body.message || x.body.error || x.r.statusText || '请求失败'
7777
+ window.alert('加载 SKILL.md 失败:' + msg)
7778
+ closeSkillMdModal()
7779
+ return
7780
+ }
7781
+ skillMdEditor.value =
7782
+ typeof x.body.content === 'string' ? x.body.content : ''
7783
+ skillMdEditor.placeholder = 'Markdown 源码…'
7784
+ })
7785
+ .catch(function (e) {
7786
+ window.alert('加载 SKILL.md 失败: ' + e)
7787
+ closeSkillMdModal()
7788
+ })
7789
+ }
7790
+
7791
+ async function saveSkillMd() {
7792
+ if (!skillMdEditor || !btnSkillMdSave || !skillMdEditingName) return
7793
+ btnSkillMdSave.disabled = true
7794
+ try {
7795
+ const r = await fetch(buildBaseSkillMdUrl(skillMdEditingName), {
7796
+ method: 'PUT',
7797
+ headers: { 'Content-Type': 'application/json; charset=utf-8' },
7798
+ body: JSON.stringify({ content: String(skillMdEditor.value) }),
7799
+ })
7800
+ const body = await r.json().catch(function () {
7801
+ return {}
7802
+ })
7803
+ if (!r.ok) {
7804
+ window.alert('保存失败:' + (body.message || body.error || r.statusText))
7805
+ return
7806
+ }
7807
+ closeSkillMdModal()
7808
+ setStatus('SKILL.md 已保存', serverReady ? 'ready' : '')
7809
+ restartCurrentSessionSubprocessWithReason('save-base-skill-md')
7810
+ if (typeof refreshSkillPickerRows === 'function') {
7811
+ void refreshSkillPickerRows()
7812
+ }
7813
+ window.alert('SKILL.md 已保存,并已重启当前 session 子进程。')
7814
+ } catch (e) {
7815
+ window.alert('保存失败: ' + e)
7816
+ } finally {
7817
+ btnSkillMdSave.disabled = false
7818
+ }
7819
+ }
7820
+
7207
7821
  function closeAgentEnvModal() {
7208
7822
  if (!agentEnvModal) return
7209
7823
  agentEnvModal.classList.remove('is-open')
@@ -7942,6 +8556,20 @@
7942
8556
  void saveAgentMd()
7943
8557
  })
7944
8558
  }
8559
+ if (btnSkillMdModalClose) {
8560
+ btnSkillMdModalClose.addEventListener('click', closeSkillMdModal)
8561
+ }
8562
+ if (btnSkillMdCancel) {
8563
+ btnSkillMdCancel.addEventListener('click', closeSkillMdModal)
8564
+ }
8565
+ if (skillMdModalBackdrop) {
8566
+ skillMdModalBackdrop.addEventListener('click', closeSkillMdModal)
8567
+ }
8568
+ if (btnSkillMdSave) {
8569
+ btnSkillMdSave.addEventListener('click', function () {
8570
+ void saveSkillMd()
8571
+ })
8572
+ }
7945
8573
  if (btnToolFilesModalClose) {
7946
8574
  btnToolFilesModalClose.addEventListener('click', closeToolFilesModal)
7947
8575
  }
@@ -7971,6 +8599,10 @@
7971
8599
  closeAgentMdModal()
7972
8600
  return
7973
8601
  }
8602
+ if (skillMdModal && skillMdModal.classList.contains('is-open')) {
8603
+ closeSkillMdModal()
8604
+ return
8605
+ }
7974
8606
  if (agentEnvModal && agentEnvModal.classList.contains('is-open')) {
7975
8607
  closeAgentEnvModal()
7976
8608
  return