@lsamien/yaovi 0.1.0 → 0.1.2
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/build-info.json +44 -3
- package/desktop/main.mjs +18 -9
- package/dist/assets/{AboutDialog-BW25cB-W.js → AboutDialog-CJ9tCjSs.js} +2 -2
- package/dist/assets/AboutDialog-CJ9tCjSs.js.map +1 -0
- package/dist/assets/{BotAutomationsView-BoK2R918.js → BotAutomationsView-CsoI3js3.js} +2 -2
- package/dist/assets/{BotAutomationsView-BoK2R918.js.map → BotAutomationsView-CsoI3js3.js.map} +1 -1
- package/dist/assets/{BotControlSettingsPanel-BbhD2eC0.js → BotControlSettingsPanel-DIuBZlLu.js} +2 -2
- package/dist/assets/{BotControlSettingsPanel-BbhD2eC0.js.map → BotControlSettingsPanel-DIuBZlLu.js.map} +1 -1
- package/dist/assets/{BotPluginsDialog-DjwFw-lt.js → BotPluginsDialog-BsGszDMH.js} +2 -2
- package/dist/assets/{BotPluginsDialog-DjwFw-lt.js.map → BotPluginsDialog-BsGszDMH.js.map} +1 -1
- package/dist/assets/{BotSettingsPanel-DLmnL6pH.js → BotSettingsPanel-j3ThYgt2.js} +3 -3
- package/dist/assets/{BotSettingsPanel-DLmnL6pH.js.map → BotSettingsPanel-j3ThYgt2.js.map} +1 -1
- package/dist/assets/{ComputerPanel-CRIF1YEd.js → ComputerPanel-DdlgOm-B.js} +2 -2
- package/dist/assets/{ComputerPanel-CRIF1YEd.js.map → ComputerPanel-DdlgOm-B.js.map} +1 -1
- package/dist/assets/{ComputerViewerView-CizYWH2R.js → ComputerViewerView-I3adPI6O.js} +2 -2
- package/dist/assets/{ComputerViewerView-CizYWH2R.js.map → ComputerViewerView-I3adPI6O.js.map} +1 -1
- package/dist/assets/ConversationsView-CBhzg-9w.css +1 -0
- package/dist/assets/{ConversationsView-1igFR9VY.js → ConversationsView-CxVFk5sQ.js} +73 -73
- package/dist/assets/ConversationsView-CxVFk5sQ.js.map +1 -0
- package/dist/assets/{DevicePairingDialog-orOS4xqu.js → DevicePairingDialog-C307ARt-.js} +2 -2
- package/dist/assets/{DevicePairingDialog-orOS4xqu.js.map → DevicePairingDialog-C307ARt-.js.map} +1 -1
- package/dist/assets/{LocalVmSettingsPanel-DzM--Lpg.js → LocalVmSettingsPanel-Zs7CiXdf.js} +2 -2
- package/dist/assets/{LocalVmSettingsPanel-DzM--Lpg.js.map → LocalVmSettingsPanel-Zs7CiXdf.js.map} +1 -1
- package/dist/assets/{ProviderLoginDialog-Bw5KVMfi.js → ProviderLoginDialog-D3mqdAlo.js} +2 -2
- package/dist/assets/{ProviderLoginDialog-Bw5KVMfi.js.map → ProviderLoginDialog-D3mqdAlo.js.map} +1 -1
- package/dist/assets/{RunnerSettingsPanel-B-fwuBEs.js → RunnerSettingsPanel-DjMGnXGP.js} +2 -2
- package/dist/assets/{RunnerSettingsPanel-B-fwuBEs.js.map → RunnerSettingsPanel-DjMGnXGP.js.map} +1 -1
- package/dist/assets/{StandaloneDialog-7GkhtRlT.js → StandaloneDialog-BXCK22Dx.js} +2 -2
- package/dist/assets/{StandaloneDialog-7GkhtRlT.js.map → StandaloneDialog-BXCK22Dx.js.map} +1 -1
- package/dist/assets/{UpdateCheckDialog-DYiM4xBv.js → UpdateCheckDialog-DAY0VEQm.js} +2 -2
- package/dist/assets/{UpdateCheckDialog-DYiM4xBv.js.map → UpdateCheckDialog-DAY0VEQm.js.map} +1 -1
- package/dist/assets/{UsageView-D1cjS1hy.js → UsageView-DNwG8LAx.js} +2 -2
- package/dist/assets/{UsageView-D1cjS1hy.js.map → UsageView-DNwG8LAx.js.map} +1 -1
- package/dist/assets/{WorkspaceKnowledgePanel-DcGdLRS1.js → WorkspaceKnowledgePanel-hy_IkIJI.js} +2 -2
- package/dist/assets/{WorkspaceKnowledgePanel-DcGdLRS1.js.map → WorkspaceKnowledgePanel-hy_IkIJI.js.map} +1 -1
- package/dist/assets/{WorkspaceRoutinesPanel-DLntimKs.js → WorkspaceRoutinesPanel-B7PkBP7x.js} +2 -2
- package/dist/assets/{WorkspaceRoutinesPanel-DLntimKs.js.map → WorkspaceRoutinesPanel-B7PkBP7x.js.map} +1 -1
- package/dist/assets/{WorkstreamsView-DMoeV8Eu.js → WorkstreamsView-BeE2TRXK.js} +2 -2
- package/dist/assets/{WorkstreamsView-DMoeV8Eu.js.map → WorkstreamsView-BeE2TRXK.js.map} +1 -1
- package/dist/assets/{index-D0pMYnOi.js → index-D11cgXI9.js} +3 -3
- package/dist/assets/{index-D0pMYnOi.js.map → index-D11cgXI9.js.map} +1 -1
- package/dist/assets/{pdf-BCisgslg.js → pdf-BjTcV6As.js} +2 -2
- package/dist/assets/{pdf-BCisgslg.js.map → pdf-BjTcV6As.js.map} +1 -1
- package/dist/index.html +1 -1
- package/dist-server/server/botControl.js +13 -1
- package/dist-server/server/desktopEnvironments.js +10 -9
- package/dist-server/server/desktopHostProtocol.js +1 -1
- package/dist-server/server/harness/agentRuntime.js +22 -8
- package/dist-server/server/workspaceDialoguePolicy.js +3 -1
- package/dist-server/server/workspaceKnowledge.js +25 -16
- package/dist-server/server/workspaceMemoryContext.js +75 -19
- package/dist-server/server/workspacePrompt.js +11 -4
- package/dist-server/server/workspaceRuntime.js +35 -13
- package/dist-server/shared/botEnvironment.js +10 -4
- package/dist-server/shared/fileTransferEndpoint.mjs +5 -5
- package/dist-server/shared/hostPaths.mjs +14 -4
- package/package.json +4 -3
- package/release.json +3 -3
- package/runtime/hermes/hermes_state_messages.py +17 -0
- package/runtime/worker.py +34 -1
- package/dist/assets/AboutDialog-BW25cB-W.js.map +0 -1
- package/dist/assets/ConversationsView-1igFR9VY.js.map +0 -1
- package/dist/assets/ConversationsView-h94_iPtv.css +0 -1
- package/dist-server/server/harness/context.js +0 -88
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BotControlSettingsPanel-BbhD2eC0.js","names":[],"sources":["../../src/client/components/app/ManagedBotProfilePanel.vue","../../src/client/components/app/ManagedBotProfilePanel.vue","../../src/client/components/app/BotControlSettingsPanel.vue","../../src/client/components/app/BotControlSettingsPanel.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport BotProfileDialog from '@/components/workspace/BotProfileDialog.vue'\nimport AgentRuntimePanel from './AgentRuntimePanel.vue'\nimport { apiRequest } from '@/api/client'\nimport type { WorkspaceAgent, WorkspaceConversation } from '@shared/workspace'\nimport { goalStatus } from '@shared/collaborationPresentation'\nimport type { BotHomeData } from '@shared/botHome'\nimport type { BotModelSettings } from '@shared/botModelSettings'\nimport type { SettingsPage } from './settingsNavigation'\nconst props = defineProps<{ agent: WorkspaceAgent; agents: WorkspaceAgent[]; permissionsEnforced?: boolean }>()\nconst emit = defineEmits<{ close: []; changed: []; navigate: [page: SettingsPage]; 'dirty-change': [value: boolean]; 'busy-change': [value: boolean] }>()\nconst agent = ref(props.agent), conversations = ref<WorkspaceConversation[]>([]), knowledgeEnabled = ref(false), busy = ref(false), childBusy = ref(false), dirty = ref(false), error = ref('')\nconst tab = ref<'profile' | 'skills' | 'execution' | 'records'>('profile'), records = ref<BotHomeData>(), recordsLoading = ref(false)\nconst profile = ref<InstanceType<typeof BotProfileDialog>>()\nconst draft = computed(() => ({ ...agent.value, canManageTeam: agent.value.canManageTeam ?? true, canCollaborate: agent.value.canCollaborate ?? true, memoryEnabled: agent.value.memoryEnabled ?? true }))\nconst conversationId = computed(() => conversations.value.find(item => item.kind === 'direct' && item.memberIds[0] === agent.value.id)?.id)\nconst rows = computed(() => [...(records.value?.activities ?? []), ...(records.value?.reviews ?? [])].sort((a, b) => (b.at ?? 0) - (a.at ?? 0)))\nconst recordStatus = (value: string) => /[\\u3400-\\u9fff]/.test(value) ? value : ({ completed: '已完成', stopped: '已停止', stopping: '正在停止', approved: '已允许', denied: '已拒绝', expired: '已过期', uncertain: '需要核对', sending: '投递中', sent: '已投递' } as Record<string, string>)[value] ?? goalStatus(value)\nlet alive = true\nwatch(dirty, value => emit('dirty-change', value))\nwatch(() => busy.value || childBusy.value, value => emit('busy-change', value))\nfunction beforeClose() { return !busy.value && !childBusy.value && (!dirty.value || window.confirm('放弃此 Bot 未保存的配置?')) }\nfunction select(value: typeof tab.value) { if (value === tab.value || !beforeClose()) return; dirty.value = false; tab.value = value; error.value = ''; if (value === 'records') void loadRecords() }\nasync function loadRecords() { recordsLoading.value = true; error.value = ''; try { const value = await apiRequest<BotHomeData>(`/api/app/agents/${encodeURIComponent(agent.value.id)}/home`); if (alive) records.value = value } catch (cause) { if (alive) error.value = cause instanceof Error ? cause.message : '读取运行记录失败' } finally { if (alive) recordsLoading.value = false } }\nasync function save(value: InstanceType<typeof BotProfileDialog>['$props']['draft'] & { expectedRevision?: number; modelSettings?: BotModelSettings }) {\n if (busy.value) return\n busy.value = true; error.value = ''\n const payload = { name: value.name, avatar: value.avatar, instructions: value.instructions, description: value.description?.trim() ?? '', job: value.job?.trim() || null, antiJobs: value.antiJobs?.length ? value.antiJobs : null, voice: value.voice || null, voiceCustom: value.voice === 'custom' ? value.voiceCustom?.trim() || null : null, actBias: value.actBias || null, memoryEnabled: value.memoryEnabled, canCollaborate: value.canCollaborate, canManageTeam: value.canManageTeam, approvalPolicy: value.approvalPolicy ?? 'ask', expectedRevision: value.expectedRevision ?? agent.value.revision, ...(value.modelSettings ? { modelSettings: value.modelSettings } : {}) }\n try {\n type Result = { agent?: WorkspaceAgent; confirmationRequired?: boolean; confirmationMessage?: string; confirmationTarget?: string }\n let result = await apiRequest<Result>(`/api/app/agents/${encodeURIComponent(agent.value.id)}`, { method: 'PATCH', body: JSON.parse(JSON.stringify(payload)) })\n if (!alive) return\n if (result.confirmationRequired) {\n if (!result.confirmationTarget) throw new Error('模型确认信息不完整,请重新读取。')\n if (!window.confirm(result.confirmationMessage || '确认使用此模型?')) return\n result = await apiRequest<Result>(`/api/app/agents/${encodeURIComponent(agent.value.id)}`, { method: 'PATCH', body: JSON.parse(JSON.stringify({ ...payload, confirmedModel: result.confirmationTarget })) })\n }\n if (!alive) return\n if (!result.agent) throw new Error('保存尚未确认,请重新读取后核对。')\n agent.value = result.agent; profile.value?.markSaved?.(result.agent); dirty.value = false; emit('changed')\n } catch (cause) { if (alive) error.value = cause instanceof Error ? cause.message : '保存失败' }\n finally { if (alive) busy.value = false }\n}\nonMounted(async () => { try { const [roster, capabilities] = await Promise.all([apiRequest<{ conversations: WorkspaceConversation[] }>('/api/app/conversations'), apiRequest<{ features: string[] }>('/api/app/capabilities')]); if (alive) { conversations.value = roster.conversations; knowledgeEnabled.value = capabilities.features.includes('bot-file-memory-v1') } } catch (cause) { if (alive) error.value = cause instanceof Error ? cause.message : '加载 Bot 配置失败' } })\nonBeforeUnmount(() => { alive = false })\ndefineExpose({ beforeClose })\n</script>\n<template>\n <section class=\"managed-bot\" :aria-label=\"`${agent.name} 的设置`\">\n <header><button :disabled=\"busy || childBusy\" @click=\"beforeClose() && emit('close')\">返回我的 Bot</button><strong>{{ agent.name }}</strong><small>只修改此 Bot</small></header>\n <nav aria-label=\"Bot 配置页面\"><button v-for=\"item in ([['profile','资料与权限'],['skills','技能'],['execution','执行设置'],['records','运行记录']] as const)\" :key=\"item[0]\" :aria-pressed=\"tab === item[0]\" :disabled=\"busy || childBusy\" @click=\"select(item[0])\">{{ item[1] }}</button></nav>\n <p v-if=\"error && tab !== 'profile'\" role=\"alert\">{{ error }}</p>\n <BotProfileDialog v-if=\"tab === 'profile'\" ref=\"profile\" embedded permission-control is-admin :agent=\"agent\" :draft=\"draft\" :agents=\"agents\" :conversations=\"conversations\" :conversation-id=\"conversationId\" :knowledge-enabled=\"knowledgeEnabled\" :busy=\"busy\" :error=\"error\" @save=\"save\" @close=\"emit('close')\" @changed=\"emit('changed')\" @dirty-change=\"dirty = $event\" @busy-change=\"childBusy = $event\" @manage-models=\"emit('navigate', 'system-models')\" @manage-permissions=\"emit('navigate', 'workspace-permissions')\" />\n <AgentRuntimePanel v-else-if=\"tab === 'skills' || tab === 'execution'\" :key=\"tab\" :section=\"tab\" :target-bot-id=\"agent.id\" :permission-control=\"permissionsEnforced\" @dirty-change=\"dirty = $event\" @busy-change=\"childBusy = $event\" />\n <section v-else class=\"bot-records\" aria-label=\"运行记录\"><button :disabled=\"recordsLoading\" @click=\"loadRecords\">刷新运行记录</button><p v-if=\"recordsLoading\" role=\"status\">正在读取…</p><p v-else-if=\"!rows.length\">暂无运行记录。</p><details v-for=\"record in rows\" :key=\"record.id\"><summary>{{ record.title }} · {{ recordStatus(record.status) }}</summary><small v-if=\"record.at\">{{ new Date(record.at).toLocaleString('zh-CN') }}</small><p>{{ record.content || record.summary || '没有附加内容。' }}</p></details></section>\n </section>\n</template>\n<style scoped>\n.managed-bot{min-width:0;display:grid;gap:20px}.managed-bot>header,.managed-bot>nav{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.managed-bot>header strong{flex:1}.managed-bot small{font-size:12px;color:var(--text-secondary)}.managed-bot>nav{border-bottom:1px solid var(--line);padding-bottom:12px}.managed-bot button{min-height:44px;border:1px solid var(--line);border-radius:9px;background:var(--surface);color:inherit;padding:9px 14px;font:inherit;cursor:pointer}.managed-bot button[aria-pressed=true]{background:var(--surface-soft);font-weight:600}.managed-bot button:disabled{opacity:.5}.managed-bot button:focus-visible,.bot-records summary:focus-visible{outline:2px solid var(--accent);outline-offset:2px}.managed-bot :deep(.bot-profile__scroll){overflow:visible}.managed-bot :deep(.bot-profile__footer){position:sticky;bottom:-24px;background:var(--surface);z-index:2}.bot-records{display:grid;gap:16px}.bot-records summary{cursor:pointer;min-height:44px;line-height:1.7}.bot-records p{font-size:13px;line-height:1.8;white-space:pre-wrap;overflow-wrap:anywhere}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport BotProfileDialog from '@/components/workspace/BotProfileDialog.vue'\nimport AgentRuntimePanel from './AgentRuntimePanel.vue'\nimport { apiRequest } from '@/api/client'\nimport type { WorkspaceAgent, WorkspaceConversation } from '@shared/workspace'\nimport { goalStatus } from '@shared/collaborationPresentation'\nimport type { BotHomeData } from '@shared/botHome'\nimport type { BotModelSettings } from '@shared/botModelSettings'\nimport type { SettingsPage } from './settingsNavigation'\nconst props = defineProps<{ agent: WorkspaceAgent; agents: WorkspaceAgent[]; permissionsEnforced?: boolean }>()\nconst emit = defineEmits<{ close: []; changed: []; navigate: [page: SettingsPage]; 'dirty-change': [value: boolean]; 'busy-change': [value: boolean] }>()\nconst agent = ref(props.agent), conversations = ref<WorkspaceConversation[]>([]), knowledgeEnabled = ref(false), busy = ref(false), childBusy = ref(false), dirty = ref(false), error = ref('')\nconst tab = ref<'profile' | 'skills' | 'execution' | 'records'>('profile'), records = ref<BotHomeData>(), recordsLoading = ref(false)\nconst profile = ref<InstanceType<typeof BotProfileDialog>>()\nconst draft = computed(() => ({ ...agent.value, canManageTeam: agent.value.canManageTeam ?? true, canCollaborate: agent.value.canCollaborate ?? true, memoryEnabled: agent.value.memoryEnabled ?? true }))\nconst conversationId = computed(() => conversations.value.find(item => item.kind === 'direct' && item.memberIds[0] === agent.value.id)?.id)\nconst rows = computed(() => [...(records.value?.activities ?? []), ...(records.value?.reviews ?? [])].sort((a, b) => (b.at ?? 0) - (a.at ?? 0)))\nconst recordStatus = (value: string) => /[\\u3400-\\u9fff]/.test(value) ? value : ({ completed: '已完成', stopped: '已停止', stopping: '正在停止', approved: '已允许', denied: '已拒绝', expired: '已过期', uncertain: '需要核对', sending: '投递中', sent: '已投递' } as Record<string, string>)[value] ?? goalStatus(value)\nlet alive = true\nwatch(dirty, value => emit('dirty-change', value))\nwatch(() => busy.value || childBusy.value, value => emit('busy-change', value))\nfunction beforeClose() { return !busy.value && !childBusy.value && (!dirty.value || window.confirm('放弃此 Bot 未保存的配置?')) }\nfunction select(value: typeof tab.value) { if (value === tab.value || !beforeClose()) return; dirty.value = false; tab.value = value; error.value = ''; if (value === 'records') void loadRecords() }\nasync function loadRecords() { recordsLoading.value = true; error.value = ''; try { const value = await apiRequest<BotHomeData>(`/api/app/agents/${encodeURIComponent(agent.value.id)}/home`); if (alive) records.value = value } catch (cause) { if (alive) error.value = cause instanceof Error ? cause.message : '读取运行记录失败' } finally { if (alive) recordsLoading.value = false } }\nasync function save(value: InstanceType<typeof BotProfileDialog>['$props']['draft'] & { expectedRevision?: number; modelSettings?: BotModelSettings }) {\n if (busy.value) return\n busy.value = true; error.value = ''\n const payload = { name: value.name, avatar: value.avatar, instructions: value.instructions, description: value.description?.trim() ?? '', job: value.job?.trim() || null, antiJobs: value.antiJobs?.length ? value.antiJobs : null, voice: value.voice || null, voiceCustom: value.voice === 'custom' ? value.voiceCustom?.trim() || null : null, actBias: value.actBias || null, memoryEnabled: value.memoryEnabled, canCollaborate: value.canCollaborate, canManageTeam: value.canManageTeam, approvalPolicy: value.approvalPolicy ?? 'ask', expectedRevision: value.expectedRevision ?? agent.value.revision, ...(value.modelSettings ? { modelSettings: value.modelSettings } : {}) }\n try {\n type Result = { agent?: WorkspaceAgent; confirmationRequired?: boolean; confirmationMessage?: string; confirmationTarget?: string }\n let result = await apiRequest<Result>(`/api/app/agents/${encodeURIComponent(agent.value.id)}`, { method: 'PATCH', body: JSON.parse(JSON.stringify(payload)) })\n if (!alive) return\n if (result.confirmationRequired) {\n if (!result.confirmationTarget) throw new Error('模型确认信息不完整,请重新读取。')\n if (!window.confirm(result.confirmationMessage || '确认使用此模型?')) return\n result = await apiRequest<Result>(`/api/app/agents/${encodeURIComponent(agent.value.id)}`, { method: 'PATCH', body: JSON.parse(JSON.stringify({ ...payload, confirmedModel: result.confirmationTarget })) })\n }\n if (!alive) return\n if (!result.agent) throw new Error('保存尚未确认,请重新读取后核对。')\n agent.value = result.agent; profile.value?.markSaved?.(result.agent); dirty.value = false; emit('changed')\n } catch (cause) { if (alive) error.value = cause instanceof Error ? cause.message : '保存失败' }\n finally { if (alive) busy.value = false }\n}\nonMounted(async () => { try { const [roster, capabilities] = await Promise.all([apiRequest<{ conversations: WorkspaceConversation[] }>('/api/app/conversations'), apiRequest<{ features: string[] }>('/api/app/capabilities')]); if (alive) { conversations.value = roster.conversations; knowledgeEnabled.value = capabilities.features.includes('bot-file-memory-v1') } } catch (cause) { if (alive) error.value = cause instanceof Error ? cause.message : '加载 Bot 配置失败' } })\nonBeforeUnmount(() => { alive = false })\ndefineExpose({ beforeClose })\n</script>\n<template>\n <section class=\"managed-bot\" :aria-label=\"`${agent.name} 的设置`\">\n <header><button :disabled=\"busy || childBusy\" @click=\"beforeClose() && emit('close')\">返回我的 Bot</button><strong>{{ agent.name }}</strong><small>只修改此 Bot</small></header>\n <nav aria-label=\"Bot 配置页面\"><button v-for=\"item in ([['profile','资料与权限'],['skills','技能'],['execution','执行设置'],['records','运行记录']] as const)\" :key=\"item[0]\" :aria-pressed=\"tab === item[0]\" :disabled=\"busy || childBusy\" @click=\"select(item[0])\">{{ item[1] }}</button></nav>\n <p v-if=\"error && tab !== 'profile'\" role=\"alert\">{{ error }}</p>\n <BotProfileDialog v-if=\"tab === 'profile'\" ref=\"profile\" embedded permission-control is-admin :agent=\"agent\" :draft=\"draft\" :agents=\"agents\" :conversations=\"conversations\" :conversation-id=\"conversationId\" :knowledge-enabled=\"knowledgeEnabled\" :busy=\"busy\" :error=\"error\" @save=\"save\" @close=\"emit('close')\" @changed=\"emit('changed')\" @dirty-change=\"dirty = $event\" @busy-change=\"childBusy = $event\" @manage-models=\"emit('navigate', 'system-models')\" @manage-permissions=\"emit('navigate', 'workspace-permissions')\" />\n <AgentRuntimePanel v-else-if=\"tab === 'skills' || tab === 'execution'\" :key=\"tab\" :section=\"tab\" :target-bot-id=\"agent.id\" :permission-control=\"permissionsEnforced\" @dirty-change=\"dirty = $event\" @busy-change=\"childBusy = $event\" />\n <section v-else class=\"bot-records\" aria-label=\"运行记录\"><button :disabled=\"recordsLoading\" @click=\"loadRecords\">刷新运行记录</button><p v-if=\"recordsLoading\" role=\"status\">正在读取…</p><p v-else-if=\"!rows.length\">暂无运行记录。</p><details v-for=\"record in rows\" :key=\"record.id\"><summary>{{ record.title }} · {{ recordStatus(record.status) }}</summary><small v-if=\"record.at\">{{ new Date(record.at).toLocaleString('zh-CN') }}</small><p>{{ record.content || record.summary || '没有附加内容。' }}</p></details></section>\n </section>\n</template>\n<style scoped>\n.managed-bot{min-width:0;display:grid;gap:20px}.managed-bot>header,.managed-bot>nav{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.managed-bot>header strong{flex:1}.managed-bot small{font-size:12px;color:var(--text-secondary)}.managed-bot>nav{border-bottom:1px solid var(--line);padding-bottom:12px}.managed-bot button{min-height:44px;border:1px solid var(--line);border-radius:9px;background:var(--surface);color:inherit;padding:9px 14px;font:inherit;cursor:pointer}.managed-bot button[aria-pressed=true]{background:var(--surface-soft);font-weight:600}.managed-bot button:disabled{opacity:.5}.managed-bot button:focus-visible,.bot-records summary:focus-visible{outline:2px solid var(--accent);outline-offset:2px}.managed-bot :deep(.bot-profile__scroll){overflow:visible}.managed-bot :deep(.bot-profile__footer){position:sticky;bottom:-24px;background:var(--surface);z-index:2}.bot-records{display:grid;gap:16px}.bot-records summary{cursor:pointer;min-height:44px;line-height:1.7}.bot-records p{font-size:13px;line-height:1.8;white-space:pre-wrap;overflow-wrap:anywhere}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport { apiRequest } from '@/api/client'\nimport type { SettingsPage } from './settingsNavigation'\nimport type { WorkspaceAgent } from '@shared/workspace'\nimport type { BotControlState, BotPermissionRequest } from '@shared/botControl'\nimport PermissionSettingsPanel from './PermissionSettingsPanel.vue'\nimport ManagedBotProfilePanel from './ManagedBotProfilePanel.vue'\nimport MainBotSwitchDialog from '@/components/workspace/MainBotSwitchDialog.vue'\nconst props=defineProps<{page:'bots'|'permissions'|'requests';targetBotId?:string}>()\nconst emit=defineEmits<{changed:[];navigate:[SettingsPage];'dirty-change':[boolean];'busy-change':[boolean]}>()\nconst state=ref<BotControlState>(),agents=ref<WorkspaceAgent[]>([]),error=ref(''),busy=ref(false),selected=ref(props.targetBotId??''),switching=ref(''),mainId=ref('')\nconst selectedBot=computed(()=>agents.value.find(a=>a.id===selected.value)),pending=computed(()=>state.value?.requests.filter(r=>r.status==='pending')??[])\nlet alive=true,generation=0,timer:ReturnType<typeof setInterval>|undefined\nasync function load(){const own=++generation;try{const [control,roster]=await Promise.all([apiRequest<BotControlState>('/api/app/permissions/control'),apiRequest<{agents:WorkspaceAgent[]}>('/api/app/agents')]);if(alive&&own===generation){state.value=control;mainId.value=control.mainBotId??'';agents.value=roster.agents;error.value=''}}catch(e){if(alive&&own===generation)error.value=e instanceof Error?e.message:'读取失败'}}\nconst botName=(id?:string)=>agents.value.find(a=>a.id===id)?.name??id??'待确定'\nfunction executor(r:BotPermissionRequest){if(r.capability!=='tasks.delegate')return botName(r.agentId);const ids=r.resources.filter(s=>s.startsWith('peer:')).map(s=>s.slice(5)).filter(Boolean);return ids.length?ids.map(botName).join('、'):'待确定'}\nasync function respond(request:BotPermissionRequest,decision:'once'|'always'|'deny'){if(busy.value)return;busy.value=true;try{await apiRequest(`/api/app/approvals/${request.id}/respond`,{method:'POST',body:{decision,expectedRevision:request.revision}});await load();emit('changed')}catch(e){error.value=e instanceof Error?e.message:'处理失败'}finally{busy.value=false}}\nwatch(()=>props.targetBotId,id=>{if(id)selected.value=id})\nonMounted(()=>{void load();timer=setInterval(()=>{if(!busy.value)void load()},5000)})\nonBeforeUnmount(()=>{alive=false;generation++;clearInterval(timer)})\n</script>\n<template>\n <section class=\"control-settings\">\n <p v-if=\"error\" role=\"alert\" class=\"error\">{{ error }}<button type=\"button\" @click=\"load\">重新加载</button></p>\n <MainBotSwitchDialog v-if=\"switching\" :target-bot-id=\"switching\" @close=\"switching=''\" @changed=\"load();emit('changed')\" />\n <PermissionSettingsPanel v-if=\"page==='permissions'\" @changed=\"emit('changed')\" @dirty-change=\"emit('dirty-change',$event)\" @busy-change=\"emit('busy-change',$event)\" />\n <template v-else-if=\"page==='bots'\">\n <template v-if=\"selectedBot\">\n <ManagedBotProfilePanel :agent=\"selectedBot\" :agents=\"agents\" :permissions-enforced=\"true\" @close=\"selected=''\" @changed=\"load();emit('changed')\" @navigate=\"emit('navigate',$event)\" @dirty-change=\"emit('dirty-change',$event)\" @busy-change=\"emit('busy-change',$event)\" />\n <PermissionSettingsPanel kind=\"agents\" :target-id=\"selectedBot.id\" @changed=\"emit('changed')\" @dirty-change=\"emit('dirty-change',$event)\" @busy-change=\"emit('busy-change',$event)\" />\n </template>\n <template v-else>\n <section class=\"card\"><h3>主 Bot</h3><p>默认对话与工作安排的入口。切换身份不会改变任何 Bot 的权限。</p><label>选择主 Bot<select v-model=\"mainId\"><option value=\"\" disabled>请选择</option><option v-for=\"bot in agents.filter(a=>!a.archived&&!a.temporaryGoalId&&!a.remoteAgentId&&a.nodeId==='local')\" :key=\"bot.id\" :value=\"bot.id\">{{ bot.name }}</option></select></label><button type=\"button\" :disabled=\"!mainId||mainId===state?.mainBotId\" @click=\"switching=mainId\">确认切换</button></section>\n <section class=\"card\"><h3>我的 Bot</h3><p>默认使用服务器授权方式,也可为每个 Bot 独立选择授权方式和额外限制。</p><article v-for=\"bot in agents.filter(a=>!a.archived&&!a.temporaryGoalId)\" :key=\"bot.id\"><strong>{{ bot.name }}{{ bot.id===state?.mainBotId?' · 主 Bot':'' }}</strong><button type=\"button\" @click=\"selected=bot.id\">配置 Bot 与权限</button></article></section>\n </template>\n </template>\n <template v-else-if=\"page==='requests'\">\n <section class=\"card\"><h3>待确认操作 · {{ pending.length }}</h3><p v-if=\"!pending.length\">暂无需要确认的操作。</p><article v-for=\"request in pending\" :key=\"request.id\" class=\"request\"><strong>{{ agents.find(a=>a.id===request.agentId)?.name??'Bot' }}</strong><small>发起者:{{ botName(request.initiatorId??request.agentId) }}</small><small>实际执行者:{{ executor(request) }}</small><p>{{ request.message??request.reason }}</p><small>{{ request.toolId }} · {{ request.resources.join('、') }}</small><small v-if=\"request.originConversationId!==request.displayConversationId\">来自群任务,在执行 Bot 单聊中也可以处理。</small><div class=\"actions\"><button type=\"button\" :disabled=\"busy\" @click=\"respond(request,'deny')\">拒绝</button><button type=\"button\" :disabled=\"busy\" @click=\"respond(request,'once')\">允许一次</button><button v-if=\"!request.manualOnly\" type=\"button\" :disabled=\"busy\" @click=\"respond(request,'always')\">始终允许此类操作</button></div></article></section>\n <section class=\"card\"><h3>操作确认记录</h3><article v-for=\"request in state?.requests.filter(r=>r.status!=='pending')??[]\" :key=\"request.id\" class=\"request\"><strong>{{ ({approved:'已允许',denied:'已拒绝',expired:'已失效',pending:'待确认'})[request.status] }}</strong><small>发起者:{{ botName(request.initiatorId??request.agentId) }}</small><small>实际执行者:{{ executor(request) }}</small><p>{{ request.reason }}</p><small>{{ request.toolId }} · {{ request.resources.join('、') }}</small></article></section>\n </template>\n </section>\n</template>\n<style scoped>\n.control-settings,.card{display:grid;gap:18px;min-width:0;color:var(--text-primary);font-size:14px}.card{padding:20px;border:1px solid var(--line);border-radius:14px}h3,p{margin:0}p,small{line-height:1.7;color:var(--text-secondary);white-space:pre-wrap;overflow-wrap:anywhere}label{display:grid;gap:8px}article,.actions{display:flex;gap:12px;align-items:center;justify-content:space-between;flex-wrap:wrap}.request{display:grid;justify-content:stretch;padding-block:12px;border-top:1px solid var(--line)}button,select{min-height:44px;min-width:0;padding:10px 12px;border:1px solid var(--line);border-radius:9px;background:var(--surface);color:inherit;font:inherit}button{cursor:pointer}button:disabled{opacity:.5;cursor:default}.error{color:var(--danger)}button:focus-visible,select:focus-visible{outline:2px solid var(--accent);outline-offset:3px}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport { apiRequest } from '@/api/client'\nimport type { SettingsPage } from './settingsNavigation'\nimport type { WorkspaceAgent } from '@shared/workspace'\nimport type { BotControlState, BotPermissionRequest } from '@shared/botControl'\nimport PermissionSettingsPanel from './PermissionSettingsPanel.vue'\nimport ManagedBotProfilePanel from './ManagedBotProfilePanel.vue'\nimport MainBotSwitchDialog from '@/components/workspace/MainBotSwitchDialog.vue'\nconst props=defineProps<{page:'bots'|'permissions'|'requests';targetBotId?:string}>()\nconst emit=defineEmits<{changed:[];navigate:[SettingsPage];'dirty-change':[boolean];'busy-change':[boolean]}>()\nconst state=ref<BotControlState>(),agents=ref<WorkspaceAgent[]>([]),error=ref(''),busy=ref(false),selected=ref(props.targetBotId??''),switching=ref(''),mainId=ref('')\nconst selectedBot=computed(()=>agents.value.find(a=>a.id===selected.value)),pending=computed(()=>state.value?.requests.filter(r=>r.status==='pending')??[])\nlet alive=true,generation=0,timer:ReturnType<typeof setInterval>|undefined\nasync function load(){const own=++generation;try{const [control,roster]=await Promise.all([apiRequest<BotControlState>('/api/app/permissions/control'),apiRequest<{agents:WorkspaceAgent[]}>('/api/app/agents')]);if(alive&&own===generation){state.value=control;mainId.value=control.mainBotId??'';agents.value=roster.agents;error.value=''}}catch(e){if(alive&&own===generation)error.value=e instanceof Error?e.message:'读取失败'}}\nconst botName=(id?:string)=>agents.value.find(a=>a.id===id)?.name??id??'待确定'\nfunction executor(r:BotPermissionRequest){if(r.capability!=='tasks.delegate')return botName(r.agentId);const ids=r.resources.filter(s=>s.startsWith('peer:')).map(s=>s.slice(5)).filter(Boolean);return ids.length?ids.map(botName).join('、'):'待确定'}\nasync function respond(request:BotPermissionRequest,decision:'once'|'always'|'deny'){if(busy.value)return;busy.value=true;try{await apiRequest(`/api/app/approvals/${request.id}/respond`,{method:'POST',body:{decision,expectedRevision:request.revision}});await load();emit('changed')}catch(e){error.value=e instanceof Error?e.message:'处理失败'}finally{busy.value=false}}\nwatch(()=>props.targetBotId,id=>{if(id)selected.value=id})\nonMounted(()=>{void load();timer=setInterval(()=>{if(!busy.value)void load()},5000)})\nonBeforeUnmount(()=>{alive=false;generation++;clearInterval(timer)})\n</script>\n<template>\n <section class=\"control-settings\">\n <p v-if=\"error\" role=\"alert\" class=\"error\">{{ error }}<button type=\"button\" @click=\"load\">重新加载</button></p>\n <MainBotSwitchDialog v-if=\"switching\" :target-bot-id=\"switching\" @close=\"switching=''\" @changed=\"load();emit('changed')\" />\n <PermissionSettingsPanel v-if=\"page==='permissions'\" @changed=\"emit('changed')\" @dirty-change=\"emit('dirty-change',$event)\" @busy-change=\"emit('busy-change',$event)\" />\n <template v-else-if=\"page==='bots'\">\n <template v-if=\"selectedBot\">\n <ManagedBotProfilePanel :agent=\"selectedBot\" :agents=\"agents\" :permissions-enforced=\"true\" @close=\"selected=''\" @changed=\"load();emit('changed')\" @navigate=\"emit('navigate',$event)\" @dirty-change=\"emit('dirty-change',$event)\" @busy-change=\"emit('busy-change',$event)\" />\n <PermissionSettingsPanel kind=\"agents\" :target-id=\"selectedBot.id\" @changed=\"emit('changed')\" @dirty-change=\"emit('dirty-change',$event)\" @busy-change=\"emit('busy-change',$event)\" />\n </template>\n <template v-else>\n <section class=\"card\"><h3>主 Bot</h3><p>默认对话与工作安排的入口。切换身份不会改变任何 Bot 的权限。</p><label>选择主 Bot<select v-model=\"mainId\"><option value=\"\" disabled>请选择</option><option v-for=\"bot in agents.filter(a=>!a.archived&&!a.temporaryGoalId&&!a.remoteAgentId&&a.nodeId==='local')\" :key=\"bot.id\" :value=\"bot.id\">{{ bot.name }}</option></select></label><button type=\"button\" :disabled=\"!mainId||mainId===state?.mainBotId\" @click=\"switching=mainId\">确认切换</button></section>\n <section class=\"card\"><h3>我的 Bot</h3><p>默认使用服务器授权方式,也可为每个 Bot 独立选择授权方式和额外限制。</p><article v-for=\"bot in agents.filter(a=>!a.archived&&!a.temporaryGoalId)\" :key=\"bot.id\"><strong>{{ bot.name }}{{ bot.id===state?.mainBotId?' · 主 Bot':'' }}</strong><button type=\"button\" @click=\"selected=bot.id\">配置 Bot 与权限</button></article></section>\n </template>\n </template>\n <template v-else-if=\"page==='requests'\">\n <section class=\"card\"><h3>待确认操作 · {{ pending.length }}</h3><p v-if=\"!pending.length\">暂无需要确认的操作。</p><article v-for=\"request in pending\" :key=\"request.id\" class=\"request\"><strong>{{ agents.find(a=>a.id===request.agentId)?.name??'Bot' }}</strong><small>发起者:{{ botName(request.initiatorId??request.agentId) }}</small><small>实际执行者:{{ executor(request) }}</small><p>{{ request.message??request.reason }}</p><small>{{ request.toolId }} · {{ request.resources.join('、') }}</small><small v-if=\"request.originConversationId!==request.displayConversationId\">来自群任务,在执行 Bot 单聊中也可以处理。</small><div class=\"actions\"><button type=\"button\" :disabled=\"busy\" @click=\"respond(request,'deny')\">拒绝</button><button type=\"button\" :disabled=\"busy\" @click=\"respond(request,'once')\">允许一次</button><button v-if=\"!request.manualOnly\" type=\"button\" :disabled=\"busy\" @click=\"respond(request,'always')\">始终允许此类操作</button></div></article></section>\n <section class=\"card\"><h3>操作确认记录</h3><article v-for=\"request in state?.requests.filter(r=>r.status!=='pending')??[]\" :key=\"request.id\" class=\"request\"><strong>{{ ({approved:'已允许',denied:'已拒绝',expired:'已失效',pending:'待确认'})[request.status] }}</strong><small>发起者:{{ botName(request.initiatorId??request.agentId) }}</small><small>实际执行者:{{ executor(request) }}</small><p>{{ request.reason }}</p><small>{{ request.toolId }} · {{ request.resources.join('、') }}</small></article></section>\n </template>\n </section>\n</template>\n<style scoped>\n.control-settings,.card{display:grid;gap:18px;min-width:0;color:var(--text-primary);font-size:14px}.card{padding:20px;border:1px solid var(--line);border-radius:14px}h3,p{margin:0}p,small{line-height:1.7;color:var(--text-secondary);white-space:pre-wrap;overflow-wrap:anywhere}label{display:grid;gap:8px}article,.actions{display:flex;gap:12px;align-items:center;justify-content:space-between;flex-wrap:wrap}.request{display:grid;justify-content:stretch;padding-block:12px;border-top:1px solid var(--line)}button,select{min-height:44px;min-width:0;padding:10px 12px;border:1px solid var(--line);border-radius:9px;background:var(--surface);color:inherit;font:inherit}button{cursor:pointer}button:disabled{opacity:.5;cursor:default}.error{color:var(--danger)}button:focus-visible,select:focus-visible{outline:2px solid var(--accent);outline-offset:3px}\n</style>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BotControlSettingsPanel-DIuBZlLu.js","names":[],"sources":["../../src/client/components/app/ManagedBotProfilePanel.vue","../../src/client/components/app/ManagedBotProfilePanel.vue","../../src/client/components/app/BotControlSettingsPanel.vue","../../src/client/components/app/BotControlSettingsPanel.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport BotProfileDialog from '@/components/workspace/BotProfileDialog.vue'\nimport AgentRuntimePanel from './AgentRuntimePanel.vue'\nimport { apiRequest } from '@/api/client'\nimport type { WorkspaceAgent, WorkspaceConversation } from '@shared/workspace'\nimport { goalStatus } from '@shared/collaborationPresentation'\nimport type { BotHomeData } from '@shared/botHome'\nimport type { BotModelSettings } from '@shared/botModelSettings'\nimport type { SettingsPage } from './settingsNavigation'\nconst props = defineProps<{ agent: WorkspaceAgent; agents: WorkspaceAgent[]; permissionsEnforced?: boolean }>()\nconst emit = defineEmits<{ close: []; changed: []; navigate: [page: SettingsPage]; 'dirty-change': [value: boolean]; 'busy-change': [value: boolean] }>()\nconst agent = ref(props.agent), conversations = ref<WorkspaceConversation[]>([]), knowledgeEnabled = ref(false), busy = ref(false), childBusy = ref(false), dirty = ref(false), error = ref('')\nconst tab = ref<'profile' | 'skills' | 'execution' | 'records'>('profile'), records = ref<BotHomeData>(), recordsLoading = ref(false)\nconst profile = ref<InstanceType<typeof BotProfileDialog>>()\nconst draft = computed(() => ({ ...agent.value, canManageTeam: agent.value.canManageTeam ?? true, canCollaborate: agent.value.canCollaborate ?? true, memoryEnabled: agent.value.memoryEnabled ?? true }))\nconst conversationId = computed(() => conversations.value.find(item => item.kind === 'direct' && item.memberIds[0] === agent.value.id)?.id)\nconst rows = computed(() => [...(records.value?.activities ?? []), ...(records.value?.reviews ?? [])].sort((a, b) => (b.at ?? 0) - (a.at ?? 0)))\nconst recordStatus = (value: string) => /[\\u3400-\\u9fff]/.test(value) ? value : ({ completed: '已完成', stopped: '已停止', stopping: '正在停止', approved: '已允许', denied: '已拒绝', expired: '已过期', uncertain: '需要核对', sending: '投递中', sent: '已投递' } as Record<string, string>)[value] ?? goalStatus(value)\nlet alive = true\nwatch(dirty, value => emit('dirty-change', value))\nwatch(() => busy.value || childBusy.value, value => emit('busy-change', value))\nfunction beforeClose() { return !busy.value && !childBusy.value && (!dirty.value || window.confirm('放弃此 Bot 未保存的配置?')) }\nfunction select(value: typeof tab.value) { if (value === tab.value || !beforeClose()) return; dirty.value = false; tab.value = value; error.value = ''; if (value === 'records') void loadRecords() }\nasync function loadRecords() { recordsLoading.value = true; error.value = ''; try { const value = await apiRequest<BotHomeData>(`/api/app/agents/${encodeURIComponent(agent.value.id)}/home`); if (alive) records.value = value } catch (cause) { if (alive) error.value = cause instanceof Error ? cause.message : '读取运行记录失败' } finally { if (alive) recordsLoading.value = false } }\nasync function save(value: InstanceType<typeof BotProfileDialog>['$props']['draft'] & { expectedRevision?: number; modelSettings?: BotModelSettings }) {\n if (busy.value) return\n busy.value = true; error.value = ''\n const payload = { name: value.name, avatar: value.avatar, instructions: value.instructions, description: value.description?.trim() ?? '', job: value.job?.trim() || null, antiJobs: value.antiJobs?.length ? value.antiJobs : null, voice: value.voice || null, voiceCustom: value.voice === 'custom' ? value.voiceCustom?.trim() || null : null, actBias: value.actBias || null, memoryEnabled: value.memoryEnabled, canCollaborate: value.canCollaborate, canManageTeam: value.canManageTeam, approvalPolicy: value.approvalPolicy ?? 'ask', expectedRevision: value.expectedRevision ?? agent.value.revision, ...(value.modelSettings ? { modelSettings: value.modelSettings } : {}) }\n try {\n type Result = { agent?: WorkspaceAgent; confirmationRequired?: boolean; confirmationMessage?: string; confirmationTarget?: string }\n let result = await apiRequest<Result>(`/api/app/agents/${encodeURIComponent(agent.value.id)}`, { method: 'PATCH', body: JSON.parse(JSON.stringify(payload)) })\n if (!alive) return\n if (result.confirmationRequired) {\n if (!result.confirmationTarget) throw new Error('模型确认信息不完整,请重新读取。')\n if (!window.confirm(result.confirmationMessage || '确认使用此模型?')) return\n result = await apiRequest<Result>(`/api/app/agents/${encodeURIComponent(agent.value.id)}`, { method: 'PATCH', body: JSON.parse(JSON.stringify({ ...payload, confirmedModel: result.confirmationTarget })) })\n }\n if (!alive) return\n if (!result.agent) throw new Error('保存尚未确认,请重新读取后核对。')\n agent.value = result.agent; profile.value?.markSaved?.(result.agent); dirty.value = false; emit('changed')\n } catch (cause) { if (alive) error.value = cause instanceof Error ? cause.message : '保存失败' }\n finally { if (alive) busy.value = false }\n}\nonMounted(async () => { try { const [roster, capabilities] = await Promise.all([apiRequest<{ conversations: WorkspaceConversation[] }>('/api/app/conversations'), apiRequest<{ features: string[] }>('/api/app/capabilities')]); if (alive) { conversations.value = roster.conversations; knowledgeEnabled.value = capabilities.features.includes('bot-file-memory-v1') } } catch (cause) { if (alive) error.value = cause instanceof Error ? cause.message : '加载 Bot 配置失败' } })\nonBeforeUnmount(() => { alive = false })\ndefineExpose({ beforeClose })\n</script>\n<template>\n <section class=\"managed-bot\" :aria-label=\"`${agent.name} 的设置`\">\n <header><button :disabled=\"busy || childBusy\" @click=\"beforeClose() && emit('close')\">返回我的 Bot</button><strong>{{ agent.name }}</strong><small>只修改此 Bot</small></header>\n <nav aria-label=\"Bot 配置页面\"><button v-for=\"item in ([['profile','资料与权限'],['skills','技能'],['execution','执行设置'],['records','运行记录']] as const)\" :key=\"item[0]\" :aria-pressed=\"tab === item[0]\" :disabled=\"busy || childBusy\" @click=\"select(item[0])\">{{ item[1] }}</button></nav>\n <p v-if=\"error && tab !== 'profile'\" role=\"alert\">{{ error }}</p>\n <BotProfileDialog v-if=\"tab === 'profile'\" ref=\"profile\" embedded permission-control is-admin :agent=\"agent\" :draft=\"draft\" :agents=\"agents\" :conversations=\"conversations\" :conversation-id=\"conversationId\" :knowledge-enabled=\"knowledgeEnabled\" :busy=\"busy\" :error=\"error\" @save=\"save\" @close=\"emit('close')\" @changed=\"emit('changed')\" @dirty-change=\"dirty = $event\" @busy-change=\"childBusy = $event\" @manage-models=\"emit('navigate', 'system-models')\" @manage-permissions=\"emit('navigate', 'workspace-permissions')\" />\n <AgentRuntimePanel v-else-if=\"tab === 'skills' || tab === 'execution'\" :key=\"tab\" :section=\"tab\" :target-bot-id=\"agent.id\" :permission-control=\"permissionsEnforced\" @dirty-change=\"dirty = $event\" @busy-change=\"childBusy = $event\" />\n <section v-else class=\"bot-records\" aria-label=\"运行记录\"><button :disabled=\"recordsLoading\" @click=\"loadRecords\">刷新运行记录</button><p v-if=\"recordsLoading\" role=\"status\">正在读取…</p><p v-else-if=\"!rows.length\">暂无运行记录。</p><details v-for=\"record in rows\" :key=\"record.id\"><summary>{{ record.title }} · {{ recordStatus(record.status) }}</summary><small v-if=\"record.at\">{{ new Date(record.at).toLocaleString('zh-CN') }}</small><p>{{ record.content || record.summary || '没有附加内容。' }}</p></details></section>\n </section>\n</template>\n<style scoped>\n.managed-bot{min-width:0;display:grid;gap:20px}.managed-bot>header,.managed-bot>nav{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.managed-bot>header strong{flex:1}.managed-bot small{font-size:12px;color:var(--text-secondary)}.managed-bot>nav{border-bottom:1px solid var(--line);padding-bottom:12px}.managed-bot button{min-height:44px;border:1px solid var(--line);border-radius:9px;background:var(--surface);color:inherit;padding:9px 14px;font:inherit;cursor:pointer}.managed-bot button[aria-pressed=true]{background:var(--surface-soft);font-weight:600}.managed-bot button:disabled{opacity:.5}.managed-bot button:focus-visible,.bot-records summary:focus-visible{outline:2px solid var(--accent);outline-offset:2px}.managed-bot :deep(.bot-profile__scroll){overflow:visible}.managed-bot :deep(.bot-profile__footer){position:sticky;bottom:-24px;background:var(--surface);z-index:2}.bot-records{display:grid;gap:16px}.bot-records summary{cursor:pointer;min-height:44px;line-height:1.7}.bot-records p{font-size:13px;line-height:1.8;white-space:pre-wrap;overflow-wrap:anywhere}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport BotProfileDialog from '@/components/workspace/BotProfileDialog.vue'\nimport AgentRuntimePanel from './AgentRuntimePanel.vue'\nimport { apiRequest } from '@/api/client'\nimport type { WorkspaceAgent, WorkspaceConversation } from '@shared/workspace'\nimport { goalStatus } from '@shared/collaborationPresentation'\nimport type { BotHomeData } from '@shared/botHome'\nimport type { BotModelSettings } from '@shared/botModelSettings'\nimport type { SettingsPage } from './settingsNavigation'\nconst props = defineProps<{ agent: WorkspaceAgent; agents: WorkspaceAgent[]; permissionsEnforced?: boolean }>()\nconst emit = defineEmits<{ close: []; changed: []; navigate: [page: SettingsPage]; 'dirty-change': [value: boolean]; 'busy-change': [value: boolean] }>()\nconst agent = ref(props.agent), conversations = ref<WorkspaceConversation[]>([]), knowledgeEnabled = ref(false), busy = ref(false), childBusy = ref(false), dirty = ref(false), error = ref('')\nconst tab = ref<'profile' | 'skills' | 'execution' | 'records'>('profile'), records = ref<BotHomeData>(), recordsLoading = ref(false)\nconst profile = ref<InstanceType<typeof BotProfileDialog>>()\nconst draft = computed(() => ({ ...agent.value, canManageTeam: agent.value.canManageTeam ?? true, canCollaborate: agent.value.canCollaborate ?? true, memoryEnabled: agent.value.memoryEnabled ?? true }))\nconst conversationId = computed(() => conversations.value.find(item => item.kind === 'direct' && item.memberIds[0] === agent.value.id)?.id)\nconst rows = computed(() => [...(records.value?.activities ?? []), ...(records.value?.reviews ?? [])].sort((a, b) => (b.at ?? 0) - (a.at ?? 0)))\nconst recordStatus = (value: string) => /[\\u3400-\\u9fff]/.test(value) ? value : ({ completed: '已完成', stopped: '已停止', stopping: '正在停止', approved: '已允许', denied: '已拒绝', expired: '已过期', uncertain: '需要核对', sending: '投递中', sent: '已投递' } as Record<string, string>)[value] ?? goalStatus(value)\nlet alive = true\nwatch(dirty, value => emit('dirty-change', value))\nwatch(() => busy.value || childBusy.value, value => emit('busy-change', value))\nfunction beforeClose() { return !busy.value && !childBusy.value && (!dirty.value || window.confirm('放弃此 Bot 未保存的配置?')) }\nfunction select(value: typeof tab.value) { if (value === tab.value || !beforeClose()) return; dirty.value = false; tab.value = value; error.value = ''; if (value === 'records') void loadRecords() }\nasync function loadRecords() { recordsLoading.value = true; error.value = ''; try { const value = await apiRequest<BotHomeData>(`/api/app/agents/${encodeURIComponent(agent.value.id)}/home`); if (alive) records.value = value } catch (cause) { if (alive) error.value = cause instanceof Error ? cause.message : '读取运行记录失败' } finally { if (alive) recordsLoading.value = false } }\nasync function save(value: InstanceType<typeof BotProfileDialog>['$props']['draft'] & { expectedRevision?: number; modelSettings?: BotModelSettings }) {\n if (busy.value) return\n busy.value = true; error.value = ''\n const payload = { name: value.name, avatar: value.avatar, instructions: value.instructions, description: value.description?.trim() ?? '', job: value.job?.trim() || null, antiJobs: value.antiJobs?.length ? value.antiJobs : null, voice: value.voice || null, voiceCustom: value.voice === 'custom' ? value.voiceCustom?.trim() || null : null, actBias: value.actBias || null, memoryEnabled: value.memoryEnabled, canCollaborate: value.canCollaborate, canManageTeam: value.canManageTeam, approvalPolicy: value.approvalPolicy ?? 'ask', expectedRevision: value.expectedRevision ?? agent.value.revision, ...(value.modelSettings ? { modelSettings: value.modelSettings } : {}) }\n try {\n type Result = { agent?: WorkspaceAgent; confirmationRequired?: boolean; confirmationMessage?: string; confirmationTarget?: string }\n let result = await apiRequest<Result>(`/api/app/agents/${encodeURIComponent(agent.value.id)}`, { method: 'PATCH', body: JSON.parse(JSON.stringify(payload)) })\n if (!alive) return\n if (result.confirmationRequired) {\n if (!result.confirmationTarget) throw new Error('模型确认信息不完整,请重新读取。')\n if (!window.confirm(result.confirmationMessage || '确认使用此模型?')) return\n result = await apiRequest<Result>(`/api/app/agents/${encodeURIComponent(agent.value.id)}`, { method: 'PATCH', body: JSON.parse(JSON.stringify({ ...payload, confirmedModel: result.confirmationTarget })) })\n }\n if (!alive) return\n if (!result.agent) throw new Error('保存尚未确认,请重新读取后核对。')\n agent.value = result.agent; profile.value?.markSaved?.(result.agent); dirty.value = false; emit('changed')\n } catch (cause) { if (alive) error.value = cause instanceof Error ? cause.message : '保存失败' }\n finally { if (alive) busy.value = false }\n}\nonMounted(async () => { try { const [roster, capabilities] = await Promise.all([apiRequest<{ conversations: WorkspaceConversation[] }>('/api/app/conversations'), apiRequest<{ features: string[] }>('/api/app/capabilities')]); if (alive) { conversations.value = roster.conversations; knowledgeEnabled.value = capabilities.features.includes('bot-file-memory-v1') } } catch (cause) { if (alive) error.value = cause instanceof Error ? cause.message : '加载 Bot 配置失败' } })\nonBeforeUnmount(() => { alive = false })\ndefineExpose({ beforeClose })\n</script>\n<template>\n <section class=\"managed-bot\" :aria-label=\"`${agent.name} 的设置`\">\n <header><button :disabled=\"busy || childBusy\" @click=\"beforeClose() && emit('close')\">返回我的 Bot</button><strong>{{ agent.name }}</strong><small>只修改此 Bot</small></header>\n <nav aria-label=\"Bot 配置页面\"><button v-for=\"item in ([['profile','资料与权限'],['skills','技能'],['execution','执行设置'],['records','运行记录']] as const)\" :key=\"item[0]\" :aria-pressed=\"tab === item[0]\" :disabled=\"busy || childBusy\" @click=\"select(item[0])\">{{ item[1] }}</button></nav>\n <p v-if=\"error && tab !== 'profile'\" role=\"alert\">{{ error }}</p>\n <BotProfileDialog v-if=\"tab === 'profile'\" ref=\"profile\" embedded permission-control is-admin :agent=\"agent\" :draft=\"draft\" :agents=\"agents\" :conversations=\"conversations\" :conversation-id=\"conversationId\" :knowledge-enabled=\"knowledgeEnabled\" :busy=\"busy\" :error=\"error\" @save=\"save\" @close=\"emit('close')\" @changed=\"emit('changed')\" @dirty-change=\"dirty = $event\" @busy-change=\"childBusy = $event\" @manage-models=\"emit('navigate', 'system-models')\" @manage-permissions=\"emit('navigate', 'workspace-permissions')\" />\n <AgentRuntimePanel v-else-if=\"tab === 'skills' || tab === 'execution'\" :key=\"tab\" :section=\"tab\" :target-bot-id=\"agent.id\" :permission-control=\"permissionsEnforced\" @dirty-change=\"dirty = $event\" @busy-change=\"childBusy = $event\" />\n <section v-else class=\"bot-records\" aria-label=\"运行记录\"><button :disabled=\"recordsLoading\" @click=\"loadRecords\">刷新运行记录</button><p v-if=\"recordsLoading\" role=\"status\">正在读取…</p><p v-else-if=\"!rows.length\">暂无运行记录。</p><details v-for=\"record in rows\" :key=\"record.id\"><summary>{{ record.title }} · {{ recordStatus(record.status) }}</summary><small v-if=\"record.at\">{{ new Date(record.at).toLocaleString('zh-CN') }}</small><p>{{ record.content || record.summary || '没有附加内容。' }}</p></details></section>\n </section>\n</template>\n<style scoped>\n.managed-bot{min-width:0;display:grid;gap:20px}.managed-bot>header,.managed-bot>nav{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.managed-bot>header strong{flex:1}.managed-bot small{font-size:12px;color:var(--text-secondary)}.managed-bot>nav{border-bottom:1px solid var(--line);padding-bottom:12px}.managed-bot button{min-height:44px;border:1px solid var(--line);border-radius:9px;background:var(--surface);color:inherit;padding:9px 14px;font:inherit;cursor:pointer}.managed-bot button[aria-pressed=true]{background:var(--surface-soft);font-weight:600}.managed-bot button:disabled{opacity:.5}.managed-bot button:focus-visible,.bot-records summary:focus-visible{outline:2px solid var(--accent);outline-offset:2px}.managed-bot :deep(.bot-profile__scroll){overflow:visible}.managed-bot :deep(.bot-profile__footer){position:sticky;bottom:-24px;background:var(--surface);z-index:2}.bot-records{display:grid;gap:16px}.bot-records summary{cursor:pointer;min-height:44px;line-height:1.7}.bot-records p{font-size:13px;line-height:1.8;white-space:pre-wrap;overflow-wrap:anywhere}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport { apiRequest } from '@/api/client'\nimport type { SettingsPage } from './settingsNavigation'\nimport type { WorkspaceAgent } from '@shared/workspace'\nimport type { BotControlState, BotPermissionRequest } from '@shared/botControl'\nimport PermissionSettingsPanel from './PermissionSettingsPanel.vue'\nimport ManagedBotProfilePanel from './ManagedBotProfilePanel.vue'\nimport MainBotSwitchDialog from '@/components/workspace/MainBotSwitchDialog.vue'\nconst props=defineProps<{page:'bots'|'permissions'|'requests';targetBotId?:string}>()\nconst emit=defineEmits<{changed:[];navigate:[SettingsPage];'dirty-change':[boolean];'busy-change':[boolean]}>()\nconst state=ref<BotControlState>(),agents=ref<WorkspaceAgent[]>([]),error=ref(''),busy=ref(false),selected=ref(props.targetBotId??''),switching=ref(''),mainId=ref('')\nconst selectedBot=computed(()=>agents.value.find(a=>a.id===selected.value)),pending=computed(()=>state.value?.requests.filter(r=>r.status==='pending')??[])\nlet alive=true,generation=0,timer:ReturnType<typeof setInterval>|undefined\nasync function load(){const own=++generation;try{const [control,roster]=await Promise.all([apiRequest<BotControlState>('/api/app/permissions/control'),apiRequest<{agents:WorkspaceAgent[]}>('/api/app/agents')]);if(alive&&own===generation){state.value=control;mainId.value=control.mainBotId??'';agents.value=roster.agents;error.value=''}}catch(e){if(alive&&own===generation)error.value=e instanceof Error?e.message:'读取失败'}}\nconst botName=(id?:string)=>agents.value.find(a=>a.id===id)?.name??id??'待确定'\nfunction executor(r:BotPermissionRequest){if(r.capability!=='tasks.delegate')return botName(r.agentId);const ids=r.resources.filter(s=>s.startsWith('peer:')).map(s=>s.slice(5)).filter(Boolean);return ids.length?ids.map(botName).join('、'):'待确定'}\nasync function respond(request:BotPermissionRequest,decision:'once'|'always'|'deny'){if(busy.value)return;busy.value=true;try{await apiRequest(`/api/app/approvals/${request.id}/respond`,{method:'POST',body:{decision,expectedRevision:request.revision}});await load();emit('changed')}catch(e){error.value=e instanceof Error?e.message:'处理失败'}finally{busy.value=false}}\nwatch(()=>props.targetBotId,id=>{if(id)selected.value=id})\nonMounted(()=>{void load();timer=setInterval(()=>{if(!busy.value)void load()},5000)})\nonBeforeUnmount(()=>{alive=false;generation++;clearInterval(timer)})\n</script>\n<template>\n <section class=\"control-settings\">\n <p v-if=\"error\" role=\"alert\" class=\"error\">{{ error }}<button type=\"button\" @click=\"load\">重新加载</button></p>\n <MainBotSwitchDialog v-if=\"switching\" :target-bot-id=\"switching\" @close=\"switching=''\" @changed=\"load();emit('changed')\" />\n <PermissionSettingsPanel v-if=\"page==='permissions'\" @changed=\"emit('changed')\" @dirty-change=\"emit('dirty-change',$event)\" @busy-change=\"emit('busy-change',$event)\" />\n <template v-else-if=\"page==='bots'\">\n <template v-if=\"selectedBot\">\n <ManagedBotProfilePanel :agent=\"selectedBot\" :agents=\"agents\" :permissions-enforced=\"true\" @close=\"selected=''\" @changed=\"load();emit('changed')\" @navigate=\"emit('navigate',$event)\" @dirty-change=\"emit('dirty-change',$event)\" @busy-change=\"emit('busy-change',$event)\" />\n <PermissionSettingsPanel kind=\"agents\" :target-id=\"selectedBot.id\" @changed=\"emit('changed')\" @dirty-change=\"emit('dirty-change',$event)\" @busy-change=\"emit('busy-change',$event)\" />\n </template>\n <template v-else>\n <section class=\"card\"><h3>主 Bot</h3><p>默认对话与工作安排的入口。切换身份不会改变任何 Bot 的权限。</p><label>选择主 Bot<select v-model=\"mainId\"><option value=\"\" disabled>请选择</option><option v-for=\"bot in agents.filter(a=>!a.archived&&!a.temporaryGoalId&&!a.remoteAgentId&&a.nodeId==='local')\" :key=\"bot.id\" :value=\"bot.id\">{{ bot.name }}</option></select></label><button type=\"button\" :disabled=\"!mainId||mainId===state?.mainBotId\" @click=\"switching=mainId\">确认切换</button></section>\n <section class=\"card\"><h3>我的 Bot</h3><p>默认使用服务器授权方式,也可为每个 Bot 独立选择授权方式和额外限制。</p><article v-for=\"bot in agents.filter(a=>!a.archived&&!a.temporaryGoalId)\" :key=\"bot.id\"><strong>{{ bot.name }}{{ bot.id===state?.mainBotId?' · 主 Bot':'' }}</strong><button type=\"button\" @click=\"selected=bot.id\">配置 Bot 与权限</button></article></section>\n </template>\n </template>\n <template v-else-if=\"page==='requests'\">\n <section class=\"card\"><h3>待确认操作 · {{ pending.length }}</h3><p v-if=\"!pending.length\">暂无需要确认的操作。</p><article v-for=\"request in pending\" :key=\"request.id\" class=\"request\"><strong>{{ agents.find(a=>a.id===request.agentId)?.name??'Bot' }}</strong><small>发起者:{{ botName(request.initiatorId??request.agentId) }}</small><small>实际执行者:{{ executor(request) }}</small><p>{{ request.message??request.reason }}</p><small>{{ request.toolId }} · {{ request.resources.join('、') }}</small><small v-if=\"request.originConversationId!==request.displayConversationId\">来自群任务,在执行 Bot 单聊中也可以处理。</small><div class=\"actions\"><button type=\"button\" :disabled=\"busy\" @click=\"respond(request,'deny')\">拒绝</button><button type=\"button\" :disabled=\"busy\" @click=\"respond(request,'once')\">允许一次</button><button v-if=\"!request.manualOnly\" type=\"button\" :disabled=\"busy\" @click=\"respond(request,'always')\">始终允许此类操作</button></div></article></section>\n <section class=\"card\"><h3>操作确认记录</h3><article v-for=\"request in state?.requests.filter(r=>r.status!=='pending')??[]\" :key=\"request.id\" class=\"request\"><strong>{{ ({approved:'已允许',denied:'已拒绝',expired:'已失效',pending:'待确认'})[request.status] }}</strong><small>发起者:{{ botName(request.initiatorId??request.agentId) }}</small><small>实际执行者:{{ executor(request) }}</small><p>{{ request.reason }}</p><small>{{ request.toolId }} · {{ request.resources.join('、') }}</small></article></section>\n </template>\n </section>\n</template>\n<style scoped>\n.control-settings,.card{display:grid;gap:18px;min-width:0;color:var(--text-primary);font-size:14px}.card{padding:20px;border:1px solid var(--line);border-radius:14px}h3,p{margin:0}p,small{line-height:1.7;color:var(--text-secondary);white-space:pre-wrap;overflow-wrap:anywhere}label{display:grid;gap:8px}article,.actions{display:flex;gap:12px;align-items:center;justify-content:space-between;flex-wrap:wrap}.request{display:grid;justify-content:stretch;padding-block:12px;border-top:1px solid var(--line)}button,select{min-height:44px;min-width:0;padding:10px 12px;border:1px solid var(--line);border-radius:9px;background:var(--surface);color:inherit;font:inherit}button{cursor:pointer}button:disabled{opacity:.5;cursor:default}.error{color:var(--danger)}button:focus-visible,select:focus-visible{outline:2px solid var(--accent);outline-offset:3px}\n</style>\n","<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport { apiRequest } from '@/api/client'\nimport type { SettingsPage } from './settingsNavigation'\nimport type { WorkspaceAgent } from '@shared/workspace'\nimport type { BotControlState, BotPermissionRequest } from '@shared/botControl'\nimport PermissionSettingsPanel from './PermissionSettingsPanel.vue'\nimport ManagedBotProfilePanel from './ManagedBotProfilePanel.vue'\nimport MainBotSwitchDialog from '@/components/workspace/MainBotSwitchDialog.vue'\nconst props=defineProps<{page:'bots'|'permissions'|'requests';targetBotId?:string}>()\nconst emit=defineEmits<{changed:[];navigate:[SettingsPage];'dirty-change':[boolean];'busy-change':[boolean]}>()\nconst state=ref<BotControlState>(),agents=ref<WorkspaceAgent[]>([]),error=ref(''),busy=ref(false),selected=ref(props.targetBotId??''),switching=ref(''),mainId=ref('')\nconst selectedBot=computed(()=>agents.value.find(a=>a.id===selected.value)),pending=computed(()=>state.value?.requests.filter(r=>r.status==='pending')??[])\nlet alive=true,generation=0,timer:ReturnType<typeof setInterval>|undefined\nasync function load(){const own=++generation;try{const [control,roster]=await Promise.all([apiRequest<BotControlState>('/api/app/permissions/control'),apiRequest<{agents:WorkspaceAgent[]}>('/api/app/agents')]);if(alive&&own===generation){state.value=control;mainId.value=control.mainBotId??'';agents.value=roster.agents;error.value=''}}catch(e){if(alive&&own===generation)error.value=e instanceof Error?e.message:'读取失败'}}\nconst botName=(id?:string)=>agents.value.find(a=>a.id===id)?.name??id??'待确定'\nfunction executor(r:BotPermissionRequest){if(r.capability!=='tasks.delegate')return botName(r.agentId);const ids=r.resources.filter(s=>s.startsWith('peer:')).map(s=>s.slice(5)).filter(Boolean);return ids.length?ids.map(botName).join('、'):'待确定'}\nasync function respond(request:BotPermissionRequest,decision:'once'|'always'|'deny'){if(busy.value)return;busy.value=true;try{await apiRequest(`/api/app/approvals/${request.id}/respond`,{method:'POST',body:{decision,expectedRevision:request.revision}});await load();emit('changed')}catch(e){error.value=e instanceof Error?e.message:'处理失败'}finally{busy.value=false}}\nwatch(()=>props.targetBotId,id=>{if(id)selected.value=id})\nonMounted(()=>{void load();timer=setInterval(()=>{if(!busy.value)void load()},5000)})\nonBeforeUnmount(()=>{alive=false;generation++;clearInterval(timer)})\n</script>\n<template>\n <section class=\"control-settings\">\n <p v-if=\"error\" role=\"alert\" class=\"error\">{{ error }}<button type=\"button\" @click=\"load\">重新加载</button></p>\n <MainBotSwitchDialog v-if=\"switching\" :target-bot-id=\"switching\" @close=\"switching=''\" @changed=\"load();emit('changed')\" />\n <PermissionSettingsPanel v-if=\"page==='permissions'\" @changed=\"emit('changed')\" @dirty-change=\"emit('dirty-change',$event)\" @busy-change=\"emit('busy-change',$event)\" />\n <template v-else-if=\"page==='bots'\">\n <template v-if=\"selectedBot\">\n <ManagedBotProfilePanel :agent=\"selectedBot\" :agents=\"agents\" :permissions-enforced=\"true\" @close=\"selected=''\" @changed=\"load();emit('changed')\" @navigate=\"emit('navigate',$event)\" @dirty-change=\"emit('dirty-change',$event)\" @busy-change=\"emit('busy-change',$event)\" />\n <PermissionSettingsPanel kind=\"agents\" :target-id=\"selectedBot.id\" @changed=\"emit('changed')\" @dirty-change=\"emit('dirty-change',$event)\" @busy-change=\"emit('busy-change',$event)\" />\n </template>\n <template v-else>\n <section class=\"card\"><h3>主 Bot</h3><p>默认对话与工作安排的入口。切换身份不会改变任何 Bot 的权限。</p><label>选择主 Bot<select v-model=\"mainId\"><option value=\"\" disabled>请选择</option><option v-for=\"bot in agents.filter(a=>!a.archived&&!a.temporaryGoalId&&!a.remoteAgentId&&a.nodeId==='local')\" :key=\"bot.id\" :value=\"bot.id\">{{ bot.name }}</option></select></label><button type=\"button\" :disabled=\"!mainId||mainId===state?.mainBotId\" @click=\"switching=mainId\">确认切换</button></section>\n <section class=\"card\"><h3>我的 Bot</h3><p>默认使用服务器授权方式,也可为每个 Bot 独立选择授权方式和额外限制。</p><article v-for=\"bot in agents.filter(a=>!a.archived&&!a.temporaryGoalId)\" :key=\"bot.id\"><strong>{{ bot.name }}{{ bot.id===state?.mainBotId?' · 主 Bot':'' }}</strong><button type=\"button\" @click=\"selected=bot.id\">配置 Bot 与权限</button></article></section>\n </template>\n </template>\n <template v-else-if=\"page==='requests'\">\n <section class=\"card\"><h3>待确认操作 · {{ pending.length }}</h3><p v-if=\"!pending.length\">暂无需要确认的操作。</p><article v-for=\"request in pending\" :key=\"request.id\" class=\"request\"><strong>{{ agents.find(a=>a.id===request.agentId)?.name??'Bot' }}</strong><small>发起者:{{ botName(request.initiatorId??request.agentId) }}</small><small>实际执行者:{{ executor(request) }}</small><p>{{ request.message??request.reason }}</p><small>{{ request.toolId }} · {{ request.resources.join('、') }}</small><small v-if=\"request.originConversationId!==request.displayConversationId\">来自群任务,在执行 Bot 单聊中也可以处理。</small><div class=\"actions\"><button type=\"button\" :disabled=\"busy\" @click=\"respond(request,'deny')\">拒绝</button><button type=\"button\" :disabled=\"busy\" @click=\"respond(request,'once')\">允许一次</button><button v-if=\"!request.manualOnly\" type=\"button\" :disabled=\"busy\" @click=\"respond(request,'always')\">始终允许此类操作</button></div></article></section>\n <section class=\"card\"><h3>操作确认记录</h3><article v-for=\"request in state?.requests.filter(r=>r.status!=='pending')??[]\" :key=\"request.id\" class=\"request\"><strong>{{ ({approved:'已允许',denied:'已拒绝',expired:'已失效',pending:'待确认'})[request.status] }}</strong><small>发起者:{{ botName(request.initiatorId??request.agentId) }}</small><small>实际执行者:{{ executor(request) }}</small><p>{{ request.reason }}</p><small>{{ request.toolId }} · {{ request.resources.join('、') }}</small></article></section>\n </template>\n </section>\n</template>\n<style scoped>\n.control-settings,.card{display:grid;gap:18px;min-width:0;color:var(--text-primary);font-size:14px}.card{padding:20px;border:1px solid var(--line);border-radius:14px}h3,p{margin:0}p,small{line-height:1.7;color:var(--text-secondary);white-space:pre-wrap;overflow-wrap:anywhere}label{display:grid;gap:8px}article,.actions{display:flex;gap:12px;align-items:center;justify-content:space-between;flex-wrap:wrap}.request{display:grid;justify-content:stretch;padding-block:12px;border-top:1px solid var(--line)}button,select{min-height:44px;min-width:0;padding:10px 12px;border:1px solid var(--line);border-radius:9px;background:var(--surface);color:inherit;font:inherit}button{cursor:pointer}button:disabled{opacity:.5;cursor:default}.error{color:var(--danger)}button:focus-visible,select:focus-visible{outline:2px solid var(--accent);outline-offset:3px}\n</style>\n"],"mappings":"gxBAUA,IAAM,EAAQ,EACR,EAAO,EACP,EAAQ,EAAI,EAAM,KAAK,EAAG,EAAgB,EAA6B,CAAC,CAAC,EAAG,EAAmB,EAAI,EAAK,EAAG,EAAO,EAAI,EAAK,EAAG,EAAY,EAAI,EAAK,EAAG,EAAQ,EAAI,EAAK,EAAG,EAAQ,EAAI,EAAE,EACxL,EAAM,EAAoD,SAAS,EAAG,EAAU,EAAiB,EAAG,EAAiB,EAAI,EAAK,EAC9H,EAAU,EAA2C,EACrD,EAAQ,OAAgB,CAAE,GAAG,EAAM,MAAO,cAAe,EAAM,MAAM,eAAiB,GAAM,eAAgB,EAAM,MAAM,gBAAkB,GAAM,cAAe,EAAM,MAAM,eAAiB,EAAK,EAAE,EACnM,EAAiB,MAAe,EAAc,MAAM,KAAK,GAAQ,EAAK,OAAS,UAAY,EAAK,UAAU,KAAO,EAAM,MAAM,EAAE,CAAC,EAAE,EAAE,EACpI,EAAO,MAAe,CAAC,GAAI,EAAQ,OAAO,YAAc,CAAC,EAAI,GAAI,EAAQ,OAAO,SAAW,CAAC,CAAE,CAAC,CAAC,MAAM,EAAG,KAAO,EAAE,IAAM,IAAM,EAAE,IAAM,EAAE,CAAC,EACzI,EAAgB,GAAkB,kBAAkB,KAAK,CAAK,EAAI,EAAS,CAAE,UAAW,MAAO,QAAS,MAAO,SAAU,OAAQ,SAAU,MAAO,OAAQ,MAAO,QAAS,MAAO,UAAW,OAAQ,QAAS,MAAO,KAAM,KAAM,EAA6B,IAAU,EAAW,CAAK,EACzR,EAAQ,GACZ,EAAM,EAAO,GAAS,EAAK,eAAgB,CAAK,CAAC,EACjD,MAAY,EAAK,OAAS,EAAU,MAAO,GAAS,EAAK,cAAe,CAAK,CAAC,EAC9E,SAAS,GAAc,CAAE,MAAO,CAAC,EAAK,OAAS,CAAC,EAAU,QAAU,CAAC,EAAM,OAAS,OAAO,QAAQ,iBAAiB,EAAG,CACvH,SAAS,GAAO,EAAyB,CAAM,IAAU,EAAI,OAAS,CAAC,EAAY,IAAW,EAAM,MAAQ,GAAO,EAAI,MAAQ,EAAO,EAAM,MAAQ,GAAQ,IAAU,WAAW,EAAiB,EAAE,CACpM,eAAe,GAAc,CAAE,EAAe,MAAQ,GAAM,EAAM,MAAQ,GAAI,GAAI,CAAE,IAAM,EAAQ,MAAM,EAAwB,mBAAmB,mBAAmB,EAAM,MAAM,EAAE,EAAE,MAAM,EAAO,IAAO,EAAQ,MAAQ,EAAM,OAAS,EAAO,CAAM,IAAO,EAAM,MAAQ,aAAiB,MAAQ,EAAM,QAAU,WAAW,QAAU,CAAM,IAAO,EAAe,MAAQ,GAAM,CAAE,CACrX,eAAe,EAAK,EAAmI,CACrJ,GAAI,EAAK,MAAO,OAChB,EAAK,MAAQ,GAAM,EAAM,MAAQ,GACjC,IAAM,EAAU,CAAE,KAAM,EAAM,KAAM,OAAQ,EAAM,OAAQ,aAAc,EAAM,aAAc,YAAa,EAAM,aAAa,KAAK,GAAK,GAAI,IAAK,EAAM,KAAK,KAAK,GAAK,KAAM,SAAU,EAAM,UAAU,OAAS,EAAM,SAAW,KAAM,MAAO,EAAM,OAAS,KAAM,YAAa,EAAM,QAAU,UAAW,EAAM,aAAa,KAAK,GAAY,KAAM,QAAS,EAAM,SAAW,KAAM,cAAe,EAAM,cAAe,eAAgB,EAAM,eAAgB,cAAe,EAAM,cAAe,eAAgB,EAAM,gBAAkB,MAAO,iBAAkB,EAAM,kBAAoB,EAAM,MAAM,SAAU,GAAI,EAAM,cAAgB,CAAE,cAAe,EAAM,aAAc,EAAI,CAAC,CAAG,EACxpB,GAAI,CAEF,IAAI,EAAS,MAAM,EAAmB,mBAAmB,mBAAmB,EAAM,MAAM,EAAE,IAAK,CAAE,OAAQ,QAAS,KAAM,KAAK,MAAM,KAAK,UAAU,CAAO,CAAC,CAAE,CAAC,EAC7J,GAAI,CAAC,EAAO,OACZ,GAAI,EAAO,qBAAsB,CAC/B,GAAI,CAAC,EAAO,mBAAoB,MAAU,MAAM,kBAAkB,EAClE,GAAI,CAAC,OAAO,QAAQ,EAAO,qBAAuB,UAAU,EAAG,OAC/D,EAAS,MAAM,EAAmB,mBAAmB,mBAAmB,EAAM,MAAM,EAAE,IAAK,CAAE,OAAQ,QAAS,KAAM,KAAK,MAAM,KAAK,UAAU,CAAE,GAAG,EAAS,eAAgB,EAAO,kBAAmB,CAAC,CAAC,CAAE,CAAC,CAC7M,CACA,GAAI,CAAC,EAAO,OACZ,GAAI,CAAC,EAAO,MAAO,MAAU,MAAM,kBAAkB,EACrD,EAAM,MAAQ,EAAO,MAAO,EAAQ,OAAO,YAAY,EAAO,KAAK,EAAG,EAAM,MAAQ,GAAO,EAAK,SAAS,CAC3G,OAAS,EAAO,CAAM,IAAO,EAAM,MAAQ,aAAiB,MAAQ,EAAM,QAAU,OAAO,QACnF,CAAM,IAAO,EAAK,MAAQ,GAAM,CAC1C,QACA,EAAU,SAAY,CAAE,GAAI,CAAE,GAAM,CAAC,EAAQ,GAAgB,MAAM,QAAQ,IAAI,CAAC,EAAuD,wBAAwB,EAAG,EAAmC,uBAAuB,CAAC,CAAC,EAAO,IAAS,EAAc,MAAQ,EAAO,cAAe,EAAiB,MAAQ,EAAa,SAAS,SAAS,oBAAoB,EAAI,OAAS,EAAO,CAAM,IAAO,EAAM,MAAQ,aAAiB,MAAQ,EAAM,QAAU,cAAc,CAAE,CAAC,EAC/c,MAAsB,CAAE,EAAQ,EAAM,CAAC,EACvC,EAAa,CAAE,aAAY,CAAC,UAG1B,EAAA,EAAA,EAOU,UAAA,CAPD,MAAM,cAAe,aAAU,GAAK,EAAA,MAAM,KAAI,QACrD,EAAwK,SAAA,KAAA,CAAhK,EAA+F,SAAA,CAAtF,SAAU,EAAA,OAAQ,EAAA,MAAY,QAAK,AAAA,EAAA,KAAA,GAAE,EAAW,GAAM,EAAI,OAAA,CAAW,EAAA,WAAQ,EAAA,CAAA,EAAS,EAAiC,SAAA,KAAA,EAAtB,EAAA,MAAM,IAAI,EAAA,CAAA,EAAY,AAAA,EAAA,KAAA,EAAuB,QAAA,KAAhB,WAAQ,EAAA,IACvJ,EAA8Q,MAA9Q,EAA8Q,EAAnP,EAAA,EAAA,EAA6O,EAAA,KAAA,EAAtN,CAAA,CAAA,UAAA,OAAA,EAAA,CAAA,SAAA,IAAA,EAAA,CAAA,YAAA,MAAA,EAAA,CAAA,UAAA,MAAA,CAAA,EAAR,GAAf,EAA6O,SAAA,CAA3H,IAAK,EAAI,GAAM,eAAc,EAAA,QAAQ,EAAI,GAAM,SAAU,EAAA,OAAQ,EAAA,MAAY,QAAK,GAAE,GAAO,EAAI,EAAA,CAAS,EAAA,EAAA,EAAI,EAAA,EAAA,EAAA,CAAA,UAChP,EAAA,OAAS,EAAA,QAAG,WAArB,EAAA,EAAA,EAAiE,IAAjE,EAAiE,EAAZ,EAAA,KAAK,EAAA,CAAA,GAAA,EAAA,GAAA,EAAA,EAClC,EAAA,QAAG,WAA3B,EAAA,EAAA,EAAqgB,EAAA,OAAtd,QAAA,UAAJ,IAAI,EAAU,SAAA,GAAS,qBAAA,GAAmB,WAAA,GAAU,MAAO,EAAA,MAAQ,MAAO,EAAA,MAAQ,OAAQ,EAAA,OAAS,cAAe,EAAA,MAAgB,kBAAiB,EAAA,MAAiB,oBAAmB,EAAA,MAAmB,KAAM,EAAA,MAAO,MAAO,EAAA,MAAQ,OAAM,EAAO,QAAK,AAAA,EAAA,KAAA,GAAE,EAAI,OAAA,EAAY,UAAO,AAAA,EAAA,KAAA,GAAE,EAAI,SAAA,EAAc,cAAY,AAAA,EAAA,KAAA,GAAE,EAAA,MAAQ,EAAS,aAAW,AAAA,EAAA,KAAA,GAAE,EAAA,MAAY,EAAS,eAAa,AAAA,EAAA,KAAA,GAAE,EAAI,WAAA,eAAA,EAAgC,oBAAkB,AAAA,EAAA,KAAA,GAAE,EAAI,WAAA,uBAAA,wGAC9b,CAAA,GAAA,EAAA,QAAG,UAAiB,EAAA,QAAG,aAArD,EAAA,EAAA,EAAwO,EAAA,CAAhK,IAAK,EAAA,MAAM,QAAS,EAAA,MAAM,gBAAe,EAAA,MAAM,GAAK,qBAAoB,EAAA,oBAAsB,cAAY,AAAA,EAAA,KAAA,GAAE,EAAA,MAAQ,EAAS,aAAW,AAAA,EAAA,KAAA,GAAE,EAAA,MAAY,yDAC9N,CAAA,IAAA,EAAA,EAAA,EAA6e,UAA7e,EAA6e,CAAvb,EAAuE,SAAA,CAA9D,SAAU,EAAA,MAAiB,QAAO,CAAa,EAAA,SAAM,EAAA,CAAA,EAAkB,EAAA,OAAT,EAAA,EAAA,EAAgD,IAAhD,EAAuC,OAAK,GAAmB,EAAA,MAAK,OAAe,EAAA,GAAA,EAAA,GAAnC,EAAA,EAAA,EAAuC,IAAA,EAAX,SAAO,IAAI,EAAA,EAAA,EAAA,EAA+Q,EAAA,KAAA,EAArP,EAAA,MAAV,IAAhB,EAAA,EAAA,EAA+Q,UAAA,CAA9O,IAAK,EAAO,EAAA,EAAA,CAAI,EAAyE,UAAA,KAAA,EAA7D,EAAO,KAAK,EAAG,MAAG,EAAG,EAAa,EAAO,MAAM,CAAA,EAAA,CAAA,EAA2B,EAAO,IAApB,EAAA,EAAA,EAAiF,QAAA,EAAA,EAAA,IAAlD,KAAK,EAAO,EAAE,CAAA,CAAE,eAAc,OAAA,CAAA,EAAA,CAAA,GAAA,EAAA,GAAA,EAAA,EAAoB,EAA0D,IAAA,KAAA,EAApD,EAAO,SAAW,EAAO,SAAO,SAAA,EAAA,CAAA,kfE9Czc,IAAM,EAAM,EACN,EAAK,EACL,EAAM,EAAqB,EAAE,EAAO,EAAsB,CAAC,CAAC,EAAE,EAAM,EAAI,EAAE,EAAE,EAAK,EAAI,EAAK,EAAE,EAAS,EAAI,EAAM,aAAa,EAAE,EAAE,EAAU,EAAI,EAAE,EAAE,EAAO,EAAI,EAAE,EAC/J,EAAY,MAAa,EAAO,MAAM,KAAK,GAAG,EAAE,KAAK,EAAS,KAAK,CAAC,EAAE,EAAQ,MAAa,EAAM,OAAO,SAAS,OAAO,GAAG,EAAE,SAAS,SAAS,GAAG,CAAC,CAAC,EACtJ,EAAM,GAAK,EAAW,EAAE,EAC5B,eAAe,GAAM,CAAC,IAAM,EAAI,EAAE,EAAW,GAAG,CAAC,GAAM,CAAC,EAAQ,GAAQ,MAAM,QAAQ,IAAI,CAAC,EAA4B,8BAA8B,EAAE,EAAsC,iBAAiB,CAAC,CAAC,EAAK,GAAO,IAAM,IAAY,EAAM,MAAM,EAAQ,EAAO,MAAM,EAAQ,WAAW,GAAG,EAAO,MAAM,EAAO,OAAO,EAAM,MAAM,GAAG,OAAO,EAAE,CAAI,GAAO,IAAM,IAAW,EAAM,MAAM,aAAa,MAAM,EAAE,QAAQ,OAAM,CAAC,CACpa,IAAM,EAAS,GAAa,EAAO,MAAM,KAAK,GAAG,EAAE,KAAK,CAAE,CAAC,EAAE,MAAM,GAAI,MACvE,SAAS,GAAS,EAAuB,CAAC,GAAG,EAAE,aAAa,iBAAiB,OAAO,EAAQ,EAAE,OAAO,EAAE,IAAM,EAAI,EAAE,UAAU,OAAO,GAAG,EAAE,WAAW,OAAO,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,OAAO,EAAE,OAAO,EAAI,OAAO,EAAI,IAAI,CAAO,CAAC,CAAC,KAAK,GAAG,EAAE,KAAK,CACnP,eAAe,EAAQ,EAA6B,EAAgC,CAAI,MAAK,MAAa,GAAK,MAAM,GAAK,GAAG,CAAC,MAAM,EAAW,sBAAsB,EAAQ,GAAG,UAAU,CAAC,OAAO,OAAO,KAAK,CAAC,WAAS,iBAAiB,EAAQ,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAK,EAAE,EAAK,SAAS,CAAC,OAAO,EAAE,CAAC,EAAM,MAAM,aAAa,MAAM,EAAE,QAAQ,MAAM,QAAQ,CAAC,EAAK,MAAM,EAAK,CAAtP,CAAuP,QAC5W,MAAU,EAAM,YAAY,GAAI,CAAI,IAAG,EAAS,MAAM,EAAE,CAAC,EACzD,MAAc,CAAC,EAAU,EAAE,EAAM,gBAAgB,CAAK,EAAK,OAAM,EAAU,CAAC,EAAE,GAAI,CAAC,CAAC,EACpF,MAAoB,CAAC,EAAM,GAAM,IAAa,cAAc,CAAK,CAAC,CAAC,UAGjE,EAAA,EAAA,EAkBU,UAlBV,EAkBU,CAjBC,EAAA,OAAT,EAAA,EAAA,EAA2G,IAA3G,EAA2G,CAA7D,EAAA,EAAA,EAAA,KAAK,EAAA,CAAA,EAAG,EAAiD,SAAA,CAAzC,KAAK,SAAU,QAAO,CAAM,EAAA,MAAI,CAAA,CAAA,GAAA,EAAA,GAAA,EAAA,EACnE,EAAA,OAA3B,EAAA,EAAA,EAA2H,EAAA,OAApF,gBAAe,EAAA,MAAY,QAAK,AAAA,EAAA,KAAA,GAAE,EAAA,MAAS,GAAM,UAAO,AAAA,EAAA,KAAA,GAAA,CAAE,EAAI,EAAG,EAAI,SAAA,CAAA,uCAC7E,EAAA,OAAI,eAAnC,EAAA,EAAA,EAAwK,EAAA,OAAlH,UAAO,AAAA,EAAA,KAAA,GAAE,EAAI,SAAA,EAAc,cAAY,AAAA,EAAA,KAAA,GAAE,EAAI,eAAgB,CAAM,EAAI,aAAW,AAAA,EAAA,KAAA,GAAE,EAAI,cAAe,CAAM,CAC9I,CAAA,GAAA,EAAA,OAAI,QAAzB,EAAA,EAAA,EASW,EAAA,CAAA,IAAA,CAAA,EAAA,CARO,EAAA,OAAhB,EAAA,EAAA,EAGW,EAAA,CAAA,IAAA,CAAA,EAAA,CAFT,EAA8Q,EAAA,CAArP,MAAO,EAAA,MAAc,OAAQ,EAAA,MAAS,uBAAsB,GAAO,QAAK,AAAA,EAAA,KAAA,GAAE,EAAA,MAAQ,GAAM,UAAO,AAAA,EAAA,KAAA,GAAA,CAAE,EAAI,EAAG,EAAI,SAAA,CAAA,EAAc,WAAQ,AAAA,EAAA,KAAA,GAAE,EAAI,WAAY,CAAM,EAAI,cAAY,AAAA,EAAA,KAAA,GAAE,EAAI,eAAgB,CAAM,EAAI,aAAW,AAAA,EAAA,KAAA,GAAE,EAAI,cAAe,CAAM,CACzQ,EAAA,KAAA,EAAA,CAAA,QAAA,QAAA,CAAA,EAAA,EAAsL,EAAA,CAA7J,KAAK,SAAU,YAAW,EAAA,MAAY,GAAK,UAAO,AAAA,EAAA,MAAA,GAAE,EAAI,SAAA,EAAc,cAAY,AAAA,EAAA,MAAA,GAAE,EAAI,eAAgB,CAAM,EAAI,aAAW,AAAA,EAAA,MAAA,GAAE,EAAI,cAAe,CAAM,CAEnL,EAAA,KAAA,EAAA,CAAA,WAAA,CAAA,CAAA,EAAA,EAAA,IAAA,EAAA,EAAA,EAGW,EAAA,CAAA,IAAA,CAAA,EAAA,CAFT,EAAmc,UAAnc,EAAmc,CAA7a,AAAA,EAAA,MAAA,EAAc,KAAA,KAAV,QAAK,EAAA,EAAK,AAAA,EAAA,MAAA,EAAuC,IAAA,KAApC,mCAAgC,EAAA,EAAI,EAAkQ,QAAA,KAAA,CAA3P,AAAA,EAAA,MAAA,EAAA,UAAO,EAAA,EAAA,EAAA,EAA4O,SAAA,CAA3N,sBAAA,AAAA,EAAA,MAAA,GAAA,EAAM,MAAA,CAAA,EAAA,CAAE,AAAA,EAAA,MAAA,EAAsC,SAAA,CAA9B,MAAM,GAAG,SAAA,EAAS,EAAA,MAAG,EAAA,GAAS,EAAA,EAAA,EAAA,EAAoK,EAAA,KAAA,EAA9I,EAAA,MAAO,OAAO,GAAC,CAAG,EAAE,UAAQ,CAAG,EAAE,iBAAe,CAAG,EAAE,eAAe,EAAE,SAAM,OAAA,EAAnF,IAAf,EAAA,EAAA,EAAoK,SAAA,CAApD,IAAK,EAAI,GAAK,MAAO,EAAI,EAAO,EAAA,EAAA,EAAI,IAAI,EAAA,EAAA,CAAA,EAAtM,EAAA,GAAA,EAAA,EAAA,GAAA,EAAA,CAAA,CAAA,EAAA,EAAA,KAAM,CAAA,CAAA,CAAA,CAAA,EAA6N,EAA4G,SAAA,CAApG,KAAK,SAAU,SAAQ,CAAG,EAAA,OAAQ,EAAA,QAAS,EAAA,OAAO,UAAY,QAAK,AAAA,EAAA,MAAA,GAAE,EAAA,MAAU,EAAA,KAAQ,EAAA,OAAI,EAAA,CAAA,CAChb,CAAA,EAAA,EAA0U,UAA1U,EAA0U,CAApT,AAAA,EAAA,MAAA,EAAe,KAAA,KAAX,SAAM,EAAA,EAAK,AAAA,EAAA,MAAA,EAA2C,IAAA,KAAxC,uCAAoC,EAAA,GAAI,EAAA,EAAA,EAAA,EAAgP,EAAA,KAAA,EAAzN,EAAA,MAAO,OAAO,GAAC,CAAG,EAAE,UAAQ,CAAG,EAAE,eAAe,EAAvD,IAAhB,EAAA,EAAA,EAAgP,UAAA,CAArK,IAAK,EAAI,EAAA,EAAA,CAAI,EAA4E,SAAA,KAAA,EAAjE,EAAI,IAAI,EAAA,EAAM,EAAI,KAAK,EAAA,OAAO,UAAS,WAAA,EAAA,EAAA,CAAA,EAA0B,EAAkE,SAAA,CAA1D,KAAK,SAAU,QAAK,GAAE,EAAA,MAAS,EAAI,EAAI,EAAA,aAAU,EAAA,CAAA,CAAA,CAAA,SAG5R,CAAA,CAAA,EAAA,EAAA,EAAA,EAAA,EAAA,GAAA,EAAA,OAAI,YAAzB,EAAA,EAAA,EAGW,EAAA,CAAA,IAAA,CAAA,EAAA,CAFT,EAA+4B,UAA/4B,EAA+4B,CAAz3B,EAAqC,KAAA,KAAjC,WAAQ,EAAG,EAAA,MAAQ,MAAM,EAAA,CAAA,EAAkB,EAAA,MAAQ,OAAkB,EAAA,GAAA,EAAA,GAApC,EAAA,EAAA,EAAwC,IAAA,EAAd,YAAU,IAAI,EAAA,EAAA,EAAA,EAAkyB,EAAA,KAAA,EAAvwB,EAAA,MAAX,IAAhB,EAAA,EAAA,EAAkyB,UAAA,CAA7vB,IAAK,EAAQ,GAAI,MAAM,YAAU,EAA0E,SAAA,KAAA,EAA/D,EAAA,MAAO,KAAK,GAAG,EAAE,KAAK,EAAQ,OAAO,CAAA,EAAG,MAAI,KAAA,EAAA,CAAA,EAAmB,EAAsE,QAAA,KAA/D,OAAI,EAAG,EAAQ,EAAQ,aAAa,EAAQ,OAAO,CAAA,EAAA,CAAA,EAAY,EAA4C,QAAA,KAArC,SAAM,EAAG,GAAS,CAAO,CAAA,EAAA,CAAA,EAAY,EAA4C,IAAA,KAAA,EAAtC,EAAQ,SAAS,EAAQ,MAAM,EAAA,CAAA,EAAO,EAAuE,QAAA,KAAA,EAA7D,EAAQ,MAAM,EAAG,MAAG,EAAG,EAAQ,UAAU,KAAI,GAAA,CAAA,EAAA,CAAA,EAA6B,EAAQ,uBAAuB,EAAQ,sBAA8C,EAAA,GAAA,EAAA,GAAlG,EAAA,EAAA,EAA0G,QAAA,EAA/B,yBAAuB,GAAQ,EAAyT,MAAzT,EAAyT,CAApS,EAAmF,SAAA,CAA3E,KAAK,SAAU,SAAU,EAAA,MAAO,QAAK,GAAE,EAAQ,EAAO,MAAA,CAAU,EAAA,KAAE,EAAA,CAAA,EAAS,EAAqF,SAAA,CAA7E,KAAK,SAAU,SAAU,EAAA,MAAO,QAAK,GAAE,EAAQ,EAAO,MAAA,CAAU,EAAA,OAAI,EAAA,CAAA,EAAwB,EAAQ,WAAsF,EAAA,GAAA,EAAA,GAA7G,EAAA,EAAA,EAAsH,SAAA,OAAnF,KAAK,SAAU,SAAU,EAAA,MAAO,QAAK,GAAE,EAAQ,EAAO,QAAA,CAAY,EAAA,WAAQ,EAAA,EAAA,cAC52B,CAAA,EAAA,EAAie,UAAje,EAAie,CAA3c,AAAA,EAAA,MAAA,EAAe,KAAA,KAAX,SAAM,EAAA,GAAK,EAAA,EAAA,EAAA,EAAkb,EAAA,KAAA,EAAvZ,EAAA,OAAO,SAAS,OAAO,GAAG,EAAE,SAAM,SAAA,GAAA,CAAA,EAA7C,IAAhB,EAAA,EAAA,EAAkb,UAAA,CAAjW,IAAK,EAAQ,GAAI,MAAM,YAAU,EAAkG,SAAA,KAAA,EAAA,CAAA,SAAA,MAAA,OAAA,MAAA,QAAA,MAAA,QAAA,KAAA,EAA3B,EAAQ,OAAM,EAAA,CAAA,EAAa,EAAsE,QAAA,KAA/D,OAAI,EAAG,EAAQ,EAAQ,aAAa,EAAQ,OAAO,CAAA,EAAA,CAAA,EAAY,EAA4C,QAAA,KAArC,SAAM,EAAG,GAAS,CAAO,CAAA,EAAA,CAAA,EAAY,EAA2B,IAAA,KAAA,EAArB,EAAQ,MAAM,EAAA,CAAA,EAAO,EAAuE,QAAA,KAAA,EAA7D,EAAQ,MAAM,EAAG,MAAG,EAAG,EAAQ,UAAU,KAAI,GAAA,CAAA,EAAA,CAAA"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{A as e,Dt as t,F as n,G as r,H as i,L as a,M as o,Tt as s,W as c,_ as l,a as u,b as d,d as f,et as p,f as m,m as h,ot as g,p as _,t as v,u as y,v as b}from"./_plugin-vue_export-helper-BumXM028.js";import{G as x,J as S,M as C,V as w,W as T,w as E}from"./index-D0pMYnOi.js";import{t as D}from"./StandaloneDialog-7GkhtRlT.js";import{r as O,t as k}from"./ProviderLoginDialog-Bw5KVMfi.js";import{_ as A,s as j,v as M,y as N}from"./ConversationsView-1igFR9VY.js";var P={class:`integration-panel plugins`,"aria-label":`本地原生插件`},F={class:`integration-header`},I={class:`catalog-intro`},L=[`disabled`],R={class:`plugin-trust`},z={key:0,class:`integration-alert`,role:`alert`},B={key:1,class:`integration-alert`,role:`status`},V={class:`integration-toolbar`},H={class:`integration-search`},U={class:`integration-check`},W={key:2,class:`integration-card update-review`},G={class:`capability-compare`},K={class:`integration-actions`},q=[`disabled`],ee={class:`catalog-results`},J={class:`integration-count`},Y={class:`plugins-grid`},X={class:`plugin-heading`},Z={class:`integration-mark`},te={class:`plugin-version`},ne={class:`plugin-description`},re={class:`compatibility`},Q={class:`plugin-details`},$=[`href`],ie={class:`source-sha`},ae={key:0},oe={key:0,class:`plugin-failure`},se={class:`integration-actions plugin-footer`},ce=[`disabled`,`onClick`],le=[`disabled`,`onClick`],ue=[`disabled`,`onClick`],de={key:3,class:`integration-empty`},fe=v(d({__name:`NativePluginsPanel`,setup(e){let i=p([]),c=p(``),d=p(!1),m=p(!1),g=p(``),v=p(``),S=p(),T=p(),D=y(()=>i.value.filter(e=>(!d.value||e.installed)&&`${e.name} ${e.title} ${e.description}`.toLowerCase().includes(c.value.toLowerCase())));async function O(){i.value=(await E(`/api/app/admin/hermes/local/plugins/catalog`)).plugins}async function k(e){if(!m.value){m.value=!0,g.value=``;try{await e()}catch(e){g.value=e instanceof Error?e.message:`插件操作失败`}finally{m.value=!1}}}async function A(e,t=!1){await k(async()=>{let n=await E(`/api/app/admin/hermes/local/plugins/install`,{method:`POST`,timeoutMs:61e4,body:{name:e.name,sha:e.sha,acceptChanges:t}});if(n.consent_required){S.value=e,T.value=n,v.value=`更新版本可能改变能力和依赖,请审阅后确认。`;return}if(!n.ok)throw Error(n.error??`插件未安装`);S.value=void 0,v.value=`安装完成。插件保持停用,启用时检查宿主兼容性。`,await O()})}async function j(e){await k(async()=>{let t=await E(`/api/app/admin/hermes/local/plugins/enabled`,{method:`POST`,body:{name:e.name,enabled:!e.installed?.enabled}});if(!t.ok)throw Error(t.error??`插件状态未改变`);await O()})}async function M(e){window.confirm(`移除 `+e.name+`?原包会保留在主机备份目录。`)&&await k(async()=>{await E(`/api/app/admin/hermes/local/plugins/remove`,{method:`POST`,body:{name:e.name}}),await O()})}return o(()=>k(O)),(e,o)=>(n(),h(`section`,P,[f(`header`,F,[f(`div`,null,[o[5]||=f(`h3`,null,`发现更多能力`,-1),f(`p`,I,t(i.value.length)+` 项本地插件,按固定版本安装。`,1)]),f(`button`,{class:`quiet`,disabled:m.value,"aria-label":`刷新本地目录`,onClick:o[0]||=e=>k(O)},[b(C,{name:`refresh`,size:17})],8,L)]),f(`details`,R,[f(`summary`,null,[b(C,{name:`shield`,size:17}),o[6]||=l(`仅安装你信任的插件`,-1)]),o[7]||=f(`p`,null,`插件运行在主机上,可访问文件和网络。Bot 权限控制工具入口,不能隔离插件的初始化或内部行为。桌面、Hook、供应商等能力需要各自宿主适配,安装成功不代表已可用。`,-1)]),g.value?(n(),h(`p`,z,[b(C,{name:`alert`,size:17}),l(t(g.value),1)])):_(``,!0),v.value?(n(),h(`p`,B,[b(C,{name:`check`,size:17}),l(t(v.value),1)])):_(``,!0),f(`div`,V,[f(`label`,H,[o[8]||=f(`span`,{class:`sr-only`},`搜索插件`,-1),b(C,{name:`search`,size:17}),r(f(`input`,{"onUpdate:modelValue":o[1]||=e=>c.value=e,type:`search`,placeholder:`搜索插件名称或用途`},null,512),[[x,c.value]])]),f(`label`,U,[r(f(`input`,{"onUpdate:modelValue":o[2]||=e=>d.value=e,type:`checkbox`},null,512),[[w,d.value]]),o[9]||=l(`仅显示已安装`,-1)])]),S.value?(n(),h(`article`,W,[o[12]||=f(`span`,{class:`integration-tag warning`},`需要审阅`,-1),f(`h4`,null,`审阅 `+t(S.value.name)+` 更新`,1),f(`p`,null,t(S.value.description),1),f(`p`,null,`版本 `+t(S.value.version)+` · `+t(S.value.sha),1),f(`div`,G,[f(`div`,null,[o[10]||=f(`h4`,null,`旧能力`,-1),f(`pre`,null,t(JSON.stringify(T.value?.oldCapabilities,null,2)),1)]),f(`div`,null,[o[11]||=f(`h4`,null,`新能力`,-1),f(`pre`,null,t(JSON.stringify(T.value?.newCapabilities,null,2)),1)])]),o[13]||=f(`h4`,null,`当前依赖`,-1),f(`pre`,null,t(T.value?.oldDependencies),1),o[14]||=f(`p`,null,`新版本按固定 SHA 扫描并校验实际能力;依赖安装受 Host 版本约束,安装后保持停用。`,-1),f(`div`,K,[f(`button`,{class:`primary`,disabled:m.value,onClick:o[3]||=e=>A(S.value,!0)},`确认更新到此版本`,8,q),f(`button`,{onClick:o[4]||=e=>S.value=void 0},`取消更新`)])])):_(``,!0),f(`div`,ee,[f(`span`,J,t(c.value||d.value?`匹配 `+D.value.length+` 项`:`全部 `+i.value.length+` 项`),1),o[15]||=f(`span`,{class:`integration-count`},`安装后默认停用`,-1)]),f(`ul`,Y,[(n(!0),h(u,null,a(D.value,e=>(n(),h(`li`,{key:e.name,class:`integration-card plugin-card`},[f(`div`,X,[f(`span`,Z,[b(C,{name:e.compatibility===`tools`?`tools`:e.category===`desktop`?`monitor`:`artifacts`,size:20},null,8,[`name`])]),f(`div`,null,[f(`h4`,null,t(e.title||e.name),1),f(`span`,te,`v`+t(e.version),1)]),e.installed?(n(),h(`span`,{key:0,class:s([`integration-tag`,{success:e.installed.enabled}])},t(e.installed.enabled?`已启用`:`已安装`),3)):_(``,!0)]),f(`p`,ne,t(e.description),1),f(`p`,re,[f(`span`,{class:s([`integration-tag`,{success:e.compatibility===`tools`,warning:e.compatibility!==`tools`}])},t(e.compatibility===`tools`?`工具可接入`:`需适配`),3),l(t(e.compatibilityNote),1)]),f(`details`,Q,[o[16]||=f(`summary`,null,`来源、能力与依赖`,-1),f(`p`,null,t(e.description),1),f(`a`,{href:e.repo,target:`_blank`,rel:`noopener noreferrer`},`查看源码 ↗`,8,$),f(`p`,ie,`固定版本:`+t(e.sha),1),f(`pre`,null,t(JSON.stringify(e.capabilities,null,2)),1),e.installed?.dependencies?.length?(n(),h(`p`,ae,`已安装依赖:`+t(e.installed.dependencies.join(`、`)),1)):_(``,!0)]),e.installed?.lastError?(n(),h(`p`,oe,t(e.installed.lastError),1)):_(``,!0),f(`div`,se,[!e.installed||e.installed.sha!==e.sha?(n(),h(`button`,{key:0,disabled:m.value,onClick:t=>A(e)},[b(C,{name:e.installed?`refresh`:`plus`,size:15},null,8,[`name`]),l(t(e.installed?`检查并更新`:`安装固定版本`),1)],8,ce)):_(``,!0),e.installed?(n(),h(`button`,{key:1,class:s({primary:!e.installed.enabled}),disabled:m.value||!e.installed.enabled&&e.compatibility!==`tools`,onClick:t=>j(e)},t(e.installed.enabled?`停用`:`检查并启用工具`),11,le)):_(``,!0),e.installed?(n(),h(`button`,{key:2,class:`quiet danger`,disabled:m.value,onClick:t=>M(e)},`移除`,8,ue)):_(``,!0)])]))),128))]),!m.value&&!D.value.length?(n(),h(`div`,de,[b(C,{name:`search`,size:28}),o[17]||=f(`strong`,null,`没有匹配的插件`,-1),o[18]||=f(`p`,null,`试试其他关键词,或取消已安装筛选。`,-1)])):_(``,!0)]))}}),[[`__scopeId`,`data-v-2e231ffc`]]),pe=[`aria-label`],me={class:`integration-header`},he={class:`integration-heading`},ge=[`disabled`],_e={class:`mail-account`},ve=[`disabled`],ye=[`value`],be={class:`integration-search`},xe=[`disabled`],Se={key:0,class:`mail-loading`,role:`status`},Ce={key:1,class:`integration-alert`,role:`alert`},we={key:2,class:`integration-alert`,role:`status`},Te={key:3,class:`mail-unknown`},Ee={class:`integration-heading`},De={class:`integration-actions`},Oe=[`disabled`],ke=[`disabled`],Ae={class:`mail-layout`},je={class:`mail-list`},Me={class:`mail-list-heading`},Ne={class:`messages`},Pe=[`aria-pressed`,`disabled`,`onClick`],Fe={class:`message-from`},Ie={key:0,class:`integration-empty`},Le={class:`mail-reading`},Re={class:`compose-heading`},ze={class:`integration-tag`},Be=[`disabled`],Ve=[`disabled`],He={class:`integration-actions`},Ue=[`disabled`],We=[`disabled`],Ge={key:1,class:`mail-detail`},Ke={class:`mail-detail-heading`},qe={class:`message-meta`},Je=[`innerHTML`],Ye={key:0,class:`mail-attachments`},Xe=[`disabled`,`onClick`],Ze={class:`integration-actions mail-actions`},Qe=[`disabled`],$e=[`disabled`],et=[`disabled`],tt={class:`mail-labels`},nt=[`value`],rt={class:`integration-actions`},it=[`disabled`],at=[`disabled`],ot={key:2,class:`integration-empty reading-empty`},st={class:`reading-illustration`},ct=v(d({__name:`GmailPanel`,props:{accounts:{},source:{default:`local`}},setup(e){let c=e,d=y(()=>c.source===`composio`?`Composio 托管`:`本地连接`),m=(e=c.source)=>e===`composio`?`/api/app/admin/composio`:`/api/app/admin/hermes/local/google`,g=p(c.accounts[0]?.id??``),v=p(`in:inbox`),w=p([]),D=p(),O=p(!1),k=p(``),A=p(``),M=p(!1),N=p(!1),P=p(``),F=p(``),I=p(``),L=p(``),R=p([]),z=p(!1),B=0,V=!1,H,U=p(),W=(e,t)=>e?.payload?.headers?.find(e=>e.name.toLowerCase()===t.toLowerCase())?.value??``;async function G(e,t,n=!1,r=g.value,i,a=c.source){let o=n?i??crypto.randomUUID():void 0;try{let i=await E(m(a)+`/call`,{method:`POST`,timeoutMs:95e3,body:{accountId:r,operation:e,arguments:t,...n?{operationId:o}:{}}});if(i?.isError){n&&i.outcomeUnknown&&(z.value=!0,U.value={accountId:r,operationId:o,source:a});let e=Error(i.error?.message??`Google 请求失败`);throw Object.assign(e,{known:!i.outcomeUnknown}),e}return i}catch(e){throw a===`composio`&&[400,401,403,404,409,413,422].includes(e?.status??0)&&Object.assign(e,{known:!0}),n&&!e?.known&&(z.value=!0,U.value={accountId:r,operationId:o,source:a}),e}}async function K(e){if(O.value){e===q&&(V=!0);return}O.value=!0,k.value=``,A.value=``;try{await e()}catch(e){k.value=e instanceof Error?e.message:`邮箱操作失败`}finally{O.value=!1,V&&(V=!1,K(q))}}async function q(){if(!g.value)return;let e=++B,t=g.value,n=c.source;D.value=void 0;let r=await G(`gmail.search`,{query:v.value,max:15},!1,t,void 0,n),i=[];if(e!==B||t!==g.value||n!==c.source)return;for(let a of r.messages??[]){let r=await G(`gmail.get`,{id:a.id},!1,t,void 0,n);if(e!==B||t!==g.value)return;i.push(r)}let a=await G(`gmail.labels`,{},!1,t,void 0,n);e===B&&t===g.value&&(w.value=i,R.value=a.labels??[])}async function ee(e){await K(async()=>{let t=g.value,n=B,r=c.source,i=await G(`gmail.get`,{id:e.id},!1,t,void 0,r);t===g.value&&n===B&&(D.value=i)})}async function J(){await K(async()=>{if(!U.value)return;let e=await E(m(U.value.source)+`/receipts/`+U.value.accountId+`/`+encodeURIComponent(U.value.operationId));A.value=e.status===`complete`?`邮箱操作已完成,已读取保存的结果。`:e.status===`rejected`?`邮箱服务已拒绝此操作。`:`仍无确认结果,请在 Gmail 核对。`,[`complete`,`rejected`].includes(e.status)&&(z.value=!1,M.value=!1,H=void 0,U.value=void 0,await q())})}function Y(e){let t=Uint8Array.from(atob(e.replace(/-/g,`+`).replace(/_/g,`/`)),e=>e.charCodeAt(0));return new TextDecoder().decode(t)}function X(e){if(!e)return``;if(e.mimeType===`text/plain`&&e.body?.data)return`<pre>`+Y(e.body.data).replace(/&/g,`&`).replace(/</g,`<`).replace(/>/g,`>`).replace(/\n/g,`<br>`)+`</pre>`;let t=e.parts??[],n=t.find(e=>e.mimeType===`text/plain`);return n?X(n):e.mimeType===`text/html`&&e.body?.data?j.sanitize(Y(e.body.data),{FORBID_TAGS:[`img`,`style`,`script`,`iframe`,`form`,`svg`,`math`,`video`,`audio`,`link`],FORBID_ATTR:[`style`,`src`,`srcset`,`background`]}):t.map(X).join(``)}function Z(e){return[...e?.filename&&(e?.body?.attachmentId||e?.body?.data)?[e]:[],...(e?.parts??[]).flatMap(Z)]}async function te(e){await K(async()=>{let t=e.body.data?e.body:await G(`gmail.attachment`,{id:D.value.id,attachmentId:e.body.attachmentId});if(t.size>26214400||String(t.data??``).length>104857600/3+4)throw Error(`附件超过25MB限制`);let n=Uint8Array.from(atob(t.data.replace(/-/g,`+`).replace(/_/g,`/`)),e=>e.charCodeAt(0)),r=URL.createObjectURL(new Blob([n],{type:`application/octet-stream`})),i=document.createElement(`a`);i.href=r,i.download=String(e.filename).replace(/[\\/\x00-\x1f]/g,`_`).slice(0,180)||`attachment`,document.body.append(i),i.click(),i.remove(),setTimeout(()=>URL.revokeObjectURL(r),3e4)})}function ne(e=!1){z.value||(H={accountId:g.value,...e?{messageId:D.value.id}:{},operationId:crypto.randomUUID(),source:c.source},N.value=e,M.value=!0,P.value=e?W(D.value,`Reply-To`)||W(D.value,`From`):``,F.value=e?`Re: `+W(D.value,`Subject`):``,I.value=``)}async function re(){await K(async()=>{let e=H;if(!e||e.accountId!==g.value||e.source!==c.source||z.value)throw Error(`草稿账号已改变,请重新编辑。`);try{let t=await G(e.messageId?`gmail.reply`:`gmail.send`,e.messageId?{id:e.messageId,body:I.value}:{to:P.value,subject:F.value,body:I.value},!0,e.accountId,e.operationId,e.source);if(e.accountId!==g.value||e.source!==c.source)return;M.value=!1,H=void 0,A.value=`邮件已发送,消息编号:`+(t.id??`已确认`),t.id&&(D.value=await G(`gmail.get`,{id:t.id},!1,e.accountId,void 0,e.source))}catch(e){throw!z.value&&H&&(H.operationId=crypto.randomUUID()),e}})}async function Q(e,t){z.value||await K(async()=>{let n=g.value;await G(e,t,!0,n),await q(),A.value=`邮箱操作已完成。`})}return i(()=>c.accounts.map(e=>e.id).join(`,`),()=>{c.accounts.some(e=>e.id===g.value)||(g.value=c.accounts[0]?.id??``,B++,w.value=[],D.value=void 0,M.value=!1,H=void 0)}),i(()=>c.source,()=>{B++,w.value=[],D.value=void 0,M.value=!1,H=void 0,k.value=``,A.value=``,K(q)}),i(g,()=>{B++,w.value=[],D.value=void 0,M.value=!1,H=void 0,K(q)}),o(()=>K(q)),(i,o)=>(n(),h(`section`,{class:`integration-panel mailbox`,"aria-label":e.source===`composio`?`Composio Gmail 邮箱`:`本地 Gmail 邮箱`},[f(`header`,me,[f(`div`,he,[o[16]||=f(`span`,{class:`integration-mark gmail-mark`},[f(`img`,{src:`/provider-logos/gmail.svg`,alt:``,width:`25`,height:`25`})],-1),f(`div`,null,[o[15]||=f(`h3`,null,`Gmail`,-1),f(`p`,null,t(d.value)+` · `+t(w.value.length)+` 封邮件`,1)])]),f(`button`,{class:`primary`,type:`button`,disabled:O.value||z.value||!g.value,onClick:o[0]||=e=>ne()},[b(C,{name:`edit`,size:16}),o[17]||=l(`写邮件`,-1)],8,ge)]),f(`label`,_e,[o[18]||=l(`账号`,-1),r(f(`select`,{"onUpdate:modelValue":o[1]||=e=>g.value=e,disabled:O.value},[(n(!0),h(u,null,a(e.accounts,e=>(n(),h(`option`,{value:e.id,key:e.id},t(e.label),9,ye))),128))],8,ve),[[T,g.value]])]),f(`form`,{class:`mail-search`,onSubmit:o[3]||=S(e=>K(q),[`prevent`])},[f(`label`,be,[o[19]||=f(`span`,{class:`sr-only`},`搜索邮件`,-1),b(C,{name:`search`,size:17}),r(f(`input`,{"onUpdate:modelValue":o[2]||=e=>v.value=e,placeholder:`in:inbox 或 Gmail 搜索语法`},null,512),[[x,v.value]])]),f(`button`,{disabled:O.value},[b(C,{name:`refresh`,size:16}),o[20]||=l(`搜索 / 刷新`,-1)],8,xe)],32),O.value?(n(),h(`p`,Se,[b(C,{name:`clock`,size:15}),o[21]||=l(`正在处理邮箱…`,-1)])):_(``,!0),k.value?(n(),h(`p`,Ce,t(k.value),1)):_(``,!0),A.value?(n(),h(`p`,we,t(A.value),1)):_(``,!0),z.value?(n(),h(`div`,Te,[f(`div`,Ee,[b(C,{name:`alert`,size:19}),o[22]||=f(`strong`,null,`写入结果尚未确认`,-1)]),o[23]||=f(`p`,null,`请先在 Gmail 核对,再继续操作。`,-1),f(`div`,De,[f(`button`,{disabled:O.value,onClick:J},`查询操作收据`,8,Oe),f(`button`,{class:`quiet`,disabled:O.value,onClick:o[4]||=e=>{z.value=!1,M.value=!1,A.value=`已按你的确认允许新的操作;原操作不会自动重发。`}},`我已在 Gmail 核对,允许新操作`,8,ke)])])):_(``,!0),f(`div`,Ae,[f(`aside`,je,[f(`div`,Me,[o[24]||=f(`span`,null,`邮件列表`,-1),f(`span`,null,t(w.value.length),1)]),f(`ul`,Ne,[(n(!0),h(u,null,a(w.value,e=>(n(),h(`li`,{key:e.id},[f(`button`,{class:s({active:D.value?.id===e.id}),"aria-pressed":D.value?.id===e.id,disabled:O.value,onClick:t=>ee(e)},[f(`span`,Fe,t(W(e,`From`)),1),f(`strong`,null,t(W(e,`Subject`)||`(无主题)`),1),f(`small`,null,t(e.snippet),1)],10,Pe)]))),128))]),!O.value&&!w.value.length?(n(),h(`div`,Ie,[b(C,{name:`archive`,size:26}),o[25]||=f(`p`,null,`没有匹配的邮件。`,-1)])):_(``,!0)]),f(`div`,Le,[M.value?(n(),h(`form`,{key:0,class:`mail-compose`,onSubmit:S(re,[`prevent`])},[f(`div`,Re,[f(`h4`,null,t(N.value?`回复邮件`:`新邮件`),1),f(`span`,ze,t(e.accounts.find(e=>e.id===g.value)?.label),1)]),f(`label`,null,[o[26]||=l(`收件人`,-1),r(f(`input`,{"onUpdate:modelValue":o[5]||=e=>P.value=e,disabled:N.value,required:``},null,8,Be),[[x,P.value]])]),f(`label`,null,[o[27]||=l(`主题`,-1),r(f(`input`,{"onUpdate:modelValue":o[6]||=e=>F.value=e,disabled:N.value,required:``},null,8,Ve),[[x,F.value]])]),f(`label`,null,[o[28]||=l(`正文`,-1),r(f(`textarea`,{"onUpdate:modelValue":o[7]||=e=>I.value=e,rows:`7`,placeholder:`写下你的邮件…`,required:``},null,512),[[x,I.value]])]),f(`div`,He,[f(`button`,{class:`primary`,disabled:O.value||z.value},[b(C,{name:`arrow-up`,size:16}),o[29]||=l(`发送邮件`,-1)],8,Ue),f(`button`,{class:`quiet`,type:`button`,disabled:O.value,onClick:o[8]||=e=>M.value=!1},`取消编辑`,8,We)])],32)):_(``,!0),D.value?(n(),h(`article`,Ge,[f(`header`,Ke,[f(`h4`,null,t(W(D.value,`Subject`)||`(无主题)`),1),f(`p`,null,t(W(D.value,`From`)),1),f(`p`,qe,[l(`发送至 `+t(W(D.value,`To`)),1),o[30]||=f(`br`,null,null,-1),l(t(W(D.value,`Date`)),1)])]),f(`div`,{class:`email-body`,innerHTML:X(D.value.payload)},null,8,Je),Z(D.value.payload).length?(n(),h(`div`,Ye,[(n(!0),h(u,null,a(Z(D.value.payload),e=>(n(),h(`button`,{key:e.partId??e.body.attachmentId??e.filename,disabled:O.value,onClick:t=>te(e)},[b(C,{name:`download`,size:16}),l(`下载 `+t(e.filename)+`(`+t(e.body.size)+` 字节)`,1)],8,Xe))),128))])):_(``,!0),f(`div`,Ze,[f(`button`,{disabled:O.value||z.value,onClick:o[9]||=e=>ne(!0)},[b(C,{name:`edit`,size:15}),o[31]||=l(`回复`,-1)],8,Qe),f(`button`,{class:`quiet`,disabled:O.value||z.value,onClick:o[10]||=e=>Q(`gmail.modify`,{id:D.value.id,removeLabels:[`INBOX`]})},[b(C,{name:`archive`,size:15}),o[32]||=l(`归档`,-1)],8,$e),f(`button`,{class:`quiet danger`,disabled:O.value||z.value,onClick:o[11]||=e=>Q(`gmail.trash`,{id:D.value.id})},[b(C,{name:`trash`,size:15}),o[33]||=l(`移入垃圾箱`,-1)],8,et)]),f(`div`,tt,[f(`label`,null,[o[35]||=l(`标签`,-1),r(f(`select`,{"onUpdate:modelValue":o[12]||=e=>L.value=e},[o[34]||=f(`option`,{value:``},`选择标签`,-1),(n(!0),h(u,null,a(R.value,e=>(n(),h(`option`,{key:e.id,value:e.id},t(e.name),9,nt))),128))],512),[[T,L.value]])]),f(`div`,rt,[f(`button`,{disabled:O.value||z.value||!L.value.trim(),onClick:o[13]||=e=>Q(`gmail.modify`,{id:D.value.id,addLabels:[L.value]})},`添加标签`,8,it),f(`button`,{class:`quiet`,disabled:O.value||z.value||!L.value,onClick:o[14]||=e=>Q(`gmail.modify`,{id:D.value.id,removeLabels:[L.value]})},`移除标签`,8,at)])])])):M.value?_(``,!0):(n(),h(`div`,ot,[f(`span`,st,[b(C,{name:`file`,size:32})]),o[36]||=f(`strong`,null,`选择一封邮件开始阅读`,-1),o[37]||=f(`p`,null,`也可以写封新邮件,继续你的对话。`,-1)]))])])],8,pe))}}),[[`__scopeId`,`data-v-c7018d71`]]),lt={class:`integration-panel local-apps`,"aria-label":`本地应用`},ut={class:`integration-header`},dt=[`disabled`],ft={key:0,class:`integration-alert`,role:`alert`},pt={key:1,class:`integration-alert`,role:`status`},mt={class:`integration-card google-card`},ht={class:`integration-header`},gt={class:`google-setup`},_t={class:`setup-content`},vt=[`disabled`],yt={class:`google-services`},bt={class:`service-grid`},xt=[`value`],St=[`src`],Ct={class:`connect-row`},wt={class:`integration-actions`},Tt=[`disabled`],Et=[`disabled`],Dt={key:0,class:`auth-progress`,role:`status`},Ot={key:0},kt={class:`integration-actions`},At=[`href`],jt=[`disabled`],Mt={class:`google-accounts`},Nt={class:`accounts-heading`},Pt={class:`integration-count`},Ft={key:0},It={class:`account-row`},Lt={class:`account-avatar`},Rt={class:`account-copy`},zt={class:`account-manage`},Bt={class:`integration-actions`},Vt=[`disabled`,`onClick`],Ht=[`disabled`,`onClick`],Ut=[`disabled`,`onClick`],Wt={key:1,class:`accounts-empty`},Gt=v(d({__name:`LocalAppsPanel`,setup(i){let c=p(),d=p(``),g=p([`gmail`]),v=p(),y=p(!1),T=p(``),D=p(``),O=p(!1),k=p(),A={gmail:`gmail`,calendar:`googlecalendar`,drive:`googledrive`},j={gmail:`Gmail`,calendar:`日历`,drive:`云盘`,contacts:`联系人`,sheets:`表格`,docs:`文档`},M,N=!1;async function P(){c.value=await E(`/api/app/admin/hermes/local/google/status`)}async function F(e){if(!y.value){y.value=!0,T.value=``;try{await e()}catch(e){T.value=e instanceof Error?e.message:`操作失败`}finally{y.value=!1}}}async function I(){await F(async()=>{await E(`/api/app/admin/hermes/local/google/client`,{method:`POST`,body:{client:JSON.parse(d.value)}}),d.value=``,D.value=`客户端已保存在主机。请选择服务并连接账号。`,await P()})}async function L(e){if(y.value)return;let t=window.open(`about:blank`,`_blank`);t&&(t.opener=null),await F(async()=>{try{v.value=await E(`/api/app/admin/hermes/local/google/auth`,{method:`POST`,body:{services:g.value,...e?{accountId:e}:{}}}),t&&v.value.authUrl?t.location.href=v.value.authUrl:t?.close(),z()}catch(e){throw t?.close(),e}})}function R(e){let t=c.value?.accounts.find(t=>t.id===e);t&&(g.value=[...t.services],k.value=e,D.value=`已选择 `+t.label+`。请在上方勾选本次服务,再点击重新授权。`)}function z(){clearTimeout(M),!(N||!v.value||![`pending`,`received`,`exchanging`].includes(v.value.status))&&(M=setTimeout(async()=>{try{let e=await E(`/api/app/admin/hermes/local/google/auth/`+v.value.id);if(N)return;v.value={...v.value,...e},e.status===`approved`&&(D.value=`Google 已连接。`,await P())}catch(e){N||(T.value=e instanceof Error?e.message:`授权状态读取失败`)}z()},2e3))}async function B(){await F(async()=>{v.value&&=await E(`/api/app/admin/hermes/local/google/auth/`+v.value.id,{method:`DELETE`}),clearTimeout(M)})}async function V(e,t,n=!1){window.confirm(n?`撤销Google授权并断开?同一Google账号和客户端的其他本地连接也可能需要重新授权。`:`断开这个本地 Google 账号?使用此连接的 Bot 将无法继续访问。`)&&await F(async()=>{let r=await E(`/api/app/admin/hermes/local/google/accounts/`+e,{method:`DELETE`,body:{revision:t,revoke:n}});D.value=r.note,await P()})}let H=e=>({pending:`等待授权`,received:`授权已收到`,exchanging:`确认授权中`,approved:`已连接`,failed:`授权未完成`,expired:`授权已过期`,cancelled:`已取消`,connected:`已连接`,partial:`部分服务未获授权`,reauth_required:`需要重新授权`})[e]??e;return o(()=>F(P)),e(()=>{N=!0,clearTimeout(M),v.value&&[`pending`,`received`,`exchanging`].includes(v.value.status)&&E(`/api/app/admin/hermes/local/google/auth/`+v.value.id,{method:`DELETE`}).catch(()=>{})}),(e,i)=>(n(),h(`section`,lt,[f(`header`,ut,[i[6]||=f(`div`,null,[f(`h3`,null,`连接你的日常工具`),f(`p`,{class:`local-intro`},`由当前主机直接连接,账号与 Nous 应用独立管理。`)],-1),f(`button`,{class:`quiet refresh-local`,type:`button`,disabled:y.value,"aria-label":`刷新本地连接`,onClick:i[0]||=e=>F(P)},[b(C,{name:`refresh`,size:17})],8,dt)]),T.value?(n(),h(`p`,ft,[b(C,{name:`alert`,size:17}),l(t(T.value),1)])):_(``,!0),D.value?(n(),h(`p`,pt,[b(C,{name:`check`,size:17}),l(t(D.value),1)])):_(``,!0),f(`article`,mt,[f(`header`,ht,[i[7]||=f(`div`,{class:`integration-heading`},[f(`span`,{class:`google-mark`},[f(`span`,null,`G`)]),f(`div`,null,[f(`h3`,null,`Google Workspace`),f(`p`,null,`邮件、日程和文件,一处连接。`)])],-1),f(`span`,{class:s([`integration-tag`,{success:c.value?.configured}])},t(c.value?.configured?`客户端已配置`:`待配置`),3)]),f(`details`,gt,[f(`summary`,null,[b(C,{name:`settings`,size:16}),l(t(c.value?.configured?`更新 Google 客户端`:`配置 Google 客户端`),1)]),f(`div`,_t,[i[9]||=f(`p`,null,`在 Google Cloud 创建“桌面应用”客户端,启用所需 API,然后粘贴下载的 JSON。`,-1),i[10]||=f(`a`,{href:`https://console.cloud.google.com/auth/clients`,target:`_blank`,rel:`noopener noreferrer`},`打开 Google Cloud ↗`,-1),f(`form`,{onSubmit:S(I,[`prevent`])},[f(`label`,null,[i[8]||=l(`桌面客户端 JSON`,-1),r(f(`textarea`,{"onUpdate:modelValue":i[1]||=e=>d.value=e,rows:`5`,autocomplete:`off`,spellcheck:`false`,placeholder:`{ "installed": { … } }`,required:``},null,512),[[x,d.value]])]),f(`button`,{class:`primary`,disabled:y.value||!d.value.trim()},`保存到主机`,8,vt)],32)])]),f(`fieldset`,yt,[i[11]||=f(`legend`,null,`选择本次授权的服务`,-1),f(`div`,bt,[(n(),h(u,null,a(j,(e,a)=>f(`label`,{key:a,class:s([`service-option`,{selected:g.value.includes(a)}])},[r(f(`input`,{"onUpdate:modelValue":i[2]||=e=>g.value=e,type:`checkbox`,value:a},null,8,xt),[[w,g.value]]),[`gmail`,`calendar`,`drive`].includes(a)?(n(),h(`img`,{key:0,src:`/provider-logos/`+A[a]+`.svg`,alt:``,width:`19`,height:`19`},null,8,St)):(n(),m(C,{key:1,name:a===`contacts`?`users`:a===`sheets`?`board`:`file`,size:19},null,8,[`name`])),f(`span`,null,t(e),1)],2)),64))])]),f(`div`,Ct,[f(`p`,null,[b(C,{name:`monitor`,size:15}),i[12]||=l(`首次授权需在主机电脑的浏览器完成。`,-1)]),f(`div`,wt,[f(`button`,{class:`primary`,type:`button`,disabled:y.value||!c.value?.configured||!g.value.length||!!v.value&&[`pending`,`received`,`exchanging`].includes(v.value.status),onClick:i[3]||=e=>L(k.value)},[b(C,{name:`plus`,size:16}),l(t(k.value?`重新授权选中的账号`:`连接 Google 账号`),1)],8,Tt),k.value?(n(),h(`button`,{key:0,class:`quiet`,disabled:y.value,onClick:i[4]||=e=>{k.value=void 0,g.value=[`gmail`]}},`改为添加账号`,8,Et)):_(``,!0)])]),v.value?(n(),h(`div`,Dt,[f(`span`,{class:s([`integration-tag`,{success:v.value.status===`approved`}])},t(H(v.value.status)),3),v.value.error?(n(),h(`p`,Ot,t(v.value.error),1)):_(``,!0),f(`div`,kt,[v.value.authUrl&&v.value.status===`pending`?(n(),h(`a`,{key:0,href:v.value.authUrl,target:`_blank`,rel:`noopener noreferrer`},`在 Host 电脑浏览器继续授权 ↗`,8,At)):_(``,!0),[`pending`,`received`,`exchanging`].includes(v.value.status)?(n(),h(`button`,{key:1,class:`quiet`,disabled:y.value,onClick:B},`取消授权`,8,jt)):_(``,!0)])])):_(``,!0),f(`div`,Mt,[f(`div`,Nt,[i[13]||=f(`h4`,null,`已连接账号`,-1),f(`span`,Pt,t(c.value?.accounts.length??0)+` 个账号`,1)]),c.value?.accounts.length?(n(),h(`ul`,Ft,[(n(!0),h(u,null,a(c.value.accounts,e=>(n(),h(`li`,{key:e.id},[f(`div`,It,[f(`span`,Lt,[b(C,{name:`users`,size:18})]),f(`div`,Rt,[f(`strong`,null,t(e.label),1),f(`p`,null,t(e.services.map(e=>j[e]??e).join(` · `)),1)]),f(`span`,{class:s([`integration-tag`,{success:e.status===`connected`,warning:e.status!==`connected`}])},t(H(e.status)),3)]),f(`details`,zt,[i[14]||=f(`summary`,null,`管理账号`,-1),f(`div`,Bt,[f(`button`,{disabled:y.value,onClick:t=>R(e.id)},`重新授权`,8,Vt),f(`button`,{class:`quiet`,disabled:y.value,onClick:t=>V(e.id,e.revision)},`断开`,8,Ht),f(`button`,{class:`quiet danger`,disabled:y.value,onClick:t=>V(e.id,e.revision,!0)},`撤销 Google 授权`,8,Ut)])])]))),128))])):(n(),h(`p`,Wt,`连接账号后,所有设备都可以使用已授权的服务。`))]),c.value?.accounts?.some(e=>e.services.includes(`gmail`))?(n(),h(`button`,{key:1,class:`mail-entry`,onClick:i[5]||=e=>O.value=!O.value},[i[15]||=f(`img`,{src:`/provider-logos/gmail.svg`,alt:``,width:`20`,height:`20`},null,-1),l(t(O.value?`收起邮箱`:`打开本地 Gmail 邮箱`),1),b(C,{name:O.value?`chevron-down`:`chevron-right`,size:17},null,8,[`name`])])):_(``,!0)]),O.value&&c.value?(n(),m(ct,{key:2,accounts:c.value.accounts.filter(e=>e.services.includes(`gmail`))},null,8,[`accounts`])):_(``,!0)]))}}),[[`__scopeId`,`data-v-dfc4941d`]]),Kt={class:`integration-panel composio-apps`,"aria-label":`Composio 应用`},qt={class:`integration-header`},Jt=[`disabled`],Yt={key:0,class:`integration-alert`,role:`alert`},Xt={key:1,class:`integration-alert`,role:`status`},Zt={key:2,class:`integration-card import-card`},Qt={class:`integration-heading`},$t={class:`integration-mark`},en={key:0},tn=[`value`],nn={key:1,class:`hint`},rn=[`disabled`],an={class:`integration-card gmail-connection`},on={class:`integration-header`},sn={class:`composio-setup`},cn=[`disabled`],ln={class:`accounts-heading`},un={class:`integration-count`},dn={key:0,class:`composio-accounts`},fn={class:`account-copy`},pn=[`disabled`,`aria-label`,`onClick`],mn={key:1,class:`hint`},hn=[`required`,`disabled`],gn=[`disabled`],_n={key:2,class:`authorization-link`},vn=[`href`],yn=v(d({__name:`ComposioAppsPanel`,setup(i){let c=p(),d=p([]),g=p(!1),v=p(``),y=p(``),w=p(``),D=p(``),O=p(``),k=p(``),A=p(``),j=p(!1),M=0,N=new Set,P=!1,F,I=e=>({ACTIVE:`已连接`,INITIATED:`等待授权`,PENDING:`等待授权`,INITIALIZING:`连接中`,EXPIRED:`已过期`,FAILED:`连接失败`,INACTIVE:`未启用`,REVOKED:`已撤销`})[e.toUpperCase()]??e;async function L(){let e=await E(`/api/app/admin/composio/status`);if(P)return;if(c.value=e,e.legacy.some(e=>e.id===k.value)||(k.value=e.legacy[0]?.id??``),!e.configured){d.value=[];return}let t=await E(`/api/app/admin/composio/accounts`);P||(d.value=t.accounts)}async function R(e){if(!g.value){g.value=!0,v.value=``;try{await e()}catch(e){P||(v.value=e instanceof Error?e.message:`Composio 操作失败`)}finally{g.value=!1}}}async function z(){await R(async()=>{await E(`/api/app/admin/composio/import`,{method:`POST`,body:{candidateId:k.value,revision:c.value?.revision??0}}),y.value=`已导入旧连接。原 Gmail 授权和 yaoyao 数据均已保留。`,A.value=``,await L()})}async function B(){await R(async()=>{await E(`/api/app/admin/composio/settings`,{method:`PUT`,body:{apiKey:w.value.trim(),...D.value.trim()?{userId:D.value.trim()}:{},revision:c.value?.revision??0}}),w.value=``,D.value=``,y.value=`Composio 连接配置已保存到主机。`,await L()})}function V(){A.value=``,clearTimeout(F)}function H(){if(clearTimeout(F),!(P||!A.value)){if(Date.now()>M){y.value=`授权检查已结束,完成授权后可以手动刷新连接。`;return}F=setTimeout(async()=>{try{await L(),d.value.some(e=>e.status===`ACTIVE`&&!N.has(e.id))&&(A.value=``,y.value=`Gmail 已连接。`)}catch(e){P||(v.value=e instanceof Error?e.message:`授权状态读取失败`)}H()},5e3)}}function U(e){try{let t=new URL(e);return t.protocol===`https:`&&!t.username&&!t.password&&(t.hostname===`composio.dev`||t.hostname.endsWith(`.composio.dev`))?t.href:``}catch{return``}}async function W(){if(g.value)return;let e=window.open(`about:blank`,`_blank`);e&&(e.opener=null),await R(async()=>{try{let t=await E(`/api/app/admin/composio/authorize`,{method:`POST`,body:O.value.trim()?{alias:O.value.trim()}:{}});N=new Set(d.value.filter(e=>e.status===`ACTIVE`).map(e=>e.id)),M=Date.now()+12e4,A.value=U(t.url),e&&A.value?e.location.href=A.value:e?.close(),O.value=``,y.value=`请在浏览器完成 Gmail 授权,然后刷新连接。`,H()}catch(t){throw e?.close(),t}})}async function G(e){window.confirm(`断开此 Composio Gmail 账号并撤销其授权?原 yaoyao 中使用此连接的功能也会受到影响。`)&&await R(async()=>{await E(`/api/app/admin/composio/accounts/`+encodeURIComponent(e.id),{method:`DELETE`,body:{revision:c.value?.revision??0}}),y.value=`已断开指定 Gmail 账号。`,await L()})}return o(()=>R(L)),e(()=>{P=!0,clearTimeout(F)}),(e,i)=>(n(),h(`section`,Kt,[f(`header`,qt,[i[6]||=f(`div`,null,[f(`h3`,null,`继续使用你的 Gmail`),f(`p`,null,`通过 Composio 托管连接,与本地 Google 和 Nous 独立管理。`)],-1),f(`button`,{class:`quiet`,disabled:g.value,"aria-label":`刷新 Composio 连接`,onClick:i[0]||=e=>R(L)},[b(C,{name:`refresh`,size:17})],8,Jt)]),v.value?(n(),h(`p`,Yt,t(v.value),1)):_(``,!0),y.value?(n(),h(`p`,Xt,t(y.value),1)):_(``,!0),c.value?.legacy.length?(n(),h(`article`,Zt,[f(`div`,Qt,[f(`span`,$t,[b(C,{name:`archive`,size:22})]),i[7]||=f(`div`,null,[f(`h4`,null,`找到了 yaoyao 的旧连接`),f(`p`,null,`导入项目配置,继续使用已有 Gmail 授权。`)],-1)]),c.value.legacy.length>1?(n(),h(`label`,en,[i[8]||=l(`选择旧配置`,-1),r(f(`select`,{"onUpdate:modelValue":i[1]||=e=>k.value=e},[(n(!0),h(u,null,a(c.value.legacy,e=>(n(),h(`option`,{key:e.id,value:e.id},t(e.label),9,tn))),128))],512),[[T,k.value]])])):_(``,!0),c.value.configured?(n(),h(`p`,nn,`导入将替换当前 Composio 项目配置。`)):_(``,!0),f(`button`,{class:`primary`,disabled:g.value||!k.value,onClick:z},[b(C,{name:`download`,size:15}),i[9]||=l(`导入 yaoyao 旧连接`,-1)],8,rn)])):_(``,!0),f(`article`,an,[f(`header`,on,[i[10]||=f(`div`,{class:`integration-heading`},[f(`span`,{class:`integration-mark`},[f(`img`,{src:`/provider-logos/gmail.svg`,alt:``,width:`25`,height:`25`})]),f(`div`,null,[f(`h3`,null,`Gmail`),f(`p`,null,`邮件与草稿 · Composio`)])],-1),f(`span`,{class:s([`integration-tag`,{success:c.value?.configured}])},t(c.value?.configured?`项目已配置`:`待配置`),3)]),f(`details`,sn,[f(`summary`,null,[b(C,{name:`settings`,size:16}),l(t(c.value?.configured?`更新项目配置`:`手动配置 Composio`),1)]),f(`form`,{onSubmit:S(B,[`prevent`])},[i[13]||=f(`p`,null,`也可以使用自己的 Composio 项目 API Key。凭据加密保存在这台主机,不会回显。`,-1),i[14]||=f(`a`,{href:`https://platform.composio.dev`,target:`_blank`,rel:`noopener noreferrer`},`打开 Composio ↗`,-1),f(`label`,null,[i[11]||=l(`项目 API Key`,-1),r(f(`input`,{"onUpdate:modelValue":i[2]||=e=>w.value=e,type:`password`,autocomplete:`new-password`,placeholder:`输入 Composio API Key`,required:``},null,512),[[x,w.value]])]),f(`label`,null,[i[12]||=l(`已有用户标识(可选)`,-1),r(f(`input`,{"onUpdate:modelValue":i[3]||=e=>D.value=e,placeholder:`留空自动创建或保留现有标识`,maxlength:`256`},null,512),[[x,D.value]])]),f(`button`,{class:`primary`,disabled:g.value||!w.value.trim()},`保存项目配置`,8,cn)],32)]),f(`div`,ln,[i[15]||=f(`h4`,null,`已连接账号`,-1),f(`span`,un,t(d.value.length)+` 个账号`,1)]),d.value.length?(n(),h(`ul`,dn,[(n(!0),h(u,null,a(d.value,e=>(n(),h(`li`,{key:e.id},[f(`div`,fn,[f(`strong`,null,t(e.label),1),i[16]||=f(`p`,null,`Composio 托管授权`,-1)]),f(`span`,{class:s([`integration-tag`,{success:e.status===`ACTIVE`}])},t(I(e.status)),3),f(`button`,{class:`quiet danger`,disabled:g.value,"aria-label":`断开 `+e.label,onClick:t=>G(e)},`断开`,8,pn)]))),128))])):(n(),h(`p`,mn,t(c.value?.configured?`还没有 Gmail 连接,可以添加账号。`:`导入旧连接或配置项目后,即可连接 Gmail。`),1)),f(`form`,{class:`add-account`,onSubmit:S(W,[`prevent`])},[f(`label`,null,[l(t(d.value.length?`新账号别名`:`账号别名(可选)`),1),r(f(`input`,{"onUpdate:modelValue":i[4]||=e=>O.value=e,placeholder:`例如:工作邮箱`,maxlength:`64`,required:!!d.value.length,disabled:g.value||!c.value?.configured},null,8,hn),[[x,O.value]])]),f(`button`,{disabled:g.value||!c.value?.configured},[b(C,{name:`plus`,size:16}),i[17]||=l(`连接 Gmail 账号`,-1)],8,gn)],32),A.value?(n(),h(`div`,_n,[f(`a`,{href:A.value,target:`_blank`,rel:`noopener noreferrer`},`继续 Gmail 授权 ↗`,8,vn),f(`button`,{class:`quiet`,onClick:V},`停止检查授权状态`)])):_(``,!0),d.value.some(e=>e.status===`ACTIVE`)?(n(),h(`button`,{key:3,class:`mail-entry`,onClick:i[5]||=e=>j.value=!j.value},[i[18]||=f(`img`,{src:`/provider-logos/gmail.svg`,alt:``,width:`20`,height:`20`},null,-1),l(t(j.value?`收起邮箱`:`打开 Composio Gmail 邮箱`),1),b(C,{name:j.value?`chevron-down`:`chevron-right`,size:17},null,8,[`name`])])):_(``,!0)]),j.value?(n(),m(ct,{key:3,source:`composio`,accounts:d.value.filter(e=>e.status===`ACTIVE`)},null,8,[`accounts`])):_(``,!0)]))}}),[[`__scopeId`,`data-v-a0eb0c09`]]),bn={class:`bot-plugins`,"aria-label":`Bot 插件管理`},xn={class:`intro`},Sn={class:`plugin-tabs`,role:`tablist`,"aria-label":`插件类型`},Cn=[`aria-selected`],wn=[`aria-selected`],Tn=[`aria-selected`],En=[`aria-selected`],Dn=[`aria-selected`],On={key:1},kn={key:3},An={key:5},jn={key:0,class:`plugin-notice`},Mn={key:0,class:`plugin-error`,role:`alert`},Nn=[`disabled`],Pn={key:1,class:`plugin-notice`,role:`status`},Fn={key:2,role:`status`},In={key:3,class:`connection-settings`},Ln={class:`hint`},Rn={key:0,class:`hint`},zn=[`disabled`],Bn=[`disabled`],Vn={key:2,class:`hint`},Hn={key:4,class:`connection-settings`,"aria-label":`应用授权进度`},Un={role:`status`},Wn={key:0,class:`plugin-error`},Gn={key:0,class:`hint`},Kn=[`href`],qn=[`disabled`],Jn={class:`plugin-toolbar`},Yn={class:`view-tabs`,role:`tablist`,"aria-label":`应用列表`},Xn=[`aria-selected`],Zn=[`aria-selected`],Qn=[`disabled`],$n={class:`plugin-search`},er={class:`app-grid`},tr={class:`card-heading`},nr={class:`hint`},rr={class:`app-account`},ir=[`disabled`,`aria-label`,`onClick`],ar={key:0,class:`hint`},or=[`onSubmit`],sr={class:`card-actions`},cr=[`disabled`],lr={key:2,class:`card-actions`},ur=[`disabled`,`onClick`],dr=[`disabled`,`onClick`],fr=[`onSubmit`],pr={class:`card-actions`},mr=[`disabled`,`onClick`],hr={key:6,class:`plugin-empty`},gr=`/api/app/admin/hermes/connectors`,_r=v(d({__name:`BotPluginsPanel`,emits:[`dirty-change`],setup(s,{emit:c}){let d=c,v=p(`local`),w=p(`marketplace`),T=p(!1),D=p(),j=p([]),P=p([]),F=p(!0),I=p(!1),L=p(``),R=p(``),z=p(``),B=p(``),V=p(``),H=p(),U=p(),W=p(40),G=p(``),K=p(``);i([z,w],()=>{W.value=40}),i([V,G],e=>d(`dirty-change`,e.some(Boolean)));let q=!1,ee=0,J,Y=(e,t,n)=>E(gr+e,{method:t,...n===void 0?{}:{body:n}}),X=e=>P.value.filter(t=>t.connector===e),Z=y(()=>{let e=new Map(j.value.map(e=>[e.slug,e]));for(let t of P.value)e.has(t.connector)||e.set(t.connector,{slug:t.connector,name:t.connector,description:``,category:``});let t=z.value.trim().toLowerCase();return[...e.values()].filter(e=>(w.value!==`connected`||X(e.slug).length)&&`${e.name} ${e.slug} ${e.description}`.toLowerCase().includes(t))}),te=e=>({active:`已连接`,pending:`待授权`,failed:`连接失败`,expired:`已过期`,revoked:`已撤销`,inactive:`未启用`})[e]??e,ne=y(()=>({pending:`等待完成授权`,complete:`连接已完成`,failed:`连接失败`,cancelled:`已取消授权`,expired:`授权已过期`})[U.value?.status??`pending`]);function re(e){try{let t=new URL(e??``);return t.protocol===`https:`&&!t.username&&!t.password?t.href:``}catch{return``}}async function Q(){let e=++ee,t=await Promise.allSettled([E(`/api/app/admin/hermes/connectors/status`),E(`/api/app/admin/hermes/connectors/catalog`),E(`/api/app/admin/hermes/connectors/accounts`)]);if(q||e!==ee)return;let[n,r,i]=t;n.status===`fulfilled`&&(D.value=n.value),r.status===`fulfilled`&&(j.value=r.value.connectors),i.status===`fulfilled`&&(P.value=i.value.accounts),L.value=t.filter(e=>e.status===`rejected`).map(e=>e.reason instanceof Error?e.reason.message:`读取失败,请重试`).join(`;`),F.value=!1}async function $(e){if(!I.value){I.value=!0,L.value=``,R.value=``;try{await e(),q||await Q()}catch(e){q||(L.value=e instanceof Error?e.message:`操作失败,请重试`)}finally{I.value=!1}}}function ie(){if(clearTimeout(J),!(q||U.value?.status!==`pending`)){if(Date.now()>U.value.deadlineAt){U.value={...U.value,status:`expired`};return}J=setTimeout(async()=>{let e=U.value?.id;if(!(!e||q)){try{let t=await E(`${gr}/operations/${encodeURIComponent(e)}`);if(q||U.value?.id!==e)return;U.value=t,t.status===`complete`&&(R.value=`应用已连接,所有 Bot 均可使用。`,await Q())}catch(e){q||(L.value=e instanceof Error?e.message:`暂时无法刷新授权状态`)}ie()}},2500)}}async function ae(e,t){if(I.value||U.value?.status===`pending`)return;if(!t&&X(e.slug).length&&G.value!==e.slug){G.value=e.slug,K.value=``;return}let n=!t&&G.value===e.slug?K.value.trim():void 0;if(n!==void 0&&!/^[a-z0-9][a-z0-9-]{0,31}$/.test(n)){L.value=`新账号别名需为 1–32 位小写字母、数字或连字符,以字母或数字开头。`;return}if(n&&X(e.slug).some(e=>e.alias===n)){L.value=`该应用已有同名账号,请换一个别名。`;return}let r=window.open(`about:blank`,`_blank`);r&&(r.opener=null),await $(async()=>{try{let i={connector:e.slug,...n?{alias:n}:{},...t?{reconnect:!0,connectionId:t.id}:{}},a=await Y(`/operations`,`POST`,i);if(q){r?.close();return}U.value=a,G.value=``,K.value=``;let o=re(a.targets.find(e=>e.connectUrl)?.connectUrl);r&&o?r.location.href=o:r?.close(),R.value=`请在浏览器完成授权。授权状态会自动刷新。`,ie()}catch(e){throw r?.close(),e}})}async function oe(){await $(async()=>{U.value&&=await Y(`/operations/${encodeURIComponent(U.value.id)}`,`DELETE`),clearTimeout(J)})}async function se(e){window.confirm(`断开这个应用账号?所有 Bot 将失去此账号的访问权限。`)&&await $(async()=>{await Y(`/accounts/${encodeURIComponent(e.id)}`,`DELETE`)})}async function ce(e){await $(async()=>{if(!/^[a-z0-9][a-z0-9-]{0,31}$/.test(B.value.trim()))throw Error(`别名需为 1–32 位小写字母、数字或连字符,以字母或数字开头。`);await Y(`/accounts/${encodeURIComponent(e.id)}`,`PATCH`,{alias:B.value.trim()}),V.value=``,B.value=``})}async function le(){await $(async()=>{let e=(await O.oauth()).providers.find(e=>e.id===`nous`);if(!e)throw Error(`Nous 登录暂不可用,请检查主机版本。`);H.value=e})}return o(async()=>{try{let e=await E(`/api/app/bootstrap`);T.value=e.user?.role===`admin`}catch(e){L.value=e instanceof Error?e.message:`无法读取管理权限`}q||(T.value?await Q():F.value=!1)}),e(()=>{q=!0,ee++,clearTimeout(J)}),(e,i)=>(n(),h(`section`,bn,[f(`p`,xn,[b(C,{name:`link`,size:14}),i[16]||=l(`连接的应用由这台服务器的所有 Bot 共用。`,-1)]),f(`div`,Sn,[f(`button`,{type:`button`,role:`tab`,"aria-selected":v.value===`local`,onClick:i[0]||=e=>v.value=`local`},[b(C,{name:`monitor`,size:16}),i[17]||=l(`本地应用`,-1)],8,Cn),f(`button`,{type:`button`,role:`tab`,"aria-selected":v.value===`native`,onClick:i[1]||=e=>v.value=`native`},[b(C,{name:`artifacts`,size:16}),i[18]||=l(`本地插件`,-1)],8,wn),f(`button`,{type:`button`,role:`tab`,"aria-selected":v.value===`composio`,onClick:i[2]||=e=>v.value=`composio`},[b(C,{name:`link`,size:16}),i[19]||=l(`Composio`,-1)],8,Tn),f(`button`,{type:`button`,role:`tab`,"aria-selected":v.value===`apps`,onClick:i[3]||=e=>v.value=`apps`},[b(C,{name:`link`,size:17}),i[20]||=l(`Nous 应用`,-1)],8,En),f(`button`,{type:`button`,role:`tab`,"aria-selected":v.value===`mcp`,onClick:i[4]||=e=>v.value=`mcp`},[b(C,{name:`tools`,size:17}),i[21]||=l(`MCP 服务`,-1)],8,Dn)]),v.value===`native`&&T.value?(n(),m(fe,{key:0})):v.value===`native`?(n(),h(`p`,On,`本地插件由管理员管理。`)):v.value===`composio`&&T.value?(n(),m(yn,{key:2})):v.value===`composio`?(n(),h(`p`,kn,`Composio 连接由管理员管理。`)):v.value===`local`&&T.value?(n(),m(Gt,{key:4})):v.value===`local`?(n(),h(`p`,An,`本地连接由管理员管理。`)):v.value===`mcp`?(n(),m(A,{key:6,"can-manage":T.value,onDirtyChange:i[5]||=e=>d(`dirty-change`,e)},null,8,[`can-manage`])):(n(),h(u,{key:7},[!F.value&&!T.value?(n(),h(`p`,jn,`应用连接由管理员管理。`)):(n(),h(u,{key:1},[L.value?(n(),h(`p`,Mn,[l(t(L.value)+` `,1),f(`button`,{type:`button`,disabled:I.value,onClick:Q},`重试`,8,Nn)])):_(``,!0),R.value?(n(),h(`p`,Pn,t(R.value),1)):_(``,!0),F.value?(n(),h(`p`,Fn,`正在读取应用…`)):(n(),h(`div`,In,[D.value?.authenticated?(n(),h(u,{key:0},[f(`p`,Ln,t(D.value.accountLabel||`Nous 账号已登录`),1),D.value.available?_(``,!0):(n(),h(`p`,Rn,t(D.value.reason===`disabled`||D.value.reason===`not_enabled`?`应用连接服务尚未启用,请检查主机设置后刷新。`:`应用连接服务暂不可用,请刷新或检查主机设置。`),1)),f(`button`,{disabled:I.value,onClick:le},`重新登录 Nous`,8,zn)],64)):D.value?.reason===`needs_auth`||D.value?.available&&!D.value.authenticated?(n(),h(u,{key:1},[i[22]||=f(`p`,null,`登录 Nous 后即可连接应用。登录只用于应用授权,当前主模型保持不变。`,-1),f(`button`,{disabled:I.value,onClick:le},`登录 Nous`,8,Bn)],64)):D.value?.available?_(``,!0):(n(),h(`p`,Vn,t(D.value?.reason===`disabled`||D.value?.reason===`not_enabled`?`应用连接服务尚未启用,请检查主机设置后刷新。`:`应用连接服务暂不可用,请刷新或检查主机设置。`),1))])),U.value?(n(),h(`section`,Hn,[f(`p`,Un,t(ne.value),1),U.value.error?(n(),h(`p`,Wn,t(U.value.error),1)):_(``,!0),(n(!0),h(u,null,a(U.value.targets,e=>(n(),h(`div`,{key:e.connector},[e.detail?(n(),h(`p`,Gn,t(e.detail),1)):_(``,!0),U.value.status===`pending`&&re(e.connectUrl)?(n(),h(`a`,{key:1,href:re(e.connectUrl),target:`_blank`,rel:`noopener noreferrer`},[i[23]||=l(`继续授权 `,-1),b(C,{name:`external`,size:13})],8,Kn)):_(``,!0)]))),128)),U.value.status===`pending`?(n(),h(`button`,{key:1,disabled:I.value,onClick:oe},`取消授权`,8,qn)):_(``,!0)])):_(``,!0),f(`div`,Jn,[f(`div`,Yn,[f(`button`,{role:`tab`,"aria-selected":w.value===`marketplace`,onClick:i[6]||=e=>w.value=`marketplace`},`应用目录`,8,Xn),f(`button`,{role:`tab`,"aria-selected":w.value===`connected`,onClick:i[7]||=e=>w.value=`connected`},`已连接 `+t(P.value.length||``),9,Zn)]),f(`button`,{disabled:I.value||F.value,"aria-label":`刷新应用连接`,onClick:Q},[b(C,{name:`refresh`,size:17})],8,Qn)]),f(`label`,$n,[b(C,{name:`search`,size:17}),r(f(`input`,{"onUpdate:modelValue":i[8]||=e=>z.value=e,type:`search`,"aria-label":`搜索应用`,placeholder:`搜索应用`},null,512),[[x,z.value]])]),f(`div`,er,[(n(!0),h(u,null,a(Z.value.slice(0,W.value),e=>(n(),h(`article`,{key:e.slug,class:`app-card`},[f(`div`,tr,[b(M,{name:e.name,logo:e.logoUrl,"bundled-logo":g(N)(e.slug)},null,8,[`name`,`logo`,`bundled-logo`]),f(`h4`,null,t(e.name),1)]),f(`p`,nr,t(e.description),1),(n(!0),h(u,null,a(X(e.slug),a=>(n(),h(`div`,{key:a.id,class:`account-block`},[f(`div`,rr,[f(`span`,null,[l(t(a.alias||a.label),1),f(`small`,null,t(te(a.status)),1)]),f(`button`,{class:`danger`,disabled:I.value,"aria-label":`断开 ${e.name} ${a.alias||a.label}`,onClick:e=>se(a)},`断开`,8,ir)]),a.statusReason?(n(),h(`p`,ar,t(a.statusReason),1)):_(``,!0),V.value===a.id?(n(),h(`form`,{key:1,onSubmit:S(e=>ce(a),[`prevent`])},[f(`label`,null,[i[24]||=l(`账号别名`,-1),r(f(`input`,{"onUpdate:modelValue":i[9]||=e=>B.value=e,maxlength:`32`,pattern:`[a-z0-9][a-z0-9-]{0,31}`,required:``,placeholder:`work-mail`},null,512),[[x,B.value]]),i[25]||=f(`small`,{class:`hint`},`1–32 位小写字母、数字或连字符,以字母或数字开头。`,-1)]),f(`div`,sr,[f(`button`,{type:`button`,onClick:i[10]||=e=>V.value=``},`取消`),f(`button`,{disabled:I.value,type:`submit`},`保存别名`,8,cr)])],40,or)):(n(),h(`div`,lr,[f(`button`,{disabled:I.value,onClick:e=>{V.value=a.id,B.value=a.alias||``}},`修改别名`,8,ur),a.active?_(``,!0):(n(),h(`button`,{key:0,disabled:I.value||U.value?.status===`pending`||!D.value?.authenticated,onClick:t=>ae(e,a)},`重新连接`,8,dr))]))]))),128)),G.value===e.slug?(n(),h(`form`,{key:0,onSubmit:S(t=>ae(e),[`prevent`])},[f(`label`,null,[i[26]||=l(`新账号别名`,-1),r(f(`input`,{"onUpdate:modelValue":i[11]||=e=>K.value=e,maxlength:`32`,pattern:`[a-z0-9][a-z0-9-]{0,31}`,required:``,placeholder:`personal-mail`},null,512),[[x,K.value]]),i[27]||=f(`small`,{class:`hint`},`使用不同的别名添加第二个账号:1–32 位小写字母、数字或连字符。`,-1)]),f(`button`,{type:`button`,onClick:i[12]||=e=>{G.value=``,K.value=``}},`取消添加`)],40,fr)):_(``,!0),f(`div`,pr,[f(`button`,{disabled:I.value||!D.value?.authenticated||!D.value?.available||U.value?.status===`pending`,onClick:t=>ae(e)},t(G.value===e.slug?`继续连接`:X(e.slug).length?`添加账号`:`连接`),9,mr)])]))),128))]),Z.value.length>W.value?(n(),h(`button`,{key:5,type:`button`,onClick:i[13]||=e=>W.value+=40},`显示更多应用(`+t(Z.value.length-W.value)+`)`,1)):_(``,!0),!F.value&&!Z.value.length?(n(),h(`p`,hr,t(z.value?`没有匹配的应用。`:w.value===`connected`?`还没有已连接的应用,可前往应用目录添加。`:`应用目录暂为空。`),1)):_(``,!0)],64))],64)),H.value?(n(),m(k,{key:8,provider:H.value,onClose:i[14]||=e=>H.value=void 0,onSuccess:i[15]||=e=>{H.value=void 0,Q()}},null,8,[`provider`])):_(``,!0)]))}}),[[`__scopeId`,`data-v-ed72ee2f`]]),vr=d({__name:`BotPluginsDialog`,emits:[`close`],setup(e,{emit:t}){let r=t,i=p(!1),a=()=>!i.value||window.confirm(`放弃尚未保存的插件更改?`);return(e,t)=>(n(),m(D,{title:`已连接应用`,"before-close":a,onClose:t[1]||=e=>r(`close`)},{default:c(()=>[b(_r,{onDirtyChange:t[0]||=e=>i.value=e})]),_:1}))}});export{vr as default};
|
|
2
|
-
//# sourceMappingURL=BotPluginsDialog-
|
|
1
|
+
import{A as e,Dt as t,F as n,G as r,H as i,L as a,M as o,Tt as s,W as c,_ as l,a as u,b as d,d as f,et as p,f as m,m as h,ot as g,p as _,t as v,u as y,v as b}from"./_plugin-vue_export-helper-BumXM028.js";import{G as x,J as S,M as C,V as w,W as T,w as E}from"./index-D11cgXI9.js";import{t as D}from"./StandaloneDialog-BXCK22Dx.js";import{r as O,t as k}from"./ProviderLoginDialog-D3mqdAlo.js";import{_ as A,s as j,v as M,y as N}from"./ConversationsView-CxVFk5sQ.js";var P={class:`integration-panel plugins`,"aria-label":`本地原生插件`},F={class:`integration-header`},I={class:`catalog-intro`},L=[`disabled`],R={class:`plugin-trust`},z={key:0,class:`integration-alert`,role:`alert`},B={key:1,class:`integration-alert`,role:`status`},V={class:`integration-toolbar`},H={class:`integration-search`},U={class:`integration-check`},W={key:2,class:`integration-card update-review`},G={class:`capability-compare`},K={class:`integration-actions`},q=[`disabled`],ee={class:`catalog-results`},J={class:`integration-count`},Y={class:`plugins-grid`},X={class:`plugin-heading`},Z={class:`integration-mark`},te={class:`plugin-version`},ne={class:`plugin-description`},re={class:`compatibility`},Q={class:`plugin-details`},$=[`href`],ie={class:`source-sha`},ae={key:0},oe={key:0,class:`plugin-failure`},se={class:`integration-actions plugin-footer`},ce=[`disabled`,`onClick`],le=[`disabled`,`onClick`],ue=[`disabled`,`onClick`],de={key:3,class:`integration-empty`},fe=v(d({__name:`NativePluginsPanel`,setup(e){let i=p([]),c=p(``),d=p(!1),m=p(!1),g=p(``),v=p(``),S=p(),T=p(),D=y(()=>i.value.filter(e=>(!d.value||e.installed)&&`${e.name} ${e.title} ${e.description}`.toLowerCase().includes(c.value.toLowerCase())));async function O(){i.value=(await E(`/api/app/admin/hermes/local/plugins/catalog`)).plugins}async function k(e){if(!m.value){m.value=!0,g.value=``;try{await e()}catch(e){g.value=e instanceof Error?e.message:`插件操作失败`}finally{m.value=!1}}}async function A(e,t=!1){await k(async()=>{let n=await E(`/api/app/admin/hermes/local/plugins/install`,{method:`POST`,timeoutMs:61e4,body:{name:e.name,sha:e.sha,acceptChanges:t}});if(n.consent_required){S.value=e,T.value=n,v.value=`更新版本可能改变能力和依赖,请审阅后确认。`;return}if(!n.ok)throw Error(n.error??`插件未安装`);S.value=void 0,v.value=`安装完成。插件保持停用,启用时检查宿主兼容性。`,await O()})}async function j(e){await k(async()=>{let t=await E(`/api/app/admin/hermes/local/plugins/enabled`,{method:`POST`,body:{name:e.name,enabled:!e.installed?.enabled}});if(!t.ok)throw Error(t.error??`插件状态未改变`);await O()})}async function M(e){window.confirm(`移除 `+e.name+`?原包会保留在主机备份目录。`)&&await k(async()=>{await E(`/api/app/admin/hermes/local/plugins/remove`,{method:`POST`,body:{name:e.name}}),await O()})}return o(()=>k(O)),(e,o)=>(n(),h(`section`,P,[f(`header`,F,[f(`div`,null,[o[5]||=f(`h3`,null,`发现更多能力`,-1),f(`p`,I,t(i.value.length)+` 项本地插件,按固定版本安装。`,1)]),f(`button`,{class:`quiet`,disabled:m.value,"aria-label":`刷新本地目录`,onClick:o[0]||=e=>k(O)},[b(C,{name:`refresh`,size:17})],8,L)]),f(`details`,R,[f(`summary`,null,[b(C,{name:`shield`,size:17}),o[6]||=l(`仅安装你信任的插件`,-1)]),o[7]||=f(`p`,null,`插件运行在主机上,可访问文件和网络。Bot 权限控制工具入口,不能隔离插件的初始化或内部行为。桌面、Hook、供应商等能力需要各自宿主适配,安装成功不代表已可用。`,-1)]),g.value?(n(),h(`p`,z,[b(C,{name:`alert`,size:17}),l(t(g.value),1)])):_(``,!0),v.value?(n(),h(`p`,B,[b(C,{name:`check`,size:17}),l(t(v.value),1)])):_(``,!0),f(`div`,V,[f(`label`,H,[o[8]||=f(`span`,{class:`sr-only`},`搜索插件`,-1),b(C,{name:`search`,size:17}),r(f(`input`,{"onUpdate:modelValue":o[1]||=e=>c.value=e,type:`search`,placeholder:`搜索插件名称或用途`},null,512),[[x,c.value]])]),f(`label`,U,[r(f(`input`,{"onUpdate:modelValue":o[2]||=e=>d.value=e,type:`checkbox`},null,512),[[w,d.value]]),o[9]||=l(`仅显示已安装`,-1)])]),S.value?(n(),h(`article`,W,[o[12]||=f(`span`,{class:`integration-tag warning`},`需要审阅`,-1),f(`h4`,null,`审阅 `+t(S.value.name)+` 更新`,1),f(`p`,null,t(S.value.description),1),f(`p`,null,`版本 `+t(S.value.version)+` · `+t(S.value.sha),1),f(`div`,G,[f(`div`,null,[o[10]||=f(`h4`,null,`旧能力`,-1),f(`pre`,null,t(JSON.stringify(T.value?.oldCapabilities,null,2)),1)]),f(`div`,null,[o[11]||=f(`h4`,null,`新能力`,-1),f(`pre`,null,t(JSON.stringify(T.value?.newCapabilities,null,2)),1)])]),o[13]||=f(`h4`,null,`当前依赖`,-1),f(`pre`,null,t(T.value?.oldDependencies),1),o[14]||=f(`p`,null,`新版本按固定 SHA 扫描并校验实际能力;依赖安装受 Host 版本约束,安装后保持停用。`,-1),f(`div`,K,[f(`button`,{class:`primary`,disabled:m.value,onClick:o[3]||=e=>A(S.value,!0)},`确认更新到此版本`,8,q),f(`button`,{onClick:o[4]||=e=>S.value=void 0},`取消更新`)])])):_(``,!0),f(`div`,ee,[f(`span`,J,t(c.value||d.value?`匹配 `+D.value.length+` 项`:`全部 `+i.value.length+` 项`),1),o[15]||=f(`span`,{class:`integration-count`},`安装后默认停用`,-1)]),f(`ul`,Y,[(n(!0),h(u,null,a(D.value,e=>(n(),h(`li`,{key:e.name,class:`integration-card plugin-card`},[f(`div`,X,[f(`span`,Z,[b(C,{name:e.compatibility===`tools`?`tools`:e.category===`desktop`?`monitor`:`artifacts`,size:20},null,8,[`name`])]),f(`div`,null,[f(`h4`,null,t(e.title||e.name),1),f(`span`,te,`v`+t(e.version),1)]),e.installed?(n(),h(`span`,{key:0,class:s([`integration-tag`,{success:e.installed.enabled}])},t(e.installed.enabled?`已启用`:`已安装`),3)):_(``,!0)]),f(`p`,ne,t(e.description),1),f(`p`,re,[f(`span`,{class:s([`integration-tag`,{success:e.compatibility===`tools`,warning:e.compatibility!==`tools`}])},t(e.compatibility===`tools`?`工具可接入`:`需适配`),3),l(t(e.compatibilityNote),1)]),f(`details`,Q,[o[16]||=f(`summary`,null,`来源、能力与依赖`,-1),f(`p`,null,t(e.description),1),f(`a`,{href:e.repo,target:`_blank`,rel:`noopener noreferrer`},`查看源码 ↗`,8,$),f(`p`,ie,`固定版本:`+t(e.sha),1),f(`pre`,null,t(JSON.stringify(e.capabilities,null,2)),1),e.installed?.dependencies?.length?(n(),h(`p`,ae,`已安装依赖:`+t(e.installed.dependencies.join(`、`)),1)):_(``,!0)]),e.installed?.lastError?(n(),h(`p`,oe,t(e.installed.lastError),1)):_(``,!0),f(`div`,se,[!e.installed||e.installed.sha!==e.sha?(n(),h(`button`,{key:0,disabled:m.value,onClick:t=>A(e)},[b(C,{name:e.installed?`refresh`:`plus`,size:15},null,8,[`name`]),l(t(e.installed?`检查并更新`:`安装固定版本`),1)],8,ce)):_(``,!0),e.installed?(n(),h(`button`,{key:1,class:s({primary:!e.installed.enabled}),disabled:m.value||!e.installed.enabled&&e.compatibility!==`tools`,onClick:t=>j(e)},t(e.installed.enabled?`停用`:`检查并启用工具`),11,le)):_(``,!0),e.installed?(n(),h(`button`,{key:2,class:`quiet danger`,disabled:m.value,onClick:t=>M(e)},`移除`,8,ue)):_(``,!0)])]))),128))]),!m.value&&!D.value.length?(n(),h(`div`,de,[b(C,{name:`search`,size:28}),o[17]||=f(`strong`,null,`没有匹配的插件`,-1),o[18]||=f(`p`,null,`试试其他关键词,或取消已安装筛选。`,-1)])):_(``,!0)]))}}),[[`__scopeId`,`data-v-2e231ffc`]]),pe=[`aria-label`],me={class:`integration-header`},he={class:`integration-heading`},ge=[`disabled`],_e={class:`mail-account`},ve=[`disabled`],ye=[`value`],be={class:`integration-search`},xe=[`disabled`],Se={key:0,class:`mail-loading`,role:`status`},Ce={key:1,class:`integration-alert`,role:`alert`},we={key:2,class:`integration-alert`,role:`status`},Te={key:3,class:`mail-unknown`},Ee={class:`integration-heading`},De={class:`integration-actions`},Oe=[`disabled`],ke=[`disabled`],Ae={class:`mail-layout`},je={class:`mail-list`},Me={class:`mail-list-heading`},Ne={class:`messages`},Pe=[`aria-pressed`,`disabled`,`onClick`],Fe={class:`message-from`},Ie={key:0,class:`integration-empty`},Le={class:`mail-reading`},Re={class:`compose-heading`},ze={class:`integration-tag`},Be=[`disabled`],Ve=[`disabled`],He={class:`integration-actions`},Ue=[`disabled`],We=[`disabled`],Ge={key:1,class:`mail-detail`},Ke={class:`mail-detail-heading`},qe={class:`message-meta`},Je=[`innerHTML`],Ye={key:0,class:`mail-attachments`},Xe=[`disabled`,`onClick`],Ze={class:`integration-actions mail-actions`},Qe=[`disabled`],$e=[`disabled`],et=[`disabled`],tt={class:`mail-labels`},nt=[`value`],rt={class:`integration-actions`},it=[`disabled`],at=[`disabled`],ot={key:2,class:`integration-empty reading-empty`},st={class:`reading-illustration`},ct=v(d({__name:`GmailPanel`,props:{accounts:{},source:{default:`local`}},setup(e){let c=e,d=y(()=>c.source===`composio`?`Composio 托管`:`本地连接`),m=(e=c.source)=>e===`composio`?`/api/app/admin/composio`:`/api/app/admin/hermes/local/google`,g=p(c.accounts[0]?.id??``),v=p(`in:inbox`),w=p([]),D=p(),O=p(!1),k=p(``),A=p(``),M=p(!1),N=p(!1),P=p(``),F=p(``),I=p(``),L=p(``),R=p([]),z=p(!1),B=0,V=!1,H,U=p(),W=(e,t)=>e?.payload?.headers?.find(e=>e.name.toLowerCase()===t.toLowerCase())?.value??``;async function G(e,t,n=!1,r=g.value,i,a=c.source){let o=n?i??crypto.randomUUID():void 0;try{let i=await E(m(a)+`/call`,{method:`POST`,timeoutMs:95e3,body:{accountId:r,operation:e,arguments:t,...n?{operationId:o}:{}}});if(i?.isError){n&&i.outcomeUnknown&&(z.value=!0,U.value={accountId:r,operationId:o,source:a});let e=Error(i.error?.message??`Google 请求失败`);throw Object.assign(e,{known:!i.outcomeUnknown}),e}return i}catch(e){throw a===`composio`&&[400,401,403,404,409,413,422].includes(e?.status??0)&&Object.assign(e,{known:!0}),n&&!e?.known&&(z.value=!0,U.value={accountId:r,operationId:o,source:a}),e}}async function K(e){if(O.value){e===q&&(V=!0);return}O.value=!0,k.value=``,A.value=``;try{await e()}catch(e){k.value=e instanceof Error?e.message:`邮箱操作失败`}finally{O.value=!1,V&&(V=!1,K(q))}}async function q(){if(!g.value)return;let e=++B,t=g.value,n=c.source;D.value=void 0;let r=await G(`gmail.search`,{query:v.value,max:15},!1,t,void 0,n),i=[];if(e!==B||t!==g.value||n!==c.source)return;for(let a of r.messages??[]){let r=await G(`gmail.get`,{id:a.id},!1,t,void 0,n);if(e!==B||t!==g.value)return;i.push(r)}let a=await G(`gmail.labels`,{},!1,t,void 0,n);e===B&&t===g.value&&(w.value=i,R.value=a.labels??[])}async function ee(e){await K(async()=>{let t=g.value,n=B,r=c.source,i=await G(`gmail.get`,{id:e.id},!1,t,void 0,r);t===g.value&&n===B&&(D.value=i)})}async function J(){await K(async()=>{if(!U.value)return;let e=await E(m(U.value.source)+`/receipts/`+U.value.accountId+`/`+encodeURIComponent(U.value.operationId));A.value=e.status===`complete`?`邮箱操作已完成,已读取保存的结果。`:e.status===`rejected`?`邮箱服务已拒绝此操作。`:`仍无确认结果,请在 Gmail 核对。`,[`complete`,`rejected`].includes(e.status)&&(z.value=!1,M.value=!1,H=void 0,U.value=void 0,await q())})}function Y(e){let t=Uint8Array.from(atob(e.replace(/-/g,`+`).replace(/_/g,`/`)),e=>e.charCodeAt(0));return new TextDecoder().decode(t)}function X(e){if(!e)return``;if(e.mimeType===`text/plain`&&e.body?.data)return`<pre>`+Y(e.body.data).replace(/&/g,`&`).replace(/</g,`<`).replace(/>/g,`>`).replace(/\n/g,`<br>`)+`</pre>`;let t=e.parts??[],n=t.find(e=>e.mimeType===`text/plain`);return n?X(n):e.mimeType===`text/html`&&e.body?.data?j.sanitize(Y(e.body.data),{FORBID_TAGS:[`img`,`style`,`script`,`iframe`,`form`,`svg`,`math`,`video`,`audio`,`link`],FORBID_ATTR:[`style`,`src`,`srcset`,`background`]}):t.map(X).join(``)}function Z(e){return[...e?.filename&&(e?.body?.attachmentId||e?.body?.data)?[e]:[],...(e?.parts??[]).flatMap(Z)]}async function te(e){await K(async()=>{let t=e.body.data?e.body:await G(`gmail.attachment`,{id:D.value.id,attachmentId:e.body.attachmentId});if(t.size>26214400||String(t.data??``).length>104857600/3+4)throw Error(`附件超过25MB限制`);let n=Uint8Array.from(atob(t.data.replace(/-/g,`+`).replace(/_/g,`/`)),e=>e.charCodeAt(0)),r=URL.createObjectURL(new Blob([n],{type:`application/octet-stream`})),i=document.createElement(`a`);i.href=r,i.download=String(e.filename).replace(/[\\/\x00-\x1f]/g,`_`).slice(0,180)||`attachment`,document.body.append(i),i.click(),i.remove(),setTimeout(()=>URL.revokeObjectURL(r),3e4)})}function ne(e=!1){z.value||(H={accountId:g.value,...e?{messageId:D.value.id}:{},operationId:crypto.randomUUID(),source:c.source},N.value=e,M.value=!0,P.value=e?W(D.value,`Reply-To`)||W(D.value,`From`):``,F.value=e?`Re: `+W(D.value,`Subject`):``,I.value=``)}async function re(){await K(async()=>{let e=H;if(!e||e.accountId!==g.value||e.source!==c.source||z.value)throw Error(`草稿账号已改变,请重新编辑。`);try{let t=await G(e.messageId?`gmail.reply`:`gmail.send`,e.messageId?{id:e.messageId,body:I.value}:{to:P.value,subject:F.value,body:I.value},!0,e.accountId,e.operationId,e.source);if(e.accountId!==g.value||e.source!==c.source)return;M.value=!1,H=void 0,A.value=`邮件已发送,消息编号:`+(t.id??`已确认`),t.id&&(D.value=await G(`gmail.get`,{id:t.id},!1,e.accountId,void 0,e.source))}catch(e){throw!z.value&&H&&(H.operationId=crypto.randomUUID()),e}})}async function Q(e,t){z.value||await K(async()=>{let n=g.value;await G(e,t,!0,n),await q(),A.value=`邮箱操作已完成。`})}return i(()=>c.accounts.map(e=>e.id).join(`,`),()=>{c.accounts.some(e=>e.id===g.value)||(g.value=c.accounts[0]?.id??``,B++,w.value=[],D.value=void 0,M.value=!1,H=void 0)}),i(()=>c.source,()=>{B++,w.value=[],D.value=void 0,M.value=!1,H=void 0,k.value=``,A.value=``,K(q)}),i(g,()=>{B++,w.value=[],D.value=void 0,M.value=!1,H=void 0,K(q)}),o(()=>K(q)),(i,o)=>(n(),h(`section`,{class:`integration-panel mailbox`,"aria-label":e.source===`composio`?`Composio Gmail 邮箱`:`本地 Gmail 邮箱`},[f(`header`,me,[f(`div`,he,[o[16]||=f(`span`,{class:`integration-mark gmail-mark`},[f(`img`,{src:`/provider-logos/gmail.svg`,alt:``,width:`25`,height:`25`})],-1),f(`div`,null,[o[15]||=f(`h3`,null,`Gmail`,-1),f(`p`,null,t(d.value)+` · `+t(w.value.length)+` 封邮件`,1)])]),f(`button`,{class:`primary`,type:`button`,disabled:O.value||z.value||!g.value,onClick:o[0]||=e=>ne()},[b(C,{name:`edit`,size:16}),o[17]||=l(`写邮件`,-1)],8,ge)]),f(`label`,_e,[o[18]||=l(`账号`,-1),r(f(`select`,{"onUpdate:modelValue":o[1]||=e=>g.value=e,disabled:O.value},[(n(!0),h(u,null,a(e.accounts,e=>(n(),h(`option`,{value:e.id,key:e.id},t(e.label),9,ye))),128))],8,ve),[[T,g.value]])]),f(`form`,{class:`mail-search`,onSubmit:o[3]||=S(e=>K(q),[`prevent`])},[f(`label`,be,[o[19]||=f(`span`,{class:`sr-only`},`搜索邮件`,-1),b(C,{name:`search`,size:17}),r(f(`input`,{"onUpdate:modelValue":o[2]||=e=>v.value=e,placeholder:`in:inbox 或 Gmail 搜索语法`},null,512),[[x,v.value]])]),f(`button`,{disabled:O.value},[b(C,{name:`refresh`,size:16}),o[20]||=l(`搜索 / 刷新`,-1)],8,xe)],32),O.value?(n(),h(`p`,Se,[b(C,{name:`clock`,size:15}),o[21]||=l(`正在处理邮箱…`,-1)])):_(``,!0),k.value?(n(),h(`p`,Ce,t(k.value),1)):_(``,!0),A.value?(n(),h(`p`,we,t(A.value),1)):_(``,!0),z.value?(n(),h(`div`,Te,[f(`div`,Ee,[b(C,{name:`alert`,size:19}),o[22]||=f(`strong`,null,`写入结果尚未确认`,-1)]),o[23]||=f(`p`,null,`请先在 Gmail 核对,再继续操作。`,-1),f(`div`,De,[f(`button`,{disabled:O.value,onClick:J},`查询操作收据`,8,Oe),f(`button`,{class:`quiet`,disabled:O.value,onClick:o[4]||=e=>{z.value=!1,M.value=!1,A.value=`已按你的确认允许新的操作;原操作不会自动重发。`}},`我已在 Gmail 核对,允许新操作`,8,ke)])])):_(``,!0),f(`div`,Ae,[f(`aside`,je,[f(`div`,Me,[o[24]||=f(`span`,null,`邮件列表`,-1),f(`span`,null,t(w.value.length),1)]),f(`ul`,Ne,[(n(!0),h(u,null,a(w.value,e=>(n(),h(`li`,{key:e.id},[f(`button`,{class:s({active:D.value?.id===e.id}),"aria-pressed":D.value?.id===e.id,disabled:O.value,onClick:t=>ee(e)},[f(`span`,Fe,t(W(e,`From`)),1),f(`strong`,null,t(W(e,`Subject`)||`(无主题)`),1),f(`small`,null,t(e.snippet),1)],10,Pe)]))),128))]),!O.value&&!w.value.length?(n(),h(`div`,Ie,[b(C,{name:`archive`,size:26}),o[25]||=f(`p`,null,`没有匹配的邮件。`,-1)])):_(``,!0)]),f(`div`,Le,[M.value?(n(),h(`form`,{key:0,class:`mail-compose`,onSubmit:S(re,[`prevent`])},[f(`div`,Re,[f(`h4`,null,t(N.value?`回复邮件`:`新邮件`),1),f(`span`,ze,t(e.accounts.find(e=>e.id===g.value)?.label),1)]),f(`label`,null,[o[26]||=l(`收件人`,-1),r(f(`input`,{"onUpdate:modelValue":o[5]||=e=>P.value=e,disabled:N.value,required:``},null,8,Be),[[x,P.value]])]),f(`label`,null,[o[27]||=l(`主题`,-1),r(f(`input`,{"onUpdate:modelValue":o[6]||=e=>F.value=e,disabled:N.value,required:``},null,8,Ve),[[x,F.value]])]),f(`label`,null,[o[28]||=l(`正文`,-1),r(f(`textarea`,{"onUpdate:modelValue":o[7]||=e=>I.value=e,rows:`7`,placeholder:`写下你的邮件…`,required:``},null,512),[[x,I.value]])]),f(`div`,He,[f(`button`,{class:`primary`,disabled:O.value||z.value},[b(C,{name:`arrow-up`,size:16}),o[29]||=l(`发送邮件`,-1)],8,Ue),f(`button`,{class:`quiet`,type:`button`,disabled:O.value,onClick:o[8]||=e=>M.value=!1},`取消编辑`,8,We)])],32)):_(``,!0),D.value?(n(),h(`article`,Ge,[f(`header`,Ke,[f(`h4`,null,t(W(D.value,`Subject`)||`(无主题)`),1),f(`p`,null,t(W(D.value,`From`)),1),f(`p`,qe,[l(`发送至 `+t(W(D.value,`To`)),1),o[30]||=f(`br`,null,null,-1),l(t(W(D.value,`Date`)),1)])]),f(`div`,{class:`email-body`,innerHTML:X(D.value.payload)},null,8,Je),Z(D.value.payload).length?(n(),h(`div`,Ye,[(n(!0),h(u,null,a(Z(D.value.payload),e=>(n(),h(`button`,{key:e.partId??e.body.attachmentId??e.filename,disabled:O.value,onClick:t=>te(e)},[b(C,{name:`download`,size:16}),l(`下载 `+t(e.filename)+`(`+t(e.body.size)+` 字节)`,1)],8,Xe))),128))])):_(``,!0),f(`div`,Ze,[f(`button`,{disabled:O.value||z.value,onClick:o[9]||=e=>ne(!0)},[b(C,{name:`edit`,size:15}),o[31]||=l(`回复`,-1)],8,Qe),f(`button`,{class:`quiet`,disabled:O.value||z.value,onClick:o[10]||=e=>Q(`gmail.modify`,{id:D.value.id,removeLabels:[`INBOX`]})},[b(C,{name:`archive`,size:15}),o[32]||=l(`归档`,-1)],8,$e),f(`button`,{class:`quiet danger`,disabled:O.value||z.value,onClick:o[11]||=e=>Q(`gmail.trash`,{id:D.value.id})},[b(C,{name:`trash`,size:15}),o[33]||=l(`移入垃圾箱`,-1)],8,et)]),f(`div`,tt,[f(`label`,null,[o[35]||=l(`标签`,-1),r(f(`select`,{"onUpdate:modelValue":o[12]||=e=>L.value=e},[o[34]||=f(`option`,{value:``},`选择标签`,-1),(n(!0),h(u,null,a(R.value,e=>(n(),h(`option`,{key:e.id,value:e.id},t(e.name),9,nt))),128))],512),[[T,L.value]])]),f(`div`,rt,[f(`button`,{disabled:O.value||z.value||!L.value.trim(),onClick:o[13]||=e=>Q(`gmail.modify`,{id:D.value.id,addLabels:[L.value]})},`添加标签`,8,it),f(`button`,{class:`quiet`,disabled:O.value||z.value||!L.value,onClick:o[14]||=e=>Q(`gmail.modify`,{id:D.value.id,removeLabels:[L.value]})},`移除标签`,8,at)])])])):M.value?_(``,!0):(n(),h(`div`,ot,[f(`span`,st,[b(C,{name:`file`,size:32})]),o[36]||=f(`strong`,null,`选择一封邮件开始阅读`,-1),o[37]||=f(`p`,null,`也可以写封新邮件,继续你的对话。`,-1)]))])])],8,pe))}}),[[`__scopeId`,`data-v-c7018d71`]]),lt={class:`integration-panel local-apps`,"aria-label":`本地应用`},ut={class:`integration-header`},dt=[`disabled`],ft={key:0,class:`integration-alert`,role:`alert`},pt={key:1,class:`integration-alert`,role:`status`},mt={class:`integration-card google-card`},ht={class:`integration-header`},gt={class:`google-setup`},_t={class:`setup-content`},vt=[`disabled`],yt={class:`google-services`},bt={class:`service-grid`},xt=[`value`],St=[`src`],Ct={class:`connect-row`},wt={class:`integration-actions`},Tt=[`disabled`],Et=[`disabled`],Dt={key:0,class:`auth-progress`,role:`status`},Ot={key:0},kt={class:`integration-actions`},At=[`href`],jt=[`disabled`],Mt={class:`google-accounts`},Nt={class:`accounts-heading`},Pt={class:`integration-count`},Ft={key:0},It={class:`account-row`},Lt={class:`account-avatar`},Rt={class:`account-copy`},zt={class:`account-manage`},Bt={class:`integration-actions`},Vt=[`disabled`,`onClick`],Ht=[`disabled`,`onClick`],Ut=[`disabled`,`onClick`],Wt={key:1,class:`accounts-empty`},Gt=v(d({__name:`LocalAppsPanel`,setup(i){let c=p(),d=p(``),g=p([`gmail`]),v=p(),y=p(!1),T=p(``),D=p(``),O=p(!1),k=p(),A={gmail:`gmail`,calendar:`googlecalendar`,drive:`googledrive`},j={gmail:`Gmail`,calendar:`日历`,drive:`云盘`,contacts:`联系人`,sheets:`表格`,docs:`文档`},M,N=!1;async function P(){c.value=await E(`/api/app/admin/hermes/local/google/status`)}async function F(e){if(!y.value){y.value=!0,T.value=``;try{await e()}catch(e){T.value=e instanceof Error?e.message:`操作失败`}finally{y.value=!1}}}async function I(){await F(async()=>{await E(`/api/app/admin/hermes/local/google/client`,{method:`POST`,body:{client:JSON.parse(d.value)}}),d.value=``,D.value=`客户端已保存在主机。请选择服务并连接账号。`,await P()})}async function L(e){if(y.value)return;let t=window.open(`about:blank`,`_blank`);t&&(t.opener=null),await F(async()=>{try{v.value=await E(`/api/app/admin/hermes/local/google/auth`,{method:`POST`,body:{services:g.value,...e?{accountId:e}:{}}}),t&&v.value.authUrl?t.location.href=v.value.authUrl:t?.close(),z()}catch(e){throw t?.close(),e}})}function R(e){let t=c.value?.accounts.find(t=>t.id===e);t&&(g.value=[...t.services],k.value=e,D.value=`已选择 `+t.label+`。请在上方勾选本次服务,再点击重新授权。`)}function z(){clearTimeout(M),!(N||!v.value||![`pending`,`received`,`exchanging`].includes(v.value.status))&&(M=setTimeout(async()=>{try{let e=await E(`/api/app/admin/hermes/local/google/auth/`+v.value.id);if(N)return;v.value={...v.value,...e},e.status===`approved`&&(D.value=`Google 已连接。`,await P())}catch(e){N||(T.value=e instanceof Error?e.message:`授权状态读取失败`)}z()},2e3))}async function B(){await F(async()=>{v.value&&=await E(`/api/app/admin/hermes/local/google/auth/`+v.value.id,{method:`DELETE`}),clearTimeout(M)})}async function V(e,t,n=!1){window.confirm(n?`撤销Google授权并断开?同一Google账号和客户端的其他本地连接也可能需要重新授权。`:`断开这个本地 Google 账号?使用此连接的 Bot 将无法继续访问。`)&&await F(async()=>{let r=await E(`/api/app/admin/hermes/local/google/accounts/`+e,{method:`DELETE`,body:{revision:t,revoke:n}});D.value=r.note,await P()})}let H=e=>({pending:`等待授权`,received:`授权已收到`,exchanging:`确认授权中`,approved:`已连接`,failed:`授权未完成`,expired:`授权已过期`,cancelled:`已取消`,connected:`已连接`,partial:`部分服务未获授权`,reauth_required:`需要重新授权`})[e]??e;return o(()=>F(P)),e(()=>{N=!0,clearTimeout(M),v.value&&[`pending`,`received`,`exchanging`].includes(v.value.status)&&E(`/api/app/admin/hermes/local/google/auth/`+v.value.id,{method:`DELETE`}).catch(()=>{})}),(e,i)=>(n(),h(`section`,lt,[f(`header`,ut,[i[6]||=f(`div`,null,[f(`h3`,null,`连接你的日常工具`),f(`p`,{class:`local-intro`},`由当前主机直接连接,账号与 Nous 应用独立管理。`)],-1),f(`button`,{class:`quiet refresh-local`,type:`button`,disabled:y.value,"aria-label":`刷新本地连接`,onClick:i[0]||=e=>F(P)},[b(C,{name:`refresh`,size:17})],8,dt)]),T.value?(n(),h(`p`,ft,[b(C,{name:`alert`,size:17}),l(t(T.value),1)])):_(``,!0),D.value?(n(),h(`p`,pt,[b(C,{name:`check`,size:17}),l(t(D.value),1)])):_(``,!0),f(`article`,mt,[f(`header`,ht,[i[7]||=f(`div`,{class:`integration-heading`},[f(`span`,{class:`google-mark`},[f(`span`,null,`G`)]),f(`div`,null,[f(`h3`,null,`Google Workspace`),f(`p`,null,`邮件、日程和文件,一处连接。`)])],-1),f(`span`,{class:s([`integration-tag`,{success:c.value?.configured}])},t(c.value?.configured?`客户端已配置`:`待配置`),3)]),f(`details`,gt,[f(`summary`,null,[b(C,{name:`settings`,size:16}),l(t(c.value?.configured?`更新 Google 客户端`:`配置 Google 客户端`),1)]),f(`div`,_t,[i[9]||=f(`p`,null,`在 Google Cloud 创建“桌面应用”客户端,启用所需 API,然后粘贴下载的 JSON。`,-1),i[10]||=f(`a`,{href:`https://console.cloud.google.com/auth/clients`,target:`_blank`,rel:`noopener noreferrer`},`打开 Google Cloud ↗`,-1),f(`form`,{onSubmit:S(I,[`prevent`])},[f(`label`,null,[i[8]||=l(`桌面客户端 JSON`,-1),r(f(`textarea`,{"onUpdate:modelValue":i[1]||=e=>d.value=e,rows:`5`,autocomplete:`off`,spellcheck:`false`,placeholder:`{ "installed": { … } }`,required:``},null,512),[[x,d.value]])]),f(`button`,{class:`primary`,disabled:y.value||!d.value.trim()},`保存到主机`,8,vt)],32)])]),f(`fieldset`,yt,[i[11]||=f(`legend`,null,`选择本次授权的服务`,-1),f(`div`,bt,[(n(),h(u,null,a(j,(e,a)=>f(`label`,{key:a,class:s([`service-option`,{selected:g.value.includes(a)}])},[r(f(`input`,{"onUpdate:modelValue":i[2]||=e=>g.value=e,type:`checkbox`,value:a},null,8,xt),[[w,g.value]]),[`gmail`,`calendar`,`drive`].includes(a)?(n(),h(`img`,{key:0,src:`/provider-logos/`+A[a]+`.svg`,alt:``,width:`19`,height:`19`},null,8,St)):(n(),m(C,{key:1,name:a===`contacts`?`users`:a===`sheets`?`board`:`file`,size:19},null,8,[`name`])),f(`span`,null,t(e),1)],2)),64))])]),f(`div`,Ct,[f(`p`,null,[b(C,{name:`monitor`,size:15}),i[12]||=l(`首次授权需在主机电脑的浏览器完成。`,-1)]),f(`div`,wt,[f(`button`,{class:`primary`,type:`button`,disabled:y.value||!c.value?.configured||!g.value.length||!!v.value&&[`pending`,`received`,`exchanging`].includes(v.value.status),onClick:i[3]||=e=>L(k.value)},[b(C,{name:`plus`,size:16}),l(t(k.value?`重新授权选中的账号`:`连接 Google 账号`),1)],8,Tt),k.value?(n(),h(`button`,{key:0,class:`quiet`,disabled:y.value,onClick:i[4]||=e=>{k.value=void 0,g.value=[`gmail`]}},`改为添加账号`,8,Et)):_(``,!0)])]),v.value?(n(),h(`div`,Dt,[f(`span`,{class:s([`integration-tag`,{success:v.value.status===`approved`}])},t(H(v.value.status)),3),v.value.error?(n(),h(`p`,Ot,t(v.value.error),1)):_(``,!0),f(`div`,kt,[v.value.authUrl&&v.value.status===`pending`?(n(),h(`a`,{key:0,href:v.value.authUrl,target:`_blank`,rel:`noopener noreferrer`},`在 Host 电脑浏览器继续授权 ↗`,8,At)):_(``,!0),[`pending`,`received`,`exchanging`].includes(v.value.status)?(n(),h(`button`,{key:1,class:`quiet`,disabled:y.value,onClick:B},`取消授权`,8,jt)):_(``,!0)])])):_(``,!0),f(`div`,Mt,[f(`div`,Nt,[i[13]||=f(`h4`,null,`已连接账号`,-1),f(`span`,Pt,t(c.value?.accounts.length??0)+` 个账号`,1)]),c.value?.accounts.length?(n(),h(`ul`,Ft,[(n(!0),h(u,null,a(c.value.accounts,e=>(n(),h(`li`,{key:e.id},[f(`div`,It,[f(`span`,Lt,[b(C,{name:`users`,size:18})]),f(`div`,Rt,[f(`strong`,null,t(e.label),1),f(`p`,null,t(e.services.map(e=>j[e]??e).join(` · `)),1)]),f(`span`,{class:s([`integration-tag`,{success:e.status===`connected`,warning:e.status!==`connected`}])},t(H(e.status)),3)]),f(`details`,zt,[i[14]||=f(`summary`,null,`管理账号`,-1),f(`div`,Bt,[f(`button`,{disabled:y.value,onClick:t=>R(e.id)},`重新授权`,8,Vt),f(`button`,{class:`quiet`,disabled:y.value,onClick:t=>V(e.id,e.revision)},`断开`,8,Ht),f(`button`,{class:`quiet danger`,disabled:y.value,onClick:t=>V(e.id,e.revision,!0)},`撤销 Google 授权`,8,Ut)])])]))),128))])):(n(),h(`p`,Wt,`连接账号后,所有设备都可以使用已授权的服务。`))]),c.value?.accounts?.some(e=>e.services.includes(`gmail`))?(n(),h(`button`,{key:1,class:`mail-entry`,onClick:i[5]||=e=>O.value=!O.value},[i[15]||=f(`img`,{src:`/provider-logos/gmail.svg`,alt:``,width:`20`,height:`20`},null,-1),l(t(O.value?`收起邮箱`:`打开本地 Gmail 邮箱`),1),b(C,{name:O.value?`chevron-down`:`chevron-right`,size:17},null,8,[`name`])])):_(``,!0)]),O.value&&c.value?(n(),m(ct,{key:2,accounts:c.value.accounts.filter(e=>e.services.includes(`gmail`))},null,8,[`accounts`])):_(``,!0)]))}}),[[`__scopeId`,`data-v-dfc4941d`]]),Kt={class:`integration-panel composio-apps`,"aria-label":`Composio 应用`},qt={class:`integration-header`},Jt=[`disabled`],Yt={key:0,class:`integration-alert`,role:`alert`},Xt={key:1,class:`integration-alert`,role:`status`},Zt={key:2,class:`integration-card import-card`},Qt={class:`integration-heading`},$t={class:`integration-mark`},en={key:0},tn=[`value`],nn={key:1,class:`hint`},rn=[`disabled`],an={class:`integration-card gmail-connection`},on={class:`integration-header`},sn={class:`composio-setup`},cn=[`disabled`],ln={class:`accounts-heading`},un={class:`integration-count`},dn={key:0,class:`composio-accounts`},fn={class:`account-copy`},pn=[`disabled`,`aria-label`,`onClick`],mn={key:1,class:`hint`},hn=[`required`,`disabled`],gn=[`disabled`],_n={key:2,class:`authorization-link`},vn=[`href`],yn=v(d({__name:`ComposioAppsPanel`,setup(i){let c=p(),d=p([]),g=p(!1),v=p(``),y=p(``),w=p(``),D=p(``),O=p(``),k=p(``),A=p(``),j=p(!1),M=0,N=new Set,P=!1,F,I=e=>({ACTIVE:`已连接`,INITIATED:`等待授权`,PENDING:`等待授权`,INITIALIZING:`连接中`,EXPIRED:`已过期`,FAILED:`连接失败`,INACTIVE:`未启用`,REVOKED:`已撤销`})[e.toUpperCase()]??e;async function L(){let e=await E(`/api/app/admin/composio/status`);if(P)return;if(c.value=e,e.legacy.some(e=>e.id===k.value)||(k.value=e.legacy[0]?.id??``),!e.configured){d.value=[];return}let t=await E(`/api/app/admin/composio/accounts`);P||(d.value=t.accounts)}async function R(e){if(!g.value){g.value=!0,v.value=``;try{await e()}catch(e){P||(v.value=e instanceof Error?e.message:`Composio 操作失败`)}finally{g.value=!1}}}async function z(){await R(async()=>{await E(`/api/app/admin/composio/import`,{method:`POST`,body:{candidateId:k.value,revision:c.value?.revision??0}}),y.value=`已导入旧连接。原 Gmail 授权和 yaoyao 数据均已保留。`,A.value=``,await L()})}async function B(){await R(async()=>{await E(`/api/app/admin/composio/settings`,{method:`PUT`,body:{apiKey:w.value.trim(),...D.value.trim()?{userId:D.value.trim()}:{},revision:c.value?.revision??0}}),w.value=``,D.value=``,y.value=`Composio 连接配置已保存到主机。`,await L()})}function V(){A.value=``,clearTimeout(F)}function H(){if(clearTimeout(F),!(P||!A.value)){if(Date.now()>M){y.value=`授权检查已结束,完成授权后可以手动刷新连接。`;return}F=setTimeout(async()=>{try{await L(),d.value.some(e=>e.status===`ACTIVE`&&!N.has(e.id))&&(A.value=``,y.value=`Gmail 已连接。`)}catch(e){P||(v.value=e instanceof Error?e.message:`授权状态读取失败`)}H()},5e3)}}function U(e){try{let t=new URL(e);return t.protocol===`https:`&&!t.username&&!t.password&&(t.hostname===`composio.dev`||t.hostname.endsWith(`.composio.dev`))?t.href:``}catch{return``}}async function W(){if(g.value)return;let e=window.open(`about:blank`,`_blank`);e&&(e.opener=null),await R(async()=>{try{let t=await E(`/api/app/admin/composio/authorize`,{method:`POST`,body:O.value.trim()?{alias:O.value.trim()}:{}});N=new Set(d.value.filter(e=>e.status===`ACTIVE`).map(e=>e.id)),M=Date.now()+12e4,A.value=U(t.url),e&&A.value?e.location.href=A.value:e?.close(),O.value=``,y.value=`请在浏览器完成 Gmail 授权,然后刷新连接。`,H()}catch(t){throw e?.close(),t}})}async function G(e){window.confirm(`断开此 Composio Gmail 账号并撤销其授权?原 yaoyao 中使用此连接的功能也会受到影响。`)&&await R(async()=>{await E(`/api/app/admin/composio/accounts/`+encodeURIComponent(e.id),{method:`DELETE`,body:{revision:c.value?.revision??0}}),y.value=`已断开指定 Gmail 账号。`,await L()})}return o(()=>R(L)),e(()=>{P=!0,clearTimeout(F)}),(e,i)=>(n(),h(`section`,Kt,[f(`header`,qt,[i[6]||=f(`div`,null,[f(`h3`,null,`继续使用你的 Gmail`),f(`p`,null,`通过 Composio 托管连接,与本地 Google 和 Nous 独立管理。`)],-1),f(`button`,{class:`quiet`,disabled:g.value,"aria-label":`刷新 Composio 连接`,onClick:i[0]||=e=>R(L)},[b(C,{name:`refresh`,size:17})],8,Jt)]),v.value?(n(),h(`p`,Yt,t(v.value),1)):_(``,!0),y.value?(n(),h(`p`,Xt,t(y.value),1)):_(``,!0),c.value?.legacy.length?(n(),h(`article`,Zt,[f(`div`,Qt,[f(`span`,$t,[b(C,{name:`archive`,size:22})]),i[7]||=f(`div`,null,[f(`h4`,null,`找到了 yaoyao 的旧连接`),f(`p`,null,`导入项目配置,继续使用已有 Gmail 授权。`)],-1)]),c.value.legacy.length>1?(n(),h(`label`,en,[i[8]||=l(`选择旧配置`,-1),r(f(`select`,{"onUpdate:modelValue":i[1]||=e=>k.value=e},[(n(!0),h(u,null,a(c.value.legacy,e=>(n(),h(`option`,{key:e.id,value:e.id},t(e.label),9,tn))),128))],512),[[T,k.value]])])):_(``,!0),c.value.configured?(n(),h(`p`,nn,`导入将替换当前 Composio 项目配置。`)):_(``,!0),f(`button`,{class:`primary`,disabled:g.value||!k.value,onClick:z},[b(C,{name:`download`,size:15}),i[9]||=l(`导入 yaoyao 旧连接`,-1)],8,rn)])):_(``,!0),f(`article`,an,[f(`header`,on,[i[10]||=f(`div`,{class:`integration-heading`},[f(`span`,{class:`integration-mark`},[f(`img`,{src:`/provider-logos/gmail.svg`,alt:``,width:`25`,height:`25`})]),f(`div`,null,[f(`h3`,null,`Gmail`),f(`p`,null,`邮件与草稿 · Composio`)])],-1),f(`span`,{class:s([`integration-tag`,{success:c.value?.configured}])},t(c.value?.configured?`项目已配置`:`待配置`),3)]),f(`details`,sn,[f(`summary`,null,[b(C,{name:`settings`,size:16}),l(t(c.value?.configured?`更新项目配置`:`手动配置 Composio`),1)]),f(`form`,{onSubmit:S(B,[`prevent`])},[i[13]||=f(`p`,null,`也可以使用自己的 Composio 项目 API Key。凭据加密保存在这台主机,不会回显。`,-1),i[14]||=f(`a`,{href:`https://platform.composio.dev`,target:`_blank`,rel:`noopener noreferrer`},`打开 Composio ↗`,-1),f(`label`,null,[i[11]||=l(`项目 API Key`,-1),r(f(`input`,{"onUpdate:modelValue":i[2]||=e=>w.value=e,type:`password`,autocomplete:`new-password`,placeholder:`输入 Composio API Key`,required:``},null,512),[[x,w.value]])]),f(`label`,null,[i[12]||=l(`已有用户标识(可选)`,-1),r(f(`input`,{"onUpdate:modelValue":i[3]||=e=>D.value=e,placeholder:`留空自动创建或保留现有标识`,maxlength:`256`},null,512),[[x,D.value]])]),f(`button`,{class:`primary`,disabled:g.value||!w.value.trim()},`保存项目配置`,8,cn)],32)]),f(`div`,ln,[i[15]||=f(`h4`,null,`已连接账号`,-1),f(`span`,un,t(d.value.length)+` 个账号`,1)]),d.value.length?(n(),h(`ul`,dn,[(n(!0),h(u,null,a(d.value,e=>(n(),h(`li`,{key:e.id},[f(`div`,fn,[f(`strong`,null,t(e.label),1),i[16]||=f(`p`,null,`Composio 托管授权`,-1)]),f(`span`,{class:s([`integration-tag`,{success:e.status===`ACTIVE`}])},t(I(e.status)),3),f(`button`,{class:`quiet danger`,disabled:g.value,"aria-label":`断开 `+e.label,onClick:t=>G(e)},`断开`,8,pn)]))),128))])):(n(),h(`p`,mn,t(c.value?.configured?`还没有 Gmail 连接,可以添加账号。`:`导入旧连接或配置项目后,即可连接 Gmail。`),1)),f(`form`,{class:`add-account`,onSubmit:S(W,[`prevent`])},[f(`label`,null,[l(t(d.value.length?`新账号别名`:`账号别名(可选)`),1),r(f(`input`,{"onUpdate:modelValue":i[4]||=e=>O.value=e,placeholder:`例如:工作邮箱`,maxlength:`64`,required:!!d.value.length,disabled:g.value||!c.value?.configured},null,8,hn),[[x,O.value]])]),f(`button`,{disabled:g.value||!c.value?.configured},[b(C,{name:`plus`,size:16}),i[17]||=l(`连接 Gmail 账号`,-1)],8,gn)],32),A.value?(n(),h(`div`,_n,[f(`a`,{href:A.value,target:`_blank`,rel:`noopener noreferrer`},`继续 Gmail 授权 ↗`,8,vn),f(`button`,{class:`quiet`,onClick:V},`停止检查授权状态`)])):_(``,!0),d.value.some(e=>e.status===`ACTIVE`)?(n(),h(`button`,{key:3,class:`mail-entry`,onClick:i[5]||=e=>j.value=!j.value},[i[18]||=f(`img`,{src:`/provider-logos/gmail.svg`,alt:``,width:`20`,height:`20`},null,-1),l(t(j.value?`收起邮箱`:`打开 Composio Gmail 邮箱`),1),b(C,{name:j.value?`chevron-down`:`chevron-right`,size:17},null,8,[`name`])])):_(``,!0)]),j.value?(n(),m(ct,{key:3,source:`composio`,accounts:d.value.filter(e=>e.status===`ACTIVE`)},null,8,[`accounts`])):_(``,!0)]))}}),[[`__scopeId`,`data-v-a0eb0c09`]]),bn={class:`bot-plugins`,"aria-label":`Bot 插件管理`},xn={class:`intro`},Sn={class:`plugin-tabs`,role:`tablist`,"aria-label":`插件类型`},Cn=[`aria-selected`],wn=[`aria-selected`],Tn=[`aria-selected`],En=[`aria-selected`],Dn=[`aria-selected`],On={key:1},kn={key:3},An={key:5},jn={key:0,class:`plugin-notice`},Mn={key:0,class:`plugin-error`,role:`alert`},Nn=[`disabled`],Pn={key:1,class:`plugin-notice`,role:`status`},Fn={key:2,role:`status`},In={key:3,class:`connection-settings`},Ln={class:`hint`},Rn={key:0,class:`hint`},zn=[`disabled`],Bn=[`disabled`],Vn={key:2,class:`hint`},Hn={key:4,class:`connection-settings`,"aria-label":`应用授权进度`},Un={role:`status`},Wn={key:0,class:`plugin-error`},Gn={key:0,class:`hint`},Kn=[`href`],qn=[`disabled`],Jn={class:`plugin-toolbar`},Yn={class:`view-tabs`,role:`tablist`,"aria-label":`应用列表`},Xn=[`aria-selected`],Zn=[`aria-selected`],Qn=[`disabled`],$n={class:`plugin-search`},er={class:`app-grid`},tr={class:`card-heading`},nr={class:`hint`},rr={class:`app-account`},ir=[`disabled`,`aria-label`,`onClick`],ar={key:0,class:`hint`},or=[`onSubmit`],sr={class:`card-actions`},cr=[`disabled`],lr={key:2,class:`card-actions`},ur=[`disabled`,`onClick`],dr=[`disabled`,`onClick`],fr=[`onSubmit`],pr={class:`card-actions`},mr=[`disabled`,`onClick`],hr={key:6,class:`plugin-empty`},gr=`/api/app/admin/hermes/connectors`,_r=v(d({__name:`BotPluginsPanel`,emits:[`dirty-change`],setup(s,{emit:c}){let d=c,v=p(`local`),w=p(`marketplace`),T=p(!1),D=p(),j=p([]),P=p([]),F=p(!0),I=p(!1),L=p(``),R=p(``),z=p(``),B=p(``),V=p(``),H=p(),U=p(),W=p(40),G=p(``),K=p(``);i([z,w],()=>{W.value=40}),i([V,G],e=>d(`dirty-change`,e.some(Boolean)));let q=!1,ee=0,J,Y=(e,t,n)=>E(gr+e,{method:t,...n===void 0?{}:{body:n}}),X=e=>P.value.filter(t=>t.connector===e),Z=y(()=>{let e=new Map(j.value.map(e=>[e.slug,e]));for(let t of P.value)e.has(t.connector)||e.set(t.connector,{slug:t.connector,name:t.connector,description:``,category:``});let t=z.value.trim().toLowerCase();return[...e.values()].filter(e=>(w.value!==`connected`||X(e.slug).length)&&`${e.name} ${e.slug} ${e.description}`.toLowerCase().includes(t))}),te=e=>({active:`已连接`,pending:`待授权`,failed:`连接失败`,expired:`已过期`,revoked:`已撤销`,inactive:`未启用`})[e]??e,ne=y(()=>({pending:`等待完成授权`,complete:`连接已完成`,failed:`连接失败`,cancelled:`已取消授权`,expired:`授权已过期`})[U.value?.status??`pending`]);function re(e){try{let t=new URL(e??``);return t.protocol===`https:`&&!t.username&&!t.password?t.href:``}catch{return``}}async function Q(){let e=++ee,t=await Promise.allSettled([E(`/api/app/admin/hermes/connectors/status`),E(`/api/app/admin/hermes/connectors/catalog`),E(`/api/app/admin/hermes/connectors/accounts`)]);if(q||e!==ee)return;let[n,r,i]=t;n.status===`fulfilled`&&(D.value=n.value),r.status===`fulfilled`&&(j.value=r.value.connectors),i.status===`fulfilled`&&(P.value=i.value.accounts),L.value=t.filter(e=>e.status===`rejected`).map(e=>e.reason instanceof Error?e.reason.message:`读取失败,请重试`).join(`;`),F.value=!1}async function $(e){if(!I.value){I.value=!0,L.value=``,R.value=``;try{await e(),q||await Q()}catch(e){q||(L.value=e instanceof Error?e.message:`操作失败,请重试`)}finally{I.value=!1}}}function ie(){if(clearTimeout(J),!(q||U.value?.status!==`pending`)){if(Date.now()>U.value.deadlineAt){U.value={...U.value,status:`expired`};return}J=setTimeout(async()=>{let e=U.value?.id;if(!(!e||q)){try{let t=await E(`${gr}/operations/${encodeURIComponent(e)}`);if(q||U.value?.id!==e)return;U.value=t,t.status===`complete`&&(R.value=`应用已连接,所有 Bot 均可使用。`,await Q())}catch(e){q||(L.value=e instanceof Error?e.message:`暂时无法刷新授权状态`)}ie()}},2500)}}async function ae(e,t){if(I.value||U.value?.status===`pending`)return;if(!t&&X(e.slug).length&&G.value!==e.slug){G.value=e.slug,K.value=``;return}let n=!t&&G.value===e.slug?K.value.trim():void 0;if(n!==void 0&&!/^[a-z0-9][a-z0-9-]{0,31}$/.test(n)){L.value=`新账号别名需为 1–32 位小写字母、数字或连字符,以字母或数字开头。`;return}if(n&&X(e.slug).some(e=>e.alias===n)){L.value=`该应用已有同名账号,请换一个别名。`;return}let r=window.open(`about:blank`,`_blank`);r&&(r.opener=null),await $(async()=>{try{let i={connector:e.slug,...n?{alias:n}:{},...t?{reconnect:!0,connectionId:t.id}:{}},a=await Y(`/operations`,`POST`,i);if(q){r?.close();return}U.value=a,G.value=``,K.value=``;let o=re(a.targets.find(e=>e.connectUrl)?.connectUrl);r&&o?r.location.href=o:r?.close(),R.value=`请在浏览器完成授权。授权状态会自动刷新。`,ie()}catch(e){throw r?.close(),e}})}async function oe(){await $(async()=>{U.value&&=await Y(`/operations/${encodeURIComponent(U.value.id)}`,`DELETE`),clearTimeout(J)})}async function se(e){window.confirm(`断开这个应用账号?所有 Bot 将失去此账号的访问权限。`)&&await $(async()=>{await Y(`/accounts/${encodeURIComponent(e.id)}`,`DELETE`)})}async function ce(e){await $(async()=>{if(!/^[a-z0-9][a-z0-9-]{0,31}$/.test(B.value.trim()))throw Error(`别名需为 1–32 位小写字母、数字或连字符,以字母或数字开头。`);await Y(`/accounts/${encodeURIComponent(e.id)}`,`PATCH`,{alias:B.value.trim()}),V.value=``,B.value=``})}async function le(){await $(async()=>{let e=(await O.oauth()).providers.find(e=>e.id===`nous`);if(!e)throw Error(`Nous 登录暂不可用,请检查主机版本。`);H.value=e})}return o(async()=>{try{let e=await E(`/api/app/bootstrap`);T.value=e.user?.role===`admin`}catch(e){L.value=e instanceof Error?e.message:`无法读取管理权限`}q||(T.value?await Q():F.value=!1)}),e(()=>{q=!0,ee++,clearTimeout(J)}),(e,i)=>(n(),h(`section`,bn,[f(`p`,xn,[b(C,{name:`link`,size:14}),i[16]||=l(`连接的应用由这台服务器的所有 Bot 共用。`,-1)]),f(`div`,Sn,[f(`button`,{type:`button`,role:`tab`,"aria-selected":v.value===`local`,onClick:i[0]||=e=>v.value=`local`},[b(C,{name:`monitor`,size:16}),i[17]||=l(`本地应用`,-1)],8,Cn),f(`button`,{type:`button`,role:`tab`,"aria-selected":v.value===`native`,onClick:i[1]||=e=>v.value=`native`},[b(C,{name:`artifacts`,size:16}),i[18]||=l(`本地插件`,-1)],8,wn),f(`button`,{type:`button`,role:`tab`,"aria-selected":v.value===`composio`,onClick:i[2]||=e=>v.value=`composio`},[b(C,{name:`link`,size:16}),i[19]||=l(`Composio`,-1)],8,Tn),f(`button`,{type:`button`,role:`tab`,"aria-selected":v.value===`apps`,onClick:i[3]||=e=>v.value=`apps`},[b(C,{name:`link`,size:17}),i[20]||=l(`Nous 应用`,-1)],8,En),f(`button`,{type:`button`,role:`tab`,"aria-selected":v.value===`mcp`,onClick:i[4]||=e=>v.value=`mcp`},[b(C,{name:`tools`,size:17}),i[21]||=l(`MCP 服务`,-1)],8,Dn)]),v.value===`native`&&T.value?(n(),m(fe,{key:0})):v.value===`native`?(n(),h(`p`,On,`本地插件由管理员管理。`)):v.value===`composio`&&T.value?(n(),m(yn,{key:2})):v.value===`composio`?(n(),h(`p`,kn,`Composio 连接由管理员管理。`)):v.value===`local`&&T.value?(n(),m(Gt,{key:4})):v.value===`local`?(n(),h(`p`,An,`本地连接由管理员管理。`)):v.value===`mcp`?(n(),m(A,{key:6,"can-manage":T.value,onDirtyChange:i[5]||=e=>d(`dirty-change`,e)},null,8,[`can-manage`])):(n(),h(u,{key:7},[!F.value&&!T.value?(n(),h(`p`,jn,`应用连接由管理员管理。`)):(n(),h(u,{key:1},[L.value?(n(),h(`p`,Mn,[l(t(L.value)+` `,1),f(`button`,{type:`button`,disabled:I.value,onClick:Q},`重试`,8,Nn)])):_(``,!0),R.value?(n(),h(`p`,Pn,t(R.value),1)):_(``,!0),F.value?(n(),h(`p`,Fn,`正在读取应用…`)):(n(),h(`div`,In,[D.value?.authenticated?(n(),h(u,{key:0},[f(`p`,Ln,t(D.value.accountLabel||`Nous 账号已登录`),1),D.value.available?_(``,!0):(n(),h(`p`,Rn,t(D.value.reason===`disabled`||D.value.reason===`not_enabled`?`应用连接服务尚未启用,请检查主机设置后刷新。`:`应用连接服务暂不可用,请刷新或检查主机设置。`),1)),f(`button`,{disabled:I.value,onClick:le},`重新登录 Nous`,8,zn)],64)):D.value?.reason===`needs_auth`||D.value?.available&&!D.value.authenticated?(n(),h(u,{key:1},[i[22]||=f(`p`,null,`登录 Nous 后即可连接应用。登录只用于应用授权,当前主模型保持不变。`,-1),f(`button`,{disabled:I.value,onClick:le},`登录 Nous`,8,Bn)],64)):D.value?.available?_(``,!0):(n(),h(`p`,Vn,t(D.value?.reason===`disabled`||D.value?.reason===`not_enabled`?`应用连接服务尚未启用,请检查主机设置后刷新。`:`应用连接服务暂不可用,请刷新或检查主机设置。`),1))])),U.value?(n(),h(`section`,Hn,[f(`p`,Un,t(ne.value),1),U.value.error?(n(),h(`p`,Wn,t(U.value.error),1)):_(``,!0),(n(!0),h(u,null,a(U.value.targets,e=>(n(),h(`div`,{key:e.connector},[e.detail?(n(),h(`p`,Gn,t(e.detail),1)):_(``,!0),U.value.status===`pending`&&re(e.connectUrl)?(n(),h(`a`,{key:1,href:re(e.connectUrl),target:`_blank`,rel:`noopener noreferrer`},[i[23]||=l(`继续授权 `,-1),b(C,{name:`external`,size:13})],8,Kn)):_(``,!0)]))),128)),U.value.status===`pending`?(n(),h(`button`,{key:1,disabled:I.value,onClick:oe},`取消授权`,8,qn)):_(``,!0)])):_(``,!0),f(`div`,Jn,[f(`div`,Yn,[f(`button`,{role:`tab`,"aria-selected":w.value===`marketplace`,onClick:i[6]||=e=>w.value=`marketplace`},`应用目录`,8,Xn),f(`button`,{role:`tab`,"aria-selected":w.value===`connected`,onClick:i[7]||=e=>w.value=`connected`},`已连接 `+t(P.value.length||``),9,Zn)]),f(`button`,{disabled:I.value||F.value,"aria-label":`刷新应用连接`,onClick:Q},[b(C,{name:`refresh`,size:17})],8,Qn)]),f(`label`,$n,[b(C,{name:`search`,size:17}),r(f(`input`,{"onUpdate:modelValue":i[8]||=e=>z.value=e,type:`search`,"aria-label":`搜索应用`,placeholder:`搜索应用`},null,512),[[x,z.value]])]),f(`div`,er,[(n(!0),h(u,null,a(Z.value.slice(0,W.value),e=>(n(),h(`article`,{key:e.slug,class:`app-card`},[f(`div`,tr,[b(M,{name:e.name,logo:e.logoUrl,"bundled-logo":g(N)(e.slug)},null,8,[`name`,`logo`,`bundled-logo`]),f(`h4`,null,t(e.name),1)]),f(`p`,nr,t(e.description),1),(n(!0),h(u,null,a(X(e.slug),a=>(n(),h(`div`,{key:a.id,class:`account-block`},[f(`div`,rr,[f(`span`,null,[l(t(a.alias||a.label),1),f(`small`,null,t(te(a.status)),1)]),f(`button`,{class:`danger`,disabled:I.value,"aria-label":`断开 ${e.name} ${a.alias||a.label}`,onClick:e=>se(a)},`断开`,8,ir)]),a.statusReason?(n(),h(`p`,ar,t(a.statusReason),1)):_(``,!0),V.value===a.id?(n(),h(`form`,{key:1,onSubmit:S(e=>ce(a),[`prevent`])},[f(`label`,null,[i[24]||=l(`账号别名`,-1),r(f(`input`,{"onUpdate:modelValue":i[9]||=e=>B.value=e,maxlength:`32`,pattern:`[a-z0-9][a-z0-9-]{0,31}`,required:``,placeholder:`work-mail`},null,512),[[x,B.value]]),i[25]||=f(`small`,{class:`hint`},`1–32 位小写字母、数字或连字符,以字母或数字开头。`,-1)]),f(`div`,sr,[f(`button`,{type:`button`,onClick:i[10]||=e=>V.value=``},`取消`),f(`button`,{disabled:I.value,type:`submit`},`保存别名`,8,cr)])],40,or)):(n(),h(`div`,lr,[f(`button`,{disabled:I.value,onClick:e=>{V.value=a.id,B.value=a.alias||``}},`修改别名`,8,ur),a.active?_(``,!0):(n(),h(`button`,{key:0,disabled:I.value||U.value?.status===`pending`||!D.value?.authenticated,onClick:t=>ae(e,a)},`重新连接`,8,dr))]))]))),128)),G.value===e.slug?(n(),h(`form`,{key:0,onSubmit:S(t=>ae(e),[`prevent`])},[f(`label`,null,[i[26]||=l(`新账号别名`,-1),r(f(`input`,{"onUpdate:modelValue":i[11]||=e=>K.value=e,maxlength:`32`,pattern:`[a-z0-9][a-z0-9-]{0,31}`,required:``,placeholder:`personal-mail`},null,512),[[x,K.value]]),i[27]||=f(`small`,{class:`hint`},`使用不同的别名添加第二个账号:1–32 位小写字母、数字或连字符。`,-1)]),f(`button`,{type:`button`,onClick:i[12]||=e=>{G.value=``,K.value=``}},`取消添加`)],40,fr)):_(``,!0),f(`div`,pr,[f(`button`,{disabled:I.value||!D.value?.authenticated||!D.value?.available||U.value?.status===`pending`,onClick:t=>ae(e)},t(G.value===e.slug?`继续连接`:X(e.slug).length?`添加账号`:`连接`),9,mr)])]))),128))]),Z.value.length>W.value?(n(),h(`button`,{key:5,type:`button`,onClick:i[13]||=e=>W.value+=40},`显示更多应用(`+t(Z.value.length-W.value)+`)`,1)):_(``,!0),!F.value&&!Z.value.length?(n(),h(`p`,hr,t(z.value?`没有匹配的应用。`:w.value===`connected`?`还没有已连接的应用,可前往应用目录添加。`:`应用目录暂为空。`),1)):_(``,!0)],64))],64)),H.value?(n(),m(k,{key:8,provider:H.value,onClose:i[14]||=e=>H.value=void 0,onSuccess:i[15]||=e=>{H.value=void 0,Q()}},null,8,[`provider`])):_(``,!0)]))}}),[[`__scopeId`,`data-v-ed72ee2f`]]),vr=d({__name:`BotPluginsDialog`,emits:[`close`],setup(e,{emit:t}){let r=t,i=p(!1),a=()=>!i.value||window.confirm(`放弃尚未保存的插件更改?`);return(e,t)=>(n(),m(D,{title:`已连接应用`,"before-close":a,onClose:t[1]||=e=>r(`close`)},{default:c(()=>[b(_r,{onDirtyChange:t[0]||=e=>i.value=e})]),_:1}))}});export{vr as default};
|
|
2
|
+
//# sourceMappingURL=BotPluginsDialog-BsGszDMH.js.map
|