@lsamien/yaovi 0.1.3 → 0.1.4
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 +15 -4
- package/desktop/main.mjs +1 -1
- package/dist/assets/{AboutDialog-CnNkIRo8.js → AboutDialog-CDpS-zAu.js} +2 -2
- package/dist/assets/{AboutDialog-CnNkIRo8.js.map → AboutDialog-CDpS-zAu.js.map} +1 -1
- package/dist/assets/{BotAutomationsView-J9Y7Unoq.js → BotAutomationsView-RXBQzdfc.js} +2 -2
- package/dist/assets/{BotAutomationsView-J9Y7Unoq.js.map → BotAutomationsView-RXBQzdfc.js.map} +1 -1
- package/dist/assets/{BotControlSettingsPanel-CtXD24FZ.js → BotControlSettingsPanel-GQEVHXbw.js} +2 -2
- package/dist/assets/{BotControlSettingsPanel-CtXD24FZ.js.map → BotControlSettingsPanel-GQEVHXbw.js.map} +1 -1
- package/dist/assets/BotPluginsDialog-HIhXqyGn.js +2 -0
- package/dist/assets/{BotPluginsDialog-qRw8dCbX.js.map → BotPluginsDialog-HIhXqyGn.js.map} +1 -1
- package/dist/assets/{BotSettingsPanel-DbCMOfAW.js → BotSettingsPanel-Bkqal3lR.js} +3 -3
- package/dist/assets/{BotSettingsPanel-DbCMOfAW.js.map → BotSettingsPanel-Bkqal3lR.js.map} +1 -1
- package/dist/assets/{ComputerPanel-CI-jDmC3.js → ComputerPanel-Dt73pgTG.js} +2 -2
- package/dist/assets/{ComputerPanel-CI-jDmC3.js.map → ComputerPanel-Dt73pgTG.js.map} +1 -1
- package/dist/assets/{ComputerViewerView-B76D6Fln.js → ComputerViewerView-ChYgaS9q.js} +2 -2
- package/dist/assets/{ComputerViewerView-B76D6Fln.js.map → ComputerViewerView-ChYgaS9q.js.map} +1 -1
- package/dist/assets/{ConversationsView-DsuaLKva.js → ConversationsView-DzcDJZh3.js} +88 -88
- package/dist/assets/ConversationsView-DzcDJZh3.js.map +1 -0
- package/dist/assets/ConversationsView-EdF5AM1T.css +1 -0
- package/dist/assets/{LocalVmSettingsPanel-BfXFdMYF.js → LocalVmSettingsPanel-DLbDb5Tq.js} +4 -4
- package/dist/assets/{LocalVmSettingsPanel-BfXFdMYF.js.map → LocalVmSettingsPanel-DLbDb5Tq.js.map} +1 -1
- package/dist/assets/{ModelNetworkChoice-DB6cLOBw.js → ModelNetworkChoice-Cfyt4Unl.js} +2 -2
- package/dist/assets/{ModelNetworkChoice-DB6cLOBw.js.map → ModelNetworkChoice-Cfyt4Unl.js.map} +1 -1
- package/dist/assets/{StandaloneDialog-BWUp2Wxo.js → StandaloneDialog-Cte829Ai.js} +2 -2
- package/dist/assets/{StandaloneDialog-BWUp2Wxo.js.map → StandaloneDialog-Cte829Ai.js.map} +1 -1
- package/dist/assets/{UpdateCheckDialog-CpZSPlUI.js → UpdateCheckDialog-BaMo_M4n.js} +2 -2
- package/dist/assets/{UpdateCheckDialog-CpZSPlUI.js.map → UpdateCheckDialog-BaMo_M4n.js.map} +1 -1
- package/dist/assets/{UsageView-BhiRCw7p.js → UsageView-CklMPG4n.js} +3 -3
- package/dist/assets/{UsageView-BhiRCw7p.js.map → UsageView-CklMPG4n.js.map} +1 -1
- package/dist/assets/WorkspaceKnowledgePanel-BdbhD3rO.js +3 -0
- package/dist/assets/{WorkspaceKnowledgePanel-D34YxglF.js.map → WorkspaceKnowledgePanel-BdbhD3rO.js.map} +1 -1
- package/dist/assets/WorkspaceRoutinesPanel-VpRoMe1x.js +2 -0
- package/dist/assets/{WorkspaceRoutinesPanel-Bn-W52Im.js.map → WorkspaceRoutinesPanel-VpRoMe1x.js.map} +1 -1
- package/dist/assets/{WorkstreamsView-CH6qDPvj.js → WorkstreamsView-BwZpuuhs.js} +2 -2
- package/dist/assets/{WorkstreamsView-CH6qDPvj.js.map → WorkstreamsView-BwZpuuhs.js.map} +1 -1
- package/dist/assets/index-C-5Gq82f.css +1 -0
- package/dist/assets/{index-DjhQ-RMG.js → index-Cx1SdzRY.js} +18 -18
- package/dist/assets/index-Cx1SdzRY.js.map +1 -0
- package/dist/assets/{pdf-wqiF06Qz.js → pdf-CoNh_Rmj.js} +2 -2
- package/dist/assets/{pdf-wqiF06Qz.js.map → pdf-CoNh_Rmj.js.map} +1 -1
- package/dist/index.html +2 -2
- package/dist-server/server/remoteAccess/dispatcher.js +5 -1
- package/node_modules/@yaovi/remote-core/index.mjs +13 -10
- package/node_modules/@yaovi/remote-core/package.json +2 -2
- package/node_modules/@yaovi/remote-core/types/remote-core/src/control/recovery.d.ts +1 -1
- package/node_modules/@yaovi/remote-core/types/remote-core/src/control/remote.d.ts +2 -0
- package/node_modules/@yaovi/remote-core/types/remote-core/src/index.d.ts +1 -0
- package/node_modules/@yaovi/remote-core/types/remote-core/src/transport/lan.d.ts +10 -4
- package/node_modules/@yaovi/remote-core/types/remote-core/src/transport/packet.d.ts +2 -2
- package/package.json +2 -2
- package/release.json +3 -3
- package/vendor/yaovi-remote-core-0.2.0-remote.18.tgz +0 -0
- package/dist/assets/BotPluginsDialog-qRw8dCbX.js +0 -2
- package/dist/assets/ConversationsView-DoA0eNiz.css +0 -1
- package/dist/assets/ConversationsView-DsuaLKva.js.map +0 -1
- package/dist/assets/WorkspaceKnowledgePanel-D34YxglF.js +0 -3
- package/dist/assets/WorkspaceRoutinesPanel-Bn-W52Im.js +0 -2
- package/dist/assets/index-DjhQ-RMG.js.map +0 -1
- package/dist/assets/index-DrIgDgnN.css +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WorkspaceKnowledgePanel-D34YxglF.js","names":["_hoisted_1","_openBlock","_createElementBlock","_createElementVNode"],"sources":["../../node_modules/@vicons/ionicons5/es/ChevronForwardOutline.js","../../src/client/components/workspace/MemoryFilesPanel.vue","../../src/client/components/workspace/MemoryFilesPanel.vue","../../src/shared/collaborationPresentation.ts","../../src/shared/collaborationTimeline.ts","../../src/client/components/workspace/WorkspaceKnowledgePanel.vue","../../src/client/components/workspace/WorkspaceKnowledgePanel.vue"],"sourcesContent":["import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock, defineComponent } from 'vue'\nconst _hoisted_1 = {\n xmlns: 'http://www.w3.org/2000/svg',\n 'xmlns:xlink': 'http://www.w3.org/1999/xlink',\n viewBox: '0 0 512 512'\n}\nexport default defineComponent({\n name: 'ChevronForwardOutline',\n render: function render(_ctx, _cache) {\n return (\n _openBlock(),\n _createElementBlock(\n 'svg',\n _hoisted_1,\n _cache[0] ||\n (_cache[0] = [\n _createElementVNode(\n 'path',\n {\n fill: 'none',\n stroke: 'currentColor',\n 'stroke-linecap': 'round',\n 'stroke-linejoin': 'round',\n 'stroke-width': '48',\n d: 'M184 112l144 144l-144 144'\n },\n null,\n -1 /* HOISTED */\n )\n ])\n )\n )\n }\n})\n","<script setup lang=\"ts\">\nimport { ref, watch, onBeforeUnmount } from \"vue\";\nimport { apiRequest } from \"@/api/client\";\nimport { createUuid } from \"@/utils/id\";\nconst props = defineProps<{\n agentId: string;\n scope: string;\n projectId?: string;\n}>();\nconst emit = defineEmits<{ \"dirty-change\": [dirty: boolean]; changed: [] }>();\nconst base = \"/api/app/workspace\";\ntype Doc = { path: string; content: string; hash: string };\ntype Revision = {\n id: string;\n path: string;\n before: string;\n after: string;\n afterHash: string;\n at: number;\n};\nconst files = ref<{ path: string; bytes: number }[]>([]),\n doc = ref<Doc>(),\n draft = ref(\"\"),\n newPath = ref(\"memory/notes.md\"),\n error = ref(\"\"),\n notice = ref(\"\"),\n busy = ref(false),\n history = ref<Revision[]>([]);\nlet generation = 0;\nconst scope = () => ({\n scope: props.scope,\n agentId: props.agentId,\n ...(props.scope === \"project\" ? { projectId: props.projectId } : {}),\n});\nconst query = (extra: Record<string, string> = {}) =>\n new URLSearchParams({ ...scope(), ...extra } as Record<string, string>);\nasync function action(fn: () => Promise<void>) {\n if (busy.value) return;\n busy.value = true;\n error.value = \"\";\n notice.value = \"\";\n try {\n await fn();\n } catch (e) {\n error.value = e instanceof Error ? e.message : \"操作失败\";\n } finally {\n busy.value = false;\n }\n}\nasync function load() {\n const epoch = ++generation;\n if (!props.agentId || (props.scope === \"project\" && !props.projectId)) {\n files.value = [];\n return;\n }\n try {\n const result = await apiRequest<{\n files: { path: string; bytes: number }[];\n }>(`${base}/memory-files?${query()}`);\n if (epoch === generation) files.value = result.files;\n } catch (e) {\n if (epoch === generation) error.value = String(e);\n }\n}\nasync function open(path: string) {\n await action(async () => {\n const epoch = generation;\n const result = await apiRequest<Doc>(\n `${base}/memory-file?${query({ path })}`,\n );\n if (epoch !== generation) return;\n doc.value = result;\n draft.value = result.content;\n history.value = [];\n });\n}\nasync function save() {\n if (!doc.value) return;\n await action(async () => {\n doc.value = await apiRequest<Doc>(base + \"/memory-file\", {\n method: \"PUT\",\n body: {\n ...scope(),\n requestId: createUuid(),\n path: doc.value!.path,\n content: draft.value,\n expectedHash: doc.value!.hash,\n },\n });\n draft.value = doc.value.content;\n notice.value = \"文件已保存,下一轮对话生效。\";\n emit(\"changed\");\n await load();\n });\n}\nasync function revisions() {\n await action(async () => {\n history.value = (\n await apiRequest<{ revisions: Revision[] }>(\n `${base}/memory-file-history?${query()}`,\n )\n ).revisions.filter((r) => r.path === doc.value?.path);\n });\n}\nasync function revert(r: Revision) {\n await action(async () => {\n doc.value = await apiRequest<Doc>(base + \"/memory-file-revert\", {\n method: \"POST\",\n body: {\n ...scope(),\n requestId: createUuid(),\n id: r.id,\n expectedHash: doc.value!.hash,\n },\n });\n draft.value = doc.value.content;\n notice.value = \"已撤销该次修改。\";\n await load();\n emit(\"changed\");\n });\n}\nwatch(\n () => [props.scope, props.agentId, props.projectId],\n () => {\n doc.value = undefined;\n draft.value = \"\";\n history.value = [];\n void load();\n },\n { immediate: true },\n);\nwatch(\n () => !!doc.value && draft.value !== doc.value.content,\n (v) => emit(\"dirty-change\", v),\n);\nonBeforeUnmount(() => {\n generation++;\n});\n</script>\n<template>\n <section class=\"memory-files\" aria-label=\"Markdown 记忆文件\">\n <h3>记忆文件</h3>\n <p>MEMORY.md 自动加载;主题和日记按需读取。可以直接编辑 Markdown。</p>\n <p v-if=\"error\" role=\"alert\">{{ error }}</p>\n <p v-if=\"notice\" role=\"status\">{{ notice }}</p>\n <template v-if=\"!doc\"\n ><div class=\"file-list\">\n <button\n v-for=\"file in files\"\n :key=\"file.path\"\n :disabled=\"busy\"\n @click=\"open(file.path)\"\n >\n {{ file.path }} · {{ file.bytes }} B\n </button>\n </div>\n <form @submit.prevent=\"open(newPath)\">\n <label\n >新文件路径<input\n v-model=\"newPath\"\n placeholder=\"memory/主题.md\"\n :disabled=\"busy\" /></label\n ><button :disabled=\"busy || !agentId\">创建或打开</button>\n </form></template\n >\n <template v-else\n ><label\n >{{ doc.path\n }}<textarea\n v-model=\"draft\"\n :disabled=\"busy\"\n rows=\"16\"\n spellcheck=\"false\"\n aria-label=\"记忆 Markdown 内容\"\n />\n </label>\n <div class=\"actions\">\n <button :disabled=\"busy || draft === doc.content\" @click=\"save\">\n 保存</button\n ><button\n :disabled=\"busy\"\n @click=\"\n doc = undefined;\n history = [];\n \"\n >\n 取消编辑</button\n ><button :disabled=\"busy\" @click=\"revisions\">修改历史</button>\n </div>\n <details v-for=\"revision in history\" :key=\"revision.id\">\n <summary>{{ new Date(revision.at).toLocaleString() }}</summary>\n <p>修改前</p>\n <pre>{{ revision.before }}</pre>\n <p>修改后</p>\n <pre>{{ revision.after }}</pre>\n <button\n :disabled=\"\n busy || revision.afterHash !== doc.hash || draft !== doc.content\n \"\n @click=\"revert(revision)\"\n >\n 撤销此修改\n </button>\n </details></template\n >\n </section>\n</template>\n<style scoped>\n.memory-files {\n display: grid;\n gap: 12px;\n margin-block: 20px;\n}\n.memory-files h3,\n.memory-files p {\n margin: 0;\n line-height: 1.6;\n}\n.memory-files p {\n color: var(--text-secondary);\n}\n.memory-files label {\n display: grid;\n gap: 8px;\n}\n.memory-files input,\n.memory-files textarea,\n.memory-files button {\n font: inherit;\n padding: 10px;\n border: 1px solid var(--line);\n border-radius: 8px;\n color: var(--text-primary);\n background: var(--surface);\n min-height: 44px;\n box-sizing: border-box;\n max-width: 100%;\n}\n.memory-files textarea {\n width: 100%;\n resize: vertical;\n font-family: monospace;\n}\n.file-list,\n.actions,\n.memory-files form {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n.memory-files pre {\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n.memory-files [role=\"alert\"] {\n color: var(--color-error, #d44);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { ref, watch, onBeforeUnmount } from \"vue\";\nimport { apiRequest } from \"@/api/client\";\nimport { createUuid } from \"@/utils/id\";\nconst props = defineProps<{\n agentId: string;\n scope: string;\n projectId?: string;\n}>();\nconst emit = defineEmits<{ \"dirty-change\": [dirty: boolean]; changed: [] }>();\nconst base = \"/api/app/workspace\";\ntype Doc = { path: string; content: string; hash: string };\ntype Revision = {\n id: string;\n path: string;\n before: string;\n after: string;\n afterHash: string;\n at: number;\n};\nconst files = ref<{ path: string; bytes: number }[]>([]),\n doc = ref<Doc>(),\n draft = ref(\"\"),\n newPath = ref(\"memory/notes.md\"),\n error = ref(\"\"),\n notice = ref(\"\"),\n busy = ref(false),\n history = ref<Revision[]>([]);\nlet generation = 0;\nconst scope = () => ({\n scope: props.scope,\n agentId: props.agentId,\n ...(props.scope === \"project\" ? { projectId: props.projectId } : {}),\n});\nconst query = (extra: Record<string, string> = {}) =>\n new URLSearchParams({ ...scope(), ...extra } as Record<string, string>);\nasync function action(fn: () => Promise<void>) {\n if (busy.value) return;\n busy.value = true;\n error.value = \"\";\n notice.value = \"\";\n try {\n await fn();\n } catch (e) {\n error.value = e instanceof Error ? e.message : \"操作失败\";\n } finally {\n busy.value = false;\n }\n}\nasync function load() {\n const epoch = ++generation;\n if (!props.agentId || (props.scope === \"project\" && !props.projectId)) {\n files.value = [];\n return;\n }\n try {\n const result = await apiRequest<{\n files: { path: string; bytes: number }[];\n }>(`${base}/memory-files?${query()}`);\n if (epoch === generation) files.value = result.files;\n } catch (e) {\n if (epoch === generation) error.value = String(e);\n }\n}\nasync function open(path: string) {\n await action(async () => {\n const epoch = generation;\n const result = await apiRequest<Doc>(\n `${base}/memory-file?${query({ path })}`,\n );\n if (epoch !== generation) return;\n doc.value = result;\n draft.value = result.content;\n history.value = [];\n });\n}\nasync function save() {\n if (!doc.value) return;\n await action(async () => {\n doc.value = await apiRequest<Doc>(base + \"/memory-file\", {\n method: \"PUT\",\n body: {\n ...scope(),\n requestId: createUuid(),\n path: doc.value!.path,\n content: draft.value,\n expectedHash: doc.value!.hash,\n },\n });\n draft.value = doc.value.content;\n notice.value = \"文件已保存,下一轮对话生效。\";\n emit(\"changed\");\n await load();\n });\n}\nasync function revisions() {\n await action(async () => {\n history.value = (\n await apiRequest<{ revisions: Revision[] }>(\n `${base}/memory-file-history?${query()}`,\n )\n ).revisions.filter((r) => r.path === doc.value?.path);\n });\n}\nasync function revert(r: Revision) {\n await action(async () => {\n doc.value = await apiRequest<Doc>(base + \"/memory-file-revert\", {\n method: \"POST\",\n body: {\n ...scope(),\n requestId: createUuid(),\n id: r.id,\n expectedHash: doc.value!.hash,\n },\n });\n draft.value = doc.value.content;\n notice.value = \"已撤销该次修改。\";\n await load();\n emit(\"changed\");\n });\n}\nwatch(\n () => [props.scope, props.agentId, props.projectId],\n () => {\n doc.value = undefined;\n draft.value = \"\";\n history.value = [];\n void load();\n },\n { immediate: true },\n);\nwatch(\n () => !!doc.value && draft.value !== doc.value.content,\n (v) => emit(\"dirty-change\", v),\n);\nonBeforeUnmount(() => {\n generation++;\n});\n</script>\n<template>\n <section class=\"memory-files\" aria-label=\"Markdown 记忆文件\">\n <h3>记忆文件</h3>\n <p>MEMORY.md 自动加载;主题和日记按需读取。可以直接编辑 Markdown。</p>\n <p v-if=\"error\" role=\"alert\">{{ error }}</p>\n <p v-if=\"notice\" role=\"status\">{{ notice }}</p>\n <template v-if=\"!doc\"\n ><div class=\"file-list\">\n <button\n v-for=\"file in files\"\n :key=\"file.path\"\n :disabled=\"busy\"\n @click=\"open(file.path)\"\n >\n {{ file.path }} · {{ file.bytes }} B\n </button>\n </div>\n <form @submit.prevent=\"open(newPath)\">\n <label\n >新文件路径<input\n v-model=\"newPath\"\n placeholder=\"memory/主题.md\"\n :disabled=\"busy\" /></label\n ><button :disabled=\"busy || !agentId\">创建或打开</button>\n </form></template\n >\n <template v-else\n ><label\n >{{ doc.path\n }}<textarea\n v-model=\"draft\"\n :disabled=\"busy\"\n rows=\"16\"\n spellcheck=\"false\"\n aria-label=\"记忆 Markdown 内容\"\n />\n </label>\n <div class=\"actions\">\n <button :disabled=\"busy || draft === doc.content\" @click=\"save\">\n 保存</button\n ><button\n :disabled=\"busy\"\n @click=\"\n doc = undefined;\n history = [];\n \"\n >\n 取消编辑</button\n ><button :disabled=\"busy\" @click=\"revisions\">修改历史</button>\n </div>\n <details v-for=\"revision in history\" :key=\"revision.id\">\n <summary>{{ new Date(revision.at).toLocaleString() }}</summary>\n <p>修改前</p>\n <pre>{{ revision.before }}</pre>\n <p>修改后</p>\n <pre>{{ revision.after }}</pre>\n <button\n :disabled=\"\n busy || revision.afterHash !== doc.hash || draft !== doc.content\n \"\n @click=\"revert(revision)\"\n >\n 撤销此修改\n </button>\n </details></template\n >\n </section>\n</template>\n<style scoped>\n.memory-files {\n display: grid;\n gap: 12px;\n margin-block: 20px;\n}\n.memory-files h3,\n.memory-files p {\n margin: 0;\n line-height: 1.6;\n}\n.memory-files p {\n color: var(--text-secondary);\n}\n.memory-files label {\n display: grid;\n gap: 8px;\n}\n.memory-files input,\n.memory-files textarea,\n.memory-files button {\n font: inherit;\n padding: 10px;\n border: 1px solid var(--line);\n border-radius: 8px;\n color: var(--text-primary);\n background: var(--surface);\n min-height: 44px;\n box-sizing: border-box;\n max-width: 100%;\n}\n.memory-files textarea {\n width: 100%;\n resize: vertical;\n font-family: monospace;\n}\n.file-list,\n.actions,\n.memory-files form {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n.memory-files pre {\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n.memory-files [role=\"alert\"] {\n color: var(--color-error, #d44);\n}\n</style>\n","/** Execution acknowledgement and a real return delivery are distinct facts. */\nexport function communicationStatus(value: { status?: string; hasReply?: boolean; replyTo?: string }): string {\n if (value.status === 'failed') return '投递或执行失败'\n if (value.status === 'stopped') return '协作已停止'\n if (value.hasReply) return '已收到回复'\n if (value.replyTo) return '回复已投递'\n return ({ queued: '已投递 · 排队中', running: '正在处理', waiting: '等待补充信息', complete: '执行已结束 · 暂无回复' } as Record<string, string>)[value.status ?? ''] ?? '协作消息'\n}\nexport function goalStatus(status: string): string {\n return ({ queued: '排队中', pending: '待执行', failed: '执行失败', interrupted: '已中断', running: '进行中', review: '待复核', waiting: '需要补充信息', blocked: '遇到阻碍', complete: '已完成', cancelling: '正在停止', cancelled: '已停止' } as Record<string, string>)[status] ?? '状态待确认'\n}\nexport const activityLabels = { bot_created: '创建了 Bot', helper_created: '创建了临时助手', team_created: '组建了团队', assignment_created: '派发了任务' } as const\n/** Host-authored caption for a real Bot-to-Bot delivery, in the Bot's voice (specs/022 contracts/bot-voice.md).\n * The peer's name sits between `before` and `after`. Outgoing rows are a caption only (plus attachments);\n * incoming rows keep the delivered body. */\nexport function peerCaption(value: { direction: 'outgoing' | 'incoming'; status?: string; hasReply?: boolean; replyTo?: string }): { before: string; after: string } {\n const reply = !!value.replyTo\n const word = value.status === 'failed' ? '没成功' : value.status === 'stopped' ? '已停止'\n : ({ queued: '排队中', running: '处理中', waiting: '在等补充信息' } as Record<string, string>)[value.status ?? '']\n ?? (value.status === 'complete' && !reply ? value.hasReply ? '已回复' : '处理完了,没有回复' : '')\n const state = word ? ` · ${word}` : ''\n if (value.direction === 'incoming') return { before: '', after: `${reply ? '回复了' : '发来消息'}${state}` }\n return reply ? { before: '已回复', after: state.slice(1) } : { before: '已请', after: `帮忙${state}` }\n}\nexport function communicationShowsBody(direction: 'outgoing' | 'incoming'): boolean {\n return direction === 'incoming'\n}\n","import { activityLabels, communicationStatus, goalStatus } from './collaborationPresentation.js'\n\nexport interface CollaborationPeer {\n id: string; fromAgentId: string; toAgentId?: string; targetGroupId?: string;\n fromName?: string; targetName?: string; content: string; status: string;\n hasReply?: boolean; replyTo?: string; error?: string; createdAt?: number;\n}\ninterface Assignment {\n id: string; agentId: string; title: string; brief?: string; status: string;\n result?: string | null; review?: string | null; createdAt?: number; updatedAt?: number;\n}\ninterface ActivityMessage {\n id: string; createdAt: number;\n activity?: { kind: keyof typeof activityLabels; actorName: string; targetName: string; description: string } | null;\n}\nexport interface CollaborationEvent {\n id: string; title: string; status: string; content: string; at: number;\n error?: string; peer?: CollaborationPeer;\n}\n/** Read projection only: assignment IDs own their events; retries never execute work. */\nexport function collaborationTimeline(input: {\n peers: CollaborationPeer[]; assignments: Assignment[]; activities?: ActivityMessage[];\n coordinatorId?: string; name: (id?: string) => string;\n}): CollaborationEvent[] {\n const events: CollaborationEvent[] = [];\n const leader = input.coordinatorId ? input.name(input.coordinatorId) : '负责人';\n for (const message of input.activities ?? []) {\n const a = message.activity;\n // Canonical assignments below cover dispatch, result and review without text matching.\n if (!a || (a.kind === 'assignment_created' && input.assignments.length)) continue;\n events.push({ id: `activity:${message.id}`, title: `${a.actorName} ${activityLabels[a.kind]} ${a.targetName}`, status: '已记录', content: a.description, at: message.createdAt });\n }\n for (const a of input.assignments) {\n const member = input.name(a.agentId);\n events.push({ id: `assignment:${a.id}:created`, title: `${leader} → ${member} · 派发任务`, status: goalStatus(a.status), content: [a.title, a.brief].filter(Boolean).join('\\n'), at: a.createdAt ?? 0 });\n if (a.result) events.push({ id: `assignment:${a.id}:result`, title: `${member} → ${leader} · 回传结果`, status: '已回传', content: `${a.title}\\n${a.result}`, at: a.updatedAt ?? a.createdAt ?? 0 });\n if (a.review) events.push({ id: `assignment:${a.id}:review`, title: `${leader} → ${member} · 复核意见`, status: goalStatus(a.status), content: a.review, at: a.updatedAt ?? a.createdAt ?? 0 });\n }\n for (const p of input.peers) events.push({\n id: `peer:${p.id}`, title: `${p.fromName || input.name(p.fromAgentId)} → ${p.targetName || (p.toAgentId ? input.name(p.toAgentId) : '群聊')}`,\n status: communicationStatus(p), content: p.content, at: p.createdAt ?? 0, error: p.error, peer: p,\n });\n return [...new Map(events.map(event => [event.id, event])).values()].sort((a, b) => a.at - b.at);\n}\n","<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport MemoryFilesPanel from './MemoryFilesPanel.vue'\nimport type { AgentAssignment, AgentGoal } from '@shared/agentTasks'\nimport { collaborationTimeline } from '@shared/collaborationTimeline'\nimport { apiRequest } from '@/api/client'\nimport { createUuid } from '@/utils/id'\nimport AppIcon from '@/components/common/AppIcon.vue'\nimport AgentAvatar from '@/components/common/AgentAvatar.vue'\nimport { ChevronForwardOutline } from '@vicons/ionicons5'\nimport type { WorkspaceAgent, WorkspaceConversation, WorkspaceMessage } from '@shared/workspace'\nimport type { MemoryScope, MemorySkipReason, WorkspaceMemory, WorkspaceMemoryJob, WorkspaceMemoryRevision, WorkspacePeerMessage, WorkspaceProject } from '@shared/workspaceKnowledge'\n\nconst props = defineProps<{ agents: WorkspaceAgent[]; conversations: WorkspaceConversation[]; conversationId?: string; taskId?: string; assignments?: AgentAssignment[]; goal?: AgentGoal; revision?: number; embedded?: boolean; initialTab?: 'projects' | 'user' | 'agent'; selectedAgentId?: string; hideAgentControls?: boolean }>()\nconst emit = defineEmits<{ changed: []; 'dirty-change': [dirty: boolean] }>()\nconst dialog = ref<HTMLDialogElement>(), opened = ref(false), busy = ref(false), error = ref(''), tab = ref('agent'), agentId = ref(''), projectId = ref(''), search = ref('')\nconst projects = ref<WorkspaceProject[]>([]), memories = ref<WorkspaceMemory[]>([]), peers = ref<WorkspacePeerMessage[]>([]), jobs = ref<WorkspaceMemoryJob[]>([]), revisions = ref<WorkspaceMemoryRevision[]>([])\nconst draft = ref<{ id?: string; expectedRevision?: number; agentId: string; content: string; tier: WorkspaceMemory['tier'] }>()\nconst projectDraft = ref<WorkspaceProject>()\nconst memoryTotal=ref(0), nextMemoryOffset=ref<number>(), loadedMore=ref(false)\nconst fileDirty=ref(false)\nconst activities = ref<WorkspaceMessage[]>([])\nlet generation = 0, timer: ReturnType<typeof setInterval> | undefined\nconst available = computed(() => props.agents.filter(a => !a.archived && !a.temporaryGoalId))\nconst currentAgent = computed(() => props.agents.find(a => a.id === agentId.value))\nconst currentProject = computed(() => projects.value.find(p => p.id === projectId.value))\nconst scope = computed(() => (['agent', 'user', 'project'].includes(tab.value) ? tab.value : 'agent') as MemoryScope)\nconst name = (id?: string) => props.agents.find(a => a.id === id)?.name ?? '原贡献者'\nconst collaboration = computed(() => collaborationTimeline({ peers: peers.value, activities: activities.value, assignments: props.assignments ?? [], coordinatorId: props.goal?.coordinatorId, name }))\nconst query = () => new URLSearchParams({ scope: scope.value, ...(tab.value === 'agent' && agentId.value ? { agentId: agentId.value } : {}), ...(tab.value === 'project' && projectId.value ? { projectId: projectId.value } : {}), ...(search.value ? { search: search.value } : {}) }).toString()\nconst stateNames: Record<string, string> = { queued: '已排队', pending: '待提炼', running: '处理中', waiting: '等待同伴', complete: '已完成', failed: '失败', stopped: '已停止', skipped: '已跳过' }\nconst skipReasonNames: Record<MemorySkipReason, string> = {\n source_missing: '找不到对应的来源消息', quote_mismatch: '引用与原文不一致', sensitive_content: '包含凭据等敏感内容',\n project_unbound: '项目记忆缺少关联项目', user_not_explicit: '缺少用户明确表达的长期信息', forgotten: '已遗忘的内容或来源不再保存', stale: '推理期间记忆已更新,本次旧提炼结果未应用',\n}\nfunction jobSummary(job: WorkspaceMemoryJob): string {\n if (job.status !== 'complete') return stateNames[job.status] ?? job.status\n const result = job.result\n if (!result) return '已结束(旧记录未统计保存结果)'\n if (!result.extractedCount) return '本轮没有可记录内容'\n if (result.writtenCount) return `已保存 ${result.writtenCount} 条记忆`\n if (result.replayedCount) return `重试已确认 ${result.replayedCount} 条记录`\n if (result.duplicateCount) return '未新增记忆,已有相同内容'\n return '候选记忆均未保存'\n}\nfunction skippedReasons(job: WorkspaceMemoryJob): string[] {\n return Object.entries(job.result?.skippedReasons ?? {}).filter(([, count]) => count > 0)\n .map(([reason, count]) => `${skipReasonNames[reason as MemorySkipReason] ?? '其他原因'}:${count} 条`)\n}\nasync function load(silent = false) {\n if (silent && loadedMore.value && tab.value !== 'collaboration') return\n const epoch = ++generation\n if (!silent) error.value = ''\n try {\n const projectResult = await apiRequest<{ projects: WorkspaceProject[] }>('/api/app/workspace/projects')\n if (epoch !== generation || !opened.value) return\n projects.value = projectResult.projects\n if (!projectId.value) projectId.value = projects.value.find(p => !p.archived)?.id ?? ''\n if (tab.value === 'collaboration') {\n const [result, milestones] = await Promise.all([\n apiRequest<{ messages: WorkspacePeerMessage[] }>(`/api/app/workspace/collaboration?${new URLSearchParams({ ...(props.conversationId ? { conversationId: props.conversationId } : {}), ...(props.taskId ? { taskId: props.taskId } : {}) })}`),\n props.conversationId ? apiRequest<{ messages: WorkspaceMessage[] }>(`/api/app/conversations/${encodeURIComponent(props.conversationId)}/activities${props.taskId ? `?taskId=${encodeURIComponent(props.taskId)}` : ''}`) : Promise.resolve({ messages: [] }),\n ])\n if (epoch === generation) { peers.value = result.messages; activities.value = milestones.messages }\n } else if (tab.value !== 'projects' && (tab.value !== 'project' || projectId.value)) {\n const result = await apiRequest<{ memories: WorkspaceMemory[]; total?: number; nextOffset?: number }>(`/api/app/workspace/memories?${query()}`)\n if (epoch === generation) { memories.value = result.memories; memoryTotal.value = result.total ?? result.memories.length; nextMemoryOffset.value = result.nextOffset; loadedMore.value = false }\n } else { memories.value = []; memoryTotal.value = 0; nextMemoryOffset.value = undefined; loadedMore.value = false }\n if (agentId.value) {\n const result = await apiRequest<{ jobs: WorkspaceMemoryJob[] }>(`/api/app/workspace/memory-jobs?agentId=${agentId.value}`)\n if (epoch === generation) jobs.value = result.jobs\n }\n } catch (cause) { if (epoch === generation) error.value = String(cause) }\n}\nasync function loadMoreMemories() {\n if (busy.value || nextMemoryOffset.value === undefined) return\n const epoch = generation, filter = query(), offset = nextMemoryOffset.value\n busy.value = true; error.value = ''\n try {\n const result = await apiRequest<{ memories: WorkspaceMemory[]; total: number; nextOffset?: number }>(`/api/app/workspace/memories?${filter}&offset=${offset}&limit=100`)\n if (epoch !== generation || !opened.value || filter !== query()) return\n const existing = new Set(memories.value.map(m => `${m.scope}:${m.agentId}:${m.id}`))\n memories.value.push(...result.memories.filter(m => !existing.has(`${m.scope}:${m.agentId}:${m.id}`)))\n memoryTotal.value = result.total; nextMemoryOffset.value = result.nextOffset; loadedMore.value = true\n } catch (cause) { if (epoch === generation) error.value = String(cause) } finally { busy.value = false }\n}\nasync function open(initial = 'agent', selectedAgent?: string, selectedProject?: string) {\n tab.value = initial; agentId.value = selectedAgent ?? available.value[0]?.id ?? ''; projectId.value = selectedProject ?? ''\n opened.value = true; draft.value = undefined; projectDraft.value = undefined; revisions.value = []; search.value = ''\n await nextTick(); if (!props.embedded) dialog.value?.showModal(); await load()\n clearInterval(timer); timer = setInterval(() => { if (!busy.value && !draft.value && !projectDraft.value) void load(true) }, 5000)\n}\nfunction close() { if(fileDirty.value){error.value='请先保存文件或取消编辑。';return} opened.value = false; generation++; clearInterval(timer); if (!props.embedded) dialog.value?.close() }\nfunction switchTab(value: string) { if(fileDirty.value)return; tab.value = value; draft.value = undefined; projectDraft.value = undefined; revisions.value = []; void load() }\nasync function perform(action: () => Promise<void>) {\n if (busy.value) return\n busy.value = true; error.value = ''\n try { await action(); emit('changed'); await load() } catch (cause) { error.value = String(cause) } finally { busy.value = false }\n}\nfunction newMemory(memory?: WorkspaceMemory) {\n revisions.value = []\n draft.value = memory ? { id: memory.id, expectedRevision: memory.revision, agentId: memory.agentId, content: memory.content, tier: memory.tier } : { agentId: agentId.value || available.value[0]?.id || '', content: '', tier: 'log' }\n}\nasync function saveMemory() {\n const value = draft.value\n if (!value?.content.trim()) { error.value = '请输入需要记住的事实'; return }\n await perform(async () => {\n await apiRequest('/api/app/workspace/memories', { method: 'POST', body: { requestId: createUuid(), scope: scope.value, ...(scope.value === 'project' ? { projectId: projectId.value } : {}), ...value } })\n draft.value = undefined\n })\n}\nasync function forget(memory: WorkspaceMemory) {\n await perform(async () => { await apiRequest('/api/app/workspace/memories/forget', { method: 'POST', body: { requestId: createUuid(), scope: memory.scope, agentId: memory.agentId, ...(memory.projectId ? { projectId: memory.projectId } : {}), id: memory.id, expectedRevision: memory.revision } }) })\n}\nasync function history(memory: WorkspaceMemory) {\n const query = new URLSearchParams({ scope: memory.scope, agentId: memory.agentId, ...(memory.projectId ? { projectId: memory.projectId } : {}) })\n await perform(async () => { revisions.value = (await apiRequest<{ revisions: WorkspaceMemoryRevision[] }>(`/api/app/workspace/memories/${memory.id}/revisions?${query}`)).revisions })\n}\nfunction editProject(project?: WorkspaceProject) {\n projectDraft.value = project ? { ...project, memberIds: [...project.memberIds], groupIds: [...project.groupIds] } : { id: '', name: '', description: '', memberIds: [], groupIds: [], revision: 0, archived: false, createdAt: 0, updatedAt: 0 }\n}\nasync function saveProject() {\n const value = projectDraft.value\n if (!value?.name.trim()) { error.value = '请输入项目名称'; return }\n await perform(async () => {\n const result = await apiRequest<{ project: WorkspaceProject }>('/api/app/workspace/projects', { method: 'POST', body: { requestId: createUuid(), ...(value.id ? { id: value.id, expectedRevision: value.revision } : {}), name: value.name, description: value.description, memberIds: value.memberIds, groupIds: value.groupIds, archived: value.archived } })\n projectId.value = result.project.id; projectDraft.value = undefined\n })\n}\nasync function setAgent(field: 'canCollaborate' | 'memoryEnabled', enabled: boolean) {\n await perform(async () => { await apiRequest(`/api/app/agents/${agentId.value}`, { method: 'PATCH', body: { [field]: enabled } }) })\n}\nonBeforeUnmount(() => { generation++; clearInterval(timer) })\nonMounted(() => { if (props.embedded) void open(props.initialTab ?? 'projects', props.selectedAgentId) })\nwatch(() => props.initialTab, value => { if (props.embedded && value) switchTab(value) })\nwatch(() => props.revision, () => { if (opened.value && !busy.value && !draft.value && !projectDraft.value) void load(true) })\nwatch(() => [props.conversationId, props.taskId], () => { generation++; peers.value = []; activities.value = []; if (opened.value && tab.value === 'collaboration') void load() })\nwatch(() => fileDirty.value || !!draft.value || !!projectDraft.value, value => emit('dirty-change', value))\ndefineExpose({ open, close })\n</script>\n\n<template>\n <component :is=\"embedded ? 'section' : 'dialog'\" ref=\"dialog\" class=\"knowledge-dialog\" :class=\"{ 'knowledge-dialog--embedded': embedded }\" :aria-labelledby=\"embedded ? undefined : 'knowledge-title'\" @cancel.prevent=\"close\" @close=\"opened = false\">\n <header v-if=\"!embedded\"><div><h2 id=\"knowledge-title\">Bot 记忆与协作</h2><p>管理长期事实、项目和同伴请求</p></div><button type=\"button\" @click=\"close\" aria-label=\"关闭记忆与协作\">关闭</button></header>\n <nav v-if=\"!embedded\" aria-label=\"记忆与项目分类\"><button v-for=\"item in [['agent','Bot 记忆'],['user','用户记忆'],['projects','项目'],['project','项目记忆'],['collaboration','协作']]\" :key=\"item[0]\" :aria-pressed=\"tab === item[0]\" @click=\"switchTab(item[0]!)\">{{ item[1] }}</button></nav>\n <div class=\"knowledge-body\" :aria-busy=\"busy\">\n <div v-if=\"embedded && tab === 'project'\" class=\"actions\"><button type=\"button\" @click=\"switchTab('projects')\">返回项目</button><h3>项目记忆</h3></div>\n <p v-if=\"error\" role=\"alert\" class=\"knowledge-error\">{{ error }}</p>\n <template v-if=\"tab === 'projects'\">\n <div v-if=\"embedded\" class=\"project-heading\"><div><h3>项目</h3><p>让同一项目的 Bot 共享决策与约定。</p></div><button v-if=\"!projectDraft\" type=\"button\" class=\"project-primary\" @click=\"editProject()\">新建项目</button></div>\n <button v-else-if=\"!projectDraft\" @click=\"editProject()\">新建项目</button>\n <form v-if=\"projectDraft\" class=\"knowledge-editor\" @submit.prevent=\"saveProject\">\n <h3>{{ projectDraft.id ? '编辑项目' : '新建项目' }}</h3>\n <label>名称<input v-model=\"projectDraft.name\" required maxlength=\"100\" /></label>\n <label>说明<textarea v-model=\"projectDraft.description\" rows=\"3\" maxlength=\"16000\" /></label>\n <fieldset><legend>项目成员</legend><label v-for=\"agent in available\" :key=\"agent.id\" class=\"check\"><input v-model=\"projectDraft.memberIds\" type=\"checkbox\" :value=\"agent.id\" />{{ agent.name }}</label></fieldset>\n <fieldset><legend>关联群聊</legend><p>群内所有 Bot 需要先加入此项目。</p><label v-for=\"group in conversations.filter(c => c.kind === 'group' && !c.archived)\" :key=\"group.id\" class=\"check\"><input v-model=\"projectDraft.groupIds\" type=\"checkbox\" :value=\"group.id\" :disabled=\"group.memberIds.some(id => !projectDraft!.memberIds.includes(id)) || !!group.projectId && group.projectId !== projectDraft.id\" />{{ group.name }}</label></fieldset>\n <label v-if=\"projectDraft.id\" class=\"check\"><input v-model=\"projectDraft.archived\" type=\"checkbox\" />归档项目</label>\n <div class=\"actions\"><button type=\"submit\" :disabled=\"busy\">保存项目</button><button type=\"button\" @click=\"projectDraft = undefined\">取消</button></div>\n </form>\n <template v-if=\"embedded && !projectDraft\">\n <div v-if=\"projects.length\" class=\"project-list\" aria-label=\"项目列表\"><button v-for=\"project in projects\" :key=\"project.id\" type=\"button\" :aria-pressed=\"projectId === project.id\" @click=\"projectId = project.id\"><AppIcon name=\"files\" :size=\"21\"/><span><strong>{{project.name}}{{project.archived ? ' · 已归档' : ''}}</strong><small>{{project.memberIds.length}} 位 Bot · {{project.groupIds.length}} 个群聊</small></span><ChevronForwardOutline class=\"project-chevron\" aria-hidden=\"true\"/></button></div>\n <section v-if=\"currentProject\" class=\"project-details\" aria-label=\"当前项目详情\">\n <h3>{{currentProject.name}}</h3><p v-if=\"currentProject.description\" class=\"project-description\">{{currentProject.description}}</p>\n <div class=\"project-detail-row\"><span>项目成员</span><div class=\"project-members\"><span v-for=\"id in currentProject.memberIds\" :key=\"id\"><AgentAvatar :name=\"name(id)\" :avatar=\"agents.find(a => a.id === id)?.avatar || ''\" :size=\"24\"/>{{name(id)}}</span><small v-if=\"!currentProject.memberIds.length\">尚无成员</small></div></div>\n <div class=\"project-detail-row\"><span>关联群聊</span><div>{{currentProject.groupIds.map(id => conversations.find(c => c.id === id)?.name ?? '原群聊').join('、') || '尚未关联群聊'}}</div></div>\n <div class=\"project-detail-row\"><span>项目记忆</span><div><button type=\"button\" @click=\"switchTab('project')\">查看记忆</button></div></div>\n <div class=\"project-detail-actions\"><button type=\"button\" class=\"project-primary\" @click=\"editProject(currentProject)\">编辑项目</button></div>\n </section>\n </template>\n <template v-else-if=\"!embedded\"><article v-for=\"project in projects\" :key=\"project.id\"><h3>{{ project.name }}{{ project.archived ? ' · 已归档' : '' }}</h3><p>{{ project.description || '暂无说明' }}</p><small>{{ project.memberIds.map(id => name(id)).join('、') || '尚无成员' }} · {{ project.groupIds.length }} 个群</small><div class=\"actions\"><button @click=\"editProject(project)\">编辑</button><button @click=\"projectId = project.id; switchTab('project')\">查看记忆</button></div></article></template>\n <p v-if=\"!projects.length && !projectDraft\" class=\"empty\">创建项目后,多个群可以共享该项目的决策和约定。</p>\n </template>\n <template v-else-if=\"tab === 'collaboration'\">\n <p class=\"scope-note\">{{ taskId ? '当前话题' : '当前聊天' }} · {{ collaboration.length }} 条协作记录</p>\n <article v-for=\"event in collaboration\" :key=\"event.id\"><details><summary>{{ event.title }} · {{ event.status }}</summary><p class=\"pre-wrap\">{{ event.content }}</p><small v-if=\"event.at\">{{ new Date(event.at).toLocaleString() }}</small><p v-if=\"event.error\" class=\"knowledge-error\">{{ event.error }}</p></details><button v-if=\"event.peer && ['queued','running','waiting'].includes(event.peer.status)\" :disabled=\"busy\" @click=\"perform(async () => { await apiRequest(`/api/app/workspace/collaboration/${encodeURIComponent(event.peer!.id)}/stop`, { method: 'POST' }) })\">停止此次协作</button></article>\n <p v-if=\"!collaboration.length\" class=\"empty\">暂无协作记录。你可以在聊天中让 Bot 联系同伴,或派发任务。</p>\n </template>\n <template v-else>\n <MemoryFilesPanel v-if=\"agentId && (scope !== 'project' || projectId)\" :agent-id=\"agentId\" :scope=\"scope\" :project-id=\"projectId\" @dirty-change=\"fileDirty=$event\" @changed=\"emit('changed');load()\" />\n <div class=\"filters\">\n <label v-if=\"['agent','user','project'].includes(tab) && !selectedAgentId\">记忆贡献 Bot<select :disabled=\"fileDirty\" v-model=\"agentId\" @change=\"draft = undefined; load()\"><option v-for=\"agent in available\" :key=\"agent.id\" :value=\"agent.id\">{{ agent.name }}</option></select></label>\n <label v-if=\"tab === 'project'\">项目<select :disabled=\"fileDirty\" v-model=\"projectId\" @change=\"draft = undefined; load()\"><option v-for=\"project in projects\" :key=\"project.id\" :value=\"project.id\">{{ project.name }}</option></select></label>\n <form @submit.prevent=\"load()\"><label>搜索记忆<input v-model=\"search\" type=\"search\" placeholder=\"搜索事实、偏好或决策\" /></label><button type=\"submit\">搜索</button></form>\n </div>\n <p class=\"scope-note\">{{ tab === 'agent' ? '仅此 Bot 使用,可跨单聊和群聊延续。' : tab === 'user' ? '同一账号的 Bot 共享,按贡献者保存。' : `仅「${currentProject?.name ?? '当前项目'}」成员读取。` }}</p>\n <template v-if=\"tab === 'agent' && currentAgent\"><label v-if=\"!hideAgentControls\" class=\"check\"><input type=\"checkbox\" :checked=\"currentAgent.memoryEnabled !== false\" :disabled=\"busy\" @change=\"setAgent('memoryEnabled', ($event.target as HTMLInputElement).checked)\" />自动记录长期事实</label><p v-if=\"currentAgent.memoryStatus === 'upgrade_required'\" role=\"status\">执行节点需要升级后才能启用隔离记忆;已保存的文件仍可管理。</p></template>\n <div v-if=\"tab !== 'project' || projectId\" class=\"actions\"><button @click=\"newMemory()\" :disabled=\"!available.length\">添加记忆</button><a :href=\"`/api/app/workspace/memory-export?${query()}`\" download=\"bot-memory.md\">导出 Markdown</a></div>\n <form v-if=\"draft\" class=\"knowledge-editor\" @submit.prevent=\"saveMemory\"><h3>{{ draft.id ? '编辑记忆' : '添加记忆' }}</h3><label v-if=\"!draft.id && tab !== 'agent'\">贡献 Bot<select v-model=\"draft.agentId\"><option v-for=\"agent in available.filter(a => tab !== 'project' || currentProject?.memberIds.includes(a.id))\" :key=\"agent.id\" :value=\"agent.id\">{{ agent.name }}</option></select></label><label>事实<textarea v-model=\"draft.content\" required rows=\"4\" maxlength=\"2000\" /></label><label>类别<select v-model=\"draft.tier\"><option value=\"profile\">长期事实</option><option value=\"log\">历史记录</option><option value=\"note\">补充笔记</option></select></label><div class=\"actions\"><button type=\"submit\" :disabled=\"busy\">保存</button><button type=\"button\" @click=\"draft = undefined\">取消</button></div></form>\n <article v-for=\"memory in memories\" :key=\"`${memory.scope}:${memory.agentId}:${memory.id}`\"><p class=\"pre-wrap\">{{ memory.content }}</p><p v-if=\"memory.conflict\" role=\"status\">同主题有不同贡献,请核对来源。</p><small>{{ name(memory.agentId) }} · {{ memory.origin === 'manual' ? '用户维护' : memory.origin === 'explicit' ? '明确保存' : '自动提炼' }} · {{ new Date(memory.updatedAt).toLocaleString() }} · 版本 {{ memory.revision }}</small><details v-if=\"memory.sources.length\"><summary>查看来源</summary><p v-for=\"source in memory.sources\" :key=\"source.messageId\"><a :href=\"`/conversations/${source.conversationId}${source.taskId ? `?taskId=${source.taskId}` : ''}`\">{{ source.quote || '查看原话题' }}</a><small v-if=\"source.at\"> · 来源 {{ new Date(source.at).toLocaleString() }}</small></p></details><div class=\"actions\"><button @click=\"newMemory(memory)\">编辑</button><button @click=\"history(memory)\" :disabled=\"busy\">修订记录</button><button @click=\"forget(memory)\" :disabled=\"busy\">遗忘</button></div></article>\n <div v-if=\"memories.length\" class=\"actions\"><small role=\"status\">已显示 {{ memories.length }} / {{ memoryTotal }} 条</small><button v-if=\"nextMemoryOffset !== undefined\" :disabled=\"busy\" @click=\"loadMoreMemories\">加载更多记忆</button><button v-if=\"loadedMore\" :disabled=\"busy\" @click=\"load()\">刷新结果</button></div>\n <p v-if=\"!memories.length && !draft\" class=\"empty\">暂无记忆。可手动添加,也可在对话中说明需要长期记住的事实。</p>\n <section v-if=\"revisions.length\" class=\"knowledge-editor\"><h3>修订记录</h3><article v-for=\"revision in revisions\" :key=\"revision.id\"><small>版本 {{ revision.revision }} · {{ revision.operation === 'forget' ? '遗忘' : '保存' }} · {{ new Date(revision.at).toLocaleString() }}</small><p>{{ revision.after?.content ?? revision.before?.content }}</p></article><button @click=\"revisions = []\">收起</button></section>\n <details v-if=\"tab === 'agent' && jobs.length\">\n <summary>后台提炼记录</summary>\n <article v-for=\"job in jobs\" :key=\"job.id\">\n <small>{{ new Date(job.createdAt).toLocaleString() }} · {{ jobSummary(job) }}</small>\n <p v-if=\"job.result\">本次提炼 {{ job.result.extractedCount }} 条 · 新增保存 {{ job.result.writtenCount }} 条 · 重复 {{ job.result.duplicateCount }} 条 · 重试确认 {{ job.result.replayedCount }} 条</p>\n <p v-for=\"reason in skippedReasons(job)\" :key=\"reason\">{{ reason }}</p>\n <p v-if=\"job.error\">{{ job.error }}</p>\n <button v-if=\"job.status === 'failed'\" :disabled=\"busy\" @click=\"perform(async () => { await apiRequest(`/api/app/workspace/memory-jobs/${job.id}/retry`, { method: 'POST' }) })\">重试</button>\n </article>\n </details>\n </template>\n </div>\n </component>\n</template>\n\n<style scoped>\n.knowledge-dialog{width:min(820px,calc(100vw - 24px));max-height:calc(100dvh - 32px);padding:0;border:1px solid var(--line);border-radius:18px;background:var(--surface);color:var(--text-primary)}\n.knowledge-dialog::backdrop{background:rgb(0 0 0 / .5)}header{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:20px 24px;border-bottom:1px solid var(--line)}h2,h3,p{margin:0}header p,.scope-note,.empty,small{color:var(--text-secondary)}header p{margin-top:5px;font-size:13px}nav{display:flex;flex-wrap:wrap;gap:4px;padding:10px 20px;border-bottom:1px solid var(--line)}button,a{min-height:44px;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--line);border-radius:9px;padding:8px 12px;background:var(--surface);color:var(--text-primary);font:inherit;font-size:14px;cursor:pointer;text-decoration:none}button:hover,a:hover{background:var(--surface-hover)}button[aria-pressed=true]{background:var(--surface-hover);border-color:var(--accent);color:var(--accent)}button:disabled{opacity:.5;cursor:default}button:focus-visible,a:focus-visible,input:focus-visible,textarea:focus-visible,select:focus-visible,summary:focus-visible{outline:2px solid var(--accent);outline-offset:2px}.knowledge-body{display:grid;gap:16px;padding:20px 24px;max-height:calc(100dvh - 210px);overflow:auto;overscroll-behavior:contain}label{display:grid;gap:6px;font-size:14px}input:not([type=checkbox]),textarea,select{min-height:44px;padding:9px 10px;border:1px solid var(--line);border-radius:8px;background:var(--surface);color:var(--text-primary);font:inherit;box-sizing:border-box;width:100%}textarea{resize:vertical}.filters{display:flex;flex-wrap:wrap;align-items:end;gap:12px}.filters>label{min-width:160px}.filters form{display:flex;align-items:end;gap:8px;flex:1}.filters form label{flex:1}.actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}article{padding:16px;border:1px solid var(--line);border-radius:12px;display:grid;gap:9px}.knowledge-editor{display:grid;gap:12px;padding:16px;border:1px solid var(--accent);border-radius:12px}fieldset{border:1px solid var(--line);border-radius:10px;padding:12px;display:grid;gap:8px;max-height:240px;overflow:auto}.check{display:flex;align-items:center;min-height:44px;gap:9px}.check input{width:18px;height:18px;accent-color:var(--accent)}small,.scope-note{font-size:13px;line-height:1.5}.pre-wrap{white-space:pre-wrap;overflow-wrap:anywhere;line-height:1.6}.knowledge-error{color:var(--danger,#c0392b);white-space:pre-wrap}.empty{padding:24px 8px;text-align:center;line-height:1.6}summary{cursor:pointer;min-height:36px;line-height:1.6}details p{margin-top:8px}\n@media(max-width:520px){header{padding:16px}h2{font-size:19px}nav{padding:8px}nav button{flex:1;white-space:nowrap}.knowledge-body{padding:16px;max-height:calc(100dvh - 250px)}.filters{display:grid}.filters form{min-width:0}}\n.knowledge-dialog--embedded{width:100%;max-height:none;border:0;border-radius:0;background:transparent;min-width:0}.knowledge-dialog--embedded .knowledge-body{padding:0;max-height:none;overflow:visible}.knowledge-dialog--embedded .actions{align-items:center}\n.project-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:20px;margin-bottom:8px}.project-heading h3{font-size:18px;font-weight:650}.project-heading p{font-size:13px;color:var(--text-secondary);margin-top:6px;line-height:1.6}.knowledge-dialog--embedded .project-primary{flex-shrink:0;padding:8px 16px;background:var(--accent);color:var(--text-on-solid);border-color:var(--accent);font-size:13px}.project-list{border:1px solid var(--line);border-radius:11px;overflow:hidden}.project-list button{display:flex;gap:20px;width:100%;padding:18px 22px;border:0;border-radius:0;text-align:left;justify-content:flex-start;min-height:76px}.project-list button+button{border-top:1px solid var(--line)}.project-list button[aria-pressed=true]{background:var(--settings-selected);color:var(--text-primary)}.project-list button>span{flex:1;min-width:0;display:grid;gap:4px}.project-list strong{font-size:15px;font-weight:600;overflow-wrap:anywhere}.project-list small{font-size:12px}.project-list .app-icon{color:var(--text-muted)}.project-details{background:var(--settings-panel);padding:20px;border-radius:12px}.project-details h3{font-size:17px;font-weight:650;margin-bottom:12px}.project-description{font-size:13px;color:var(--text-secondary);line-height:1.6;padding-bottom:12px;white-space:pre-wrap;overflow-wrap:anywhere}.project-detail-row{display:grid;grid-template-columns:104px minmax(0,1fr);align-items:center;gap:16px;min-height:48px;border-top:1px solid var(--line);font-size:14px}.project-detail-row>span{color:var(--text-secondary)}.project-detail-row>div{overflow-wrap:anywhere}.project-detail-row button{min-height:36px;background:var(--settings-selected);border:0;font-size:12px}.project-members{display:flex;gap:10px;flex-wrap:wrap;padding-block:10px}.project-members>span{display:inline-flex;align-items:center;gap:7px}.project-detail-actions{display:flex;justify-content:flex-end;margin-top:8px}.project-detail-actions .project-primary{min-height:36px}.knowledge-dialog--embedded article{border:0;background:var(--settings-panel)}@media(max-width:520px){.project-heading{gap:10px}.project-heading p{max-width:210px}.project-list button{padding:16px;gap:12px}.project-details{padding:16px}.project-detail-row{grid-template-columns:76px minmax(0,1fr);gap:10px}}\n</style>\n<style scoped>.project-chevron{width:17px;height:17px;flex-shrink:0;color:var(--text-muted)}</style>\n","<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport MemoryFilesPanel from './MemoryFilesPanel.vue'\nimport type { AgentAssignment, AgentGoal } from '@shared/agentTasks'\nimport { collaborationTimeline } from '@shared/collaborationTimeline'\nimport { apiRequest } from '@/api/client'\nimport { createUuid } from '@/utils/id'\nimport AppIcon from '@/components/common/AppIcon.vue'\nimport AgentAvatar from '@/components/common/AgentAvatar.vue'\nimport { ChevronForwardOutline } from '@vicons/ionicons5'\nimport type { WorkspaceAgent, WorkspaceConversation, WorkspaceMessage } from '@shared/workspace'\nimport type { MemoryScope, MemorySkipReason, WorkspaceMemory, WorkspaceMemoryJob, WorkspaceMemoryRevision, WorkspacePeerMessage, WorkspaceProject } from '@shared/workspaceKnowledge'\n\nconst props = defineProps<{ agents: WorkspaceAgent[]; conversations: WorkspaceConversation[]; conversationId?: string; taskId?: string; assignments?: AgentAssignment[]; goal?: AgentGoal; revision?: number; embedded?: boolean; initialTab?: 'projects' | 'user' | 'agent'; selectedAgentId?: string; hideAgentControls?: boolean }>()\nconst emit = defineEmits<{ changed: []; 'dirty-change': [dirty: boolean] }>()\nconst dialog = ref<HTMLDialogElement>(), opened = ref(false), busy = ref(false), error = ref(''), tab = ref('agent'), agentId = ref(''), projectId = ref(''), search = ref('')\nconst projects = ref<WorkspaceProject[]>([]), memories = ref<WorkspaceMemory[]>([]), peers = ref<WorkspacePeerMessage[]>([]), jobs = ref<WorkspaceMemoryJob[]>([]), revisions = ref<WorkspaceMemoryRevision[]>([])\nconst draft = ref<{ id?: string; expectedRevision?: number; agentId: string; content: string; tier: WorkspaceMemory['tier'] }>()\nconst projectDraft = ref<WorkspaceProject>()\nconst memoryTotal=ref(0), nextMemoryOffset=ref<number>(), loadedMore=ref(false)\nconst fileDirty=ref(false)\nconst activities = ref<WorkspaceMessage[]>([])\nlet generation = 0, timer: ReturnType<typeof setInterval> | undefined\nconst available = computed(() => props.agents.filter(a => !a.archived && !a.temporaryGoalId))\nconst currentAgent = computed(() => props.agents.find(a => a.id === agentId.value))\nconst currentProject = computed(() => projects.value.find(p => p.id === projectId.value))\nconst scope = computed(() => (['agent', 'user', 'project'].includes(tab.value) ? tab.value : 'agent') as MemoryScope)\nconst name = (id?: string) => props.agents.find(a => a.id === id)?.name ?? '原贡献者'\nconst collaboration = computed(() => collaborationTimeline({ peers: peers.value, activities: activities.value, assignments: props.assignments ?? [], coordinatorId: props.goal?.coordinatorId, name }))\nconst query = () => new URLSearchParams({ scope: scope.value, ...(tab.value === 'agent' && agentId.value ? { agentId: agentId.value } : {}), ...(tab.value === 'project' && projectId.value ? { projectId: projectId.value } : {}), ...(search.value ? { search: search.value } : {}) }).toString()\nconst stateNames: Record<string, string> = { queued: '已排队', pending: '待提炼', running: '处理中', waiting: '等待同伴', complete: '已完成', failed: '失败', stopped: '已停止', skipped: '已跳过' }\nconst skipReasonNames: Record<MemorySkipReason, string> = {\n source_missing: '找不到对应的来源消息', quote_mismatch: '引用与原文不一致', sensitive_content: '包含凭据等敏感内容',\n project_unbound: '项目记忆缺少关联项目', user_not_explicit: '缺少用户明确表达的长期信息', forgotten: '已遗忘的内容或来源不再保存', stale: '推理期间记忆已更新,本次旧提炼结果未应用',\n}\nfunction jobSummary(job: WorkspaceMemoryJob): string {\n if (job.status !== 'complete') return stateNames[job.status] ?? job.status\n const result = job.result\n if (!result) return '已结束(旧记录未统计保存结果)'\n if (!result.extractedCount) return '本轮没有可记录内容'\n if (result.writtenCount) return `已保存 ${result.writtenCount} 条记忆`\n if (result.replayedCount) return `重试已确认 ${result.replayedCount} 条记录`\n if (result.duplicateCount) return '未新增记忆,已有相同内容'\n return '候选记忆均未保存'\n}\nfunction skippedReasons(job: WorkspaceMemoryJob): string[] {\n return Object.entries(job.result?.skippedReasons ?? {}).filter(([, count]) => count > 0)\n .map(([reason, count]) => `${skipReasonNames[reason as MemorySkipReason] ?? '其他原因'}:${count} 条`)\n}\nasync function load(silent = false) {\n if (silent && loadedMore.value && tab.value !== 'collaboration') return\n const epoch = ++generation\n if (!silent) error.value = ''\n try {\n const projectResult = await apiRequest<{ projects: WorkspaceProject[] }>('/api/app/workspace/projects')\n if (epoch !== generation || !opened.value) return\n projects.value = projectResult.projects\n if (!projectId.value) projectId.value = projects.value.find(p => !p.archived)?.id ?? ''\n if (tab.value === 'collaboration') {\n const [result, milestones] = await Promise.all([\n apiRequest<{ messages: WorkspacePeerMessage[] }>(`/api/app/workspace/collaboration?${new URLSearchParams({ ...(props.conversationId ? { conversationId: props.conversationId } : {}), ...(props.taskId ? { taskId: props.taskId } : {}) })}`),\n props.conversationId ? apiRequest<{ messages: WorkspaceMessage[] }>(`/api/app/conversations/${encodeURIComponent(props.conversationId)}/activities${props.taskId ? `?taskId=${encodeURIComponent(props.taskId)}` : ''}`) : Promise.resolve({ messages: [] }),\n ])\n if (epoch === generation) { peers.value = result.messages; activities.value = milestones.messages }\n } else if (tab.value !== 'projects' && (tab.value !== 'project' || projectId.value)) {\n const result = await apiRequest<{ memories: WorkspaceMemory[]; total?: number; nextOffset?: number }>(`/api/app/workspace/memories?${query()}`)\n if (epoch === generation) { memories.value = result.memories; memoryTotal.value = result.total ?? result.memories.length; nextMemoryOffset.value = result.nextOffset; loadedMore.value = false }\n } else { memories.value = []; memoryTotal.value = 0; nextMemoryOffset.value = undefined; loadedMore.value = false }\n if (agentId.value) {\n const result = await apiRequest<{ jobs: WorkspaceMemoryJob[] }>(`/api/app/workspace/memory-jobs?agentId=${agentId.value}`)\n if (epoch === generation) jobs.value = result.jobs\n }\n } catch (cause) { if (epoch === generation) error.value = String(cause) }\n}\nasync function loadMoreMemories() {\n if (busy.value || nextMemoryOffset.value === undefined) return\n const epoch = generation, filter = query(), offset = nextMemoryOffset.value\n busy.value = true; error.value = ''\n try {\n const result = await apiRequest<{ memories: WorkspaceMemory[]; total: number; nextOffset?: number }>(`/api/app/workspace/memories?${filter}&offset=${offset}&limit=100`)\n if (epoch !== generation || !opened.value || filter !== query()) return\n const existing = new Set(memories.value.map(m => `${m.scope}:${m.agentId}:${m.id}`))\n memories.value.push(...result.memories.filter(m => !existing.has(`${m.scope}:${m.agentId}:${m.id}`)))\n memoryTotal.value = result.total; nextMemoryOffset.value = result.nextOffset; loadedMore.value = true\n } catch (cause) { if (epoch === generation) error.value = String(cause) } finally { busy.value = false }\n}\nasync function open(initial = 'agent', selectedAgent?: string, selectedProject?: string) {\n tab.value = initial; agentId.value = selectedAgent ?? available.value[0]?.id ?? ''; projectId.value = selectedProject ?? ''\n opened.value = true; draft.value = undefined; projectDraft.value = undefined; revisions.value = []; search.value = ''\n await nextTick(); if (!props.embedded) dialog.value?.showModal(); await load()\n clearInterval(timer); timer = setInterval(() => { if (!busy.value && !draft.value && !projectDraft.value) void load(true) }, 5000)\n}\nfunction close() { if(fileDirty.value){error.value='请先保存文件或取消编辑。';return} opened.value = false; generation++; clearInterval(timer); if (!props.embedded) dialog.value?.close() }\nfunction switchTab(value: string) { if(fileDirty.value)return; tab.value = value; draft.value = undefined; projectDraft.value = undefined; revisions.value = []; void load() }\nasync function perform(action: () => Promise<void>) {\n if (busy.value) return\n busy.value = true; error.value = ''\n try { await action(); emit('changed'); await load() } catch (cause) { error.value = String(cause) } finally { busy.value = false }\n}\nfunction newMemory(memory?: WorkspaceMemory) {\n revisions.value = []\n draft.value = memory ? { id: memory.id, expectedRevision: memory.revision, agentId: memory.agentId, content: memory.content, tier: memory.tier } : { agentId: agentId.value || available.value[0]?.id || '', content: '', tier: 'log' }\n}\nasync function saveMemory() {\n const value = draft.value\n if (!value?.content.trim()) { error.value = '请输入需要记住的事实'; return }\n await perform(async () => {\n await apiRequest('/api/app/workspace/memories', { method: 'POST', body: { requestId: createUuid(), scope: scope.value, ...(scope.value === 'project' ? { projectId: projectId.value } : {}), ...value } })\n draft.value = undefined\n })\n}\nasync function forget(memory: WorkspaceMemory) {\n await perform(async () => { await apiRequest('/api/app/workspace/memories/forget', { method: 'POST', body: { requestId: createUuid(), scope: memory.scope, agentId: memory.agentId, ...(memory.projectId ? { projectId: memory.projectId } : {}), id: memory.id, expectedRevision: memory.revision } }) })\n}\nasync function history(memory: WorkspaceMemory) {\n const query = new URLSearchParams({ scope: memory.scope, agentId: memory.agentId, ...(memory.projectId ? { projectId: memory.projectId } : {}) })\n await perform(async () => { revisions.value = (await apiRequest<{ revisions: WorkspaceMemoryRevision[] }>(`/api/app/workspace/memories/${memory.id}/revisions?${query}`)).revisions })\n}\nfunction editProject(project?: WorkspaceProject) {\n projectDraft.value = project ? { ...project, memberIds: [...project.memberIds], groupIds: [...project.groupIds] } : { id: '', name: '', description: '', memberIds: [], groupIds: [], revision: 0, archived: false, createdAt: 0, updatedAt: 0 }\n}\nasync function saveProject() {\n const value = projectDraft.value\n if (!value?.name.trim()) { error.value = '请输入项目名称'; return }\n await perform(async () => {\n const result = await apiRequest<{ project: WorkspaceProject }>('/api/app/workspace/projects', { method: 'POST', body: { requestId: createUuid(), ...(value.id ? { id: value.id, expectedRevision: value.revision } : {}), name: value.name, description: value.description, memberIds: value.memberIds, groupIds: value.groupIds, archived: value.archived } })\n projectId.value = result.project.id; projectDraft.value = undefined\n })\n}\nasync function setAgent(field: 'canCollaborate' | 'memoryEnabled', enabled: boolean) {\n await perform(async () => { await apiRequest(`/api/app/agents/${agentId.value}`, { method: 'PATCH', body: { [field]: enabled } }) })\n}\nonBeforeUnmount(() => { generation++; clearInterval(timer) })\nonMounted(() => { if (props.embedded) void open(props.initialTab ?? 'projects', props.selectedAgentId) })\nwatch(() => props.initialTab, value => { if (props.embedded && value) switchTab(value) })\nwatch(() => props.revision, () => { if (opened.value && !busy.value && !draft.value && !projectDraft.value) void load(true) })\nwatch(() => [props.conversationId, props.taskId], () => { generation++; peers.value = []; activities.value = []; if (opened.value && tab.value === 'collaboration') void load() })\nwatch(() => fileDirty.value || !!draft.value || !!projectDraft.value, value => emit('dirty-change', value))\ndefineExpose({ open, close })\n</script>\n\n<template>\n <component :is=\"embedded ? 'section' : 'dialog'\" ref=\"dialog\" class=\"knowledge-dialog\" :class=\"{ 'knowledge-dialog--embedded': embedded }\" :aria-labelledby=\"embedded ? undefined : 'knowledge-title'\" @cancel.prevent=\"close\" @close=\"opened = false\">\n <header v-if=\"!embedded\"><div><h2 id=\"knowledge-title\">Bot 记忆与协作</h2><p>管理长期事实、项目和同伴请求</p></div><button type=\"button\" @click=\"close\" aria-label=\"关闭记忆与协作\">关闭</button></header>\n <nav v-if=\"!embedded\" aria-label=\"记忆与项目分类\"><button v-for=\"item in [['agent','Bot 记忆'],['user','用户记忆'],['projects','项目'],['project','项目记忆'],['collaboration','协作']]\" :key=\"item[0]\" :aria-pressed=\"tab === item[0]\" @click=\"switchTab(item[0]!)\">{{ item[1] }}</button></nav>\n <div class=\"knowledge-body\" :aria-busy=\"busy\">\n <div v-if=\"embedded && tab === 'project'\" class=\"actions\"><button type=\"button\" @click=\"switchTab('projects')\">返回项目</button><h3>项目记忆</h3></div>\n <p v-if=\"error\" role=\"alert\" class=\"knowledge-error\">{{ error }}</p>\n <template v-if=\"tab === 'projects'\">\n <div v-if=\"embedded\" class=\"project-heading\"><div><h3>项目</h3><p>让同一项目的 Bot 共享决策与约定。</p></div><button v-if=\"!projectDraft\" type=\"button\" class=\"project-primary\" @click=\"editProject()\">新建项目</button></div>\n <button v-else-if=\"!projectDraft\" @click=\"editProject()\">新建项目</button>\n <form v-if=\"projectDraft\" class=\"knowledge-editor\" @submit.prevent=\"saveProject\">\n <h3>{{ projectDraft.id ? '编辑项目' : '新建项目' }}</h3>\n <label>名称<input v-model=\"projectDraft.name\" required maxlength=\"100\" /></label>\n <label>说明<textarea v-model=\"projectDraft.description\" rows=\"3\" maxlength=\"16000\" /></label>\n <fieldset><legend>项目成员</legend><label v-for=\"agent in available\" :key=\"agent.id\" class=\"check\"><input v-model=\"projectDraft.memberIds\" type=\"checkbox\" :value=\"agent.id\" />{{ agent.name }}</label></fieldset>\n <fieldset><legend>关联群聊</legend><p>群内所有 Bot 需要先加入此项目。</p><label v-for=\"group in conversations.filter(c => c.kind === 'group' && !c.archived)\" :key=\"group.id\" class=\"check\"><input v-model=\"projectDraft.groupIds\" type=\"checkbox\" :value=\"group.id\" :disabled=\"group.memberIds.some(id => !projectDraft!.memberIds.includes(id)) || !!group.projectId && group.projectId !== projectDraft.id\" />{{ group.name }}</label></fieldset>\n <label v-if=\"projectDraft.id\" class=\"check\"><input v-model=\"projectDraft.archived\" type=\"checkbox\" />归档项目</label>\n <div class=\"actions\"><button type=\"submit\" :disabled=\"busy\">保存项目</button><button type=\"button\" @click=\"projectDraft = undefined\">取消</button></div>\n </form>\n <template v-if=\"embedded && !projectDraft\">\n <div v-if=\"projects.length\" class=\"project-list\" aria-label=\"项目列表\"><button v-for=\"project in projects\" :key=\"project.id\" type=\"button\" :aria-pressed=\"projectId === project.id\" @click=\"projectId = project.id\"><AppIcon name=\"files\" :size=\"21\"/><span><strong>{{project.name}}{{project.archived ? ' · 已归档' : ''}}</strong><small>{{project.memberIds.length}} 位 Bot · {{project.groupIds.length}} 个群聊</small></span><ChevronForwardOutline class=\"project-chevron\" aria-hidden=\"true\"/></button></div>\n <section v-if=\"currentProject\" class=\"project-details\" aria-label=\"当前项目详情\">\n <h3>{{currentProject.name}}</h3><p v-if=\"currentProject.description\" class=\"project-description\">{{currentProject.description}}</p>\n <div class=\"project-detail-row\"><span>项目成员</span><div class=\"project-members\"><span v-for=\"id in currentProject.memberIds\" :key=\"id\"><AgentAvatar :name=\"name(id)\" :avatar=\"agents.find(a => a.id === id)?.avatar || ''\" :size=\"24\"/>{{name(id)}}</span><small v-if=\"!currentProject.memberIds.length\">尚无成员</small></div></div>\n <div class=\"project-detail-row\"><span>关联群聊</span><div>{{currentProject.groupIds.map(id => conversations.find(c => c.id === id)?.name ?? '原群聊').join('、') || '尚未关联群聊'}}</div></div>\n <div class=\"project-detail-row\"><span>项目记忆</span><div><button type=\"button\" @click=\"switchTab('project')\">查看记忆</button></div></div>\n <div class=\"project-detail-actions\"><button type=\"button\" class=\"project-primary\" @click=\"editProject(currentProject)\">编辑项目</button></div>\n </section>\n </template>\n <template v-else-if=\"!embedded\"><article v-for=\"project in projects\" :key=\"project.id\"><h3>{{ project.name }}{{ project.archived ? ' · 已归档' : '' }}</h3><p>{{ project.description || '暂无说明' }}</p><small>{{ project.memberIds.map(id => name(id)).join('、') || '尚无成员' }} · {{ project.groupIds.length }} 个群</small><div class=\"actions\"><button @click=\"editProject(project)\">编辑</button><button @click=\"projectId = project.id; switchTab('project')\">查看记忆</button></div></article></template>\n <p v-if=\"!projects.length && !projectDraft\" class=\"empty\">创建项目后,多个群可以共享该项目的决策和约定。</p>\n </template>\n <template v-else-if=\"tab === 'collaboration'\">\n <p class=\"scope-note\">{{ taskId ? '当前话题' : '当前聊天' }} · {{ collaboration.length }} 条协作记录</p>\n <article v-for=\"event in collaboration\" :key=\"event.id\"><details><summary>{{ event.title }} · {{ event.status }}</summary><p class=\"pre-wrap\">{{ event.content }}</p><small v-if=\"event.at\">{{ new Date(event.at).toLocaleString() }}</small><p v-if=\"event.error\" class=\"knowledge-error\">{{ event.error }}</p></details><button v-if=\"event.peer && ['queued','running','waiting'].includes(event.peer.status)\" :disabled=\"busy\" @click=\"perform(async () => { await apiRequest(`/api/app/workspace/collaboration/${encodeURIComponent(event.peer!.id)}/stop`, { method: 'POST' }) })\">停止此次协作</button></article>\n <p v-if=\"!collaboration.length\" class=\"empty\">暂无协作记录。你可以在聊天中让 Bot 联系同伴,或派发任务。</p>\n </template>\n <template v-else>\n <MemoryFilesPanel v-if=\"agentId && (scope !== 'project' || projectId)\" :agent-id=\"agentId\" :scope=\"scope\" :project-id=\"projectId\" @dirty-change=\"fileDirty=$event\" @changed=\"emit('changed');load()\" />\n <div class=\"filters\">\n <label v-if=\"['agent','user','project'].includes(tab) && !selectedAgentId\">记忆贡献 Bot<select :disabled=\"fileDirty\" v-model=\"agentId\" @change=\"draft = undefined; load()\"><option v-for=\"agent in available\" :key=\"agent.id\" :value=\"agent.id\">{{ agent.name }}</option></select></label>\n <label v-if=\"tab === 'project'\">项目<select :disabled=\"fileDirty\" v-model=\"projectId\" @change=\"draft = undefined; load()\"><option v-for=\"project in projects\" :key=\"project.id\" :value=\"project.id\">{{ project.name }}</option></select></label>\n <form @submit.prevent=\"load()\"><label>搜索记忆<input v-model=\"search\" type=\"search\" placeholder=\"搜索事实、偏好或决策\" /></label><button type=\"submit\">搜索</button></form>\n </div>\n <p class=\"scope-note\">{{ tab === 'agent' ? '仅此 Bot 使用,可跨单聊和群聊延续。' : tab === 'user' ? '同一账号的 Bot 共享,按贡献者保存。' : `仅「${currentProject?.name ?? '当前项目'}」成员读取。` }}</p>\n <template v-if=\"tab === 'agent' && currentAgent\"><label v-if=\"!hideAgentControls\" class=\"check\"><input type=\"checkbox\" :checked=\"currentAgent.memoryEnabled !== false\" :disabled=\"busy\" @change=\"setAgent('memoryEnabled', ($event.target as HTMLInputElement).checked)\" />自动记录长期事实</label><p v-if=\"currentAgent.memoryStatus === 'upgrade_required'\" role=\"status\">执行节点需要升级后才能启用隔离记忆;已保存的文件仍可管理。</p></template>\n <div v-if=\"tab !== 'project' || projectId\" class=\"actions\"><button @click=\"newMemory()\" :disabled=\"!available.length\">添加记忆</button><a :href=\"`/api/app/workspace/memory-export?${query()}`\" download=\"bot-memory.md\">导出 Markdown</a></div>\n <form v-if=\"draft\" class=\"knowledge-editor\" @submit.prevent=\"saveMemory\"><h3>{{ draft.id ? '编辑记忆' : '添加记忆' }}</h3><label v-if=\"!draft.id && tab !== 'agent'\">贡献 Bot<select v-model=\"draft.agentId\"><option v-for=\"agent in available.filter(a => tab !== 'project' || currentProject?.memberIds.includes(a.id))\" :key=\"agent.id\" :value=\"agent.id\">{{ agent.name }}</option></select></label><label>事实<textarea v-model=\"draft.content\" required rows=\"4\" maxlength=\"2000\" /></label><label>类别<select v-model=\"draft.tier\"><option value=\"profile\">长期事实</option><option value=\"log\">历史记录</option><option value=\"note\">补充笔记</option></select></label><div class=\"actions\"><button type=\"submit\" :disabled=\"busy\">保存</button><button type=\"button\" @click=\"draft = undefined\">取消</button></div></form>\n <article v-for=\"memory in memories\" :key=\"`${memory.scope}:${memory.agentId}:${memory.id}`\"><p class=\"pre-wrap\">{{ memory.content }}</p><p v-if=\"memory.conflict\" role=\"status\">同主题有不同贡献,请核对来源。</p><small>{{ name(memory.agentId) }} · {{ memory.origin === 'manual' ? '用户维护' : memory.origin === 'explicit' ? '明确保存' : '自动提炼' }} · {{ new Date(memory.updatedAt).toLocaleString() }} · 版本 {{ memory.revision }}</small><details v-if=\"memory.sources.length\"><summary>查看来源</summary><p v-for=\"source in memory.sources\" :key=\"source.messageId\"><a :href=\"`/conversations/${source.conversationId}${source.taskId ? `?taskId=${source.taskId}` : ''}`\">{{ source.quote || '查看原话题' }}</a><small v-if=\"source.at\"> · 来源 {{ new Date(source.at).toLocaleString() }}</small></p></details><div class=\"actions\"><button @click=\"newMemory(memory)\">编辑</button><button @click=\"history(memory)\" :disabled=\"busy\">修订记录</button><button @click=\"forget(memory)\" :disabled=\"busy\">遗忘</button></div></article>\n <div v-if=\"memories.length\" class=\"actions\"><small role=\"status\">已显示 {{ memories.length }} / {{ memoryTotal }} 条</small><button v-if=\"nextMemoryOffset !== undefined\" :disabled=\"busy\" @click=\"loadMoreMemories\">加载更多记忆</button><button v-if=\"loadedMore\" :disabled=\"busy\" @click=\"load()\">刷新结果</button></div>\n <p v-if=\"!memories.length && !draft\" class=\"empty\">暂无记忆。可手动添加,也可在对话中说明需要长期记住的事实。</p>\n <section v-if=\"revisions.length\" class=\"knowledge-editor\"><h3>修订记录</h3><article v-for=\"revision in revisions\" :key=\"revision.id\"><small>版本 {{ revision.revision }} · {{ revision.operation === 'forget' ? '遗忘' : '保存' }} · {{ new Date(revision.at).toLocaleString() }}</small><p>{{ revision.after?.content ?? revision.before?.content }}</p></article><button @click=\"revisions = []\">收起</button></section>\n <details v-if=\"tab === 'agent' && jobs.length\">\n <summary>后台提炼记录</summary>\n <article v-for=\"job in jobs\" :key=\"job.id\">\n <small>{{ new Date(job.createdAt).toLocaleString() }} · {{ jobSummary(job) }}</small>\n <p v-if=\"job.result\">本次提炼 {{ job.result.extractedCount }} 条 · 新增保存 {{ job.result.writtenCount }} 条 · 重复 {{ job.result.duplicateCount }} 条 · 重试确认 {{ job.result.replayedCount }} 条</p>\n <p v-for=\"reason in skippedReasons(job)\" :key=\"reason\">{{ reason }}</p>\n <p v-if=\"job.error\">{{ job.error }}</p>\n <button v-if=\"job.status === 'failed'\" :disabled=\"busy\" @click=\"perform(async () => { await apiRequest(`/api/app/workspace/memory-jobs/${job.id}/retry`, { method: 'POST' }) })\">重试</button>\n </article>\n </details>\n </template>\n </div>\n </component>\n</template>\n\n<style scoped>\n.knowledge-dialog{width:min(820px,calc(100vw - 24px));max-height:calc(100dvh - 32px);padding:0;border:1px solid var(--line);border-radius:18px;background:var(--surface);color:var(--text-primary)}\n.knowledge-dialog::backdrop{background:rgb(0 0 0 / .5)}header{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:20px 24px;border-bottom:1px solid var(--line)}h2,h3,p{margin:0}header p,.scope-note,.empty,small{color:var(--text-secondary)}header p{margin-top:5px;font-size:13px}nav{display:flex;flex-wrap:wrap;gap:4px;padding:10px 20px;border-bottom:1px solid var(--line)}button,a{min-height:44px;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--line);border-radius:9px;padding:8px 12px;background:var(--surface);color:var(--text-primary);font:inherit;font-size:14px;cursor:pointer;text-decoration:none}button:hover,a:hover{background:var(--surface-hover)}button[aria-pressed=true]{background:var(--surface-hover);border-color:var(--accent);color:var(--accent)}button:disabled{opacity:.5;cursor:default}button:focus-visible,a:focus-visible,input:focus-visible,textarea:focus-visible,select:focus-visible,summary:focus-visible{outline:2px solid var(--accent);outline-offset:2px}.knowledge-body{display:grid;gap:16px;padding:20px 24px;max-height:calc(100dvh - 210px);overflow:auto;overscroll-behavior:contain}label{display:grid;gap:6px;font-size:14px}input:not([type=checkbox]),textarea,select{min-height:44px;padding:9px 10px;border:1px solid var(--line);border-radius:8px;background:var(--surface);color:var(--text-primary);font:inherit;box-sizing:border-box;width:100%}textarea{resize:vertical}.filters{display:flex;flex-wrap:wrap;align-items:end;gap:12px}.filters>label{min-width:160px}.filters form{display:flex;align-items:end;gap:8px;flex:1}.filters form label{flex:1}.actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}article{padding:16px;border:1px solid var(--line);border-radius:12px;display:grid;gap:9px}.knowledge-editor{display:grid;gap:12px;padding:16px;border:1px solid var(--accent);border-radius:12px}fieldset{border:1px solid var(--line);border-radius:10px;padding:12px;display:grid;gap:8px;max-height:240px;overflow:auto}.check{display:flex;align-items:center;min-height:44px;gap:9px}.check input{width:18px;height:18px;accent-color:var(--accent)}small,.scope-note{font-size:13px;line-height:1.5}.pre-wrap{white-space:pre-wrap;overflow-wrap:anywhere;line-height:1.6}.knowledge-error{color:var(--danger,#c0392b);white-space:pre-wrap}.empty{padding:24px 8px;text-align:center;line-height:1.6}summary{cursor:pointer;min-height:36px;line-height:1.6}details p{margin-top:8px}\n@media(max-width:520px){header{padding:16px}h2{font-size:19px}nav{padding:8px}nav button{flex:1;white-space:nowrap}.knowledge-body{padding:16px;max-height:calc(100dvh - 250px)}.filters{display:grid}.filters form{min-width:0}}\n.knowledge-dialog--embedded{width:100%;max-height:none;border:0;border-radius:0;background:transparent;min-width:0}.knowledge-dialog--embedded .knowledge-body{padding:0;max-height:none;overflow:visible}.knowledge-dialog--embedded .actions{align-items:center}\n.project-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:20px;margin-bottom:8px}.project-heading h3{font-size:18px;font-weight:650}.project-heading p{font-size:13px;color:var(--text-secondary);margin-top:6px;line-height:1.6}.knowledge-dialog--embedded .project-primary{flex-shrink:0;padding:8px 16px;background:var(--accent);color:var(--text-on-solid);border-color:var(--accent);font-size:13px}.project-list{border:1px solid var(--line);border-radius:11px;overflow:hidden}.project-list button{display:flex;gap:20px;width:100%;padding:18px 22px;border:0;border-radius:0;text-align:left;justify-content:flex-start;min-height:76px}.project-list button+button{border-top:1px solid var(--line)}.project-list button[aria-pressed=true]{background:var(--settings-selected);color:var(--text-primary)}.project-list button>span{flex:1;min-width:0;display:grid;gap:4px}.project-list strong{font-size:15px;font-weight:600;overflow-wrap:anywhere}.project-list small{font-size:12px}.project-list .app-icon{color:var(--text-muted)}.project-details{background:var(--settings-panel);padding:20px;border-radius:12px}.project-details h3{font-size:17px;font-weight:650;margin-bottom:12px}.project-description{font-size:13px;color:var(--text-secondary);line-height:1.6;padding-bottom:12px;white-space:pre-wrap;overflow-wrap:anywhere}.project-detail-row{display:grid;grid-template-columns:104px minmax(0,1fr);align-items:center;gap:16px;min-height:48px;border-top:1px solid var(--line);font-size:14px}.project-detail-row>span{color:var(--text-secondary)}.project-detail-row>div{overflow-wrap:anywhere}.project-detail-row button{min-height:36px;background:var(--settings-selected);border:0;font-size:12px}.project-members{display:flex;gap:10px;flex-wrap:wrap;padding-block:10px}.project-members>span{display:inline-flex;align-items:center;gap:7px}.project-detail-actions{display:flex;justify-content:flex-end;margin-top:8px}.project-detail-actions .project-primary{min-height:36px}.knowledge-dialog--embedded article{border:0;background:var(--settings-panel)}@media(max-width:520px){.project-heading{gap:10px}.project-heading p{max-width:210px}.project-list button{padding:16px;gap:12px}.project-details{padding:16px}.project-detail-row{grid-template-columns:76px minmax(0,1fr);gap:10px}}\n</style>\n<style scoped>.project-chevron{width:17px;height:17px;flex-shrink:0;color:var(--text-muted)}</style>\n"],"x_google_ignoreList":[0],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WorkspaceKnowledgePanel-BdbhD3rO.js","names":["_hoisted_1","_openBlock","_createElementBlock","_createElementVNode"],"sources":["../../node_modules/@vicons/ionicons5/es/ChevronForwardOutline.js","../../src/client/components/workspace/MemoryFilesPanel.vue","../../src/client/components/workspace/MemoryFilesPanel.vue","../../src/shared/collaborationPresentation.ts","../../src/shared/collaborationTimeline.ts","../../src/client/components/workspace/WorkspaceKnowledgePanel.vue","../../src/client/components/workspace/WorkspaceKnowledgePanel.vue"],"sourcesContent":["import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock, defineComponent } from 'vue'\nconst _hoisted_1 = {\n xmlns: 'http://www.w3.org/2000/svg',\n 'xmlns:xlink': 'http://www.w3.org/1999/xlink',\n viewBox: '0 0 512 512'\n}\nexport default defineComponent({\n name: 'ChevronForwardOutline',\n render: function render(_ctx, _cache) {\n return (\n _openBlock(),\n _createElementBlock(\n 'svg',\n _hoisted_1,\n _cache[0] ||\n (_cache[0] = [\n _createElementVNode(\n 'path',\n {\n fill: 'none',\n stroke: 'currentColor',\n 'stroke-linecap': 'round',\n 'stroke-linejoin': 'round',\n 'stroke-width': '48',\n d: 'M184 112l144 144l-144 144'\n },\n null,\n -1 /* HOISTED */\n )\n ])\n )\n )\n }\n})\n","<script setup lang=\"ts\">\nimport { ref, watch, onBeforeUnmount } from \"vue\";\nimport { apiRequest } from \"@/api/client\";\nimport { createUuid } from \"@/utils/id\";\nconst props = defineProps<{\n agentId: string;\n scope: string;\n projectId?: string;\n}>();\nconst emit = defineEmits<{ \"dirty-change\": [dirty: boolean]; changed: [] }>();\nconst base = \"/api/app/workspace\";\ntype Doc = { path: string; content: string; hash: string };\ntype Revision = {\n id: string;\n path: string;\n before: string;\n after: string;\n afterHash: string;\n at: number;\n};\nconst files = ref<{ path: string; bytes: number }[]>([]),\n doc = ref<Doc>(),\n draft = ref(\"\"),\n newPath = ref(\"memory/notes.md\"),\n error = ref(\"\"),\n notice = ref(\"\"),\n busy = ref(false),\n history = ref<Revision[]>([]);\nlet generation = 0;\nconst scope = () => ({\n scope: props.scope,\n agentId: props.agentId,\n ...(props.scope === \"project\" ? { projectId: props.projectId } : {}),\n});\nconst query = (extra: Record<string, string> = {}) =>\n new URLSearchParams({ ...scope(), ...extra } as Record<string, string>);\nasync function action(fn: () => Promise<void>) {\n if (busy.value) return;\n busy.value = true;\n error.value = \"\";\n notice.value = \"\";\n try {\n await fn();\n } catch (e) {\n error.value = e instanceof Error ? e.message : \"操作失败\";\n } finally {\n busy.value = false;\n }\n}\nasync function load() {\n const epoch = ++generation;\n if (!props.agentId || (props.scope === \"project\" && !props.projectId)) {\n files.value = [];\n return;\n }\n try {\n const result = await apiRequest<{\n files: { path: string; bytes: number }[];\n }>(`${base}/memory-files?${query()}`);\n if (epoch === generation) files.value = result.files;\n } catch (e) {\n if (epoch === generation) error.value = String(e);\n }\n}\nasync function open(path: string) {\n await action(async () => {\n const epoch = generation;\n const result = await apiRequest<Doc>(\n `${base}/memory-file?${query({ path })}`,\n );\n if (epoch !== generation) return;\n doc.value = result;\n draft.value = result.content;\n history.value = [];\n });\n}\nasync function save() {\n if (!doc.value) return;\n await action(async () => {\n doc.value = await apiRequest<Doc>(base + \"/memory-file\", {\n method: \"PUT\",\n body: {\n ...scope(),\n requestId: createUuid(),\n path: doc.value!.path,\n content: draft.value,\n expectedHash: doc.value!.hash,\n },\n });\n draft.value = doc.value.content;\n notice.value = \"文件已保存,下一轮对话生效。\";\n emit(\"changed\");\n await load();\n });\n}\nasync function revisions() {\n await action(async () => {\n history.value = (\n await apiRequest<{ revisions: Revision[] }>(\n `${base}/memory-file-history?${query()}`,\n )\n ).revisions.filter((r) => r.path === doc.value?.path);\n });\n}\nasync function revert(r: Revision) {\n await action(async () => {\n doc.value = await apiRequest<Doc>(base + \"/memory-file-revert\", {\n method: \"POST\",\n body: {\n ...scope(),\n requestId: createUuid(),\n id: r.id,\n expectedHash: doc.value!.hash,\n },\n });\n draft.value = doc.value.content;\n notice.value = \"已撤销该次修改。\";\n await load();\n emit(\"changed\");\n });\n}\nwatch(\n () => [props.scope, props.agentId, props.projectId],\n () => {\n doc.value = undefined;\n draft.value = \"\";\n history.value = [];\n void load();\n },\n { immediate: true },\n);\nwatch(\n () => !!doc.value && draft.value !== doc.value.content,\n (v) => emit(\"dirty-change\", v),\n);\nonBeforeUnmount(() => {\n generation++;\n});\n</script>\n<template>\n <section class=\"memory-files\" aria-label=\"Markdown 记忆文件\">\n <h3>记忆文件</h3>\n <p>MEMORY.md 自动加载;主题和日记按需读取。可以直接编辑 Markdown。</p>\n <p v-if=\"error\" role=\"alert\">{{ error }}</p>\n <p v-if=\"notice\" role=\"status\">{{ notice }}</p>\n <template v-if=\"!doc\"\n ><div class=\"file-list\">\n <button\n v-for=\"file in files\"\n :key=\"file.path\"\n :disabled=\"busy\"\n @click=\"open(file.path)\"\n >\n {{ file.path }} · {{ file.bytes }} B\n </button>\n </div>\n <form @submit.prevent=\"open(newPath)\">\n <label\n >新文件路径<input\n v-model=\"newPath\"\n placeholder=\"memory/主题.md\"\n :disabled=\"busy\" /></label\n ><button :disabled=\"busy || !agentId\">创建或打开</button>\n </form></template\n >\n <template v-else\n ><label\n >{{ doc.path\n }}<textarea\n v-model=\"draft\"\n :disabled=\"busy\"\n rows=\"16\"\n spellcheck=\"false\"\n aria-label=\"记忆 Markdown 内容\"\n />\n </label>\n <div class=\"actions\">\n <button :disabled=\"busy || draft === doc.content\" @click=\"save\">\n 保存</button\n ><button\n :disabled=\"busy\"\n @click=\"\n doc = undefined;\n history = [];\n \"\n >\n 取消编辑</button\n ><button :disabled=\"busy\" @click=\"revisions\">修改历史</button>\n </div>\n <details v-for=\"revision in history\" :key=\"revision.id\">\n <summary>{{ new Date(revision.at).toLocaleString() }}</summary>\n <p>修改前</p>\n <pre>{{ revision.before }}</pre>\n <p>修改后</p>\n <pre>{{ revision.after }}</pre>\n <button\n :disabled=\"\n busy || revision.afterHash !== doc.hash || draft !== doc.content\n \"\n @click=\"revert(revision)\"\n >\n 撤销此修改\n </button>\n </details></template\n >\n </section>\n</template>\n<style scoped>\n.memory-files {\n display: grid;\n gap: 12px;\n margin-block: 20px;\n}\n.memory-files h3,\n.memory-files p {\n margin: 0;\n line-height: 1.6;\n}\n.memory-files p {\n color: var(--text-secondary);\n}\n.memory-files label {\n display: grid;\n gap: 8px;\n}\n.memory-files input,\n.memory-files textarea,\n.memory-files button {\n font: inherit;\n padding: 10px;\n border: 1px solid var(--line);\n border-radius: 8px;\n color: var(--text-primary);\n background: var(--surface);\n min-height: 44px;\n box-sizing: border-box;\n max-width: 100%;\n}\n.memory-files textarea {\n width: 100%;\n resize: vertical;\n font-family: monospace;\n}\n.file-list,\n.actions,\n.memory-files form {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n.memory-files pre {\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n.memory-files [role=\"alert\"] {\n color: var(--color-error, #d44);\n}\n</style>\n","<script setup lang=\"ts\">\nimport { ref, watch, onBeforeUnmount } from \"vue\";\nimport { apiRequest } from \"@/api/client\";\nimport { createUuid } from \"@/utils/id\";\nconst props = defineProps<{\n agentId: string;\n scope: string;\n projectId?: string;\n}>();\nconst emit = defineEmits<{ \"dirty-change\": [dirty: boolean]; changed: [] }>();\nconst base = \"/api/app/workspace\";\ntype Doc = { path: string; content: string; hash: string };\ntype Revision = {\n id: string;\n path: string;\n before: string;\n after: string;\n afterHash: string;\n at: number;\n};\nconst files = ref<{ path: string; bytes: number }[]>([]),\n doc = ref<Doc>(),\n draft = ref(\"\"),\n newPath = ref(\"memory/notes.md\"),\n error = ref(\"\"),\n notice = ref(\"\"),\n busy = ref(false),\n history = ref<Revision[]>([]);\nlet generation = 0;\nconst scope = () => ({\n scope: props.scope,\n agentId: props.agentId,\n ...(props.scope === \"project\" ? { projectId: props.projectId } : {}),\n});\nconst query = (extra: Record<string, string> = {}) =>\n new URLSearchParams({ ...scope(), ...extra } as Record<string, string>);\nasync function action(fn: () => Promise<void>) {\n if (busy.value) return;\n busy.value = true;\n error.value = \"\";\n notice.value = \"\";\n try {\n await fn();\n } catch (e) {\n error.value = e instanceof Error ? e.message : \"操作失败\";\n } finally {\n busy.value = false;\n }\n}\nasync function load() {\n const epoch = ++generation;\n if (!props.agentId || (props.scope === \"project\" && !props.projectId)) {\n files.value = [];\n return;\n }\n try {\n const result = await apiRequest<{\n files: { path: string; bytes: number }[];\n }>(`${base}/memory-files?${query()}`);\n if (epoch === generation) files.value = result.files;\n } catch (e) {\n if (epoch === generation) error.value = String(e);\n }\n}\nasync function open(path: string) {\n await action(async () => {\n const epoch = generation;\n const result = await apiRequest<Doc>(\n `${base}/memory-file?${query({ path })}`,\n );\n if (epoch !== generation) return;\n doc.value = result;\n draft.value = result.content;\n history.value = [];\n });\n}\nasync function save() {\n if (!doc.value) return;\n await action(async () => {\n doc.value = await apiRequest<Doc>(base + \"/memory-file\", {\n method: \"PUT\",\n body: {\n ...scope(),\n requestId: createUuid(),\n path: doc.value!.path,\n content: draft.value,\n expectedHash: doc.value!.hash,\n },\n });\n draft.value = doc.value.content;\n notice.value = \"文件已保存,下一轮对话生效。\";\n emit(\"changed\");\n await load();\n });\n}\nasync function revisions() {\n await action(async () => {\n history.value = (\n await apiRequest<{ revisions: Revision[] }>(\n `${base}/memory-file-history?${query()}`,\n )\n ).revisions.filter((r) => r.path === doc.value?.path);\n });\n}\nasync function revert(r: Revision) {\n await action(async () => {\n doc.value = await apiRequest<Doc>(base + \"/memory-file-revert\", {\n method: \"POST\",\n body: {\n ...scope(),\n requestId: createUuid(),\n id: r.id,\n expectedHash: doc.value!.hash,\n },\n });\n draft.value = doc.value.content;\n notice.value = \"已撤销该次修改。\";\n await load();\n emit(\"changed\");\n });\n}\nwatch(\n () => [props.scope, props.agentId, props.projectId],\n () => {\n doc.value = undefined;\n draft.value = \"\";\n history.value = [];\n void load();\n },\n { immediate: true },\n);\nwatch(\n () => !!doc.value && draft.value !== doc.value.content,\n (v) => emit(\"dirty-change\", v),\n);\nonBeforeUnmount(() => {\n generation++;\n});\n</script>\n<template>\n <section class=\"memory-files\" aria-label=\"Markdown 记忆文件\">\n <h3>记忆文件</h3>\n <p>MEMORY.md 自动加载;主题和日记按需读取。可以直接编辑 Markdown。</p>\n <p v-if=\"error\" role=\"alert\">{{ error }}</p>\n <p v-if=\"notice\" role=\"status\">{{ notice }}</p>\n <template v-if=\"!doc\"\n ><div class=\"file-list\">\n <button\n v-for=\"file in files\"\n :key=\"file.path\"\n :disabled=\"busy\"\n @click=\"open(file.path)\"\n >\n {{ file.path }} · {{ file.bytes }} B\n </button>\n </div>\n <form @submit.prevent=\"open(newPath)\">\n <label\n >新文件路径<input\n v-model=\"newPath\"\n placeholder=\"memory/主题.md\"\n :disabled=\"busy\" /></label\n ><button :disabled=\"busy || !agentId\">创建或打开</button>\n </form></template\n >\n <template v-else\n ><label\n >{{ doc.path\n }}<textarea\n v-model=\"draft\"\n :disabled=\"busy\"\n rows=\"16\"\n spellcheck=\"false\"\n aria-label=\"记忆 Markdown 内容\"\n />\n </label>\n <div class=\"actions\">\n <button :disabled=\"busy || draft === doc.content\" @click=\"save\">\n 保存</button\n ><button\n :disabled=\"busy\"\n @click=\"\n doc = undefined;\n history = [];\n \"\n >\n 取消编辑</button\n ><button :disabled=\"busy\" @click=\"revisions\">修改历史</button>\n </div>\n <details v-for=\"revision in history\" :key=\"revision.id\">\n <summary>{{ new Date(revision.at).toLocaleString() }}</summary>\n <p>修改前</p>\n <pre>{{ revision.before }}</pre>\n <p>修改后</p>\n <pre>{{ revision.after }}</pre>\n <button\n :disabled=\"\n busy || revision.afterHash !== doc.hash || draft !== doc.content\n \"\n @click=\"revert(revision)\"\n >\n 撤销此修改\n </button>\n </details></template\n >\n </section>\n</template>\n<style scoped>\n.memory-files {\n display: grid;\n gap: 12px;\n margin-block: 20px;\n}\n.memory-files h3,\n.memory-files p {\n margin: 0;\n line-height: 1.6;\n}\n.memory-files p {\n color: var(--text-secondary);\n}\n.memory-files label {\n display: grid;\n gap: 8px;\n}\n.memory-files input,\n.memory-files textarea,\n.memory-files button {\n font: inherit;\n padding: 10px;\n border: 1px solid var(--line);\n border-radius: 8px;\n color: var(--text-primary);\n background: var(--surface);\n min-height: 44px;\n box-sizing: border-box;\n max-width: 100%;\n}\n.memory-files textarea {\n width: 100%;\n resize: vertical;\n font-family: monospace;\n}\n.file-list,\n.actions,\n.memory-files form {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n.memory-files pre {\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n.memory-files [role=\"alert\"] {\n color: var(--color-error, #d44);\n}\n</style>\n","/** Execution acknowledgement and a real return delivery are distinct facts. */\nexport function communicationStatus(value: { status?: string; hasReply?: boolean; replyTo?: string }): string {\n if (value.status === 'failed') return '投递或执行失败'\n if (value.status === 'stopped') return '协作已停止'\n if (value.hasReply) return '已收到回复'\n if (value.replyTo) return '回复已投递'\n return ({ queued: '已投递 · 排队中', running: '正在处理', waiting: '等待补充信息', complete: '执行已结束 · 暂无回复' } as Record<string, string>)[value.status ?? ''] ?? '协作消息'\n}\nexport function goalStatus(status: string): string {\n return ({ queued: '排队中', pending: '待执行', failed: '执行失败', interrupted: '已中断', running: '进行中', review: '待复核', waiting: '需要补充信息', blocked: '遇到阻碍', complete: '已完成', cancelling: '正在停止', cancelled: '已停止' } as Record<string, string>)[status] ?? '状态待确认'\n}\nexport const activityLabels = { bot_created: '创建了 Bot', helper_created: '创建了临时助手', team_created: '组建了团队', assignment_created: '派发了任务' } as const\n/** Host-authored caption for a real Bot-to-Bot delivery, in the Bot's voice (specs/022 contracts/bot-voice.md).\n * The peer's name sits between `before` and `after`. Outgoing rows are a caption only (plus attachments);\n * incoming rows keep the delivered body. */\nexport function peerCaption(value: { direction: 'outgoing' | 'incoming'; status?: string; hasReply?: boolean; replyTo?: string }): { before: string; after: string } {\n const reply = !!value.replyTo\n const word = value.status === 'failed' ? '没成功' : value.status === 'stopped' ? '已停止'\n : ({ queued: '排队中', running: '处理中', waiting: '在等补充信息' } as Record<string, string>)[value.status ?? '']\n ?? (value.status === 'complete' && !reply ? value.hasReply ? '已回复' : '处理完了,没有回复' : '')\n const state = word ? ` · ${word}` : ''\n if (value.direction === 'incoming') return { before: '', after: `${reply ? '回复了' : '发来消息'}${state}` }\n return reply ? { before: '已回复', after: state.slice(1) } : { before: '已请', after: `帮忙${state}` }\n}\nexport function communicationShowsBody(direction: 'outgoing' | 'incoming'): boolean {\n return direction === 'incoming'\n}\n","import { activityLabels, communicationStatus, goalStatus } from './collaborationPresentation.js'\n\nexport interface CollaborationPeer {\n id: string; fromAgentId: string; toAgentId?: string; targetGroupId?: string;\n fromName?: string; targetName?: string; content: string; status: string;\n hasReply?: boolean; replyTo?: string; error?: string; createdAt?: number;\n}\ninterface Assignment {\n id: string; agentId: string; title: string; brief?: string; status: string;\n result?: string | null; review?: string | null; createdAt?: number; updatedAt?: number;\n}\ninterface ActivityMessage {\n id: string; createdAt: number;\n activity?: { kind: keyof typeof activityLabels; actorName: string; targetName: string; description: string } | null;\n}\nexport interface CollaborationEvent {\n id: string; title: string; status: string; content: string; at: number;\n error?: string; peer?: CollaborationPeer;\n}\n/** Read projection only: assignment IDs own their events; retries never execute work. */\nexport function collaborationTimeline(input: {\n peers: CollaborationPeer[]; assignments: Assignment[]; activities?: ActivityMessage[];\n coordinatorId?: string; name: (id?: string) => string;\n}): CollaborationEvent[] {\n const events: CollaborationEvent[] = [];\n const leader = input.coordinatorId ? input.name(input.coordinatorId) : '负责人';\n for (const message of input.activities ?? []) {\n const a = message.activity;\n // Canonical assignments below cover dispatch, result and review without text matching.\n if (!a || (a.kind === 'assignment_created' && input.assignments.length)) continue;\n events.push({ id: `activity:${message.id}`, title: `${a.actorName} ${activityLabels[a.kind]} ${a.targetName}`, status: '已记录', content: a.description, at: message.createdAt });\n }\n for (const a of input.assignments) {\n const member = input.name(a.agentId);\n events.push({ id: `assignment:${a.id}:created`, title: `${leader} → ${member} · 派发任务`, status: goalStatus(a.status), content: [a.title, a.brief].filter(Boolean).join('\\n'), at: a.createdAt ?? 0 });\n if (a.result) events.push({ id: `assignment:${a.id}:result`, title: `${member} → ${leader} · 回传结果`, status: '已回传', content: `${a.title}\\n${a.result}`, at: a.updatedAt ?? a.createdAt ?? 0 });\n if (a.review) events.push({ id: `assignment:${a.id}:review`, title: `${leader} → ${member} · 复核意见`, status: goalStatus(a.status), content: a.review, at: a.updatedAt ?? a.createdAt ?? 0 });\n }\n for (const p of input.peers) events.push({\n id: `peer:${p.id}`, title: `${p.fromName || input.name(p.fromAgentId)} → ${p.targetName || (p.toAgentId ? input.name(p.toAgentId) : '群聊')}`,\n status: communicationStatus(p), content: p.content, at: p.createdAt ?? 0, error: p.error, peer: p,\n });\n return [...new Map(events.map(event => [event.id, event])).values()].sort((a, b) => a.at - b.at);\n}\n","<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport MemoryFilesPanel from './MemoryFilesPanel.vue'\nimport type { AgentAssignment, AgentGoal } from '@shared/agentTasks'\nimport { collaborationTimeline } from '@shared/collaborationTimeline'\nimport { apiRequest } from '@/api/client'\nimport { createUuid } from '@/utils/id'\nimport AppIcon from '@/components/common/AppIcon.vue'\nimport AgentAvatar from '@/components/common/AgentAvatar.vue'\nimport { ChevronForwardOutline } from '@vicons/ionicons5'\nimport type { WorkspaceAgent, WorkspaceConversation, WorkspaceMessage } from '@shared/workspace'\nimport type { MemoryScope, MemorySkipReason, WorkspaceMemory, WorkspaceMemoryJob, WorkspaceMemoryRevision, WorkspacePeerMessage, WorkspaceProject } from '@shared/workspaceKnowledge'\n\nconst props = defineProps<{ agents: WorkspaceAgent[]; conversations: WorkspaceConversation[]; conversationId?: string; taskId?: string; assignments?: AgentAssignment[]; goal?: AgentGoal; revision?: number; embedded?: boolean; initialTab?: 'projects' | 'user' | 'agent'; selectedAgentId?: string; hideAgentControls?: boolean }>()\nconst emit = defineEmits<{ changed: []; 'dirty-change': [dirty: boolean] }>()\nconst dialog = ref<HTMLDialogElement>(), opened = ref(false), busy = ref(false), error = ref(''), tab = ref('agent'), agentId = ref(''), projectId = ref(''), search = ref('')\nconst projects = ref<WorkspaceProject[]>([]), memories = ref<WorkspaceMemory[]>([]), peers = ref<WorkspacePeerMessage[]>([]), jobs = ref<WorkspaceMemoryJob[]>([]), revisions = ref<WorkspaceMemoryRevision[]>([])\nconst draft = ref<{ id?: string; expectedRevision?: number; agentId: string; content: string; tier: WorkspaceMemory['tier'] }>()\nconst projectDraft = ref<WorkspaceProject>()\nconst memoryTotal=ref(0), nextMemoryOffset=ref<number>(), loadedMore=ref(false)\nconst fileDirty=ref(false)\nconst activities = ref<WorkspaceMessage[]>([])\nlet generation = 0, timer: ReturnType<typeof setInterval> | undefined\nconst available = computed(() => props.agents.filter(a => !a.archived && !a.temporaryGoalId))\nconst currentAgent = computed(() => props.agents.find(a => a.id === agentId.value))\nconst currentProject = computed(() => projects.value.find(p => p.id === projectId.value))\nconst scope = computed(() => (['agent', 'user', 'project'].includes(tab.value) ? tab.value : 'agent') as MemoryScope)\nconst name = (id?: string) => props.agents.find(a => a.id === id)?.name ?? '原贡献者'\nconst collaboration = computed(() => collaborationTimeline({ peers: peers.value, activities: activities.value, assignments: props.assignments ?? [], coordinatorId: props.goal?.coordinatorId, name }))\nconst query = () => new URLSearchParams({ scope: scope.value, ...(tab.value === 'agent' && agentId.value ? { agentId: agentId.value } : {}), ...(tab.value === 'project' && projectId.value ? { projectId: projectId.value } : {}), ...(search.value ? { search: search.value } : {}) }).toString()\nconst stateNames: Record<string, string> = { queued: '已排队', pending: '待提炼', running: '处理中', waiting: '等待同伴', complete: '已完成', failed: '失败', stopped: '已停止', skipped: '已跳过' }\nconst skipReasonNames: Record<MemorySkipReason, string> = {\n source_missing: '找不到对应的来源消息', quote_mismatch: '引用与原文不一致', sensitive_content: '包含凭据等敏感内容',\n project_unbound: '项目记忆缺少关联项目', user_not_explicit: '缺少用户明确表达的长期信息', forgotten: '已遗忘的内容或来源不再保存', stale: '推理期间记忆已更新,本次旧提炼结果未应用',\n}\nfunction jobSummary(job: WorkspaceMemoryJob): string {\n if (job.status !== 'complete') return stateNames[job.status] ?? job.status\n const result = job.result\n if (!result) return '已结束(旧记录未统计保存结果)'\n if (!result.extractedCount) return '本轮没有可记录内容'\n if (result.writtenCount) return `已保存 ${result.writtenCount} 条记忆`\n if (result.replayedCount) return `重试已确认 ${result.replayedCount} 条记录`\n if (result.duplicateCount) return '未新增记忆,已有相同内容'\n return '候选记忆均未保存'\n}\nfunction skippedReasons(job: WorkspaceMemoryJob): string[] {\n return Object.entries(job.result?.skippedReasons ?? {}).filter(([, count]) => count > 0)\n .map(([reason, count]) => `${skipReasonNames[reason as MemorySkipReason] ?? '其他原因'}:${count} 条`)\n}\nasync function load(silent = false) {\n if (silent && loadedMore.value && tab.value !== 'collaboration') return\n const epoch = ++generation\n if (!silent) error.value = ''\n try {\n const projectResult = await apiRequest<{ projects: WorkspaceProject[] }>('/api/app/workspace/projects')\n if (epoch !== generation || !opened.value) return\n projects.value = projectResult.projects\n if (!projectId.value) projectId.value = projects.value.find(p => !p.archived)?.id ?? ''\n if (tab.value === 'collaboration') {\n const [result, milestones] = await Promise.all([\n apiRequest<{ messages: WorkspacePeerMessage[] }>(`/api/app/workspace/collaboration?${new URLSearchParams({ ...(props.conversationId ? { conversationId: props.conversationId } : {}), ...(props.taskId ? { taskId: props.taskId } : {}) })}`),\n props.conversationId ? apiRequest<{ messages: WorkspaceMessage[] }>(`/api/app/conversations/${encodeURIComponent(props.conversationId)}/activities${props.taskId ? `?taskId=${encodeURIComponent(props.taskId)}` : ''}`) : Promise.resolve({ messages: [] }),\n ])\n if (epoch === generation) { peers.value = result.messages; activities.value = milestones.messages }\n } else if (tab.value !== 'projects' && (tab.value !== 'project' || projectId.value)) {\n const result = await apiRequest<{ memories: WorkspaceMemory[]; total?: number; nextOffset?: number }>(`/api/app/workspace/memories?${query()}`)\n if (epoch === generation) { memories.value = result.memories; memoryTotal.value = result.total ?? result.memories.length; nextMemoryOffset.value = result.nextOffset; loadedMore.value = false }\n } else { memories.value = []; memoryTotal.value = 0; nextMemoryOffset.value = undefined; loadedMore.value = false }\n if (agentId.value) {\n const result = await apiRequest<{ jobs: WorkspaceMemoryJob[] }>(`/api/app/workspace/memory-jobs?agentId=${agentId.value}`)\n if (epoch === generation) jobs.value = result.jobs\n }\n } catch (cause) { if (epoch === generation) error.value = String(cause) }\n}\nasync function loadMoreMemories() {\n if (busy.value || nextMemoryOffset.value === undefined) return\n const epoch = generation, filter = query(), offset = nextMemoryOffset.value\n busy.value = true; error.value = ''\n try {\n const result = await apiRequest<{ memories: WorkspaceMemory[]; total: number; nextOffset?: number }>(`/api/app/workspace/memories?${filter}&offset=${offset}&limit=100`)\n if (epoch !== generation || !opened.value || filter !== query()) return\n const existing = new Set(memories.value.map(m => `${m.scope}:${m.agentId}:${m.id}`))\n memories.value.push(...result.memories.filter(m => !existing.has(`${m.scope}:${m.agentId}:${m.id}`)))\n memoryTotal.value = result.total; nextMemoryOffset.value = result.nextOffset; loadedMore.value = true\n } catch (cause) { if (epoch === generation) error.value = String(cause) } finally { busy.value = false }\n}\nasync function open(initial = 'agent', selectedAgent?: string, selectedProject?: string) {\n tab.value = initial; agentId.value = selectedAgent ?? available.value[0]?.id ?? ''; projectId.value = selectedProject ?? ''\n opened.value = true; draft.value = undefined; projectDraft.value = undefined; revisions.value = []; search.value = ''\n await nextTick(); if (!props.embedded) dialog.value?.showModal(); await load()\n clearInterval(timer); timer = setInterval(() => { if (!busy.value && !draft.value && !projectDraft.value) void load(true) }, 5000)\n}\nfunction close() { if(fileDirty.value){error.value='请先保存文件或取消编辑。';return} opened.value = false; generation++; clearInterval(timer); if (!props.embedded) dialog.value?.close() }\nfunction switchTab(value: string) { if(fileDirty.value)return; tab.value = value; draft.value = undefined; projectDraft.value = undefined; revisions.value = []; void load() }\nasync function perform(action: () => Promise<void>) {\n if (busy.value) return\n busy.value = true; error.value = ''\n try { await action(); emit('changed'); await load() } catch (cause) { error.value = String(cause) } finally { busy.value = false }\n}\nfunction newMemory(memory?: WorkspaceMemory) {\n revisions.value = []\n draft.value = memory ? { id: memory.id, expectedRevision: memory.revision, agentId: memory.agentId, content: memory.content, tier: memory.tier } : { agentId: agentId.value || available.value[0]?.id || '', content: '', tier: 'log' }\n}\nasync function saveMemory() {\n const value = draft.value\n if (!value?.content.trim()) { error.value = '请输入需要记住的事实'; return }\n await perform(async () => {\n await apiRequest('/api/app/workspace/memories', { method: 'POST', body: { requestId: createUuid(), scope: scope.value, ...(scope.value === 'project' ? { projectId: projectId.value } : {}), ...value } })\n draft.value = undefined\n })\n}\nasync function forget(memory: WorkspaceMemory) {\n await perform(async () => { await apiRequest('/api/app/workspace/memories/forget', { method: 'POST', body: { requestId: createUuid(), scope: memory.scope, agentId: memory.agentId, ...(memory.projectId ? { projectId: memory.projectId } : {}), id: memory.id, expectedRevision: memory.revision } }) })\n}\nasync function history(memory: WorkspaceMemory) {\n const query = new URLSearchParams({ scope: memory.scope, agentId: memory.agentId, ...(memory.projectId ? { projectId: memory.projectId } : {}) })\n await perform(async () => { revisions.value = (await apiRequest<{ revisions: WorkspaceMemoryRevision[] }>(`/api/app/workspace/memories/${memory.id}/revisions?${query}`)).revisions })\n}\nfunction editProject(project?: WorkspaceProject) {\n projectDraft.value = project ? { ...project, memberIds: [...project.memberIds], groupIds: [...project.groupIds] } : { id: '', name: '', description: '', memberIds: [], groupIds: [], revision: 0, archived: false, createdAt: 0, updatedAt: 0 }\n}\nasync function saveProject() {\n const value = projectDraft.value\n if (!value?.name.trim()) { error.value = '请输入项目名称'; return }\n await perform(async () => {\n const result = await apiRequest<{ project: WorkspaceProject }>('/api/app/workspace/projects', { method: 'POST', body: { requestId: createUuid(), ...(value.id ? { id: value.id, expectedRevision: value.revision } : {}), name: value.name, description: value.description, memberIds: value.memberIds, groupIds: value.groupIds, archived: value.archived } })\n projectId.value = result.project.id; projectDraft.value = undefined\n })\n}\nasync function setAgent(field: 'canCollaborate' | 'memoryEnabled', enabled: boolean) {\n await perform(async () => { await apiRequest(`/api/app/agents/${agentId.value}`, { method: 'PATCH', body: { [field]: enabled } }) })\n}\nonBeforeUnmount(() => { generation++; clearInterval(timer) })\nonMounted(() => { if (props.embedded) void open(props.initialTab ?? 'projects', props.selectedAgentId) })\nwatch(() => props.initialTab, value => { if (props.embedded && value) switchTab(value) })\nwatch(() => props.revision, () => { if (opened.value && !busy.value && !draft.value && !projectDraft.value) void load(true) })\nwatch(() => [props.conversationId, props.taskId], () => { generation++; peers.value = []; activities.value = []; if (opened.value && tab.value === 'collaboration') void load() })\nwatch(() => fileDirty.value || !!draft.value || !!projectDraft.value, value => emit('dirty-change', value))\ndefineExpose({ open, close })\n</script>\n\n<template>\n <component :is=\"embedded ? 'section' : 'dialog'\" ref=\"dialog\" class=\"knowledge-dialog\" :class=\"{ 'knowledge-dialog--embedded': embedded }\" :aria-labelledby=\"embedded ? undefined : 'knowledge-title'\" @cancel.prevent=\"close\" @close=\"opened = false\">\n <header v-if=\"!embedded\"><div><h2 id=\"knowledge-title\">Bot 记忆与协作</h2><p>管理长期事实、项目和同伴请求</p></div><button type=\"button\" @click=\"close\" aria-label=\"关闭记忆与协作\">关闭</button></header>\n <nav v-if=\"!embedded\" aria-label=\"记忆与项目分类\"><button v-for=\"item in [['agent','Bot 记忆'],['user','用户记忆'],['projects','项目'],['project','项目记忆'],['collaboration','协作']]\" :key=\"item[0]\" :aria-pressed=\"tab === item[0]\" @click=\"switchTab(item[0]!)\">{{ item[1] }}</button></nav>\n <div class=\"knowledge-body\" :aria-busy=\"busy\">\n <div v-if=\"embedded && tab === 'project'\" class=\"actions\"><button type=\"button\" @click=\"switchTab('projects')\">返回项目</button><h3>项目记忆</h3></div>\n <p v-if=\"error\" role=\"alert\" class=\"knowledge-error\">{{ error }}</p>\n <template v-if=\"tab === 'projects'\">\n <div v-if=\"embedded\" class=\"project-heading\"><div><h3>项目</h3><p>让同一项目的 Bot 共享决策与约定。</p></div><button v-if=\"!projectDraft\" type=\"button\" class=\"project-primary\" @click=\"editProject()\">新建项目</button></div>\n <button v-else-if=\"!projectDraft\" @click=\"editProject()\">新建项目</button>\n <form v-if=\"projectDraft\" class=\"knowledge-editor\" @submit.prevent=\"saveProject\">\n <h3>{{ projectDraft.id ? '编辑项目' : '新建项目' }}</h3>\n <label>名称<input v-model=\"projectDraft.name\" required maxlength=\"100\" /></label>\n <label>说明<textarea v-model=\"projectDraft.description\" rows=\"3\" maxlength=\"16000\" /></label>\n <fieldset><legend>项目成员</legend><label v-for=\"agent in available\" :key=\"agent.id\" class=\"check\"><input v-model=\"projectDraft.memberIds\" type=\"checkbox\" :value=\"agent.id\" />{{ agent.name }}</label></fieldset>\n <fieldset><legend>关联群聊</legend><p>群内所有 Bot 需要先加入此项目。</p><label v-for=\"group in conversations.filter(c => c.kind === 'group' && !c.archived)\" :key=\"group.id\" class=\"check\"><input v-model=\"projectDraft.groupIds\" type=\"checkbox\" :value=\"group.id\" :disabled=\"group.memberIds.some(id => !projectDraft!.memberIds.includes(id)) || !!group.projectId && group.projectId !== projectDraft.id\" />{{ group.name }}</label></fieldset>\n <label v-if=\"projectDraft.id\" class=\"check\"><input v-model=\"projectDraft.archived\" type=\"checkbox\" />归档项目</label>\n <div class=\"actions\"><button type=\"submit\" :disabled=\"busy\">保存项目</button><button type=\"button\" @click=\"projectDraft = undefined\">取消</button></div>\n </form>\n <template v-if=\"embedded && !projectDraft\">\n <div v-if=\"projects.length\" class=\"project-list\" aria-label=\"项目列表\"><button v-for=\"project in projects\" :key=\"project.id\" type=\"button\" :aria-pressed=\"projectId === project.id\" @click=\"projectId = project.id\"><AppIcon name=\"files\" :size=\"21\"/><span><strong>{{project.name}}{{project.archived ? ' · 已归档' : ''}}</strong><small>{{project.memberIds.length}} 位 Bot · {{project.groupIds.length}} 个群聊</small></span><ChevronForwardOutline class=\"project-chevron\" aria-hidden=\"true\"/></button></div>\n <section v-if=\"currentProject\" class=\"project-details\" aria-label=\"当前项目详情\">\n <h3>{{currentProject.name}}</h3><p v-if=\"currentProject.description\" class=\"project-description\">{{currentProject.description}}</p>\n <div class=\"project-detail-row\"><span>项目成员</span><div class=\"project-members\"><span v-for=\"id in currentProject.memberIds\" :key=\"id\"><AgentAvatar :name=\"name(id)\" :avatar=\"agents.find(a => a.id === id)?.avatar || ''\" :size=\"24\"/>{{name(id)}}</span><small v-if=\"!currentProject.memberIds.length\">尚无成员</small></div></div>\n <div class=\"project-detail-row\"><span>关联群聊</span><div>{{currentProject.groupIds.map(id => conversations.find(c => c.id === id)?.name ?? '原群聊').join('、') || '尚未关联群聊'}}</div></div>\n <div class=\"project-detail-row\"><span>项目记忆</span><div><button type=\"button\" @click=\"switchTab('project')\">查看记忆</button></div></div>\n <div class=\"project-detail-actions\"><button type=\"button\" class=\"project-primary\" @click=\"editProject(currentProject)\">编辑项目</button></div>\n </section>\n </template>\n <template v-else-if=\"!embedded\"><article v-for=\"project in projects\" :key=\"project.id\"><h3>{{ project.name }}{{ project.archived ? ' · 已归档' : '' }}</h3><p>{{ project.description || '暂无说明' }}</p><small>{{ project.memberIds.map(id => name(id)).join('、') || '尚无成员' }} · {{ project.groupIds.length }} 个群</small><div class=\"actions\"><button @click=\"editProject(project)\">编辑</button><button @click=\"projectId = project.id; switchTab('project')\">查看记忆</button></div></article></template>\n <p v-if=\"!projects.length && !projectDraft\" class=\"empty\">创建项目后,多个群可以共享该项目的决策和约定。</p>\n </template>\n <template v-else-if=\"tab === 'collaboration'\">\n <p class=\"scope-note\">{{ taskId ? '当前话题' : '当前聊天' }} · {{ collaboration.length }} 条协作记录</p>\n <article v-for=\"event in collaboration\" :key=\"event.id\"><details><summary>{{ event.title }} · {{ event.status }}</summary><p class=\"pre-wrap\">{{ event.content }}</p><small v-if=\"event.at\">{{ new Date(event.at).toLocaleString() }}</small><p v-if=\"event.error\" class=\"knowledge-error\">{{ event.error }}</p></details><button v-if=\"event.peer && ['queued','running','waiting'].includes(event.peer.status)\" :disabled=\"busy\" @click=\"perform(async () => { await apiRequest(`/api/app/workspace/collaboration/${encodeURIComponent(event.peer!.id)}/stop`, { method: 'POST' }) })\">停止此次协作</button></article>\n <p v-if=\"!collaboration.length\" class=\"empty\">暂无协作记录。你可以在聊天中让 Bot 联系同伴,或派发任务。</p>\n </template>\n <template v-else>\n <MemoryFilesPanel v-if=\"agentId && (scope !== 'project' || projectId)\" :agent-id=\"agentId\" :scope=\"scope\" :project-id=\"projectId\" @dirty-change=\"fileDirty=$event\" @changed=\"emit('changed');load()\" />\n <div class=\"filters\">\n <label v-if=\"['agent','user','project'].includes(tab) && !selectedAgentId\">记忆贡献 Bot<select :disabled=\"fileDirty\" v-model=\"agentId\" @change=\"draft = undefined; load()\"><option v-for=\"agent in available\" :key=\"agent.id\" :value=\"agent.id\">{{ agent.name }}</option></select></label>\n <label v-if=\"tab === 'project'\">项目<select :disabled=\"fileDirty\" v-model=\"projectId\" @change=\"draft = undefined; load()\"><option v-for=\"project in projects\" :key=\"project.id\" :value=\"project.id\">{{ project.name }}</option></select></label>\n <form @submit.prevent=\"load()\"><label>搜索记忆<input v-model=\"search\" type=\"search\" placeholder=\"搜索事实、偏好或决策\" /></label><button type=\"submit\">搜索</button></form>\n </div>\n <p class=\"scope-note\">{{ tab === 'agent' ? '仅此 Bot 使用,可跨单聊和群聊延续。' : tab === 'user' ? '同一账号的 Bot 共享,按贡献者保存。' : `仅「${currentProject?.name ?? '当前项目'}」成员读取。` }}</p>\n <template v-if=\"tab === 'agent' && currentAgent\"><label v-if=\"!hideAgentControls\" class=\"check\"><input type=\"checkbox\" :checked=\"currentAgent.memoryEnabled !== false\" :disabled=\"busy\" @change=\"setAgent('memoryEnabled', ($event.target as HTMLInputElement).checked)\" />自动记录长期事实</label><p v-if=\"currentAgent.memoryStatus === 'upgrade_required'\" role=\"status\">执行节点需要升级后才能启用隔离记忆;已保存的文件仍可管理。</p></template>\n <div v-if=\"tab !== 'project' || projectId\" class=\"actions\"><button @click=\"newMemory()\" :disabled=\"!available.length\">添加记忆</button><a :href=\"`/api/app/workspace/memory-export?${query()}`\" download=\"bot-memory.md\">导出 Markdown</a></div>\n <form v-if=\"draft\" class=\"knowledge-editor\" @submit.prevent=\"saveMemory\"><h3>{{ draft.id ? '编辑记忆' : '添加记忆' }}</h3><label v-if=\"!draft.id && tab !== 'agent'\">贡献 Bot<select v-model=\"draft.agentId\"><option v-for=\"agent in available.filter(a => tab !== 'project' || currentProject?.memberIds.includes(a.id))\" :key=\"agent.id\" :value=\"agent.id\">{{ agent.name }}</option></select></label><label>事实<textarea v-model=\"draft.content\" required rows=\"4\" maxlength=\"2000\" /></label><label>类别<select v-model=\"draft.tier\"><option value=\"profile\">长期事实</option><option value=\"log\">历史记录</option><option value=\"note\">补充笔记</option></select></label><div class=\"actions\"><button type=\"submit\" :disabled=\"busy\">保存</button><button type=\"button\" @click=\"draft = undefined\">取消</button></div></form>\n <article v-for=\"memory in memories\" :key=\"`${memory.scope}:${memory.agentId}:${memory.id}`\"><p class=\"pre-wrap\">{{ memory.content }}</p><p v-if=\"memory.conflict\" role=\"status\">同主题有不同贡献,请核对来源。</p><small>{{ name(memory.agentId) }} · {{ memory.origin === 'manual' ? '用户维护' : memory.origin === 'explicit' ? '明确保存' : '自动提炼' }} · {{ new Date(memory.updatedAt).toLocaleString() }} · 版本 {{ memory.revision }}</small><details v-if=\"memory.sources.length\"><summary>查看来源</summary><p v-for=\"source in memory.sources\" :key=\"source.messageId\"><a :href=\"`/conversations/${source.conversationId}${source.taskId ? `?taskId=${source.taskId}` : ''}`\">{{ source.quote || '查看原话题' }}</a><small v-if=\"source.at\"> · 来源 {{ new Date(source.at).toLocaleString() }}</small></p></details><div class=\"actions\"><button @click=\"newMemory(memory)\">编辑</button><button @click=\"history(memory)\" :disabled=\"busy\">修订记录</button><button @click=\"forget(memory)\" :disabled=\"busy\">遗忘</button></div></article>\n <div v-if=\"memories.length\" class=\"actions\"><small role=\"status\">已显示 {{ memories.length }} / {{ memoryTotal }} 条</small><button v-if=\"nextMemoryOffset !== undefined\" :disabled=\"busy\" @click=\"loadMoreMemories\">加载更多记忆</button><button v-if=\"loadedMore\" :disabled=\"busy\" @click=\"load()\">刷新结果</button></div>\n <p v-if=\"!memories.length && !draft\" class=\"empty\">暂无记忆。可手动添加,也可在对话中说明需要长期记住的事实。</p>\n <section v-if=\"revisions.length\" class=\"knowledge-editor\"><h3>修订记录</h3><article v-for=\"revision in revisions\" :key=\"revision.id\"><small>版本 {{ revision.revision }} · {{ revision.operation === 'forget' ? '遗忘' : '保存' }} · {{ new Date(revision.at).toLocaleString() }}</small><p>{{ revision.after?.content ?? revision.before?.content }}</p></article><button @click=\"revisions = []\">收起</button></section>\n <details v-if=\"tab === 'agent' && jobs.length\">\n <summary>后台提炼记录</summary>\n <article v-for=\"job in jobs\" :key=\"job.id\">\n <small>{{ new Date(job.createdAt).toLocaleString() }} · {{ jobSummary(job) }}</small>\n <p v-if=\"job.result\">本次提炼 {{ job.result.extractedCount }} 条 · 新增保存 {{ job.result.writtenCount }} 条 · 重复 {{ job.result.duplicateCount }} 条 · 重试确认 {{ job.result.replayedCount }} 条</p>\n <p v-for=\"reason in skippedReasons(job)\" :key=\"reason\">{{ reason }}</p>\n <p v-if=\"job.error\">{{ job.error }}</p>\n <button v-if=\"job.status === 'failed'\" :disabled=\"busy\" @click=\"perform(async () => { await apiRequest(`/api/app/workspace/memory-jobs/${job.id}/retry`, { method: 'POST' }) })\">重试</button>\n </article>\n </details>\n </template>\n </div>\n </component>\n</template>\n\n<style scoped>\n.knowledge-dialog{width:min(820px,calc(100vw - 24px));max-height:calc(100dvh - 32px);padding:0;border:1px solid var(--line);border-radius:18px;background:var(--surface);color:var(--text-primary)}\n.knowledge-dialog::backdrop{background:rgb(0 0 0 / .5)}header{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:20px 24px;border-bottom:1px solid var(--line)}h2,h3,p{margin:0}header p,.scope-note,.empty,small{color:var(--text-secondary)}header p{margin-top:5px;font-size:13px}nav{display:flex;flex-wrap:wrap;gap:4px;padding:10px 20px;border-bottom:1px solid var(--line)}button,a{min-height:44px;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--line);border-radius:9px;padding:8px 12px;background:var(--surface);color:var(--text-primary);font:inherit;font-size:14px;cursor:pointer;text-decoration:none}button:hover,a:hover{background:var(--surface-hover)}button[aria-pressed=true]{background:var(--surface-hover);border-color:var(--accent);color:var(--accent)}button:disabled{opacity:.5;cursor:default}button:focus-visible,a:focus-visible,input:focus-visible,textarea:focus-visible,select:focus-visible,summary:focus-visible{outline:2px solid var(--accent);outline-offset:2px}.knowledge-body{display:grid;gap:16px;padding:20px 24px;max-height:calc(100dvh - 210px);overflow:auto;overscroll-behavior:contain}label{display:grid;gap:6px;font-size:14px}input:not([type=checkbox]),textarea,select{min-height:44px;padding:9px 10px;border:1px solid var(--line);border-radius:8px;background:var(--surface);color:var(--text-primary);font:inherit;box-sizing:border-box;width:100%}textarea{resize:vertical}.filters{display:flex;flex-wrap:wrap;align-items:end;gap:12px}.filters>label{min-width:160px}.filters form{display:flex;align-items:end;gap:8px;flex:1}.filters form label{flex:1}.actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}article{padding:16px;border:1px solid var(--line);border-radius:12px;display:grid;gap:9px}.knowledge-editor{display:grid;gap:12px;padding:16px;border:1px solid var(--accent);border-radius:12px}fieldset{border:1px solid var(--line);border-radius:10px;padding:12px;display:grid;gap:8px;max-height:240px;overflow:auto}.check{display:flex;align-items:center;min-height:44px;gap:9px}.check input{width:18px;height:18px;accent-color:var(--accent)}small,.scope-note{font-size:13px;line-height:1.5}.pre-wrap{white-space:pre-wrap;overflow-wrap:anywhere;line-height:1.6}.knowledge-error{color:var(--danger,#c0392b);white-space:pre-wrap}.empty{padding:24px 8px;text-align:center;line-height:1.6}summary{cursor:pointer;min-height:36px;line-height:1.6}details p{margin-top:8px}\n@media(max-width:520px){header{padding:16px}h2{font-size:19px}nav{padding:8px}nav button{flex:1;white-space:nowrap}.knowledge-body{padding:16px;max-height:calc(100dvh - 250px)}.filters{display:grid}.filters form{min-width:0}}\n.knowledge-dialog--embedded{width:100%;max-height:none;border:0;border-radius:0;background:transparent;min-width:0}.knowledge-dialog--embedded .knowledge-body{padding:0;max-height:none;overflow:visible}.knowledge-dialog--embedded .actions{align-items:center}\n.project-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:20px;margin-bottom:8px}.project-heading h3{font-size:18px;font-weight:650}.project-heading p{font-size:13px;color:var(--text-secondary);margin-top:6px;line-height:1.6}.knowledge-dialog--embedded .project-primary{flex-shrink:0;padding:8px 16px;background:var(--accent);color:var(--text-on-solid);border-color:var(--accent);font-size:13px}.project-list{border:1px solid var(--line);border-radius:11px;overflow:hidden}.project-list button{display:flex;gap:20px;width:100%;padding:18px 22px;border:0;border-radius:0;text-align:left;justify-content:flex-start;min-height:76px}.project-list button+button{border-top:1px solid var(--line)}.project-list button[aria-pressed=true]{background:var(--settings-selected);color:var(--text-primary)}.project-list button>span{flex:1;min-width:0;display:grid;gap:4px}.project-list strong{font-size:15px;font-weight:600;overflow-wrap:anywhere}.project-list small{font-size:12px}.project-list .app-icon{color:var(--text-muted)}.project-details{background:var(--settings-panel);padding:20px;border-radius:12px}.project-details h3{font-size:17px;font-weight:650;margin-bottom:12px}.project-description{font-size:13px;color:var(--text-secondary);line-height:1.6;padding-bottom:12px;white-space:pre-wrap;overflow-wrap:anywhere}.project-detail-row{display:grid;grid-template-columns:104px minmax(0,1fr);align-items:center;gap:16px;min-height:48px;border-top:1px solid var(--line);font-size:14px}.project-detail-row>span{color:var(--text-secondary)}.project-detail-row>div{overflow-wrap:anywhere}.project-detail-row button{min-height:36px;background:var(--settings-selected);border:0;font-size:12px}.project-members{display:flex;gap:10px;flex-wrap:wrap;padding-block:10px}.project-members>span{display:inline-flex;align-items:center;gap:7px}.project-detail-actions{display:flex;justify-content:flex-end;margin-top:8px}.project-detail-actions .project-primary{min-height:36px}.knowledge-dialog--embedded article{border:0;background:var(--settings-panel)}@media(max-width:520px){.project-heading{gap:10px}.project-heading p{max-width:210px}.project-list button{padding:16px;gap:12px}.project-details{padding:16px}.project-detail-row{grid-template-columns:76px minmax(0,1fr);gap:10px}}\n</style>\n<style scoped>.project-chevron{width:17px;height:17px;flex-shrink:0;color:var(--text-muted)}</style>\n","<script setup lang=\"ts\">\nimport { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'\nimport MemoryFilesPanel from './MemoryFilesPanel.vue'\nimport type { AgentAssignment, AgentGoal } from '@shared/agentTasks'\nimport { collaborationTimeline } from '@shared/collaborationTimeline'\nimport { apiRequest } from '@/api/client'\nimport { createUuid } from '@/utils/id'\nimport AppIcon from '@/components/common/AppIcon.vue'\nimport AgentAvatar from '@/components/common/AgentAvatar.vue'\nimport { ChevronForwardOutline } from '@vicons/ionicons5'\nimport type { WorkspaceAgent, WorkspaceConversation, WorkspaceMessage } from '@shared/workspace'\nimport type { MemoryScope, MemorySkipReason, WorkspaceMemory, WorkspaceMemoryJob, WorkspaceMemoryRevision, WorkspacePeerMessage, WorkspaceProject } from '@shared/workspaceKnowledge'\n\nconst props = defineProps<{ agents: WorkspaceAgent[]; conversations: WorkspaceConversation[]; conversationId?: string; taskId?: string; assignments?: AgentAssignment[]; goal?: AgentGoal; revision?: number; embedded?: boolean; initialTab?: 'projects' | 'user' | 'agent'; selectedAgentId?: string; hideAgentControls?: boolean }>()\nconst emit = defineEmits<{ changed: []; 'dirty-change': [dirty: boolean] }>()\nconst dialog = ref<HTMLDialogElement>(), opened = ref(false), busy = ref(false), error = ref(''), tab = ref('agent'), agentId = ref(''), projectId = ref(''), search = ref('')\nconst projects = ref<WorkspaceProject[]>([]), memories = ref<WorkspaceMemory[]>([]), peers = ref<WorkspacePeerMessage[]>([]), jobs = ref<WorkspaceMemoryJob[]>([]), revisions = ref<WorkspaceMemoryRevision[]>([])\nconst draft = ref<{ id?: string; expectedRevision?: number; agentId: string; content: string; tier: WorkspaceMemory['tier'] }>()\nconst projectDraft = ref<WorkspaceProject>()\nconst memoryTotal=ref(0), nextMemoryOffset=ref<number>(), loadedMore=ref(false)\nconst fileDirty=ref(false)\nconst activities = ref<WorkspaceMessage[]>([])\nlet generation = 0, timer: ReturnType<typeof setInterval> | undefined\nconst available = computed(() => props.agents.filter(a => !a.archived && !a.temporaryGoalId))\nconst currentAgent = computed(() => props.agents.find(a => a.id === agentId.value))\nconst currentProject = computed(() => projects.value.find(p => p.id === projectId.value))\nconst scope = computed(() => (['agent', 'user', 'project'].includes(tab.value) ? tab.value : 'agent') as MemoryScope)\nconst name = (id?: string) => props.agents.find(a => a.id === id)?.name ?? '原贡献者'\nconst collaboration = computed(() => collaborationTimeline({ peers: peers.value, activities: activities.value, assignments: props.assignments ?? [], coordinatorId: props.goal?.coordinatorId, name }))\nconst query = () => new URLSearchParams({ scope: scope.value, ...(tab.value === 'agent' && agentId.value ? { agentId: agentId.value } : {}), ...(tab.value === 'project' && projectId.value ? { projectId: projectId.value } : {}), ...(search.value ? { search: search.value } : {}) }).toString()\nconst stateNames: Record<string, string> = { queued: '已排队', pending: '待提炼', running: '处理中', waiting: '等待同伴', complete: '已完成', failed: '失败', stopped: '已停止', skipped: '已跳过' }\nconst skipReasonNames: Record<MemorySkipReason, string> = {\n source_missing: '找不到对应的来源消息', quote_mismatch: '引用与原文不一致', sensitive_content: '包含凭据等敏感内容',\n project_unbound: '项目记忆缺少关联项目', user_not_explicit: '缺少用户明确表达的长期信息', forgotten: '已遗忘的内容或来源不再保存', stale: '推理期间记忆已更新,本次旧提炼结果未应用',\n}\nfunction jobSummary(job: WorkspaceMemoryJob): string {\n if (job.status !== 'complete') return stateNames[job.status] ?? job.status\n const result = job.result\n if (!result) return '已结束(旧记录未统计保存结果)'\n if (!result.extractedCount) return '本轮没有可记录内容'\n if (result.writtenCount) return `已保存 ${result.writtenCount} 条记忆`\n if (result.replayedCount) return `重试已确认 ${result.replayedCount} 条记录`\n if (result.duplicateCount) return '未新增记忆,已有相同内容'\n return '候选记忆均未保存'\n}\nfunction skippedReasons(job: WorkspaceMemoryJob): string[] {\n return Object.entries(job.result?.skippedReasons ?? {}).filter(([, count]) => count > 0)\n .map(([reason, count]) => `${skipReasonNames[reason as MemorySkipReason] ?? '其他原因'}:${count} 条`)\n}\nasync function load(silent = false) {\n if (silent && loadedMore.value && tab.value !== 'collaboration') return\n const epoch = ++generation\n if (!silent) error.value = ''\n try {\n const projectResult = await apiRequest<{ projects: WorkspaceProject[] }>('/api/app/workspace/projects')\n if (epoch !== generation || !opened.value) return\n projects.value = projectResult.projects\n if (!projectId.value) projectId.value = projects.value.find(p => !p.archived)?.id ?? ''\n if (tab.value === 'collaboration') {\n const [result, milestones] = await Promise.all([\n apiRequest<{ messages: WorkspacePeerMessage[] }>(`/api/app/workspace/collaboration?${new URLSearchParams({ ...(props.conversationId ? { conversationId: props.conversationId } : {}), ...(props.taskId ? { taskId: props.taskId } : {}) })}`),\n props.conversationId ? apiRequest<{ messages: WorkspaceMessage[] }>(`/api/app/conversations/${encodeURIComponent(props.conversationId)}/activities${props.taskId ? `?taskId=${encodeURIComponent(props.taskId)}` : ''}`) : Promise.resolve({ messages: [] }),\n ])\n if (epoch === generation) { peers.value = result.messages; activities.value = milestones.messages }\n } else if (tab.value !== 'projects' && (tab.value !== 'project' || projectId.value)) {\n const result = await apiRequest<{ memories: WorkspaceMemory[]; total?: number; nextOffset?: number }>(`/api/app/workspace/memories?${query()}`)\n if (epoch === generation) { memories.value = result.memories; memoryTotal.value = result.total ?? result.memories.length; nextMemoryOffset.value = result.nextOffset; loadedMore.value = false }\n } else { memories.value = []; memoryTotal.value = 0; nextMemoryOffset.value = undefined; loadedMore.value = false }\n if (agentId.value) {\n const result = await apiRequest<{ jobs: WorkspaceMemoryJob[] }>(`/api/app/workspace/memory-jobs?agentId=${agentId.value}`)\n if (epoch === generation) jobs.value = result.jobs\n }\n } catch (cause) { if (epoch === generation) error.value = String(cause) }\n}\nasync function loadMoreMemories() {\n if (busy.value || nextMemoryOffset.value === undefined) return\n const epoch = generation, filter = query(), offset = nextMemoryOffset.value\n busy.value = true; error.value = ''\n try {\n const result = await apiRequest<{ memories: WorkspaceMemory[]; total: number; nextOffset?: number }>(`/api/app/workspace/memories?${filter}&offset=${offset}&limit=100`)\n if (epoch !== generation || !opened.value || filter !== query()) return\n const existing = new Set(memories.value.map(m => `${m.scope}:${m.agentId}:${m.id}`))\n memories.value.push(...result.memories.filter(m => !existing.has(`${m.scope}:${m.agentId}:${m.id}`)))\n memoryTotal.value = result.total; nextMemoryOffset.value = result.nextOffset; loadedMore.value = true\n } catch (cause) { if (epoch === generation) error.value = String(cause) } finally { busy.value = false }\n}\nasync function open(initial = 'agent', selectedAgent?: string, selectedProject?: string) {\n tab.value = initial; agentId.value = selectedAgent ?? available.value[0]?.id ?? ''; projectId.value = selectedProject ?? ''\n opened.value = true; draft.value = undefined; projectDraft.value = undefined; revisions.value = []; search.value = ''\n await nextTick(); if (!props.embedded) dialog.value?.showModal(); await load()\n clearInterval(timer); timer = setInterval(() => { if (!busy.value && !draft.value && !projectDraft.value) void load(true) }, 5000)\n}\nfunction close() { if(fileDirty.value){error.value='请先保存文件或取消编辑。';return} opened.value = false; generation++; clearInterval(timer); if (!props.embedded) dialog.value?.close() }\nfunction switchTab(value: string) { if(fileDirty.value)return; tab.value = value; draft.value = undefined; projectDraft.value = undefined; revisions.value = []; void load() }\nasync function perform(action: () => Promise<void>) {\n if (busy.value) return\n busy.value = true; error.value = ''\n try { await action(); emit('changed'); await load() } catch (cause) { error.value = String(cause) } finally { busy.value = false }\n}\nfunction newMemory(memory?: WorkspaceMemory) {\n revisions.value = []\n draft.value = memory ? { id: memory.id, expectedRevision: memory.revision, agentId: memory.agentId, content: memory.content, tier: memory.tier } : { agentId: agentId.value || available.value[0]?.id || '', content: '', tier: 'log' }\n}\nasync function saveMemory() {\n const value = draft.value\n if (!value?.content.trim()) { error.value = '请输入需要记住的事实'; return }\n await perform(async () => {\n await apiRequest('/api/app/workspace/memories', { method: 'POST', body: { requestId: createUuid(), scope: scope.value, ...(scope.value === 'project' ? { projectId: projectId.value } : {}), ...value } })\n draft.value = undefined\n })\n}\nasync function forget(memory: WorkspaceMemory) {\n await perform(async () => { await apiRequest('/api/app/workspace/memories/forget', { method: 'POST', body: { requestId: createUuid(), scope: memory.scope, agentId: memory.agentId, ...(memory.projectId ? { projectId: memory.projectId } : {}), id: memory.id, expectedRevision: memory.revision } }) })\n}\nasync function history(memory: WorkspaceMemory) {\n const query = new URLSearchParams({ scope: memory.scope, agentId: memory.agentId, ...(memory.projectId ? { projectId: memory.projectId } : {}) })\n await perform(async () => { revisions.value = (await apiRequest<{ revisions: WorkspaceMemoryRevision[] }>(`/api/app/workspace/memories/${memory.id}/revisions?${query}`)).revisions })\n}\nfunction editProject(project?: WorkspaceProject) {\n projectDraft.value = project ? { ...project, memberIds: [...project.memberIds], groupIds: [...project.groupIds] } : { id: '', name: '', description: '', memberIds: [], groupIds: [], revision: 0, archived: false, createdAt: 0, updatedAt: 0 }\n}\nasync function saveProject() {\n const value = projectDraft.value\n if (!value?.name.trim()) { error.value = '请输入项目名称'; return }\n await perform(async () => {\n const result = await apiRequest<{ project: WorkspaceProject }>('/api/app/workspace/projects', { method: 'POST', body: { requestId: createUuid(), ...(value.id ? { id: value.id, expectedRevision: value.revision } : {}), name: value.name, description: value.description, memberIds: value.memberIds, groupIds: value.groupIds, archived: value.archived } })\n projectId.value = result.project.id; projectDraft.value = undefined\n })\n}\nasync function setAgent(field: 'canCollaborate' | 'memoryEnabled', enabled: boolean) {\n await perform(async () => { await apiRequest(`/api/app/agents/${agentId.value}`, { method: 'PATCH', body: { [field]: enabled } }) })\n}\nonBeforeUnmount(() => { generation++; clearInterval(timer) })\nonMounted(() => { if (props.embedded) void open(props.initialTab ?? 'projects', props.selectedAgentId) })\nwatch(() => props.initialTab, value => { if (props.embedded && value) switchTab(value) })\nwatch(() => props.revision, () => { if (opened.value && !busy.value && !draft.value && !projectDraft.value) void load(true) })\nwatch(() => [props.conversationId, props.taskId], () => { generation++; peers.value = []; activities.value = []; if (opened.value && tab.value === 'collaboration') void load() })\nwatch(() => fileDirty.value || !!draft.value || !!projectDraft.value, value => emit('dirty-change', value))\ndefineExpose({ open, close })\n</script>\n\n<template>\n <component :is=\"embedded ? 'section' : 'dialog'\" ref=\"dialog\" class=\"knowledge-dialog\" :class=\"{ 'knowledge-dialog--embedded': embedded }\" :aria-labelledby=\"embedded ? undefined : 'knowledge-title'\" @cancel.prevent=\"close\" @close=\"opened = false\">\n <header v-if=\"!embedded\"><div><h2 id=\"knowledge-title\">Bot 记忆与协作</h2><p>管理长期事实、项目和同伴请求</p></div><button type=\"button\" @click=\"close\" aria-label=\"关闭记忆与协作\">关闭</button></header>\n <nav v-if=\"!embedded\" aria-label=\"记忆与项目分类\"><button v-for=\"item in [['agent','Bot 记忆'],['user','用户记忆'],['projects','项目'],['project','项目记忆'],['collaboration','协作']]\" :key=\"item[0]\" :aria-pressed=\"tab === item[0]\" @click=\"switchTab(item[0]!)\">{{ item[1] }}</button></nav>\n <div class=\"knowledge-body\" :aria-busy=\"busy\">\n <div v-if=\"embedded && tab === 'project'\" class=\"actions\"><button type=\"button\" @click=\"switchTab('projects')\">返回项目</button><h3>项目记忆</h3></div>\n <p v-if=\"error\" role=\"alert\" class=\"knowledge-error\">{{ error }}</p>\n <template v-if=\"tab === 'projects'\">\n <div v-if=\"embedded\" class=\"project-heading\"><div><h3>项目</h3><p>让同一项目的 Bot 共享决策与约定。</p></div><button v-if=\"!projectDraft\" type=\"button\" class=\"project-primary\" @click=\"editProject()\">新建项目</button></div>\n <button v-else-if=\"!projectDraft\" @click=\"editProject()\">新建项目</button>\n <form v-if=\"projectDraft\" class=\"knowledge-editor\" @submit.prevent=\"saveProject\">\n <h3>{{ projectDraft.id ? '编辑项目' : '新建项目' }}</h3>\n <label>名称<input v-model=\"projectDraft.name\" required maxlength=\"100\" /></label>\n <label>说明<textarea v-model=\"projectDraft.description\" rows=\"3\" maxlength=\"16000\" /></label>\n <fieldset><legend>项目成员</legend><label v-for=\"agent in available\" :key=\"agent.id\" class=\"check\"><input v-model=\"projectDraft.memberIds\" type=\"checkbox\" :value=\"agent.id\" />{{ agent.name }}</label></fieldset>\n <fieldset><legend>关联群聊</legend><p>群内所有 Bot 需要先加入此项目。</p><label v-for=\"group in conversations.filter(c => c.kind === 'group' && !c.archived)\" :key=\"group.id\" class=\"check\"><input v-model=\"projectDraft.groupIds\" type=\"checkbox\" :value=\"group.id\" :disabled=\"group.memberIds.some(id => !projectDraft!.memberIds.includes(id)) || !!group.projectId && group.projectId !== projectDraft.id\" />{{ group.name }}</label></fieldset>\n <label v-if=\"projectDraft.id\" class=\"check\"><input v-model=\"projectDraft.archived\" type=\"checkbox\" />归档项目</label>\n <div class=\"actions\"><button type=\"submit\" :disabled=\"busy\">保存项目</button><button type=\"button\" @click=\"projectDraft = undefined\">取消</button></div>\n </form>\n <template v-if=\"embedded && !projectDraft\">\n <div v-if=\"projects.length\" class=\"project-list\" aria-label=\"项目列表\"><button v-for=\"project in projects\" :key=\"project.id\" type=\"button\" :aria-pressed=\"projectId === project.id\" @click=\"projectId = project.id\"><AppIcon name=\"files\" :size=\"21\"/><span><strong>{{project.name}}{{project.archived ? ' · 已归档' : ''}}</strong><small>{{project.memberIds.length}} 位 Bot · {{project.groupIds.length}} 个群聊</small></span><ChevronForwardOutline class=\"project-chevron\" aria-hidden=\"true\"/></button></div>\n <section v-if=\"currentProject\" class=\"project-details\" aria-label=\"当前项目详情\">\n <h3>{{currentProject.name}}</h3><p v-if=\"currentProject.description\" class=\"project-description\">{{currentProject.description}}</p>\n <div class=\"project-detail-row\"><span>项目成员</span><div class=\"project-members\"><span v-for=\"id in currentProject.memberIds\" :key=\"id\"><AgentAvatar :name=\"name(id)\" :avatar=\"agents.find(a => a.id === id)?.avatar || ''\" :size=\"24\"/>{{name(id)}}</span><small v-if=\"!currentProject.memberIds.length\">尚无成员</small></div></div>\n <div class=\"project-detail-row\"><span>关联群聊</span><div>{{currentProject.groupIds.map(id => conversations.find(c => c.id === id)?.name ?? '原群聊').join('、') || '尚未关联群聊'}}</div></div>\n <div class=\"project-detail-row\"><span>项目记忆</span><div><button type=\"button\" @click=\"switchTab('project')\">查看记忆</button></div></div>\n <div class=\"project-detail-actions\"><button type=\"button\" class=\"project-primary\" @click=\"editProject(currentProject)\">编辑项目</button></div>\n </section>\n </template>\n <template v-else-if=\"!embedded\"><article v-for=\"project in projects\" :key=\"project.id\"><h3>{{ project.name }}{{ project.archived ? ' · 已归档' : '' }}</h3><p>{{ project.description || '暂无说明' }}</p><small>{{ project.memberIds.map(id => name(id)).join('、') || '尚无成员' }} · {{ project.groupIds.length }} 个群</small><div class=\"actions\"><button @click=\"editProject(project)\">编辑</button><button @click=\"projectId = project.id; switchTab('project')\">查看记忆</button></div></article></template>\n <p v-if=\"!projects.length && !projectDraft\" class=\"empty\">创建项目后,多个群可以共享该项目的决策和约定。</p>\n </template>\n <template v-else-if=\"tab === 'collaboration'\">\n <p class=\"scope-note\">{{ taskId ? '当前话题' : '当前聊天' }} · {{ collaboration.length }} 条协作记录</p>\n <article v-for=\"event in collaboration\" :key=\"event.id\"><details><summary>{{ event.title }} · {{ event.status }}</summary><p class=\"pre-wrap\">{{ event.content }}</p><small v-if=\"event.at\">{{ new Date(event.at).toLocaleString() }}</small><p v-if=\"event.error\" class=\"knowledge-error\">{{ event.error }}</p></details><button v-if=\"event.peer && ['queued','running','waiting'].includes(event.peer.status)\" :disabled=\"busy\" @click=\"perform(async () => { await apiRequest(`/api/app/workspace/collaboration/${encodeURIComponent(event.peer!.id)}/stop`, { method: 'POST' }) })\">停止此次协作</button></article>\n <p v-if=\"!collaboration.length\" class=\"empty\">暂无协作记录。你可以在聊天中让 Bot 联系同伴,或派发任务。</p>\n </template>\n <template v-else>\n <MemoryFilesPanel v-if=\"agentId && (scope !== 'project' || projectId)\" :agent-id=\"agentId\" :scope=\"scope\" :project-id=\"projectId\" @dirty-change=\"fileDirty=$event\" @changed=\"emit('changed');load()\" />\n <div class=\"filters\">\n <label v-if=\"['agent','user','project'].includes(tab) && !selectedAgentId\">记忆贡献 Bot<select :disabled=\"fileDirty\" v-model=\"agentId\" @change=\"draft = undefined; load()\"><option v-for=\"agent in available\" :key=\"agent.id\" :value=\"agent.id\">{{ agent.name }}</option></select></label>\n <label v-if=\"tab === 'project'\">项目<select :disabled=\"fileDirty\" v-model=\"projectId\" @change=\"draft = undefined; load()\"><option v-for=\"project in projects\" :key=\"project.id\" :value=\"project.id\">{{ project.name }}</option></select></label>\n <form @submit.prevent=\"load()\"><label>搜索记忆<input v-model=\"search\" type=\"search\" placeholder=\"搜索事实、偏好或决策\" /></label><button type=\"submit\">搜索</button></form>\n </div>\n <p class=\"scope-note\">{{ tab === 'agent' ? '仅此 Bot 使用,可跨单聊和群聊延续。' : tab === 'user' ? '同一账号的 Bot 共享,按贡献者保存。' : `仅「${currentProject?.name ?? '当前项目'}」成员读取。` }}</p>\n <template v-if=\"tab === 'agent' && currentAgent\"><label v-if=\"!hideAgentControls\" class=\"check\"><input type=\"checkbox\" :checked=\"currentAgent.memoryEnabled !== false\" :disabled=\"busy\" @change=\"setAgent('memoryEnabled', ($event.target as HTMLInputElement).checked)\" />自动记录长期事实</label><p v-if=\"currentAgent.memoryStatus === 'upgrade_required'\" role=\"status\">执行节点需要升级后才能启用隔离记忆;已保存的文件仍可管理。</p></template>\n <div v-if=\"tab !== 'project' || projectId\" class=\"actions\"><button @click=\"newMemory()\" :disabled=\"!available.length\">添加记忆</button><a :href=\"`/api/app/workspace/memory-export?${query()}`\" download=\"bot-memory.md\">导出 Markdown</a></div>\n <form v-if=\"draft\" class=\"knowledge-editor\" @submit.prevent=\"saveMemory\"><h3>{{ draft.id ? '编辑记忆' : '添加记忆' }}</h3><label v-if=\"!draft.id && tab !== 'agent'\">贡献 Bot<select v-model=\"draft.agentId\"><option v-for=\"agent in available.filter(a => tab !== 'project' || currentProject?.memberIds.includes(a.id))\" :key=\"agent.id\" :value=\"agent.id\">{{ agent.name }}</option></select></label><label>事实<textarea v-model=\"draft.content\" required rows=\"4\" maxlength=\"2000\" /></label><label>类别<select v-model=\"draft.tier\"><option value=\"profile\">长期事实</option><option value=\"log\">历史记录</option><option value=\"note\">补充笔记</option></select></label><div class=\"actions\"><button type=\"submit\" :disabled=\"busy\">保存</button><button type=\"button\" @click=\"draft = undefined\">取消</button></div></form>\n <article v-for=\"memory in memories\" :key=\"`${memory.scope}:${memory.agentId}:${memory.id}`\"><p class=\"pre-wrap\">{{ memory.content }}</p><p v-if=\"memory.conflict\" role=\"status\">同主题有不同贡献,请核对来源。</p><small>{{ name(memory.agentId) }} · {{ memory.origin === 'manual' ? '用户维护' : memory.origin === 'explicit' ? '明确保存' : '自动提炼' }} · {{ new Date(memory.updatedAt).toLocaleString() }} · 版本 {{ memory.revision }}</small><details v-if=\"memory.sources.length\"><summary>查看来源</summary><p v-for=\"source in memory.sources\" :key=\"source.messageId\"><a :href=\"`/conversations/${source.conversationId}${source.taskId ? `?taskId=${source.taskId}` : ''}`\">{{ source.quote || '查看原话题' }}</a><small v-if=\"source.at\"> · 来源 {{ new Date(source.at).toLocaleString() }}</small></p></details><div class=\"actions\"><button @click=\"newMemory(memory)\">编辑</button><button @click=\"history(memory)\" :disabled=\"busy\">修订记录</button><button @click=\"forget(memory)\" :disabled=\"busy\">遗忘</button></div></article>\n <div v-if=\"memories.length\" class=\"actions\"><small role=\"status\">已显示 {{ memories.length }} / {{ memoryTotal }} 条</small><button v-if=\"nextMemoryOffset !== undefined\" :disabled=\"busy\" @click=\"loadMoreMemories\">加载更多记忆</button><button v-if=\"loadedMore\" :disabled=\"busy\" @click=\"load()\">刷新结果</button></div>\n <p v-if=\"!memories.length && !draft\" class=\"empty\">暂无记忆。可手动添加,也可在对话中说明需要长期记住的事实。</p>\n <section v-if=\"revisions.length\" class=\"knowledge-editor\"><h3>修订记录</h3><article v-for=\"revision in revisions\" :key=\"revision.id\"><small>版本 {{ revision.revision }} · {{ revision.operation === 'forget' ? '遗忘' : '保存' }} · {{ new Date(revision.at).toLocaleString() }}</small><p>{{ revision.after?.content ?? revision.before?.content }}</p></article><button @click=\"revisions = []\">收起</button></section>\n <details v-if=\"tab === 'agent' && jobs.length\">\n <summary>后台提炼记录</summary>\n <article v-for=\"job in jobs\" :key=\"job.id\">\n <small>{{ new Date(job.createdAt).toLocaleString() }} · {{ jobSummary(job) }}</small>\n <p v-if=\"job.result\">本次提炼 {{ job.result.extractedCount }} 条 · 新增保存 {{ job.result.writtenCount }} 条 · 重复 {{ job.result.duplicateCount }} 条 · 重试确认 {{ job.result.replayedCount }} 条</p>\n <p v-for=\"reason in skippedReasons(job)\" :key=\"reason\">{{ reason }}</p>\n <p v-if=\"job.error\">{{ job.error }}</p>\n <button v-if=\"job.status === 'failed'\" :disabled=\"busy\" @click=\"perform(async () => { await apiRequest(`/api/app/workspace/memory-jobs/${job.id}/retry`, { method: 'POST' }) })\">重试</button>\n </article>\n </details>\n </template>\n </div>\n </component>\n</template>\n\n<style scoped>\n.knowledge-dialog{width:min(820px,calc(100vw - 24px));max-height:calc(100dvh - 32px);padding:0;border:1px solid var(--line);border-radius:18px;background:var(--surface);color:var(--text-primary)}\n.knowledge-dialog::backdrop{background:rgb(0 0 0 / .5)}header{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:20px 24px;border-bottom:1px solid var(--line)}h2,h3,p{margin:0}header p,.scope-note,.empty,small{color:var(--text-secondary)}header p{margin-top:5px;font-size:13px}nav{display:flex;flex-wrap:wrap;gap:4px;padding:10px 20px;border-bottom:1px solid var(--line)}button,a{min-height:44px;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--line);border-radius:9px;padding:8px 12px;background:var(--surface);color:var(--text-primary);font:inherit;font-size:14px;cursor:pointer;text-decoration:none}button:hover,a:hover{background:var(--surface-hover)}button[aria-pressed=true]{background:var(--surface-hover);border-color:var(--accent);color:var(--accent)}button:disabled{opacity:.5;cursor:default}button:focus-visible,a:focus-visible,input:focus-visible,textarea:focus-visible,select:focus-visible,summary:focus-visible{outline:2px solid var(--accent);outline-offset:2px}.knowledge-body{display:grid;gap:16px;padding:20px 24px;max-height:calc(100dvh - 210px);overflow:auto;overscroll-behavior:contain}label{display:grid;gap:6px;font-size:14px}input:not([type=checkbox]),textarea,select{min-height:44px;padding:9px 10px;border:1px solid var(--line);border-radius:8px;background:var(--surface);color:var(--text-primary);font:inherit;box-sizing:border-box;width:100%}textarea{resize:vertical}.filters{display:flex;flex-wrap:wrap;align-items:end;gap:12px}.filters>label{min-width:160px}.filters form{display:flex;align-items:end;gap:8px;flex:1}.filters form label{flex:1}.actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}article{padding:16px;border:1px solid var(--line);border-radius:12px;display:grid;gap:9px}.knowledge-editor{display:grid;gap:12px;padding:16px;border:1px solid var(--accent);border-radius:12px}fieldset{border:1px solid var(--line);border-radius:10px;padding:12px;display:grid;gap:8px;max-height:240px;overflow:auto}.check{display:flex;align-items:center;min-height:44px;gap:9px}.check input{width:18px;height:18px;accent-color:var(--accent)}small,.scope-note{font-size:13px;line-height:1.5}.pre-wrap{white-space:pre-wrap;overflow-wrap:anywhere;line-height:1.6}.knowledge-error{color:var(--danger,#c0392b);white-space:pre-wrap}.empty{padding:24px 8px;text-align:center;line-height:1.6}summary{cursor:pointer;min-height:36px;line-height:1.6}details p{margin-top:8px}\n@media(max-width:520px){header{padding:16px}h2{font-size:19px}nav{padding:8px}nav button{flex:1;white-space:nowrap}.knowledge-body{padding:16px;max-height:calc(100dvh - 250px)}.filters{display:grid}.filters form{min-width:0}}\n.knowledge-dialog--embedded{width:100%;max-height:none;border:0;border-radius:0;background:transparent;min-width:0}.knowledge-dialog--embedded .knowledge-body{padding:0;max-height:none;overflow:visible}.knowledge-dialog--embedded .actions{align-items:center}\n.project-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:20px;margin-bottom:8px}.project-heading h3{font-size:18px;font-weight:650}.project-heading p{font-size:13px;color:var(--text-secondary);margin-top:6px;line-height:1.6}.knowledge-dialog--embedded .project-primary{flex-shrink:0;padding:8px 16px;background:var(--accent);color:var(--text-on-solid);border-color:var(--accent);font-size:13px}.project-list{border:1px solid var(--line);border-radius:11px;overflow:hidden}.project-list button{display:flex;gap:20px;width:100%;padding:18px 22px;border:0;border-radius:0;text-align:left;justify-content:flex-start;min-height:76px}.project-list button+button{border-top:1px solid var(--line)}.project-list button[aria-pressed=true]{background:var(--settings-selected);color:var(--text-primary)}.project-list button>span{flex:1;min-width:0;display:grid;gap:4px}.project-list strong{font-size:15px;font-weight:600;overflow-wrap:anywhere}.project-list small{font-size:12px}.project-list .app-icon{color:var(--text-muted)}.project-details{background:var(--settings-panel);padding:20px;border-radius:12px}.project-details h3{font-size:17px;font-weight:650;margin-bottom:12px}.project-description{font-size:13px;color:var(--text-secondary);line-height:1.6;padding-bottom:12px;white-space:pre-wrap;overflow-wrap:anywhere}.project-detail-row{display:grid;grid-template-columns:104px minmax(0,1fr);align-items:center;gap:16px;min-height:48px;border-top:1px solid var(--line);font-size:14px}.project-detail-row>span{color:var(--text-secondary)}.project-detail-row>div{overflow-wrap:anywhere}.project-detail-row button{min-height:36px;background:var(--settings-selected);border:0;font-size:12px}.project-members{display:flex;gap:10px;flex-wrap:wrap;padding-block:10px}.project-members>span{display:inline-flex;align-items:center;gap:7px}.project-detail-actions{display:flex;justify-content:flex-end;margin-top:8px}.project-detail-actions .project-primary{min-height:36px}.knowledge-dialog--embedded article{border:0;background:var(--settings-panel)}@media(max-width:520px){.project-heading{gap:10px}.project-heading p{max-width:210px}.project-list button{padding:16px;gap:12px}.project-details{padding:16px}.project-detail-row{grid-template-columns:76px minmax(0,1fr);gap:10px}}\n</style>\n<style scoped>.project-chevron{width:17px;height:17px;flex-shrink:0;color:var(--text-muted)}</style>\n"],"x_google_ignoreList":[0],"mappings":"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"}
|