@auto-ai/agent 2.1.93 → 2.1.95

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 (50) hide show
  1. package/bin/agent.js +0 -0
  2. package/dist/404/index.html +1 -1
  3. package/dist/404.html +1 -1
  4. package/dist/_next/static/chunks/24ad0472395a5554.js +1 -0
  5. package/dist/_next/static/chunks/{ce0cac88dd992956.css → 6a750155591ba201.css} +1 -1
  6. package/dist/agent-office.html +580 -1
  7. package/dist/index.html +1 -1
  8. package/dist/index.txt +6 -6
  9. package/dist/manage/about/index.html +2 -2
  10. package/dist/manage/about/index.txt +3 -3
  11. package/dist/manage/add-account/basic/index.html +2 -2
  12. package/dist/manage/add-account/basic/index.txt +3 -3
  13. package/dist/manage/add-account/index.html +2 -2
  14. package/dist/manage/add-account/index.txt +3 -3
  15. package/dist/manage/add-account/prompt/index.html +2 -2
  16. package/dist/manage/add-account/prompt/index.txt +3 -3
  17. package/dist/manage/agent-teams/index.html +2 -2
  18. package/dist/manage/agent-teams/index.txt +3 -3
  19. package/dist/manage/env/index.html +2 -2
  20. package/dist/manage/env/index.txt +3 -3
  21. package/dist/manage/general/index.html +2 -2
  22. package/dist/manage/general/index.txt +3 -3
  23. package/dist/manage/index.html +1 -1
  24. package/dist/manage/index.txt +3 -3
  25. package/dist/manage/mcp/index.html +2 -2
  26. package/dist/manage/mcp/index.txt +3 -3
  27. package/dist/manage/permissions/index.html +2 -2
  28. package/dist/manage/permissions/index.txt +3 -3
  29. package/dist/manage/skills/index.html +2 -2
  30. package/dist/manage/skills/index.txt +3 -3
  31. package/dist/manage/task/index.html +1 -1
  32. package/dist/manage/task/index.txt +3 -3
  33. package/dist/manage/teams/index.html +1 -1
  34. package/dist/manage/teams/index.txt +3 -3
  35. package/dist/manage/tools/index.html +2 -2
  36. package/dist/manage/tools/index.txt +3 -3
  37. package/dist/slash-command-ui-patch.css +49 -0
  38. package/dist/slash-command-ui-patch.js +101 -0
  39. package/dist/ws-test.html +111 -2
  40. package/package.json +6 -6
  41. package/dist/_next/static/chunks/091dc4a67d911a93.js +0 -1
  42. package/dist/agent-office/accents.js +0 -28
  43. package/dist/agent-office/api.js +0 -142
  44. package/dist/agent-office/list.js +0 -79
  45. package/dist/agent-office/main.js +0 -38
  46. package/dist/agent-office/officeController.js +0 -13
  47. package/dist/agent-office/ui.js +0 -264
  48. /package/dist/_next/static/{nFW2vz8zx3Bz5bWQhlf33 → q0is0IhxOAG7ogFx9qQFk}/_buildManifest.js +0 -0
  49. /package/dist/_next/static/{nFW2vz8zx3Bz5bWQhlf33 → q0is0IhxOAG7ogFx9qQFk}/_clientMiddlewareManifest.json +0 -0
  50. /package/dist/_next/static/{nFW2vz8zx3Bz5bWQhlf33 → q0is0IhxOAG7ogFx9qQFk}/_ssgManifest.js +0 -0
@@ -302,6 +302,585 @@
302
302
  <div id="officeToast" role="status" aria-live="polite"></div>
303
303
  </div>
304
304
 
305
- <script type="module" src="/agent-office/main.js"></script>
305
+ <script>
306
+ ;(function () {
307
+ 'use strict'
308
+
309
+ /** 列表/写操作 API 上下文:固定使用已存在的默认 agent */
310
+ const DEFAULT_CONTEXT_AGENT = 'qihoo'
311
+
312
+ /** 解析 API 基址:支持 ?apiBase= 或当前页面 origin(与 ws-test 一致) */
313
+ function httpOriginForApi() {
314
+ try {
315
+ const fromQuery = new URLSearchParams(window.location.search).get('apiBase')
316
+ if (fromQuery && String(fromQuery).trim()) {
317
+ return String(fromQuery).trim().replace(/\/$/, '')
318
+ }
319
+ } catch {
320
+ /* ignore */
321
+ }
322
+ return window.location.origin
323
+ }
324
+
325
+ /** 构建 GET/POST /api/agents 列表地址 */
326
+ function buildAgentsListUrl(contextAgent) {
327
+ const u = new URL('/api/agents', httpOriginForApi() + '/')
328
+ u.searchParams.set('agent', contextAgent || DEFAULT_CONTEXT_AGENT)
329
+ return u.toString()
330
+ }
331
+
332
+ /** 构建单个 agent 的 REST 地址 */
333
+ function buildAgentItemUrl(id, contextAgent) {
334
+ const u = new URL(
335
+ '/api/agents/' + encodeURIComponent(String(id || '').trim()),
336
+ httpOriginForApi() + '/',
337
+ )
338
+ u.searchParams.set('agent', contextAgent || DEFAULT_CONTEXT_AGENT)
339
+ return u.toString()
340
+ }
341
+
342
+ /** 校验新建 agent id:字母数字下划线中划线,1~64 */
343
+ function isValidAgentIdInput(id) {
344
+ return /^[a-zA-Z0-9_-]{1,64}$/.test(String(id || '').trim())
345
+ }
346
+
347
+ /**
348
+ * 基于已有 agent.json 构造 PATCH config,仅更新 whentouse;
349
+ * effort 为 null 时不写入,避免覆盖服务端默认值。
350
+ */
351
+ function buildAgentConfigPatch(baseConfig, whentouse) {
352
+ const c = baseConfig && typeof baseConfig === 'object' ? baseConfig : {}
353
+ const env = c.env && typeof c.env === 'object' && !Array.isArray(c.env) ? c.env : {}
354
+ const patch = {
355
+ tools: Array.isArray(c.tools) ? c.tools.map(String) : [],
356
+ disallowedTools: Array.isArray(c.disallowedTools)
357
+ ? c.disallowedTools.map(String)
358
+ : [],
359
+ mcpServers: Array.isArray(c.mcpServers) ? c.mcpServers.map(String) : [],
360
+ skills: Array.isArray(c.skills) ? c.skills.map(String) : [],
361
+ agentTeams: Array.isArray(c.agentTeams) ? c.agentTeams.map(String) : [],
362
+ model: typeof c.model === 'string' ? c.model : '',
363
+ background: c.background === true,
364
+ isolation: typeof c.isolation === 'string' ? c.isolation : '',
365
+ whentouse: typeof whentouse === 'string' ? whentouse : '',
366
+ env,
367
+ }
368
+ if (typeof c.effort === 'string' || typeof c.effort === 'number') {
369
+ patch.effort = c.effort
370
+ }
371
+ return patch
372
+ }
373
+
374
+ /** 拉取 agent 列表 */
375
+ async function fetchAgentsList(contextAgent) {
376
+ const r = await fetch(buildAgentsListUrl(contextAgent))
377
+ const body = await r.json().catch(() => ({}))
378
+ if (!r.ok) {
379
+ throw new Error(body.message || body.error || r.statusText)
380
+ }
381
+ return Array.isArray(body.agents) ? body.agents : []
382
+ }
383
+
384
+ /** 拉取单个 agent 详情(含 config、prompt) */
385
+ async function fetchAgentDetail(id, contextAgent) {
386
+ const r = await fetch(buildAgentItemUrl(id, contextAgent))
387
+ const body = await r.json().catch(() => ({}))
388
+ if (!r.ok) {
389
+ throw new Error(body.message || body.error || r.statusText)
390
+ }
391
+ return body.agent || { id }
392
+ }
393
+
394
+ /** 删除 agent;默认 agent qihoo 不可删 */
395
+ async function deleteAgent(id, contextAgent) {
396
+ const agentId = String(id || '').trim()
397
+ if (!agentId) throw new Error('缺少 agent id')
398
+ if (agentId === DEFAULT_CONTEXT_AGENT) {
399
+ throw new Error('默认 Agent(' + DEFAULT_CONTEXT_AGENT + ')不可删除')
400
+ }
401
+ const r = await fetch(buildAgentItemUrl(agentId, contextAgent), { method: 'DELETE' })
402
+ const body = await r.json().catch(() => ({}))
403
+ if (!r.ok) {
404
+ throw new Error(body.message || body.error || r.statusText)
405
+ }
406
+ }
407
+
408
+ /**
409
+ * 保存 agent:新建走 POST + PATCH whentouse;编辑走 PATCH prompt + config。
410
+ */
411
+ async function saveAgent(params) {
412
+ const { id, whentouse, prompt, isEdit, baseConfig, contextAgent } = params
413
+ if (isEdit) {
414
+ const patchRes = await fetch(buildAgentItemUrl(id, contextAgent), {
415
+ method: 'PATCH',
416
+ headers: { 'content-type': 'application/json; charset=utf-8' },
417
+ body: JSON.stringify({
418
+ prompt,
419
+ config: buildAgentConfigPatch(baseConfig, whentouse),
420
+ }),
421
+ })
422
+ const patchBody = await patchRes.json().catch(() => ({}))
423
+ if (!patchRes.ok) {
424
+ throw new Error(patchBody.message || patchBody.error || patchRes.statusText)
425
+ }
426
+ return id
427
+ }
428
+
429
+ const createRes = await fetch(buildAgentsListUrl(contextAgent), {
430
+ method: 'POST',
431
+ headers: { 'content-type': 'application/json; charset=utf-8' },
432
+ body: JSON.stringify({ name: id, prompt }),
433
+ })
434
+ const createBody = await createRes.json().catch(() => ({}))
435
+ if (!createRes.ok) {
436
+ throw new Error(createBody.message || createBody.error || createRes.statusText)
437
+ }
438
+
439
+ const cfgBody = await fetchAgentDetail(id, contextAgent)
440
+ const baseCfg =
441
+ cfgBody.config && typeof cfgBody.config === 'object' ? cfgBody.config : null
442
+ const patchRes = await fetch(buildAgentItemUrl(id, contextAgent), {
443
+ method: 'PATCH',
444
+ headers: { 'content-type': 'application/json; charset=utf-8' },
445
+ body: JSON.stringify({
446
+ config: buildAgentConfigPatch(baseCfg, whentouse),
447
+ }),
448
+ })
449
+ const patchBody = await patchRes.json().catch(() => ({}))
450
+ if (!patchRes.ok) {
451
+ throw new Error(patchBody.message || patchBody.error || patchRes.statusText)
452
+ }
453
+ return id
454
+ }
455
+
456
+ const AGENT_ACCENT_COLORS = [
457
+ '#22d3c5',
458
+ '#4da3ff',
459
+ '#8b5cf6',
460
+ '#e84855',
461
+ '#f5c518',
462
+ '#c5e84c',
463
+ ]
464
+
465
+ const KNOWN_ACCENTS = {
466
+ dev: '#22d3c5',
467
+ edr: '#4da3ff',
468
+ qihoo: '#8b5cf6',
469
+ }
470
+
471
+ /** 根据 agent id 分配列表左侧色带 */
472
+ function accentColorForId(id) {
473
+ const key = String(id || '').trim().toLowerCase()
474
+ if (KNOWN_ACCENTS[key]) return KNOWN_ACCENTS[key]
475
+ const s = String(id || 'a')
476
+ let h = 0
477
+ for (let i = 0; i < s.length; i++) {
478
+ h = (h + s.charCodeAt(i) * 17) % AGENT_ACCENT_COLORS.length
479
+ }
480
+ return AGENT_ACCENT_COLORS[h]
481
+ }
482
+
483
+ /** 列表页选中状态:仅维护当前 agent id */
484
+ class OfficeController {
485
+ constructor() {
486
+ this.selectedId = null
487
+ this.onSelect = null
488
+ }
489
+
490
+ /** 选中或取消选中,并通知侧栏 UI */
491
+ selectAgent(id) {
492
+ this.selectedId = id || null
493
+ if (this.onSelect) this.onSelect(this.selectedId)
494
+ }
495
+ }
496
+
497
+ function truncateListDesc(text, max) {
498
+ const s = String(text || '').replace(/\s+/g, ' ').trim()
499
+ if (!s) return '暂无使用说明'
500
+ return s.length <= max ? s : s.slice(0, max - 1) + '…'
501
+ }
502
+
503
+ /** Agent 列表 DOM 渲染 */
504
+ class AgentList {
505
+ constructor(container, onPick) {
506
+ this.container = container
507
+ this.onPick = onPick
508
+ }
509
+
510
+ render(agents, selectedId) {
511
+ if (!this.container) return
512
+ this.container.innerHTML = ''
513
+
514
+ if (!agents.length) {
515
+ const empty = document.createElement('div')
516
+ empty.className = 'agent-list-empty'
517
+ empty.textContent = '暂无 Agent,点击右上角「新建 Agent」创建'
518
+ this.container.appendChild(empty)
519
+ return
520
+ }
521
+
522
+ const ul = document.createElement('ul')
523
+ ul.className = 'agent-list'
524
+ ul.setAttribute('role', 'list')
525
+
526
+ for (let i = 0; i < agents.length; i++) {
527
+ const row = agents[i]
528
+ const id = String(row.id || '').trim()
529
+ if (!id) continue
530
+
531
+ const li = document.createElement('li')
532
+ const btn = document.createElement('button')
533
+ btn.type = 'button'
534
+ btn.className =
535
+ 'agent-list-item' + (selectedId === id ? ' is-selected' : '')
536
+ btn.setAttribute('aria-pressed', selectedId === id ? 'true' : 'false')
537
+
538
+ const accent = document.createElement('span')
539
+ accent.className = 'agent-list-accent'
540
+ accent.style.background = accentColorForId(id)
541
+
542
+ const body = document.createElement('span')
543
+ body.className = 'agent-list-body'
544
+
545
+ const title = document.createElement('span')
546
+ title.className = 'agent-list-id'
547
+ title.textContent = id
548
+
549
+ const desc = document.createElement('span')
550
+ desc.className = 'agent-list-desc'
551
+ desc.textContent = truncateListDesc(row.whentouse, 80)
552
+
553
+ body.appendChild(title)
554
+ body.appendChild(desc)
555
+
556
+ const arrow = document.createElement('span')
557
+ arrow.className = 'agent-list-arrow'
558
+ arrow.textContent = '›'
559
+
560
+ btn.appendChild(accent)
561
+ btn.appendChild(body)
562
+ btn.appendChild(arrow)
563
+
564
+ btn.addEventListener('click', () => {
565
+ if (this.onPick) this.onPick(id)
566
+ })
567
+
568
+ li.appendChild(btn)
569
+ ul.appendChild(li)
570
+ }
571
+
572
+ this.container.appendChild(ul)
573
+ }
574
+ }
575
+
576
+ /** 列表 + 侧栏 CRUD 与 URL ?agent= 同步 */
577
+ class OfficeUI {
578
+ constructor(root, controller, list, hooks) {
579
+ this.root = root
580
+ this.controller = controller
581
+ this.list = list
582
+ this.hooks = hooks || {}
583
+ this.contextAgent = DEFAULT_CONTEXT_AGENT
584
+ this.agents = []
585
+ this.editingId = null
586
+ this.baseConfig = null
587
+ this.mode = 'idle'
588
+
589
+ this.panelEl = root.querySelector('#officePanel')
590
+ this.panelTitleEl = root.querySelector('#officePanelTitle')
591
+ this.panelMetaEl = root.querySelector('#officePanelMeta')
592
+ this.formEl = root.querySelector('#officeAgentForm')
593
+ this.idInput = root.querySelector('#officeAgentId')
594
+ this.whenInput = root.querySelector('#officeAgentWhen')
595
+ this.promptInput = root.querySelector('#officeAgentPrompt')
596
+ this.btnNew = root.querySelector('#btnOfficeNewAgent')
597
+ this.btnSave = root.querySelector('#btnOfficeSave')
598
+ this.btnDelete = root.querySelector('#btnOfficeDelete')
599
+ this.btnWorkbench = root.querySelector('#btnOfficeWorkbench')
600
+ this.btnClose = root.querySelector('#btnOfficePanelClose')
601
+ this.toastEl = root.querySelector('#officeToast')
602
+
603
+ this.bindEvents()
604
+ this.hidePanel()
605
+ }
606
+
607
+ bindEvents() {
608
+ if (this.btnNew) {
609
+ this.btnNew.addEventListener('click', () => this.showCreateForm())
610
+ }
611
+ if (this.btnClose) {
612
+ this.btnClose.addEventListener('click', () => {
613
+ this.hidePanel()
614
+ this.controller.selectAgent(null)
615
+ this.clearUrlAgentParam()
616
+ })
617
+ }
618
+ if (this.btnSave) {
619
+ this.btnSave.addEventListener('click', () => void this.submitForm())
620
+ }
621
+ if (this.btnDelete) {
622
+ this.btnDelete.addEventListener('click', () => void this.handleDelete())
623
+ }
624
+ if (this.btnWorkbench) {
625
+ this.btnWorkbench.addEventListener('click', () => {
626
+ const id =
627
+ this.editingId || (this.idInput ? this.idInput.value.trim() : '')
628
+ if (!id) return
629
+ window.location.href =
630
+ '/ws-test.html?agent=' + encodeURIComponent(id)
631
+ })
632
+ }
633
+ }
634
+
635
+ showToast(msg, isError) {
636
+ if (!this.toastEl) return
637
+ this.toastEl.textContent = msg
638
+ this.toastEl.classList.toggle('is-error', !!isError)
639
+ this.toastEl.classList.add('is-visible')
640
+ clearTimeout(this._toastTimer)
641
+ this._toastTimer = setTimeout(() => {
642
+ this.toastEl.classList.remove('is-visible')
643
+ }, 3200)
644
+ }
645
+
646
+ hidePanel() {
647
+ if (this.panelEl) this.panelEl.classList.remove('is-open')
648
+ this.editingId = null
649
+ this.baseConfig = null
650
+ this.mode = 'idle'
651
+ this.list.render(this.agents, null)
652
+ }
653
+
654
+ showPanelForAgent(id) {
655
+ if (!this.panelEl) return
656
+ this.panelEl.classList.add('is-open')
657
+ this.list.render(this.agents, id)
658
+ void this.loadAgentIntoForm(id)
659
+ }
660
+
661
+ showCreateForm() {
662
+ if (!this.panelEl || !this.formEl) return
663
+ this.panelEl.classList.add('is-open')
664
+ this.mode = 'create'
665
+ this.editingId = null
666
+ this.baseConfig = null
667
+ if (this.panelTitleEl) this.panelTitleEl.textContent = '新建 Agent'
668
+ if (this.panelMetaEl) {
669
+ this.panelMetaEl.textContent = '创建后可从列表进入工作台'
670
+ }
671
+ if (this.idInput) {
672
+ this.idInput.value = ''
673
+ this.idInput.readOnly = false
674
+ }
675
+ if (this.whenInput) this.whenInput.value = ''
676
+ if (this.promptInput) this.promptInput.value = ''
677
+ if (this.btnDelete) this.btnDelete.disabled = true
678
+ if (this.btnWorkbench) this.btnWorkbench.disabled = true
679
+ this.list.render(this.agents, null)
680
+ }
681
+
682
+ async loadAgentIntoForm(id) {
683
+ const agentId = String(id || '').trim()
684
+ if (!agentId) return
685
+ this.mode = 'edit'
686
+ this.editingId = agentId
687
+ if (this.panelTitleEl) this.panelTitleEl.textContent = 'Agent · ' + agentId
688
+ if (this.panelMetaEl) this.panelMetaEl.textContent = '加载中…'
689
+ if (this.btnDelete) {
690
+ this.btnDelete.disabled = agentId === DEFAULT_CONTEXT_AGENT
691
+ }
692
+ if (this.btnWorkbench) this.btnWorkbench.disabled = false
693
+ try {
694
+ const agent = await fetchAgentDetail(agentId, this.contextAgent)
695
+ this.baseConfig =
696
+ agent.config && typeof agent.config === 'object' ? agent.config : null
697
+ if (this.idInput) {
698
+ this.idInput.value = agentId
699
+ this.idInput.readOnly = true
700
+ }
701
+ const whentouse =
702
+ agent.config && typeof agent.config.whentouse === 'string'
703
+ ? agent.config.whentouse
704
+ : typeof agent.whentouse === 'string'
705
+ ? agent.whentouse
706
+ : ''
707
+ if (this.whenInput) this.whenInput.value = whentouse
708
+ if (this.promptInput) {
709
+ this.promptInput.value =
710
+ typeof agent.prompt === 'string' ? agent.prompt : ''
711
+ }
712
+ if (this.panelMetaEl) {
713
+ this.panelMetaEl.textContent =
714
+ '共 ' +
715
+ String(this.agents.length) +
716
+ ' 个 Agent · 上下文:' +
717
+ this.contextAgent
718
+ }
719
+ } catch (e) {
720
+ if (this.panelMetaEl) this.panelMetaEl.textContent = '加载失败'
721
+ this.showToast('加载 Agent 失败: ' + String(e), true)
722
+ }
723
+ }
724
+
725
+ async refreshAgents() {
726
+ this.agents = await fetchAgentsList(this.contextAgent)
727
+ this.list.render(this.agents, this.controller.selectedId)
728
+ if (this.hooks.onAgentsLoaded) this.hooks.onAgentsLoaded(this.agents)
729
+ return this.agents
730
+ }
731
+
732
+ async submitForm() {
733
+ const isEdit = this.mode === 'edit' && !!this.editingId
734
+ const id = isEdit
735
+ ? this.editingId
736
+ : this.idInput
737
+ ? this.idInput.value.trim()
738
+ : ''
739
+ const whentouse = this.whenInput ? this.whenInput.value : ''
740
+ const prompt = this.promptInput ? this.promptInput.value : ''
741
+ if (!isEdit && !isValidAgentIdInput(id)) {
742
+ this.showToast(
743
+ 'Agent ID 仅支持字母、数字、下划线和中划线,长度 1~64',
744
+ true,
745
+ )
746
+ return
747
+ }
748
+ try {
749
+ await saveAgent({
750
+ id,
751
+ whentouse,
752
+ prompt,
753
+ isEdit,
754
+ baseConfig: this.baseConfig,
755
+ contextAgent: this.contextAgent,
756
+ })
757
+ await this.refreshAgents()
758
+ this.mode = 'edit'
759
+ this.editingId = id
760
+ if (this.idInput) {
761
+ this.idInput.value = id
762
+ this.idInput.readOnly = true
763
+ }
764
+ if (this.btnDelete) {
765
+ this.btnDelete.disabled = id === DEFAULT_CONTEXT_AGENT
766
+ }
767
+ if (this.btnWorkbench) this.btnWorkbench.disabled = false
768
+ if (this.panelTitleEl) this.panelTitleEl.textContent = 'Agent · ' + id
769
+ this.controller.selectAgent(id)
770
+ this.syncUrlAgentParam(id)
771
+ this.showToast(isEdit ? '已保存' : '已创建')
772
+ } catch (e) {
773
+ this.showToast((isEdit ? '保存失败: ' : '创建失败: ') + String(e), true)
774
+ }
775
+ }
776
+
777
+ async handleDelete() {
778
+ const id = this.editingId
779
+ if (!id || id === DEFAULT_CONTEXT_AGENT) return
780
+ if (!window.confirm('确定删除 Agent「' + id + '」?此操作不可恢复。')) {
781
+ return
782
+ }
783
+ try {
784
+ await deleteAgent(id, this.contextAgent)
785
+ await this.refreshAgents()
786
+ this.hidePanel()
787
+ this.clearUrlAgentParam()
788
+ this.showToast('已删除')
789
+ } catch (e) {
790
+ this.showToast('删除失败: ' + String(e), true)
791
+ }
792
+ }
793
+
794
+ /** 支持通过 ?agent= 深链打开侧栏 */
795
+ async handleUrlAgentParam() {
796
+ let param = ''
797
+ try {
798
+ param = new URLSearchParams(window.location.search).get('agent') || ''
799
+ } catch {
800
+ return
801
+ }
802
+ const id = String(param).trim()
803
+ if (!id) return
804
+
805
+ const exists = this.agents.some((a) => String(a.id) === id)
806
+ if (!exists) {
807
+ this.showToast('agent 不存在,请先创建', true)
808
+ this.clearUrlAgentParam()
809
+ return
810
+ }
811
+
812
+ this.controller.selectAgent(id)
813
+ this.showPanelForAgent(id)
814
+ }
815
+
816
+ syncUrlAgentParam(id) {
817
+ try {
818
+ const u = new URL(window.location.href)
819
+ u.searchParams.set('agent', id)
820
+ window.history.replaceState(null, '', u.pathname + u.search)
821
+ } catch {
822
+ /* ignore */
823
+ }
824
+ }
825
+
826
+ clearUrlAgentParam() {
827
+ try {
828
+ const u = new URL(window.location.href)
829
+ u.searchParams.delete('agent')
830
+ const qs = u.searchParams.toString()
831
+ window.history.replaceState(null, '', u.pathname + (qs ? '?' + qs : ''))
832
+ } catch {
833
+ /* ignore */
834
+ }
835
+ }
836
+
837
+ onSelect(id) {
838
+ if (!id) {
839
+ this.hidePanel()
840
+ this.clearUrlAgentParam()
841
+ return
842
+ }
843
+ this.showPanelForAgent(id)
844
+ this.syncUrlAgentParam(id)
845
+ }
846
+ }
847
+
848
+ /** Agent 列表页入口 */
849
+ async function main() {
850
+ const app = document.getElementById('officeApp')
851
+ const listRoot = document.getElementById('agentListRoot')
852
+ if (!app || !listRoot) return
853
+
854
+ const controller = new OfficeController()
855
+ const list = new AgentList(listRoot, (id) => controller.selectAgent(id))
856
+
857
+ const ui = new OfficeUI(app, controller, list, {
858
+ onAgentsLoaded(agents) {
859
+ const subtitle = document.getElementById('officeSubtitle')
860
+ if (subtitle) {
861
+ subtitle.textContent =
862
+ String(agents.length) + ' 个 Agent · 点击列表项管理'
863
+ }
864
+ list.render(agents, controller.selectedId)
865
+ },
866
+ })
867
+
868
+ controller.onSelect = (id) => ui.onSelect(id)
869
+
870
+ try {
871
+ await ui.refreshAgents()
872
+ await ui.handleUrlAgentParam()
873
+ } catch (e) {
874
+ ui.showToast('加载 Agent 失败: ' + String(e), true)
875
+ const subtitle = document.getElementById('officeSubtitle')
876
+ if (subtitle) subtitle.textContent = '加载失败'
877
+ }
878
+ }
879
+
880
+ main().catch((e) => {
881
+ console.error(e)
882
+ })
883
+ })()
884
+ </script>
306
885
  </body>
307
886
  </html>