@shikeai/knowledge 0.8.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.es.js +13071 -12144
- package/lib/client.js +1755 -431
- package/lib/client.js.map +1 -1
- package/lib/index.js +4 -1
- package/package.json +1 -4
package/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["hostCtx","useSyncExternalStore","createPortal","useState","useState","createPortal","createElement","useState","useCallback","useRef","subscribeServerConfig","useMemo","useRef","useState","useCallback","useState","useMemo","useRef","useState","useState","useMemo","useState","PAGE_SIZE","useState","useMemo","useState","useCallback","useState","useCallback","Fragment","useMemo","useState","useRef","useState","useRef","useCallback","useState","useState","useState","useCallback","useState","useCallback","styles","Component","BTN_LABEL","useRef","useState","useMemo","useState"],"sources":["../src/core/host-mcp-sync.js","../src/core/dsh-agent.js","../src/core/server-config.js","../src/core/config.js","../src/core/session.js","../src/store/create-store.js","../src/store/ui-store.js","../src/store/kb-store.js","../src/store/doc-store.js","../src/store/title-store.js","../src/store/reset.js","../src/core/auth.js","../src/core/request.js","../src/api/kb.js","../src/api/doc.js","../src/core/kb-trigger.js","../src/api/task.js","../src/api/auth.js","../src/utils/file-type.js","../src/components/kb/KbCard.jsx","../src/components/common/Modal.jsx","../src/utils/validator.js","../src/components/kb/TagPicker.jsx","../src/components/kb/KbFormModal.jsx","../src/components/common/ConfirmDialog.jsx","../src/components/common/Toast.jsx","../src/components/common/icons.jsx","../src/api/user.js","../src/pages/home/HomePage.jsx","../src/store/folder-store.js","../src/api/folder.js","../src/hooks/use-kb-permission.js","../src/hooks/use-task-polling.js","../src/components/doc/DocSearchBar.jsx","../src/components/doc/DocStatusBadge.jsx","../src/components/doc/FolderTree.jsx","../src/components/doc/MoveDocModal.jsx","../src/components/doc/UploadDropzone.jsx","../src/components/doc/ChunkConfigForm.jsx","../src/components/doc/VersionTimeline.jsx","../src/hooks/use-member-info.js","../src/components/permission/MemberList.jsx","../src/components/permission/MemberGrantModal.jsx","../src/components/permission/PermissionModal.jsx","../src/pages/kb/KbDetailPage.jsx","../src/components/markdown/Markdown.jsx","../src/components/doc/MarkdownEditor.jsx","../src/pages/doc/DocDetailPage.jsx","../src/api/system.js","../package.json","../src/manifest.js","../src/components/settings/ServerFormModal.jsx","../src/components/settings/AdminFormModal.jsx","../src/components/settings/UserManagePanel.jsx","../src/pages/settings/SettingsPage.jsx","../src/app/StandaloneApp.jsx","../src/styles/knowledge.css?raw","../src/index.js","../src/app/tab-bodies.jsx","../src/slots/sidebar-right.js","../src/api/mcp.js","../src/components/chat/SaveToKbButton.jsx","../src/components/chat/ReferenceKbButton.jsx","../src/slots/chat-message.js","../src/client-entry.js"],"sourcesContent":["/**\n * DSH 宿主 MCP 配置同步(settings 活配置通道;仅 DSH client 半区生效)\n *\n * 数据链路(namespace 'knowledge' 由 Host 半区 apply 经 settings.register 注册):\n * 1. 本模块经远程 settingsController 的 settings.mutate('knowledge', ...) 把设置页\n * 当前服务器的接入点与插件 Token 写入该 namespace(远程面仅 describe/mutate——\n * register 仅宿主侧可用,勿再尝试 client 侧兜底注册)\n * 2. 用户层持久化到 ~/.dsh/settings.yaml(重启不丢);Host 半区 scope.watch 在提交\n * 变更后以新值 createMcp 重建连接并重新注册工具\n * → 智能体会话出现 mcp__knowledge__<skill> 工具\n *\n * - 推送时机:auth.syncHostMcpAuth() 的全部时机(首次验签换发、401 刷新、\n * 登录/退出/失效,以及设置页当前服务器变化:新增首个服务器自动激活、切换、\n * 编辑、删除兜底激活)\n * - 幂等:先 describe 读取 namespace 当前值与 revision,目标未变化时跳过写入\n * - 清除:删除服务器/退出登录(mcp_endpoint 为空串)时写入空 {url:'', token:''}\n * 覆盖宿主残留配置(否则重启后 Host 仍会拿旧值建连);Host 半区对空 url 仅销毁连接\n * - 启动竞态:client 半区就绪早于 Host 半区 apply(describe 查不到 namespace)\n * 时,单次延时重试;仍查不到则留诊断日志,等待下次推送时机\n * - standalone / 无 ctx 环境(注入 remote 服务缺失)自动空操作\n */\n\n/** knowledge settings 命名空间(与 Host 半区 host-entry.js 的 MCP_SETTINGS_NS 同名) */\nconst MCP_NS = 'knowledge'\n\n/** 启动竞态的单次重试延时(毫秒):等待 Host 半区 apply 完成 namespace 注册 */\nconst RETRY_DELAY_MS = 2000\n\n/** 单次重试定时器(新推送到达时清掉旧定时器,避免叠加) */\nlet retryTimer = null\n\n/**\n * 从 describe 视图取 knowledge 行(兼容宿主字段命名差异:\n * namespaces/list 顶层键 + 行内 ns/name/key/id/namespace 任一字段)\n */\nfunction findNamespaceRow(view) {\n const list = Array.isArray(view?.namespaces)\n ? view.namespaces\n : Array.isArray(view?.list)\n ? view.list\n : Array.isArray(view)\n ? view\n : []\n const row = list.find(\n (n) =>\n n &&\n (n.ns === MCP_NS || n.name === MCP_NS || n.key === MCP_NS || n.id === MCP_NS || n.namespace === MCP_NS),\n )\n if (row) return row\n // 字段命名完全未知时的兜底判定:JSON 序列化包含性(仅能判定存在,值/revision 未知)\n try {\n if (view && JSON.stringify(view).includes(`\"${MCP_NS}\"`)) {\n return { ns: MCP_NS, value: {}, revision: undefined }\n }\n } catch {}\n return null\n}\n\n/** client 半区 cordis ctx(apply 时注入;standalone 为 null) */\nlet hostCtx = null\n\n/** 写入串行链(revision 依据时序递进,防止并发 mutate 互相覆盖) */\nlet pushChain = Promise.resolve()\n\n/** 注入 client 半区 ctx(client-entry apply 首行调用;dispose 时置 null) */\nexport function setHostMcpContext(ctx) {\n hostCtx = ctx || null\n if (!ctx && retryTimer) {\n clearTimeout(retryTimer)\n retryTimer = null\n }\n}\n\n/**\n * 把当前 MCP 服务器配置写入 knowledge namespace(fire-and-forget,串行化)\n * @param {object} payload auth.syncHostMcpAuth 的登记快照\n * { api_base, mcp_endpoint, server_name, token, updated_at }\n */\nexport function pushHostMcpConfig(payload) {\n if (!hostCtx || !payload) return\n // mcp_endpoint 为空串(删除服务器/退出登录)也要推送:写入空值清除宿主残留配置\n pushChain = pushChain.then(() => syncSettings(payload, false)).catch(() => {})\n}\n\n/** 同步一次(describe → 比对 → mutate);异常仅告警,不影响业务 */\nasync function syncSettings(payload, isRetry) {\n const ctx = hostCtx\n if (!ctx || typeof ctx.remote?.settings?.describe !== 'function') return\n const settings = ctx.remote.settings\n const desired = {\n url: payload.mcp_endpoint,\n token: payload.token || '',\n }\n try {\n const result = await settings.describe()\n if (!result || result.ok !== true) {\n console.warn('[knowledge] MCP 宿主 settings 读取失败', (result && result.error) || '')\n return\n }\n const view = result.value\n if (!view || view.writable === false) return\n const row = findNamespaceRow(view)\n\n if (!row) {\n // Host 半区 apply 未完成(启动竞态):单次延时重试;仍查不到则留诊断日志\n if (!isRetry) {\n if (retryTimer) clearTimeout(retryTimer)\n retryTimer = setTimeout(() => {\n retryTimer = null\n pushChain = pushChain.then(() => syncSettings(payload, true)).catch(() => {})\n }, RETRY_DELAY_MS)\n console.info(`[knowledge] describe 未查到 '${MCP_NS}' 命名空间(Host 半区可能尚未就绪),2s 后重试一次`)\n return\n }\n try {\n const raw = JSON.stringify(view)\n console.warn(\n `[knowledge] describe 仍未查到 '${MCP_NS}' 命名空间(namespaces 原始视图:${raw.length > 600 ? raw.slice(0, 600) + '…' : raw})。` +\n 'Host 半区未加载或版本过旧——请确认插件已启用并重启 DSH 后重试',\n )\n } catch {}\n return\n }\n\n const cur = row.value || {}\n if (cur.url === desired.url && cur.token === desired.token) return\n\n const res = await settings.mutate(\n MCP_NS,\n [{ op: 'set', path: [], value: desired }],\n row.revision,\n )\n if (!res || res.ok === false) console.warn('[knowledge] MCP 宿主配置写入未接受', (res && res.error) || '')\n } catch (error) {\n console.warn('[knowledge] MCP 宿主配置同步失败', error)\n }\n}\n\n/**\n * 自检宿主 MCP 配置状态(页面加载/刷新时由 auth.checkHostMcpReady 调用)\n * @returns {Promise<{status: string, url: string, hasToken: boolean, detail: string}>}\n * status:no-ctx(非 DSH 环境/插件未激活)| no-settings(宿主 settings 不可用)\n * | no-namespace(Host 半区未注册 knowledge)| registered(已注册,\n * url/hasToken 供调用方与期望值比对)\n */\nexport async function describeHostMcpStatus() {\n if (!hostCtx) {\n return { status: 'no-ctx', url: '', hasToken: false, detail: '非 DSH 宿主环境(standalone 模式无需宿主 MCP)' }\n }\n const settings = hostCtx.remote?.settings\n if (!settings || typeof settings.describe !== 'function') {\n return { status: 'no-settings', url: '', hasToken: false, detail: '宿主 settings 服务不可用(client 半区未获得 remote.settings 注入)' }\n }\n try {\n const result = await settings.describe()\n if (!result || result.ok !== true) {\n return { status: 'no-settings', url: '', hasToken: false, detail: `宿主 settings 读取失败:${(result && result.error) || '未知错误'}` }\n }\n const view = result.value\n if (!view || view.writable === false) {\n return { status: 'no-settings', url: '', hasToken: false, detail: '宿主 settings 不可写' }\n }\n const row = findNamespaceRow(view)\n if (!row) {\n return {\n status: 'no-namespace',\n url: '',\n hasToken: false,\n detail: `宿主未注册 ${MCP_NS} 命名空间(Host 半区未加载或版本过旧,重启 DSH 后重试)`,\n }\n }\n const cur = row.value || {}\n return { status: 'registered', url: cur.url || '', hasToken: Boolean(cur.token), detail: '' }\n } catch (error) {\n return { status: 'no-settings', url: '', hasToken: false, detail: `宿主 settings 异常:${(error && error.message) || error}` }\n }\n}\n","/**\n * DSH 智能体对接封装(knowledge 版)\n *\n * 插件不直接调用 LLM。AI 编写提交到 DSH 当前打开的会话(ctx.sessions.list\n * 快照 current):follow 订阅该会话流 → prompt 提交「提示词 + 文档原文」→\n * 从 durable 的 assistant/message 事件提取全文(seq 水位过滤历史事件)。\n * 文档内容由前端页面直接携带,不经 MCP 工具读取;结果直接从会话流取回。\n *\n * 宿主上下文由 client-entry apply 时经 setHostContext 注入;standalone\n * 环境未注入则抛可读错误。\n */\n\n/** client 半区注入的宿主上下文(client-entry apply 时注入;standalone 为 null) */\nlet hostCtx = null\n\n/** client 半区注入的 sessions 服务(ctx.sessions,list 快照 current = 当前打开的会话) */\nlet sessionsSvc = null\n\n/**\n * 注入 client 半区 ctx(client-entry apply 首行调用;dispose 时置 null)\n */\nexport function setHostContext(ctx) {\n hostCtx = ctx || null\n}\n\n/**\n * 注入宿主 sessions 服务(client-entry apply 时调用;dispose 时置 null)。\n * AI 编写提交到当前打开的会话:list 快照的 current 即 DSH 界面正在查看的会话 id\n */\nexport function setSessionsContext(svc) {\n sessionsSvc = svc || null\n}\n\n/** 解析当前打开的会话 id(sessions.list 快照 current);无打开会话返回 undefined */\nfunction resolveCurrentSessionId() {\n try {\n return sessionsSvc?.list?.getSnapshot?.()?.current\n } catch {\n return undefined\n }\n}\n\n/** 解析宿主 session 远程服务(ctx.remote.session,宿主 WebUI 会话面板同源) */\nfunction resolveSessionRemote() {\n const remote = hostCtx && hostCtx.remote\n const session = remote && remote.session\n if (session && typeof session.create === 'function' && typeof session.prompt === 'function' && typeof session.follow === 'function') {\n return session\n }\n return null\n}\n\n/**\n * 解析当前打开会话的输入 facade(SessionInput:setDraft/insertReference/state)。\n * 标准路径(对齐宿主 queue dock 内部用法):\n * sessions.scope(id) 取 session 域 ctx → actx.get('conversation') →\n * conversation.input.for(actx)(要求 session scope)\n * standalone 环境 / 无打开会话 / 通道不可用时抛错,由调用方降级(如剪贴板)\n */\nfunction resolveSessionInputFacade() {\n const sessions = hostCtx && hostCtx.sessions\n if (!sessions || typeof sessions.scope !== 'function') {\n throw new Error('当前宿主未提供会话通道')\n }\n const sessionId = resolveCurrentSessionId()\n if (!sessionId) {\n throw new Error('请先在 DSH 中打开一个会话')\n }\n const actx = sessions.scope(sessionId)\n if (!actx) {\n throw new Error(`会话 \"${sessionId}\" 未解析到作用域`)\n }\n const conversation = typeof actx.get === 'function' ? actx.get('conversation') : actx.conversation\n const facade = conversation && conversation.input && typeof conversation.input.for === 'function'\n ? conversation.input.for(actx)\n : null\n if (!facade || typeof facade.setDraft !== 'function') {\n throw new Error('当前会话输入通道不可用')\n }\n return facade\n}\n\n/** 读取 facade 当前草稿(clipboard 投影;读不到视同空串) */\nfunction readFacadeDraft(facade) {\n try {\n const snap = facade.state && typeof facade.state.getSnapshot === 'function' ? facade.state.getSnapshot() : null\n return snap && typeof snap.draft === 'string' ? snap.draft : ''\n } catch {\n return ''\n }\n}\n\n/**\n * 将提示语写入 DSH 当前打开会话的输入框。\n * 合并语义:输入框已有内容时**追加**(空行分隔 + 提示语,原内容保留不覆盖),\n * 为空时直接填入。宿主公开 API(SessionInput.setDraft 全量替换、InputState 无\n * 光标字段)不暴露光标位置,无法真插到光标处——末尾追加是 API 内唯一可靠路径。\n * standalone 环境 / 无打开会话 / 写入未生效时抛错,由调用方降级(如剪贴板)\n * @param {string} text 要填入输入框的提示语\n */\nexport async function setSessionDraft(text) {\n const facade = resolveSessionInputFacade()\n // 合并:已有草稿 → 末尾空行分隔追加;空 → 直填\n const current = readFacadeDraft(facade)\n const next = current.trim()\n ? (current.endsWith('\\n') ? current + '\\n' : current + '\\n\\n') + text\n : text\n facade.setDraft(next)\n // 生效校验:正常 facade 下 draft 状态应在数帧内反映写入内容\n await new Promise((resolve) => setTimeout(resolve, 80))\n let snap = null\n try {\n snap = facade.state && typeof facade.state.getSnapshot === 'function' ? facade.state.getSnapshot() : null\n } catch { /* inert facade 读态抛错视同未生效 */ }\n if (!snap || typeof snap.draft !== 'string' || snap.draft !== next) {\n throw new Error('未能写入会话输入框')\n }\n}\n\n/**\n * 向 DSH 当前打开会话的输入框插入一条结构化引用 chip(与 `@知识库` onPick\n * 插入的芯片同构,发送时经触发源 codec.serialize 序列化)。\n *\n * 流程:setDraft 末尾追加占位文本(placeholder,与 codec.serialize 输出一致)→\n * 等草稿状态落地取最新 draftRev → 定位占位在 detect 坐标的 span →\n * facade.insertReference 将该 span 替换为 chip 节点。\n * detect 坐标换算:芯片在 clipboard 投影(draft)展开为 label,在 detect 投影\n * 仅占 1 字符(U+FFFC),故 detect 末尾 = draft.length - Σ(occurrence.length - 1)。\n *\n * 降级语义(不抛错):宿主 facade 无 insertReference 方法(旧版本)或 span CAS\n * 未通过(phase 锁定/并发编辑)时,占位文本保留在输入框——纯文本形式仍可被\n * lexicon 装饰成 chip 样式、可被 AI 解析,返回 { chip:false };\n * 无会话/通道不可用仍抛错,由调用方走剪贴板兜底。\n *\n * @param {object} reference ReferenceInsert 形状 { source, ref, label, appearance?, clipboardText }\n * @param {string} placeholder 占位文本(chip 替换目标;降级时即最终纯文本引用)\n * @returns {Promise<{chip: boolean}>} 是否成功插入为 chip\n */\nexport async function insertSessionReference(reference, placeholder) {\n const facade = resolveSessionInputFacade()\n const ph = String(placeholder || '')\n if (!ph) throw new Error('引用占位文本为空')\n const current = readFacadeDraft(facade)\n // 占位写入:非空草稿末尾以空格衔接(insertReference 会自动在芯片后补分隔空格)\n const next = current ? (/\\s$/.test(current) ? current : current + ' ') + ph : ph\n if (typeof facade.insertReference !== 'function') {\n facade.setDraft(next) // 降级:纯文本引用(serialize 同形,可被 lexicon 装饰)\n return { chip: false }\n }\n facade.setDraft(next)\n // 等草稿状态落地(芯片替换需要最新 draftRev 做 span CAS)\n let snap = null\n for (let i = 0; i < 25; i++) {\n await new Promise((resolve) => setTimeout(resolve, 40))\n try {\n snap = facade.state && typeof facade.state.getSnapshot === 'function' ? facade.state.getSnapshot() : null\n } catch { snap = null }\n if (snap && typeof snap.draft === 'string' && snap.draft.includes(ph)) break\n }\n if (!snap || typeof snap.draft !== 'string' || !snap.draft.includes(ph)) {\n throw new Error('未能写入会话输入框')\n }\n // detect 坐标换算:已存芯片 clipboard 展开 label、detect 仅占 1 字符\n const chipDelta = (snap.occurrences || []).reduce((acc, o) => acc + Math.max((o.length || 1) - 1, 0), 0)\n const detectEnd = snap.draft.length - chipDelta\n const span = { start: Math.max(detectEnd - ph.length, 0), end: detectEnd, draftRev: snap.draftRev }\n let ok = false\n try {\n ok = facade.insertReference(reference, span) === true\n } catch { ok = false }\n return { chip: ok }\n}\n\n/**\n * 从 assistant/message 事件的 message.content 中提取全部 text block 拼接全文\n * @param {object} message AssistantMessage 形状 { role:'assistant', content: ContentBlock[] }\n * @returns {string} 纯文本全文(无 text block 时返回空串)\n */\nfunction extractMessageText(message) {\n if (!message || !Array.isArray(message.content)) return ''\n return message.content\n .filter((b) => b && b.type === 'text' && typeof b.text === 'string')\n .map((b) => b.text)\n .join('')\n}\n\n/**\n * 运行一次 AI 编写:提交到 DSH 当前打开的会话 → follow 订阅 → prompt 提交 →\n * 一直等到本轮 assistant 消息落定(turn/end)→ 返回全文。无整体超时;\n * 会话中断(interrupt/cancel)或 prompt 提交失败立即停止等待并抛错。\n *\n * @param {object} p\n * @param {string} p.text 完整意图文本(提示词 + 文档原文,由前端拼装)\n * @param {(delta: string) => void} [p.onDelta] 流式增量回调(尽力而为,仅用于进度展示;\n * 最终结果以 assistant/message 事件为准)\n * @returns {Promise<string>} AI 输出的完整文本\n */\nexport async function runAIWriteSession({ text, onDelta }) {\n const session = resolveSessionRemote()\n if (!session) {\n throw new Error('当前宿主未提供会话通道(ctx.remote.session),请在 DSH 环境中重试')\n }\n // 提交到当前打开的会话(DSH 界面正在查看的那个);无打开会话时报错,不另创建\n const sessionId = resolveCurrentSessionId()\n if (!sessionId) {\n throw new Error('请先在 DSH 中打开一个会话,再使用 AI 编写')\n }\n\n // follow 打开后再 prompt:保证不会漏掉本轮 assistant 消息事件\n const followStream = await session.follow(\n { address: { kind: 'session', sessionId }, assistantStream: true },\n undefined,\n )\n const iterator = followStream[Symbol.asyncIterator]()\n\n // 尽早关闭 follow 流(async generator return 触发宿主侧订阅清理)\n const cleanup = () => {\n try {\n iterator.return?.()\n } catch { /* 已结束则忽略 */ }\n }\n\n try {\n // 先提交(follow 已在位);prompt 返回 Receipt,不代表生成完成。\n // 不在循环内 await Receipt(queue 模式可能迟至 turn 结束才落定,会阻塞流消费导致丢帧);\n // 其 rejection 转 promptFailed 参与竞速,让循环立即退出快速失败\n const promptPromise = session.prompt({\n requestId: `skai-kb-aiw-${Date.now()}`,\n sessionId,\n mode: 'queue',\n content: [{ type: 'text', text }],\n })\n // 快速失败竞速分支:prompt reject 时立即打断流等待;\n // 成功后转为永不 settle 的 promise(不干扰后续竞速,只等流事件)\n const promptFailed = promptPromise.then(\n () => new Promise(() => {}),\n (e) => {\n throw e\n },\n )\n\n // ctx.remote.session 是 typert RPC 代理,follow 返回裸 wire 帧(SessionFollowFrame):\n // {type:'snapshot', records: SessionEventEntry[]} 打开基线(已有会话含全部历史)\n // {type:'event', event:{seq, type, data}} journal durable 事件(assistant/message、turn/end 在此)\n // {type:'assistant-stream', frame: SessionAssistantStreamFrame} assistant 流片段\n let latest = null // 最后一条 assistant/message 的全文\n let interrupted = false\n // 水位:follow 打开已有会话时基线含历史事件(旧 assistant/message、旧 turn/end),\n // seq <= watermark 的一律忽略,只吸收本次 prompt 产生的新事件\n let watermark = 0\n const absorb = (ev) => {\n if (!ev) return\n if (ev.seq != null && ev.seq <= watermark) return\n if (ev.type === 'assistant/message') {\n const data = ev.data || {}\n latest = extractMessageText(data.message)\n if (data.interrupted) interrupted = true\n } else if (ev.type === 'turn/end') {\n // 一轮落定:以 turn 为完成边界(多步场景取最后一轮的助手消息)\n if (ev.data?.reason?.kind === 'interrupted') interrupted = true\n }\n }\n for (;;) {\n // 等待流下一帧;prompt 提交失败时经 promptFailed 竞速立即抛错(无整体超时,\n // 一直等到会话 turn/end 或流关闭为止)\n const next = await Promise.race([iterator.next(), promptFailed])\n if (next.done) break\n const frame = next.value\n\n if (frame?.type === 'snapshot') {\n // 基线:只取最大 seq 作水位(旧事件不吸收,防止误回填历史消息)\n for (const record of frame.records || []) {\n const seq = record?.event?.seq\n if (typeof seq === 'number' && seq > watermark) watermark = seq\n }\n continue\n }\n if (frame?.type === 'event') {\n absorb(frame.event)\n if (frame.event?.type === 'turn/end' && frame.event.seq > watermark) break\n continue\n }\n if (frame?.type === 'assistant-stream' && onDelta) {\n // 过程帧:尽力提取增量文本供进度展示(chunk 为 provider 流片段,容错解析)\n const f = frame.frame\n if (f?.type === 'chunk' && f.chunk) {\n const c = f.chunk\n const piece = typeof c === 'string' ? c : typeof c.delta === 'string' ? c.delta : c.type === 'text' && typeof c.text === 'string' ? c.text : ''\n if (piece) onDelta(piece)\n }\n continue\n }\n // 其余未知帧忽略\n }\n\n if (interrupted) throw new Error('AI 输出被中断,未获得完整结果')\n if (!latest || !latest.trim()) {\n throw new Error('会话已结束但未收到 AI 文本结果')\n }\n return latest\n } finally {\n cleanup()\n }\n}\n","/**\n * 后端服务器配置(设置页数据源,用户中心配置项云持久化)\n *\n * - 支持配置多个 Go 后端服务器(名称 + 服务器URL),一键切换当前使用的服务器;\n * 服务器 URL 只含协议 + IP/端口(如 http://127.0.0.1:8081),应用路径固定\n * /kb 由前端统一拼装,无需用户配置\n * - REST(request.js)请求发往「当前服务器」;当前服务器同时作为 MCP 接入点\n * (getMcpEndpoint() = {服务器URL}/kb/mcp/v1),新增首个服务器自动激活 /\n * 切换 / 编辑 / 删除兜底激活时经 auth.syncHostMcpAuth() 把 MCP 服务器配置登记至宿主\n * (供 DSH 智能体注册并调用知识库 MCP Skill)\n * - 持久化:经用户中心配置开放接口(window.SHIKEAI_GET_MEMBER_CONFIG /\n * window.SHIKEAI_SET_MEMBER_CONFIG)按会员维度云存储(key 前缀 knowledge.),\n * 跨设备同步;本模块维护内存态镜像,getServers / getActiveServer / getApiBase\n * 同步读取(request / session 每次请求动态取值),写入即时生效并异步上云\n * - 游客态:云接口读取返回 null、保存返回 false,配置仅本次会话内有效(不落本地)\n * - 登录态变化(登录 / 退出 / 失效)自动重新拉取云端配置,实现账号隔离,\n * 防止跨账号配置残留\n * - 不内置默认地址——未配置/未选中服务器时 getApiBase() 返回空串,请求侧统一\n * 拦截并提示先配置服务器信息\n */\n\n/** 云配置键(用户中心约定「插件名.配置项名」前缀,value 均为字符串) */\nconst KEY_SERVERS = 'knowledge.servers'\nconst KEY_ACTIVE = 'knowledge.serverActive'\n\n/** 固定应用路径(前后端约定;服务器 URL 不含该前缀,request / session / MCP 端点统一拼装) */\nexport const APP_PATH = '/kb'\n\n/** 服务器配置内存态(云端镜像;同步读取源) */\nlet servers = []\nlet activeId = ''\n\n/** 加载请求序号(丢弃过期加载结果,防慢响应覆盖新配置) */\nlet loadSeq = 0\n/** 登录态事件是否已绑定 */\nlet authBound = false\n\nconst listeners = new Set()\nfunction emit() {\n listeners.forEach((fn) => {\n try {\n fn()\n } catch {}\n })\n}\n\nlet seq = 0\nfunction genId() {\n return `srv_${Date.now()}_${++seq}`\n}\n\n/** 云端列表数据清洗:仅保留结构完整的条目;api_base 归一为 origin(旧配置 /api 后缀自动收敛) */\nfunction sanitizeServers(raw) {\n if (!Array.isArray(raw)) return { list: [], changed: false }\n let changed = false\n const list = raw\n .filter((s) => s && typeof s === 'object' && s.id && s.name && s.api_base)\n .map((s) => {\n const base = normalizeApiBase(s.api_base)\n const apiBase = base || String(s.api_base)\n if (apiBase !== s.api_base) changed = true\n return {\n id: String(s.id),\n name: String(s.name),\n api_base: apiBase,\n created_at: Number(s.created_at) || 0,\n }\n })\n return { list, changed }\n}\n\n/** 应用云端配置到内存态(activeId 失效时置空,不自动兜底选择;归一发生变化时回写云端) */\nfunction applyCloud(list, activeRaw) {\n const { list: cleaned, changed } = sanitizeServers(list)\n servers = cleaned\n const id = typeof activeRaw === 'string' ? activeRaw : ''\n activeId = servers.some((s) => s.id === id) ? id : ''\n // 旧版本存量配置(api_base 带 /api 等应用路径后缀)归一为 origin 后回写云端,仅首次触发\n if (changed) persist()\n emit()\n}\n\n/**\n * 从用户中心云配置拉取服务器配置(幂等可重入)\n * 安装时与登录态变化(登录 / 退出 / 失效,账号隔离)时调用\n *\n * 启动自动生效保障(DSH 启动后已配置服务器无需手动操作即生效):\n * - 桥接就绪等待:用户中心 bundle 可能晚于本插件挂载 window 桥接(bundle 顺序\n * 变化时),有界轮询等待(250ms × 40 = 10s 上限),就绪后立即拉取\n * - 静默恢复重拉:DSH 启动时用户中心经 restoreSession 静默恢复会话(不派发\n * login 事件),恢复成功派发 user-update;本模块监听该事件重拉云端配置,\n * 覆盖「首拉时会话/后端未就绪」的瞬时失败\n * - 瞬时失败重试:已登录(SHIKEAI_USER_INFO 存在)但云端读取返回 null(网络\n * 异常等)时有界重试 3 次(间隔 1s);返回空对象(确实未配置)或游客态不重试\n */\nconst BRIDGE_POLL_INTERVAL = 250\nconst BRIDGE_POLL_MAX = 40\nconst FETCH_RETRY_MAX = 3\nconst FETCH_RETRY_INTERVAL = 1000\n\nfunction cloudBridgeReady() {\n return typeof window !== 'undefined' && typeof window.SHIKEAI_GET_MEMBER_CONFIG === 'function'\n}\n\n/** 首次加载完成标记与等待者(whenReady 用;登录态变化的后续重拉不再放行) */\nlet firstLoadDone = false\nlet firstLoadResolvers = []\n\nfunction settleFirstLoad() {\n if (firstLoadDone) return\n firstLoadDone = true\n const resolvers = firstLoadResolvers\n firstLoadResolvers = []\n resolvers.forEach((resolve) => resolve())\n}\n\nasync function loadFromCloud() {\n const reqSeq = ++loadSeq\n try {\n await pullFromCloud(reqSeq)\n } finally {\n // 仅最后一轮加载负责放行 whenReady(被新加载顶替时由新加载放行)\n if (reqSeq === loadSeq) settleFirstLoad()\n }\n}\n\nasync function pullFromCloud(reqSeq) {\n for (let i = 0; !cloudBridgeReady() && i < BRIDGE_POLL_MAX; i++) {\n await new Promise((resolve) => setTimeout(resolve, BRIDGE_POLL_INTERVAL))\n if (reqSeq !== loadSeq) return\n }\n if (!cloudBridgeReady() || reqSeq !== loadSeq) return\n for (let attempt = 1; attempt <= FETCH_RETRY_MAX; attempt++) {\n try {\n const data = await window.SHIKEAI_GET_MEMBER_CONFIG([KEY_SERVERS, KEY_ACTIVE])\n if (reqSeq !== loadSeq) return\n if (data == null) {\n // null = 游客态或云端读取失败:已登录(用户信息在)时按瞬时失败重试,\n // 游客态无配置可读,直接放弃\n const loggedIn = Boolean(window.SHIKEAI_USER_INFO)\n if (!loggedIn || attempt >= FETCH_RETRY_MAX) return\n await new Promise((resolve) => setTimeout(resolve, FETCH_RETRY_INTERVAL))\n if (reqSeq !== loadSeq) return\n continue\n }\n const raw = typeof data === 'object' ? data : {}\n let list = []\n try {\n list = raw[KEY_SERVERS] ? JSON.parse(raw[KEY_SERVERS]) : []\n } catch {\n list = []\n }\n applyCloud(list, raw[KEY_ACTIVE])\n return\n } catch {\n if (attempt >= FETCH_RETRY_MAX) return\n await new Promise((resolve) => setTimeout(resolve, FETCH_RETRY_INTERVAL))\n if (reqSeq !== loadSeq) return\n }\n }\n}\n\n/** 云端保存(fire-and-forget;游客态 / 失败仅告警,内存态修改不受影响) */\nfunction persist() {\n if (typeof window === 'undefined' || typeof window.SHIKEAI_SET_MEMBER_CONFIG !== 'function') return\n Promise.resolve(\n window.SHIKEAI_SET_MEMBER_CONFIG({\n [KEY_SERVERS]: JSON.stringify(servers),\n [KEY_ACTIVE]: activeId,\n }),\n )\n .then((ok) => {\n if (!ok) console.warn('[knowledge] 服务器配置云端保存失败(游客态或网络异常),本次修改仅会话内有效')\n })\n .catch(() => {})\n}\n\n/** 是否具备云持久化条件(用户中心配置接口已挂载且已登录);设置页提示用 */\nexport function isCloudPersistAvailable() {\n if (typeof window === 'undefined') return false\n return typeof window.SHIKEAI_SET_MEMBER_CONFIG === 'function' && Boolean(window.SHIKEAI_USER_INFO)\n}\n\n/** 安装:绑定用户中心登录态事件(登录 / 退出 / 失效 / 静默恢复成功)并首次加载(幂等) */\nexport function initServerConfig() {\n if (typeof window === 'undefined') return\n if (!authBound) {\n authBound = true\n // user-update:DSH 启动时用户中心静默恢复会话成功(restoreSession → refreshUser)\n // 的确切信号——首拉可能因会话/后端未就绪失败,该事件到达即重拉云端配置\n ;['shikeai-usercenter:login', 'shikeai-usercenter:logout', 'shikeai-usercenter:expired', 'shikeai-usercenter:user-update'].forEach((type) => {\n window.addEventListener(type, loadFromCloud)\n })\n }\n loadFromCloud()\n}\n\n/** URL 规范化:协议必须为 http/https,仅保留 origin(协议+域名/IP+端口,应用路径不随 URL 配置) */\nexport function normalizeApiBase(url) {\n const v = String(url || '').trim()\n if (!v) return ''\n let parsed\n try {\n parsed = new URL(v)\n } catch {\n return ''\n }\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') return ''\n return parsed.origin\n}\n\n/** 服务器 URL 校验:返回错误信息,空串表示通过 */\nexport function validateServerUrl(url) {\n const v = String(url || '').trim()\n if (!v) return '请输入服务器 URL'\n if (!normalizeApiBase(v)) return 'URL 格式不正确,需为 http(s)://IP:端口 形式(如 http://127.0.0.1:8081)'\n return ''\n}\n\n/** 服务器名称校验 */\nexport function validateServerName(name) {\n const v = String(name || '').trim()\n if (!v) return '请输入服务器名称'\n if (v.length > 32) return '服务器名称不能超过 32 字符'\n return ''\n}\n\n/** 获取服务器配置列表 */\nexport function getServers() {\n return servers\n}\n\n/** 获取当前选中的服务器(未选中或已失效时为 null) */\nexport function getActiveServer() {\n if (!activeId) return null\n return servers.find((s) => s.id === activeId) || null\n}\n\n/** 获取当前请求基址(request / session 动态读取;未配置服务器时返回空串,调用方须先拦截提示) */\nexport function getApiBase() {\n const active = getActiveServer()\n return (active && active.api_base) || ''\n}\n\n/**\n * 获取当前知识库 MCP 服务接入点(后端 POST {服务器URL}/kb/mcp/v1,JSON-RPC 2.0)。\n * 当前服务器变化(新增首个服务器自动激活 / 切换 / 编辑 / 删除兜底激活)时随之更新,\n * 经 auth.syncHostMcpAuth() 登记至 DSH 宿主,供智能体注册并调用知识库 MCP Skill;\n * 未配置服务器时返回空串。\n */\nexport function getMcpEndpoint() {\n const apiBase = getApiBase()\n return apiBase ? `${apiBase}${APP_PATH}/mcp/v1` : ''\n}\n\n/** 订阅配置变更(设置页刷新列表用) */\nexport function subscribe(fn) {\n listeners.add(fn)\n return () => listeners.delete(fn)\n}\n\n/**\n * 等待首次云端配置解析完成(启动自动生效用):resolve 后 getApiBase() 即为本轮\n * 加载的最终结果(已配置则基址就绪,未配置/游客态为空串)。\n * 页面首次加载用它避免在配置到达前发起请求,被 request 拦截误报\n * 「请先在设置页配置服务器信息」(浏览器刷新后云配置异步到达的窗口期)\n */\nexport function whenReady() {\n if (firstLoadDone) return Promise.resolve()\n return new Promise((resolve) => firstLoadResolvers.push(resolve))\n}\n\n/**\n * 新增服务器;名称或 URL 非法时返回错误信息(不改状态);无当前服务器时自动激活。\n * 自动激活(新增首个服务器)会经 subscribe 通知 auth 同步宿主:当前服务器即 MCP 接入点,\n * 知识库 MCP 服务器配置随登记流程写入 DSH。\n */\nexport function addServer(name, url) {\n const errMsg = validateServerName(name) || validateServerUrl(url)\n if (errMsg) return errMsg\n const apiBase = normalizeApiBase(url)\n if (servers.some((s) => s.api_base === apiBase)) return '该接口 URL 已存在'\n const id = genId()\n servers = [...servers, { id, name: name.trim(), api_base: apiBase, created_at: Date.now() }]\n if (!getActiveServer()) activeId = id\n emit()\n persist()\n return ''\n}\n\n/** 编辑服务器;id 非法时返回错误信息 */\nexport function updateServer(id, name, url) {\n const errMsg = validateServerName(name) || validateServerUrl(url)\n if (errMsg) return errMsg\n if (!servers.find((s) => s.id === id)) return '服务器不存在或已被删除'\n const apiBase = normalizeApiBase(url)\n if (servers.some((s) => s.id !== id && s.api_base === apiBase)) return '该接口 URL 已存在'\n servers = servers.map((s) => (s.id === id ? { ...s, name: name.trim(), api_base: apiBase } : s))\n emit()\n persist()\n return ''\n}\n\n/** 删除服务器;若删除的是当前服务器则自动激活首个剩余服务器(无则当前无服务器,请求将被拦截) */\nexport function removeServer(id) {\n const list = servers.filter((s) => s.id !== id)\n servers = list\n if (activeId === id) activeId = list.length > 0 ? list[0].id : ''\n emit()\n persist()\n return ''\n}\n\n/** 切换当前服务器 */\nexport function setActiveServer(id) {\n if (activeId === id) return\n activeId = servers.some((s) => s.id === id) ? id : ''\n emit()\n persist()\n}\n","/**\n * 运行时配置\n *\n * - 不内置默认后端地址:请求基址完全由设置页配置(server-config.getApiBase())。\n * 未配置/未选中服务器时 getApiBase() 返回空串,request / session 统一\n * 拦截并提示「请先在设置页配置服务器信息」,不发任何网络请求\n */\n\n/** 请求超时(毫秒);上传/大文档可单独放宽 */\nexport const REQUEST_TIMEOUT = 20000\n","/**\n * 插件会话验签换发/吊销(原生 fetch 直连,不走 request.js 以避免循环依赖)\n *\n * 插件不接触用户中心 Token:\n * - 换发:以用户中心 JS 验签接口(window.SHIKEAI_GET_SIGN_CREDENTIAL)返回的\n * sign + message 调 POST /kb/auth/verify,后端 Ed25519 公钥本地验签\n * (时间戳容差 + 一次性消费防重放)后签发插件自有 token(Redis 会话,非活跃过期)\n * - 吊销:用户中心登出/失效时调 POST /kb/auth/logout,后端删除会话\n * - 响应结构 { code, msg, data },code === 0 判定成功\n */\nimport { REQUEST_TIMEOUT } from './config.js'\nimport { getApiBase, APP_PATH } from './server-config.js'\n\nfunction timeoutController(ms) {\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), ms)\n return { controller, done: () => clearTimeout(timer) }\n}\n\n/**\n * 以用户中心验签数据(sign + message)换发插件自有 token\n * @param {string} sign Ed25519 签名(base64,来自用户中心 JS 验签接口)\n * @param {string} message 被签名明文(uid / 手机号md5 / 秒级时间戳)\n * @returns {Promise<{token: string, uid: number, mobile_md5?: string, expires_in: number}>}\n * @throws {Error} 携带服务端 msg(验签失败/已消费等)\n */\nexport async function exchangePluginToken(sign, message) {\n const apiBase = getApiBase()\n if (!apiBase) throw new Error('请先在设置页配置服务器信息')\n const { controller, done } = timeoutController(REQUEST_TIMEOUT)\n try {\n const res = await fetch(`${apiBase}${APP_PATH}/auth/verify`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ sign, message }),\n signal: controller.signal,\n })\n const body = await res.json().catch(() => null)\n if (body && typeof body === 'object' && body.code === 0 && body.data && body.data.token) return body.data\n const error = new Error((body && body.msg) || `换发插件 token 失败(HTTP ${res.status})`)\n error.code = (body && body.code) || res.status // 透传门禁码(40302 等),调用方据此去重提示\n throw error\n } catch (error) {\n if (error.name === 'AbortError') throw new Error('换发插件 token 超时,请检查网络后重试')\n throw error\n } finally {\n done()\n }\n}\n\n/**\n * 吊销插件 token(用户中心登出/失效回调;幂等,失败静默——后端会话有 TTL 兜底)\n * @param {string} pluginToken 插件自有 token\n */\nexport async function revokePluginToken(pluginToken) {\n if (!pluginToken || !getApiBase()) return\n const { controller, done } = timeoutController(REQUEST_TIMEOUT)\n try {\n await fetch(`${getApiBase()}${APP_PATH}/auth/logout`, {\n method: 'POST',\n headers: { Authorization: `Bearer ${pluginToken}` },\n signal: controller.signal,\n })\n } catch {\n } finally {\n done()\n }\n}\n","/**\n * 轻量状态容器(框架无关,供 React 与 core 层共用)\n *\n * 注意:useStore 的 selector 必须返回稳定引用(state 上的字段或原语),\n * 不要在 selector 中构造新对象,否则 useSyncExternalStore 会死循环。\n */\nimport { useSyncExternalStore } from 'react'\n\nexport function createStore(initialState) {\n let state = initialState\n const listeners = new Set()\n return {\n getState: () => state,\n setState(patch) {\n const next = typeof patch === 'function' ? patch(state) : patch\n state = { ...state, ...next }\n listeners.forEach((listener) => listener())\n },\n subscribe(listener) {\n listeners.add(listener)\n return () => listeners.delete(listener)\n },\n }\n}\n\n/** React 绑定:订阅 store 并按 selector 取快照(第三参为 SSR 服务端快照,与服务端一致) */\nexport function useStore(store, selector = (s) => s) {\n return useSyncExternalStore(store.subscribe, () => selector(store.getState()), () => selector(store.getState()))\n}\n","/**\n * 全局 UI 状态:Toast 提示(错误处理统一出口,禁止静默吞错)\n *\n * 0.8.0 起页面导航改由 DSH 右侧 Sidebar 标签页系统承载\n * (首页 / 知识库详情 / 文档详情 / 设置 各为一个标签页,\n * 经 tab.actions.openTab(kind, { params }) 打开),本 store 不再持有页面路由。\n */\nimport { createStore } from './create-store.js'\n\nconst initialUiState = {\n toasts: [],\n}\n\nexport const uiStore = createStore(initialUiState)\n\nlet toastSeq = 0\n/** 展示中的 toast 索引(key: type|message → {id, timer}):同文案去重,重置时长不叠加 */\nconst activeToasts = new Map()\n\n/** 全局 Toast 提示(错误处理统一出口,禁止静默吞错;同文案在展示中时不重复弹出) */\nexport function toast(message, type = 'info', duration = 2600) {\n const key = `${type}|${message}`\n const exist = activeToasts.get(key)\n if (exist) {\n if (exist.timer) clearTimeout(exist.timer)\n if (duration > 0) exist.timer = setTimeout(() => dismissToast(exist.id), duration)\n return exist.id\n }\n const id = ++toastSeq\n activeToasts.set(key, {\n id,\n timer: duration > 0 ? setTimeout(() => dismissToast(id), duration) : null,\n })\n uiStore.setState((s) => ({\n toasts: [...s.toasts, { id, message, type }],\n }))\n return id\n}\n\nexport function dismissToast(id) {\n for (const [key, t] of activeToasts) {\n if (t.id === id) {\n if (t.timer) clearTimeout(t.timer)\n activeToasts.delete(key)\n }\n }\n uiStore.setState((s) => ({ toasts: s.toasts.filter((t) => t.id !== id) }))\n}\n\n/** 错误 Toast 统一出口(ApiError 透出服务端 msg);\n * 用户状态门禁错误(40301 待审核 / 40302 禁用)同样走 Toast(同文案展示期内自动去重) */\nexport function toastError(error) {\n return toast((error && (error.msg || error.message)) || '操作失败', 'error', 3600)\n}\n","/**\n * 知识库域状态:列表、筛选、统计概览\n * 角色:1 所有者 / 2 编辑者 / 3 只读(与后端 smallint 对齐)\n */\nimport { createStore } from './create-store.js'\n\nexport const ROLE = { ADMIN: 1, EDITOR: 2, READONLY: 3 }\nexport const ROLE_LABEL = { 1: '所有者', 2: '编辑者', 3: '只读', 5: '管理员' }\n\nexport const initialKbState = {\n list: [],\n total: 0,\n page: 1,\n limit: 20,\n keyword: '',\n tagFilter: '',\n loaded: false,\n /** 统计概览(首页):知识库 / 文档 / 向量块统计 */\n stats: null,\n}\n\nexport const kbStore = createStore(initialKbState)\n\nexport function setKbList(list, total, page, limit) {\n kbStore.setState({\n list: list || [],\n total: total || 0,\n page,\n limit,\n loaded: true,\n })\n}\n\nexport function setKbKeyword(keyword) {\n kbStore.setState({ keyword, page: 1 })\n}\n\nexport function setKbTagFilter(tag) {\n kbStore.setState({ tagFilter: tag, page: 1 })\n}\n\nexport function upsertKb(kb) {\n kbStore.setState((s) => {\n const idx = s.list.findIndex((k) => k.id === kb.id)\n if (idx < 0) return { list: [kb, ...s.list] }\n const list = s.list.slice()\n list[idx] = kb\n return { list }\n })\n}\n\nexport function removeKbLocally(kbId) {\n kbStore.setState((s) => ({\n list: s.list.filter((k) => k.id !== kbId),\n total: Math.max(0, s.total - 1),\n }))\n}\n\nexport function setStats(stats) {\n kbStore.setState({ stats })\n}\n","/**\n * 文档域状态:当前知识库文档列表、筛选条件\n * 文档状态:0 待解析 / 1 解析中 / 2 向量化中 / 3 已就绪 / 4 解析失败\n */\nimport { createStore } from './create-store.js'\n\nexport const initialDocState = {\n kbId: null,\n list: [],\n total: 0,\n page: 1,\n limit: 20,\n keyword: '',\n tagFilter: '',\n}\n\nexport const DOC_STATUS_LABEL = {\n 0: '待解析',\n 1: '解析中',\n 2: '向量化中',\n 3: '已就绪',\n 4: '解析失败',\n}\n\nexport const docStore = createStore(initialDocState)\n\nexport function setDocList(kbId, list, total, page, limit) {\n docStore.setState({\n kbId,\n list: list || [],\n total,\n page,\n limit,\n })\n}\n\nexport function setDocKeyword(keyword) {\n docStore.setState({ keyword, page: 1 })\n}\n\nexport function setDocTagFilter(tag) {\n docStore.setState({ tagFilter: tag, page: 1 })\n}\n\nexport function setDocPage(page) {\n docStore.setState({ page })\n}\n\n/** 轮询回填:按文档 id 就地更新状态(不整表刷新,避免闪烁) */\nexport function patchDocStatus(docId, patch) {\n docStore.setState((s) => {\n const idx = s.list.findIndex((d) => d.id === docId)\n if (idx < 0) return null\n const list = s.list.slice()\n list[idx] = { ...list[idx], ...patch }\n return { list }\n })\n}\n","/**\n * 标签页标题注册表(sidebar.right.pane.tab.title 活标题数据源)\n *\n * DSH 右侧 Sidebar 标签页的 chip 文案在打开时由 title(address) 捕获;\n * 知识库详情 / 文档详情标签页打开时往往还不知道名称(只有 id 参数),\n * 因此由页面在数据到达后把 id → 名称写入本 store,标题组件经 useStore\n * 订阅展示实时名称,未知名时回退通用文案。\n */\nimport { createStore } from './create-store.js'\n\nconst titleStore = createStore({\n /** kbId(String) → 知识库名称 */\n kbNames: {},\n /** `${kbId}:${docId}` → 文档名称 */\n docNames: {},\n})\n\nexport function setKbName(kbId, name) {\n if (kbId == null || !name) return\n titleStore.setState((s) => {\n const key = String(kbId)\n if (s.kbNames[key] === name) return null\n return { kbNames: { ...s.kbNames, [key]: name } }\n })\n}\n\nexport function setDocName(kbId, docId, name) {\n if (kbId == null || docId == null || !name) return\n titleStore.setState((s) => {\n const key = `${kbId}:${docId}`\n if (s.docNames[key] === name) return null\n return { docNames: { ...s.docNames, [key]: name } }\n })\n}\n\nexport function getKbName(kbId) {\n if (kbId == null) return ''\n return titleStore.getState().kbNames[String(kbId)] || ''\n}\n\nexport function getDocName(kbId, docId) {\n if (kbId == null || docId == null) return ''\n return titleStore.getState().docNames[`${kbId}:${docId}`] || ''\n}\n\nexport function clearNames() {\n titleStore.setState({ kbNames: {}, docNames: {} })\n}\n\nexport { titleStore }\n","/**\n * 登出/失效/切换服务器统一复位(core/auth 调用,避免 store ↔ auth 循环依赖)\n */\nimport { uiStore } from './ui-store.js'\nimport { kbStore, initialKbState } from './kb-store.js'\nimport { docStore, initialDocState } from './doc-store.js'\nimport { clearNames } from './title-store.js'\n\n/** 清空本地状态并禁用全部操作(登录态只读复用,本地不存登录数据) */\nexport function resetAllStores() {\n uiStore.setState({ toasts: [] })\n kbStore.setState(initialKbState)\n docStore.setState(initialDocState)\n clearNames()\n}\n\n/**\n * 切换后端服务器后复位业务数据(Toast 保留,清空上一服务器的\n * 知识库列表、文档、统计概览与标签页名称缓存),各标签页重新拉取\n */\nexport function resetServerScopedStores() {\n kbStore.setState(initialKbState)\n docStore.setState(initialDocState)\n clearNames()\n}\n","/**\n * 登录态桥接(用户中心验签换发,插件不接触用户中心 Token)+ 插件会话管理\n *\n * - 登录态按需获取:仅请求需要登录态的后端接口时,调用用户中心 JS 验签接口\n * window.SHIKEAI_GET_SIGN_CREDENTIAL() 获取 sign + message(游客态返回 null),\n * 经 POST /kb/auth/verify 换取插件自有 Token;有效期内复用,不重复验签\n * - Token 持久化:localStorage skai_kb_token / skai_kb_uid,跨会话复用;\n * REST 与 MCP(Authorization: Bearer)同源携带\n * - 公开用户信息只读 window.SHIKEAI_USER_INFO(脱敏手机号、昵称、头像),仅用于展示\n * - 监听 shikeai-usercenter:login / logout / expired / user-update 四类事件同步登录态:\n * 登录重置本地 Token 待下次请求重新验签;登出/失效吊销后端会话并清空本地状态与业务缓存\n * - 事件错过兜底:初始化时校验 SHIKEAI_USER_INFO,游客态或账号与本地缓存不一致\n * 时按退出登录处理(切换账号防跨账号数据残留)\n * - 宿主同步:将当前后端服务器对应的 MCP 服务器配置(MCP 接入点 {服务器URL}/kb/mcp/v1、\n * 最新插件 Token)经 settings.mutate 写入 Host 半区注册的 knowledge\n * namespace(Host 半区 scope.watch 后自动销毁旧连接、重建 MCP 并重新注册\n * 工具);登录态页面加载即自动换发 Token 并同步(DSH 启动\n * 后 MCP 配置自动就绪),设置页新增首个服务器自动激活 / 切换 / 编辑 / 删除\n * 兜底激活时同步更新\n */\nimport { getActiveServer, getApiBase, getMcpEndpoint, subscribe } from './server-config.js'\nimport { exchangePluginToken, revokePluginToken } from './session.js'\nimport { describeHostMcpStatus, pushHostMcpConfig } from './host-mcp-sync.js'\nimport { resetAllStores } from '../store/reset.js'\n\n/** 插件自有 Token 持久化键(规范约定:skai_ 平台命名空间 + kb 业务域) */\nconst LS_TOKEN = 'skai_kb_token'\n/** Token 配套 uid(账号一致性兜底检测用) */\nconst LS_UID = 'skai_kb_uid'\n/** 旧版存储键(0.2.x 命名规范遗留),仅用于一次性迁移读取 */\nconst LEGACY_LS_TOKEN = 'skb_kb_token'\nconst LEGACY_LS_UID = 'skb_kb_uid'\n\nlet initialized = false\nlet disposed = false\n/** 插件自有 Token(内存缓存,懒恢复自 localStorage) */\nlet pluginToken = ''\n/** Token 配套 uid(0 = 未知) */\nlet cachedUid = 0\n/** 最近一次成功换发的 uid(跨清空保留,用于切换账号检测) */\nlet lastUid = 0\nlet hydrated = false\nlet exchangeInflight = null\nlet offServerConfig = null\n/** 已同步宿主的基址(变更即失效本地 Token:Token 与后端服务器绑定) */\nlet syncedApiBase = ''\n\nfunction hydrateOnce() {\n if (hydrated || typeof window === 'undefined') return\n hydrated = true\n try {\n if (!window.localStorage.getItem(LS_TOKEN) && window.localStorage.getItem(LEGACY_LS_TOKEN)) {\n window.localStorage.setItem(LS_TOKEN, window.localStorage.getItem(LEGACY_LS_TOKEN))\n if (window.localStorage.getItem(LEGACY_LS_UID)) {\n window.localStorage.setItem(LS_UID, window.localStorage.getItem(LEGACY_LS_UID))\n }\n window.localStorage.removeItem(LEGACY_LS_TOKEN)\n window.localStorage.removeItem(LEGACY_LS_UID)\n }\n pluginToken = window.localStorage.getItem(LS_TOKEN) || ''\n cachedUid = Number(window.localStorage.getItem(LS_UID)) || 0\n if (cachedUid) lastUid = cachedUid\n } catch {}\n}\n\nfunction persistLocalAuth(token, uid) {\n try {\n window.localStorage.setItem(LS_TOKEN, token)\n if (uid) window.localStorage.setItem(LS_UID, String(uid))\n } catch {}\n}\n\nfunction clearLocalAuth() {\n pluginToken = ''\n cachedUid = 0\n try {\n window.localStorage.removeItem(LS_TOKEN)\n window.localStorage.removeItem(LS_UID)\n } catch {}\n}\n\n/** 读取插件自有 Token(REST/MCP 鉴权头取值源;未换发时为空串) */\nexport function getPluginToken() {\n hydrateOnce()\n return pluginToken\n}\n\n/** 读取全局公开用户信息(只读,仅用于展示,不作为可信身份) */\nexport function getUserInfo() {\n if (typeof window === 'undefined') return null\n return window.SHIKEAI_USER_INFO || null\n}\n\n/** 是否已登录(用户中心已登录或本地仍持有有效插件 Token) */\nexport function isLoggedIn() {\n return Boolean(getPluginToken() || getUserInfo())\n}\n\n/** 调用用户中心 JS 验签接口(用户中心为唯一权威提供方);未挂载或游客态返回 null */\nasync function fetchSignCredential() {\n if (typeof window === 'undefined' || typeof window.SHIKEAI_GET_SIGN_CREDENTIAL !== 'function') return null\n try {\n return await window.SHIKEAI_GET_SIGN_CREDENTIAL()\n } catch {\n return null\n }\n}\n\n/**\n * 确保插件 Token 可用:已持有则直接返回;否则按需验签换发(并发请求去重)。\n * @returns {Promise<string>} 插件自有 Token\n * @throws {Error} 游客态(验签接口返回空)抛「请先在用户中心登录」;换发失败携带服务端 msg\n */\nexport function ensurePluginToken() {\n hydrateOnce()\n if (pluginToken) return Promise.resolve(pluginToken)\n if (!exchangeInflight) {\n exchangeInflight = (async () => {\n const cred = await fetchSignCredential()\n if (!cred || !cred.sign || !cred.message) {\n clearLocalAuth()\n resetAllStores()\n syncHostMcpAuth()\n notifyAuthChange('guest')\n const error = new Error('请先在用户中心登录')\n error.guest = true\n throw error\n }\n const data = await exchangePluginToken(cred.sign, cred.message)\n const uid = Number(data.uid) || 0\n if (lastUid && uid && lastUid !== uid) resetAllStores()\n if (uid) lastUid = uid\n pluginToken = data.token\n cachedUid = uid\n persistLocalAuth(pluginToken, uid)\n syncHostMcpAuth()\n return pluginToken\n })().finally(() => {\n exchangeInflight = null\n })\n }\n return exchangeInflight\n}\n\n/** 本地失效插件 Token(不清业务缓存;401 静默重验签前调用,下次请求重新换发) */\nexport function invalidatePluginToken() {\n pluginToken = ''\n cachedUid = 0\n exchangeInflight = null\n try {\n window.localStorage.removeItem(LS_TOKEN)\n window.localStorage.removeItem(LS_UID)\n } catch {}\n}\n\n/**\n * 将当前后端服务器对应的「知识库 MCP 服务器配置」同步至 DSH 宿主(settings 活配置\n * 通道,见 core/host-mcp-sync):经 mutate 把 {url, token} 写入 Host 半区注册的\n * knowledge namespace,由 dsh-settings-file provider 持久化到 ~/.dsh/settings.yaml\n * (重启不丢);Host 半区 scope.watch 值变化后自动销毁旧 MCP 连接、重建并重新注册\n * 工具(Token 换发 / 刷新后随 mutate 同步更新)。\n * 同步时机:页面加载(登录态且已配置当前服务器:云端配置到达即自动验签换发并\n * 同步,无需手动操作)、首次验签换发、401 重验签刷新、登录/退出/失效,以及当前\n * 服务器变化(设置页新增首个服务器自动激活、切换、编辑当前服务器地址、删除后\n * 兜底激活)。\n */\nexport function syncHostMcpAuth() {\n if (typeof window === 'undefined') return\n const active = getActiveServer()\n pushHostMcpConfig(\n Object.freeze({\n api_base: getApiBase(),\n mcp_endpoint: getMcpEndpoint(),\n server_name: active ? active.name : '',\n token: getPluginToken(),\n updated_at: Date.now(),\n }),\n )\n}\n\n/**\n * 页面加载/刷新自检:知识库 MCP 是否已在宿主配置就绪;未就绪时自动修复。\n * 链路:服务器已配置 + 已登录 → 确保插件 Token(换发成功即随链路推送宿主)→\n * 读取宿主 knowledge namespace 与期望值(当前接入点 + 插件 Token)比对,\n * 不一致(服务器切换/Token 换发后未同步)则重推一次;结构性问题\n * (namespace 未注册/settings 不可用)返回原因供页面可见化展示。\n * @returns {Promise<{status: string, detail: string}>}\n * ok | mismatch-fixed(已重推修复)| no-endpoint | no-token\n * | no-ctx | no-settings | no-namespace(后三者 detail 含可展示原因)\n */\nexport async function checkHostMcpReady() {\n if (typeof window === 'undefined') return { status: 'no-host', detail: '' }\n if (!getMcpEndpoint()) {\n return { status: 'no-endpoint', detail: '尚未配置知识库服务器(设置页配置后自动同步 MCP)' }\n }\n hydrateOnce()\n if (!pluginToken) {\n try {\n await ensurePluginToken()\n } catch (error) {\n return {\n status: 'no-token',\n detail: error && error.guest ? '请先在用户中心登录' : (error && error.message) || '插件 Token 换发失败',\n }\n }\n }\n const state = await describeHostMcpStatus()\n if (state.status === 'registered') {\n if (state.url === getMcpEndpoint() && state.hasToken) {\n return { status: 'ok', detail: '' }\n }\n // 值与期望不一致(namespace 刚由 client 自动注册为空值 / 服务器切换 /\n // Token 换发后未同步到宿主)→ 重推修复,推送链路完成后复核一次\n syncHostMcpAuth()\n for (let i = 0; i < 5; i++) {\n await new Promise((resolve) => setTimeout(resolve, 150))\n const after = await describeHostMcpStatus()\n if (after.status === 'registered' && after.url === getMcpEndpoint() && after.hasToken) {\n return { status: 'ok', detail: '' }\n }\n }\n return { status: 'mismatch-fixed', detail: '宿主 MCP 配置与当前服务器/登录态不一致,已重新同步(若反复出现请查看浏览器控制台 [knowledge] 日志)' }\n }\n return { status: state.status, detail: state.detail }\n}\n\n/** 账号切换统一处理:吊销旧会话 + 清本地态与业务缓存 + 清宿主残留 → 以新登录用户立即重验签换发并同步宿主 */\nfunction resyncForAccountSwitch() {\n const token = pluginToken\n clearLocalAuth()\n resetAllStores()\n syncHostMcpAuth()\n if (token) revokePluginToken(token)\n // 立即以新用户换发(用户中心事件派发时新会话已就绪):成功路径自动把新 Token 同步\n // 宿主 MCP,不留空窗、不等首个业务请求;失败(用户中心竞态/游客)保持空宿主配置,\n // 业务请求 401 时再兜底重验签\n ensurePluginToken().catch(() => {})\n notifyAuthChange('login')\n}\n\n/** 退出/失效统一处理:吊销后端会话(幂等)→ 清空本地登录态与业务缓存 → 同步宿主 */\nfunction handleExit(reason) {\n const token = pluginToken\n clearLocalAuth()\n resetAllStores()\n syncHostMcpAuth()\n revokePluginToken(token)\n notifyAuthChange(reason)\n}\n\n/** 用户中心 login 事件(含切换账号):按换号重同步(旧 Token 吊销 + 新用户立即换发) */\nfunction onLogin() {\n resyncForAccountSwitch()\n}\n\n/**\n * 用户资料更新(昵称/头像):只读同步广播刷新展示;\n * uid 变化(切换账号的用户中心实现可能仅派发 user-update 而非 logout+login)\n * 按换号重同步,否则插件 Token 与宿主 MCP 仍是旧用户身份(越权身份错位)\n */\nfunction onUserUpdate() {\n hydrateOnce()\n const info = getUserInfo()\n const uid = Number(info && (info.uid ?? info.member_id ?? info.memberId)) || 0\n if (lastUid && uid && lastUid !== uid) {\n resyncForAccountSwitch()\n return\n }\n notifyAuthChange('user-update')\n}\n\n/**\n * 初始化兜底:抽屉未打开期间可能错过全局事件——每次初始化校验\n * window.SHIKEAI_USER_INFO,游客态或账号与本地缓存不一致时按退出登录处理\n */\nfunction reconcileAuthState() {\n hydrateOnce()\n const info = getUserInfo()\n if (!info) {\n if (pluginToken) handleExit('logout')\n return\n }\n const currentUid = Number(info.uid ?? info.member_id ?? info.memberId) || 0\n if (pluginToken && cachedUid && currentUid && cachedUid !== currentUid) resyncForAccountSwitch()\n}\n\n/** 登录态变化广播(供 hooks 订阅刷新) */\nconst authListeners = new Set()\nexport function onAuthChange(listener) {\n authListeners.add(listener)\n return () => authListeners.delete(listener)\n}\n\nfunction notifyAuthChange(reason) {\n authListeners.forEach((fn) => {\n try {\n fn(reason)\n } catch {}\n })\n}\n\n/** 安装登录态事件监听(幂等;DSH client 与 standalone 路径共用) */\nexport function initAuth() {\n if (initialized || typeof window === 'undefined') return\n initialized = true\n disposed = false\n window.addEventListener('shikeai-usercenter:login', onLogin)\n window.addEventListener('shikeai-usercenter:logout', onLogoutHandler)\n window.addEventListener('shikeai-usercenter:expired', onExpiredHandler)\n window.addEventListener('shikeai-usercenter:user-update', onUserUpdate)\n syncedApiBase = getApiBase()\n offServerConfig = subscribe(() => {\n const apiBase = getApiBase()\n if (apiBase !== syncedApiBase) {\n // 仅当此前已有生效基址(内存态非空)才是真实的服务器切换——Token 与后端绑定\n // 须失效重验签;启动时云端配置首拉('' → X)属「采纳」:保留持久化 Token\n // (仍与该服务器绑定),避免误清后与用户中心静默恢复会话竞态时清空宿主配置\n const switched = Boolean(syncedApiBase)\n syncedApiBase = apiBase\n if (switched) invalidatePluginToken()\n syncHostMcpAuth()\n notifyAuthChange('server-switch')\n }\n // 启动自动生效:云端服务器配置到达(或用户中心静默恢复会话后重拉成功)即确保\n // 插件 Token 可用(过期自动重验签换发)并同步宿主 MCP 配置——DSH 启动后无需\n // 打开插件页面,已配置的知识库服务器与 MCP 检索即自动就绪\n if (getUserInfo() && getMcpEndpoint()) ensurePluginToken().catch(() => {})\n })\n reconcileAuthState()\n syncHostMcpAuth()\n}\n\n/** 卸载监听(client 半区 dispose / standalone deactivate 时调用) */\nexport function disposeAuth() {\n if (!initialized || disposed) return\n disposed = true\n window.removeEventListener('shikeai-usercenter:login', onLogin)\n window.removeEventListener('shikeai-usercenter:logout', onLogoutHandler)\n window.removeEventListener('shikeai-usercenter:expired', onExpiredHandler)\n window.removeEventListener('shikeai-usercenter:user-update', onUserUpdate)\n if (typeof offServerConfig === 'function') offServerConfig()\n offServerConfig = null\n initialized = false\n}\n\nfunction onLogoutHandler() {\n handleExit('logout')\n}\n\nfunction onExpiredHandler() {\n handleExit('expired')\n}\n","/**\n * REST 请求适配器(插件前端唯一出口,页面禁止直接 fetch / axios)\n *\n * - 请求前经 ensurePluginToken() 按需验签确保插件自有 Token(用户中心 sign+message\n * 换发),携带 Authorization: Bearer <插件 Token>\n * - 不内置默认地址:未配置服务器(getApiBase() 为空串)时直接抛\n * 「请先在设置页配置服务器信息」,不发任何网络请求\n * - 401 兜底:静默清除本地 Token → 重新验签换取新 Token → 重放原请求(仅一次);\n * 重验签仍失败(游客态/验签失效)时抛 401 由调用方引导登录\n * - 响应结构 { code, msg, data },code === 0 判定成功,返回 data\n * - 错误统一抛 ApiError(透出服务端 msg)\n */\nimport { getApiBase, APP_PATH } from './server-config.js'\nimport { REQUEST_TIMEOUT } from './config.js'\nimport { getPluginToken, isLoggedIn, ensurePluginToken, invalidatePluginToken } from './auth.js'\n\n/** 业务错误(携带 code 与服务端 msg,调用方统一以 error.msg 读取提示) */\nexport class ApiError extends Error {\n constructor(message, code = 0, data = null) {\n super(message)\n this.name = 'ApiError'\n this.code = code\n this.data = data\n this.msg = message\n }\n}\n\n/** 用户状态门禁专用错误码(后端 pkg/response 对应;管理员豁免,由服务端判定,\n * 前端经 toastError 以服务端 msg 提示) */\nexport const USER_STATUS_CODE = {\n PENDING: 40301,\n DISABLED: 40302,\n}\n\n/** 门禁命中后清空本地业务缓存(知识库列表/文档/目录树等):\n * DSH 标签页常驻不刷新,禁用后 store 旧快照会继续渲染首页数据,\n * 收到 40301/40302 时即时清空,各标签页随后的重新拉取仍会被门禁拦截(保持空态)。\n * 动态 import 避免 store ↔ core 循环依赖;重复调用幂等(setState 同一常量引用) */\nasync function resetBusinessStoresOnGate() {\n try {\n const { resetServerScopedStores } = await import('../store/reset.js')\n resetServerScopedStores()\n } catch {\n /* 清理失败不影响错误透出 */\n }\n}\n\nfunction withQuery(url, data) {\n const params = new URLSearchParams()\n Object.entries(data || {}).forEach(([key, value]) => {\n if (value !== undefined && value !== null) params.append(key, value)\n })\n const query = params.toString()\n return query ? `${url}?${query}` : url\n}\n\nfunction buildHeaders(hasBody) {\n const headers = {}\n const token = getPluginToken()\n if (token) headers.Authorization = `Bearer ${token}`\n if (hasBody && !(typeof FormData !== 'undefined' && hasBody instanceof FormData)) {\n headers['Content-Type'] = 'application/json'\n }\n return headers\n}\n\nasync function parseResponse(res) {\n let body = null\n try {\n body = await res.json()\n } catch {\n body = null\n }\n if (body && typeof body === 'object' && 'code' in body) {\n if (body.code === 0) return body.data\n if (body.code === USER_STATUS_CODE.PENDING || body.code === USER_STATUS_CODE.DISABLED) {\n void resetBusinessStoresOnGate()\n }\n throw new ApiError(body.msg || '请求失败', body.code, body.data)\n }\n if (res.status === 401) throw new ApiError('未登录或登录已失效', 401, null)\n throw new ApiError(`请求异常(HTTP ${res.status})`, res.status, null)\n}\n\nasync function doRequest(method, url, data = {}, options = {}, retried = false) {\n const apiBase = getApiBase()\n if (!apiBase) throw new ApiError('请先在设置页配置服务器信息', 0, null)\n if (!options.allowAnonymous) {\n if (!isLoggedIn()) throw new ApiError('请先在用户中心登录', 401, null)\n try {\n await ensurePluginToken()\n } catch (error) {\n throw error instanceof ApiError\n ? error\n : new ApiError(error.message || '登录状态校验失败', error.code || 401, null) // 保留门禁码(40301/40302)\n }\n }\n // 应用路径固定 /kb(服务器 URL 仅含协议+IP/端口,由前端统一拼装)\n let fullUrl = apiBase + APP_PATH + String(url)\n if (method === 'GET' || method === 'HEAD') fullUrl = withQuery(fullUrl, data)\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), options.timeout || REQUEST_TIMEOUT)\n try {\n return await parseResponse(\n await fetch(fullUrl, {\n method,\n headers: buildHeaders(options.body),\n body: options.body != null && method !== 'GET' && method !== 'HEAD' ? options.body : undefined,\n signal: controller.signal,\n }),\n )\n } catch (error) {\n if (error instanceof ApiError && error.code === 401) {\n if (!retried && !options.allowAnonymous) {\n invalidatePluginToken()\n try {\n await ensurePluginToken()\n return await doRequest(method, url, data, options, true)\n } catch {\n throw new ApiError('请先在用户中心登录', 401, null)\n }\n }\n throw error\n }\n if (error && error.name === 'AbortError') throw new ApiError('请求超时,请检查网络后重试', 0, null)\n // 业务错误(服务端已返回 {code, msg})原样透出,保留服务端 msg 供页面提示\n if (error instanceof ApiError) throw error\n throw new ApiError('网络连接失败,请检查内网后重试', 0, null)\n } finally {\n clearTimeout(timer)\n }\n}\n\n/** JSON 请求体封装 */\nfunction jsonBody(data) {\n return JSON.stringify(data || {})\n}\n\n/** 文件上传(multipart/form-data;extra 附加字段一并以 form 提交) */\nasync function upload(url, file, extra = {}, options = {}) {\n const form = new FormData()\n form.append('file', file, file.name || 'file')\n Object.entries(extra).forEach(([key, value]) => {\n if (value !== undefined && value !== null) form.append(key, value)\n })\n return doRequest('POST', url, {}, { ...options, body: form })\n}\n\nconst request = {\n get: (url, data, options) => doRequest('GET', url, data, options),\n post: (url, data, options) => doRequest('POST', url, {}, { ...options, body: jsonBody(data) }),\n put: (url, data, options) => doRequest('PUT', url, {}, { ...options, body: jsonBody(data) }),\n delete: (url, data, options) => doRequest('DELETE', url, {}, { ...options, body: data ? jsonBody(data) : null }),\n upload,\n}\n\nexport default request\n","/**\n * 知识库管理 REST(对应后端 /kb/kb/*)\n */\nimport request from '../core/request.js'\n\n/** 知识库列表(当前 uid 有权限的 + 公开的,置顶优先;keyword/tag 过滤 + 分页) */\nexport function listKb(params = {}) {\n return request.get('/kb/list', {\n keyword: params.keyword || '',\n tag: params.tag || '',\n page: params.page || 1,\n limit: params.limit || 20,\n })\n}\n\n/** 创建知识库:{ name, description, tags, enable_mcp, chunk_size, chunk_overlap } */\nexport function createKb(data) {\n return request.post('/kb/create', data)\n}\n\n/** 编辑知识库(含 MCP 检索开关、分段默认配置;所有者) */\nexport function updateKb(kbId, data) {\n return request.put(`/kb/${kbId}/update`, data)\n}\n\n/** 归档知识库(软删除;所有者) */\nexport function archiveKb(kbId) {\n return request.delete(`/kb/${kbId}/archive`)\n}\n\n/** 置顶 / 取消置顶知识库(管理员):{ pinned: boolean } */\nexport function pinKb(kbId, pinned) {\n return request.post(`/kb/${kbId}/pin`, { pinned: Boolean(pinned) })\n}\n\n/** 成员权限列表(所有者) */\nexport function listPermission(kbId) {\n return request.get(`/kb/${kbId}/permission`)\n}\n\n/**\n * 添加成员 / 修改角色:{ mobile?, uid, role }(所有者)。\n * 传 mobile 时按手机号添加:目标未登录过则落待激活授权,返回 { pending: boolean }\n */\nexport function grantPermission(kbId, data) {\n return request.post(`/kb/${kbId}/grant`, data)\n}\n\n/** 撤销待激活授权(所有者;pid=待激活记录 ID) */\nexport function revokePendingPermission(kbId, pid) {\n return request.delete(`/kb/${kbId}/pending/${pid}`)\n}\n\n/** 移除成员:{ uid }(所有者) */\nexport function revokePermission(kbId, uid) {\n return request.delete(`/kb/${kbId}/grant`, { uid })\n}\n","/**\n * 文档管理 REST(对应后端 /kb/kb/:id/doc/*)\n */\nimport request from '../core/request.js'\n\n/**\n * 上传文档(单文件,multipart)\n * @param {object} p { kbId, file, tags?, chunkSize?, chunkOverlap?, folderId? }\n */\nexport function uploadDoc({ kbId, file, tags, chunkSize, chunkOverlap, folderId }) {\n return request.upload(`/kb/${kbId}/doc/upload`, file, {\n tags: tags && tags.length ? JSON.stringify(tags) : '',\n chunk_size: chunkSize || '',\n chunk_overlap: chunkOverlap || '',\n folder_id: folderId || 0,\n })\n}\n\n/**\n * 文档列表(keyword 名称+文本检索、tag 过滤、folder_id 目录过滤、分页)\n * @param {number} [params.folderId] 缺省=全库;0=根目录;>0=指定目录\n * @param {boolean} [params.recursive] true=目录过滤展开为该目录及全部后代目录\n */\nexport function listDocs(kbId, params = {}) {\n return request.get(`/kb/${kbId}/doc/list`, {\n keyword: params.keyword || '',\n tag: params.tag || '',\n folder_id: params.folderId ?? '',\n recursive: params.recursive ? 1 : '',\n page: params.page || 1,\n limit: params.limit || 20,\n })\n}\n\n/** 文档元数据详情(GET /kb/:id/doc/:id) */\nexport function getDoc(kbId, docId) {\n return request.get(`/kb/${kbId}/doc/${docId}`)\n}\n\n/** 文档当前文本内容(在线预览;?version_no 可选历史版本) */\nexport function getDocContent(kbId, docId, versionNo) {\n return request.get(`/kb/${kbId}/doc/${docId}/content`, versionNo ? { version_no: versionNo } : {})\n}\n\n/** 历史版本列表 */\nexport function listDocVersions(kbId, docId) {\n return request.get(`/kb/${kbId}/doc/${docId}/versions`)\n}\n\n/** 回滚至历史版本(自动触发重新向量化) */\nexport function rollbackDoc(kbId, docId, versionNo) {\n return request.post(`/kb/${kbId}/doc/${docId}/rollback`, { version_no: versionNo })\n}\n\n/** 修改文档(重命名 / 标签 / 分段覆盖配置) */\nexport function updateDoc(kbId, docId, data) {\n return request.put(`/kb/${kbId}/doc/${docId}`, data)\n}\n\n/** 删除文档(软删) */\nexport function deleteDoc(kbId, docId) {\n return request.delete(`/kb/${kbId}/doc/${docId}`)\n}\n\n/** 失败文档重新解析(编辑者) */\nexport function reparseDoc(kbId, docId) {\n return request.post(`/kb/${kbId}/doc/${docId}/reparse`)\n}\n\n/** 移动文档到目标目录(folderId 0=根目录) */\nexport function moveDoc(kbId, docId, folderId) {\n return request.post(`/kb/${kbId}/doc/${docId}/move`, { folder_id: folderId || 0 })\n}\n\n/** 目录内文档拖拽排序(folderId + 有序 doc_id 数组整批提交) */\nexport function reorderDocs(kbId, folderId, docIds) {\n return request.post(`/kb/${kbId}/doc/reorder`, { folder_id: folderId || 0, doc_ids: docIds })\n}\n\n/**\n * 保存在线编辑内容(文本类文件;保存版本快照并触发重新解析/向量化)\n * @param {object} p { content, baseUpdatedAt, force? } baseUpdatedAt 为进入编辑时的 updated_at;\n * 冲突(HTTP 409)时由页面引导放弃/覆盖,覆盖传 force=true\n */\nexport function updateDocContent(kbId, docId, { content, baseUpdatedAt, force }) {\n return request.put(`/kb/${kbId}/doc/${docId}/content`, {\n content,\n base_updated_at: baseUpdatedAt || 0,\n force: !!force,\n })\n}\n","/**\n * DSH 输入框 `@` 触发源注册:`ctx.inputTriggers.registerSource(src)`(公开契约,\n * dsh-client-ui-input-trigger InputTriggerServiceContract)\n *\n * 用户在会话输入框敲 `@知识库` → 候选菜单列出全部知识库文档 → 选中后经\n * onPick 返回 { insert: ReferenceInsert },由宿主 pipeline 插入**不可编辑的\n * reference chip**(与 @file 引用同款块)。chip 发送时宿主逐个调用\n * serialize(ref) 序列化为模型文本(kb_id/doc_id 结构化标记),失败会阻断发送,\n * 保证语义不降级为纯文本。\n *\n * 生命周期:apply 注册 → 返回 disposer 由 client-entry 的 ctx.effect 撤销。\n */\nimport { listKb } from '../api/kb.js'\nimport { listDocs } from '../api/doc.js'\n\n/** 文档候选缓存(全部库 × 文档列表,30s TTL,避免每次敲 @ 都打 REST) */\nlet cache = null\nlet cacheAt = 0\nconst CACHE_TTL = 30 * 1000\n\n/** 触发源唯一 group 名(per-trigger 唯一,重复注册宿主会 throw) */\nexport const KB_TRIGGER_NAME = '知识库'\n\nasync function loadDocs() {\n if (cache && Date.now() - cacheAt < CACHE_TTL) return cache\n const kbRes = await listKb({ page: 1, limit: 100 })\n const kbs = (kbRes && kbRes.list) || []\n const pages = await Promise.all(\n kbs.map((kb) =>\n listDocs(kb.id, { page: 1, limit: 100 })\n .then((res) => ({ kb, docs: (res && res.list) || [] }))\n .catch(() => ({ kb, docs: [] })),\n ),\n )\n cache = pages.flatMap(({ kb, docs }) =>\n docs.map((d) => ({ kbId: Number(kb.id), kbName: kb.name, docId: Number(d.id), docName: d.name })),\n )\n cacheAt = Date.now()\n return cache\n}\n\n/** ref 编解码(source-owned opaque payload;JSON 数组 [kbId, docId, docName]) */\nexport function encodeRef(item) {\n return JSON.stringify([item.kbId, item.docId, item.docName])\n}\n\nfunction decodeRef(ref) {\n try {\n const [kbId, docId, docName] = JSON.parse(ref)\n return { kbId, docId, docName }\n } catch {\n return null\n }\n}\n\n/**\n * 引用整串 token:`文档名(kb_id:N,doc_id:M)`。lexicon 条目、serialize 输出(去 @)、\n * chip label 三者逐字一致且内部无空格——无论气泡走文本匹配还是 label 渲染,\n * 名称与 id 都整体进 chip,不产生游离括号文本\n */\nexport function refToken(item) {\n return `${item.docName}(kb_id:${item.kbId},doc_id:${item.docId})`\n}\n\n/** 剪贴板投影:`知识库文档:文档名(kb_id: N, doc_id: M)`(onPick 与 codec.clipboardText 共用) */\nfunction refClipboardText(item) {\n return `知识库文档:${item.docName}(kb_id: ${item.kbId}, doc_id: ${item.docId})`\n}\n\n/**\n * serialize 输出形式:`@文档名 (kb_id: N, doc_id: M)`。发送后消息文本经\n * lexicon 精确匹配装饰成 chip(@文件 同款);其后括号补 kb_id/doc_id 结构化标记,\n * 供 AI 解析调 MCP 工具与「存入知识库」覆盖模式默认选中。\n * 程序化插芯片(DocDetailPage 引用按钮)的占位文本同用此形式——芯片插入\n * 失败时退化为纯文本仍可被 lexicon 装饰、可被 AI 解析\n */\nexport function refSerializeText(item) {\n return `@${item.docName} (kb_id: ${item.kbId}, doc_id: ${item.docId})`\n}\n\n/**\n * 构造与 `@知识库` onPick 插入完全同构的 ReferenceInsert(供文档详情页\n * 「引用文档到会话」经 SessionInput facade.insertReference 程序化插入芯片)\n */\nexport function buildDocReferenceInsert(item) {\n return {\n source: KB_TRIGGER_NAME,\n ref: encodeRef(item),\n // chip 显示文本 = label,整串含 id\n label: refToken(item),\n appearance: 'file',\n clipboardText: refClipboardText(item),\n }\n}\n\n/**\n * 注册 `@知识库` 触发源。重复注册(宿主 duplicate throw)安全降级为 no-op。\n * @param {object} ctx client 半区 ctx(需可解出 inputTriggers 服务)\n * @returns {() => void} disposer(撤销注册;不可用时为 no-op)\n */\nexport function registerKbTriggerSource(ctx) {\n const svc = ctx && ctx.inputTriggers\n if (!svc || typeof svc.registerSource !== 'function') return () => {}\n try {\n const disposer = svc.registerSource({\n trigger: '@',\n name: KB_TRIGGER_NAME,\n order: 30,\n async candidates(_session, req) {\n const query = String((req && req.query) || '').trim().toLowerCase()\n const docs = await loadDocs()\n const hit = query\n ? docs.filter((d) => d.docName.toLowerCase().includes(query) || d.kbName.toLowerCase().includes(query))\n : docs\n return hit.slice(0, 30).map((d) => ({\n name: d.docName,\n description: `知识库:${d.kbName}`,\n section: d.kbName,\n value: encodeRef(d),\n }))\n },\n onPick(pick) {\n const value = pick && pick.candidate && typeof pick.candidate.value === 'string' ? pick.candidate.value : ''\n const item = decodeRef(value)\n if (!item) return 'handled'\n return { insert: buildDocReferenceInsert(item) }\n },\n /**\n * scope-birth 预热:拉全量文档填缓存,让 lexicon 尽早就绪\n * (发送后的消息文本要靠 lexicon 装饰回 chip 样式)\n */\n warm() {\n loadDocs().catch(() => {})\n },\n /**\n * plain-text reference decoration(同步热快照,禁止 fetch):\n * 渲染侧扫描消息文本中的 `@<name>` token,精确匹配 lexicon 即装饰成 chip\n * (与 @文件 发送后样式同机制)。undefined = 未热,不装饰\n */\n lexicon() {\n return cache ? cache.map((d) => d.docName) : undefined\n },\n /**\n * Reference codec(必须挂 codec 字段——发送时宿主经 roster 找 owner.codec.serialize,\n * 缺失报 \"slash: no serializer for reference source\"):\n * serialize 必须输出 `@<文档名>` token——发送后的消息文本经 lexicon\n * 精确匹配装饰成 chip(@文件 同款);其后括号补 kb_id/doc_id 结构化标记,\n * 供 AI 解析调 MCP 工具与「存入知识库」覆盖模式默认选中\n */\n codec: {\n clipboardText(ref) {\n const item = decodeRef(ref)\n return item ? refClipboardText(item) : '知识库文档(引用已失效)'\n },\n async serialize(ref) {\n const item = decodeRef(ref)\n if (!item) throw new Error('知识库引用已失效,请删除该引用后重试')\n return refSerializeText(item)\n },\n },\n })\n return typeof disposer === 'function' ? disposer : () => {}\n } catch (e) {\n // duplicate (trigger,name):多半是热重载后残留注册,忽略即可\n console.warn('[kb-trigger] 注册 @知识库 触发源失败(可能已注册):', e && e.message)\n return () => {}\n }\n}\n","/**\n * 任务查询 REST(对应后端 /kb/task/*;重建向量为所有者操作)\n */\nimport request from '../core/request.js'\n\n/** 重建知识库全量向量(所有者) */\nexport function rebuildVector(kbId) {\n return request.post(`/kb/${kbId}/rebuild-vector`)\n}\n","/**\n * 登录态与管理员 REST(对应后端 /kb/auth/*)\n */\nimport request from '../core/request.js'\n\n/**\n * 查询当前后端是否已存在管理员\n * @returns {Promise<{ exists: boolean, is_admin: boolean }>} 需登录态;is_admin=当前用户是否管理员\n */\nexport function adminExists() {\n return request.get('/auth/admin/exists')\n}\n\n/** 初始化第一个管理员(将当前登录用户设为管理员;仅当不存在时生效) */\nexport function initAdmin() {\n return request.post('/auth/init-admin')\n}\n\n/**\n * 查询管理员列表(需登录态;登录用户均可查看)\n * @returns {Promise<{ list: Array<{ id: number, uid: number, create_time: number, update_time: number }>, pending: Array<{ id: number, masked_mobile: string, create_time: number }> }>}\n * pending=待激活授权(按手机号预添加、目标用户尚未登录过)\n */\nexport function listAdmins() {\n return request.get('/auth/admin/list')\n}\n\n/**\n * 按 uid 添加管理员(仅管理员;uid 经用户中心手机号解析而来,即时生效)\n */\nexport function addAdminByUid(uid) {\n return request.post('/auth/admin/add', { uid })\n}\n\n/**\n * 按手机号添加管理员(仅管理员;目标未登录过知识库时落待激活授权)\n * @returns {Promise<{ pending: boolean }>} pending=true 表示创建的是待激活授权\n */\nexport function addAdminByMobile(mobile) {\n return request.post('/auth/admin/add', { mobile })\n}\n\n/** 撤销管理员待激活授权(仅管理员) */\nexport function removeAdminPending(pid) {\n return request.delete(`/auth/admin/pending/${pid}`)\n}\n\n/** 删除管理员(仅管理员;最后一个管理员不可删除) */\nexport function removeAdmin(uid) {\n return request.delete(`/auth/admin/${uid}`)\n}\n","/**\n * 文件类型工具:支持格式判定、隐藏文件过滤、大小格式化\n * 支持格式:md / txt / pdf / docx / 电子表格(xlsx/xlsm/csv)/ PPT(pptx)/\n * 图片(jpg/jpeg/png/webp/bmp/gif,走视觉模型 OCR 识别)\n */\n\nexport const SUPPORTED_EXTS = [\n '.md', '.txt', '.pdf', '.docx',\n '.xlsx', '.xlsm', '.csv', '.pptx',\n '.jpg', '.jpeg', '.png', '.webp', '.bmp', '.gif',\n]\n\nexport const EXT_LABEL = {\n '.md': 'Markdown',\n '.txt': '文本',\n '.pdf': 'PDF',\n '.docx': 'Word',\n '.xlsx': 'Excel',\n '.xlsm': 'Excel',\n '.csv': 'CSV',\n '.pptx': 'PPT',\n '.jpg': '图片',\n '.jpeg': '图片',\n '.png': '图片',\n '.webp': '图片',\n '.bmp': '图片',\n '.gif': '图片',\n}\n\n/** 是否支持解析的文件(按扩展名) */\nexport function isSupportedFile(name) {\n const ext = extOf(name)\n return SUPPORTED_EXTS.includes(ext)\n}\n\n/** 扩展名(小写,含点) */\nexport function extOf(name) {\n const base = String(name).split('/').pop() || ''\n const idx = base.lastIndexOf('.')\n return idx >= 0 ? base.slice(idx).toLowerCase() : ''\n}\n\n/** 字节大小格式化 */\nexport function formatSize(bytes) {\n const n = Number(bytes) || 0\n if (n < 1024) return `${n} B`\n if (n < 1048576) return `${(n / 1024).toFixed(1)} KB`\n return `${(n / 1024 / 1024).toFixed(2)} MB`\n}\n\n/** Unix 秒时间戳 → 本地时间文案 */\nexport function formatTime(sec) {\n if (!sec) return '-'\n const d = new Date(Number(sec) * 1000)\n const pad = (x) => String(x).padStart(2, '0')\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`\n}\n","/**\n * 知识库卡片:文档总数/向量块数/最后更新时间/MCP 开关 + 角色驱动的操作按钮\n * isSysadmin 为 true 时展示置顶/取消置顶(管理员专属能力)\n * onOpen 打开「知识库详情」标签页;onOpenPermission 打开详情页并弹出权限配置\n */\nimport { ROLE_LABEL } from '../../store/kb-store.js'\nimport { formatTime } from '../../utils/file-type.js'\n\nexport default function KbCard({\n kb,\n isAdmin,\n isSysadmin,\n onOpen,\n onOpenPermission,\n onEdit,\n onArchive,\n onRebuild,\n onPin,\n}) {\n return (\n <div className=\"skai-kb-card\">\n <div className=\"skai-kb-row-between\">\n <span className=\"skai-kb-title\" title={kb.name}>\n {kb.pinned ? '📌 ' : ''}\n {kb.name}\n </span>\n <span className={`skai-kb-badge ${kb.enable_mcp ? 'skai-kb-badge-green' : 'skai-kb-badge-gray'}`}>\n {kb.enable_mcp ? 'MCP 开' : 'MCP 关'}\n </span>\n </div>\n {kb.description ? (\n <div className=\"skai-kb-sub\" title={kb.description}>\n {kb.description}\n </div>\n ) : null}\n {kb.tags && kb.tags.length ? (\n <div style={{ marginTop: 4 }}>\n {kb.tags.map((t) => (\n <span key={t} className=\"skai-kb-tag\">\n {t}\n </span>\n ))}\n </div>\n ) : null}\n <div className=\"skai-kb-kb-meta\">\n <span>\n 📄 {kb.doc_count ?? 0} 文档\n </span>\n <span>\n 🧩 {kb.chunk_count ?? 0} 向量块\n </span>\n <span>🕒 {formatTime(kb.update_time)}</span>\n <span className={`skai-kb-badge ${kb.my_role === 1 || kb.my_role === 5 ? 'skai-kb-badge-blue' : 'skai-kb-badge-gray'}`}>\n {ROLE_LABEL[kb.my_role] || '只读'}\n </span>\n </div>\n <div className=\"skai-kb-kb-actions\">\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-sm skai-kb-btn-primary\" onClick={() => onOpen(kb)}>\n 文档\n </button>\n {isSysadmin ? (\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-sm\" onClick={() => onPin(kb)}>\n {kb.pinned ? '取消置顶' : '置顶'}\n </button>\n ) : null}\n {isAdmin ? (\n <>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-sm\" onClick={() => onOpenPermission(kb)}>\n 权限\n </button>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-sm\" onClick={() => onEdit(kb)}>\n 编辑\n </button>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-sm\" onClick={() => onRebuild(kb)}>\n 重建向量\n </button>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm skai-kb-btn-ghost-danger\"\n onClick={() => onArchive(kb)}\n >\n 归档\n </button>\n </>\n ) : null}\n </div>\n </div>\n )\n}\n","/**\n * 通用弹窗(createPortal 挂载 document.body;遮罩 fixed 铺满整个窗口并居中,与 CRM 同款范式;\n * z-index 30 ≤ 35 不覆盖宿主设置菜单;弹层根 .skai-kb-modal-mask 已纳入主题令牌作用域,\n * 脱离 .skai-kb-root 祖先后 var(--skai-kb-*) 仍可解析)\n * - width:自定义弹窗最大宽度(默认 520px);fullscreen=true 时铺满窗口(忽略 width)\n * - extraHead:头部标题右侧、关闭按钮左侧的操作区(如全屏切换按钮)\n * - escClose:Esc 关闭开关;多层弹窗叠加时底层弹窗传 false,保证 Esc 只关顶层\n * - locked:锁定态(如 AI 编写运行中)——遮罩点击不关闭、隐藏标题栏关闭按钮,\n * 配合 escClose=false 实现仅显式操作(如「取消等待」按钮)可关闭\n */\nimport { useLayoutEffect } from 'react'\nimport { createPortal } from 'react-dom'\n\nexport default function Modal({ title, onClose, children, footer, width, fullscreen = false, extraHead, escClose = true, locked = false }) {\n useLayoutEffect(() => {\n if (!escClose) return undefined\n const onKey = (e) => {\n if (e.key === 'Escape') onClose?.()\n }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [onClose, escClose])\n\n return createPortal(\n <div\n className=\"skai-kb-modal-mask\"\n onMouseDown={(e) => e.target === e.currentTarget && !locked && onClose?.()}\n >\n <div\n className={`skai-kb-modal${fullscreen ? ' is-fullscreen' : ''}`}\n style={width && !fullscreen ? { maxWidth: width } : undefined}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n >\n <div className=\"skai-kb-modal-head\">\n <span className=\"skai-kb-modal-title\">{title}</span>\n <span className=\"skai-kb-modal-head-actions\">\n {extraHead}\n {!locked ? (\n <button type=\"button\" className=\"skai-kb-icon-btn\" aria-label=\"关闭\" onClick={onClose}>\n ✕\n </button>\n ) : null}\n </span>\n </div>\n <div className=\"skai-kb-modal-body\">{children}</div>\n {footer ? <div className=\"skai-kb-modal-foot\">{footer}</div> : null}\n </div>\n </div>,\n document.body,\n )\n}\n","/**\n * 表单校验:名称/标签校验、分块参数范围校验、uid 校验\n */\n\n/** 知识库名称:1-64 字符 */\nexport function validateKbName(name) {\n const v = String(name || '').trim()\n if (!v) return '请输入知识库名称'\n if (v.length > 64) return '知识库名称不能超过 64 字符'\n return ''\n}\n\n/** 标签解析与校验:逗号/空格分隔,去重,最多 20 个、单个 ≤ 32 字符 */\nexport function parseTags(input) {\n const raw = Array.isArray(input) ? input : String(input || '').split(/[,,\\s]+/)\n const seen = new Set()\n const tags = []\n for (let t of raw) {\n t = String(t).trim()\n if (!t || seen.has(t)) continue\n if (t.length > 32) return { tags: [], error: `标签「${t}」超过 32 字符` }\n seen.add(t)\n tags.push(t)\n if (tags.length >= 20) break\n }\n return { tags, error: '' }\n}\n\n/** 块大小范围:100-4000 字符 */\nexport function validateChunkSize(size) {\n const n = Number(size)\n if (!Number.isFinite(n)) return '块大小必须为数字'\n if (n < 100 || n > 4000) return '块大小范围为 100-4000'\n return ''\n}\n\n/** 重叠长度范围:0-500,且必须小于块大小 */\nexport function validateChunkOverlap(overlap, chunkSize) {\n const n = Number(overlap)\n if (!Number.isFinite(n)) return '重叠长度必须为数字'\n if (n < 0 || n > 500) return '重叠长度范围为 0-500'\n if (Number(chunkSize) && n >= Number(chunkSize)) return '重叠长度必须小于块大小'\n return ''\n}\n\n/** 中国大陆手机号:11 位,1 开头第二位 3-9(容忍空格/连字符分隔) */\nexport function validateMobile(mobile) {\n const v = String(mobile || '').replace(/[\\s-]/g, '')\n if (!/^1[3-9]\\d{9}$/.test(v)) return '手机号格式不正确(需为 11 位大陆手机号)'\n return ''\n}\n","/**\n * 业务标签选择器:输入 + 已有标签点击选择(逗号/空格分隔,去重)\n */\nimport { useState } from 'react'\nimport { parseTags } from '../../utils/validator.js'\n\nexport default function TagPicker({ value = [], onChange, placeholder = '输入标签后回车,逗号分隔' }) {\n const [input, setInput] = useState('')\n const commit = () => {\n const { tags, error } = parseTags(input)\n if (error) return\n onChange([...new Set([...(value || []), ...tags])].slice(0, 20))\n setInput('')\n }\n const remove = (tag) => onChange((value || []).filter((t) => t !== tag))\n return (\n <div>\n {value && value.length ? (\n <div style={{ marginBottom: 6 }}>\n {value.map((tag) => (\n <span\n key={tag}\n className=\"skai-kb-tag\"\n role=\"button\"\n tabIndex={0}\n onClick={() => remove(tag)}\n onKeyDown={(e) => e.key === 'Enter' && remove(tag)}\n title=\"点击移除\"\n >\n {tag} ✕\n </span>\n ))}\n </div>\n ) : null}\n <input\n className=\"skai-kb-input\"\n value={input}\n placeholder={placeholder}\n onChange={(e) => setInput(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault()\n commit()\n }\n }}\n onBlur={commit}\n />\n </div>\n )\n}\n","/**\n * 创建/编辑知识库弹窗:名称、描述、标签、MCP 检索开关、知识库级默认分段配置(所有者)\n */\nimport { useState } from 'react'\nimport Modal from '../common/Modal.jsx'\nimport TagPicker from './TagPicker.jsx'\nimport { validateKbName, validateChunkSize, validateChunkOverlap } from '../../utils/validator.js'\n\n/** 默认分段参数(与后端 config.yaml 默认值一致) */\nexport const DEFAULT_CHUNK_SIZE = 800\nexport const DEFAULT_CHUNK_OVERLAP = 100\n\nexport default function KbFormModal({ initial, busy = false, onSubmit, onClose }) {\n const isEdit = Boolean(initial && initial.id)\n const [name, setName] = useState(initial?.name || '')\n const [description, setDescription] = useState(initial?.description || '')\n const [tags, setTags] = useState(initial?.tags || [])\n const [enableMcp, setEnableMcp] = useState(initial ? Boolean(initial.enable_mcp) : true)\n const [chunkSize, setChunkSize] = useState(initial?.chunk_size || DEFAULT_CHUNK_SIZE)\n const [chunkOverlap, setChunkOverlap] = useState(initial?.chunk_overlap || DEFAULT_CHUNK_OVERLAP)\n const [error, setError] = useState('')\n\n const submit = () => {\n let msg = validateKbName(name)\n if (!msg) msg = validateChunkSize(chunkSize)\n if (!msg) msg = validateChunkOverlap(chunkOverlap, chunkSize)\n if (msg) {\n setError(msg)\n return\n }\n onSubmit({\n name: name.trim(),\n description: description.trim(),\n tags,\n enable_mcp: enableMcp ? 1 : 0,\n chunk_size: Number(chunkSize),\n chunk_overlap: Number(chunkOverlap),\n })\n }\n\n return (\n <Modal\n title={isEdit ? '编辑知识库' : '创建知识库'}\n onClose={onClose}\n footer={\n <>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={onClose} disabled={busy}>\n 取消\n </button>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-primary\" onClick={submit} disabled={busy}>\n {busy ? '保存中…' : '保存'}\n </button>\n </>\n }\n >\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">名称 *</span>\n <input\n className=\"skai-kb-input\"\n value={name}\n maxLength={64}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"知识库名称\"\n />\n </div>\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">描述</span>\n <textarea\n className=\"skai-kb-textarea\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"知识库用途说明(可选)\"\n />\n </div>\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">业务标签</span>\n <TagPicker value={tags} onChange={setTags} />\n </div>\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">分段默认配置</span>\n <div className=\"skai-kb-field-row\">\n <input\n className=\"skai-kb-input\"\n type=\"number\"\n min={100}\n max={4000}\n value={chunkSize}\n onChange={(e) => setChunkSize(e.target.value)}\n placeholder=\"块大小\"\n aria-label=\"块大小\"\n />\n <input\n className=\"skai-kb-input\"\n type=\"number\"\n min={0}\n max={500}\n value={chunkOverlap}\n onChange={(e) => setChunkOverlap(e.target.value)}\n placeholder=\"重叠长度\"\n aria-label=\"重叠长度\"\n />\n </div>\n </div>\n <label className=\"skai-kb-row\" style={{ cursor: 'pointer' }}>\n <input type=\"checkbox\" checked={enableMcp} onChange={(e) => setEnableMcp(e.target.checked)} />\n <span>允许智能体通过 MCP 检索该知识库</span>\n </label>\n {error ? <div className=\"skai-kb-field-error\">{error}</div> : null}\n </Modal>\n )\n}\n","/** 危险操作确认弹窗(归档知识库 / 删除文档 / 移除成员等) */\nimport Modal from './Modal.jsx'\n\nexport default function ConfirmDialog({\n title = '确认操作',\n message,\n confirmText = '确认',\n danger = true,\n busy = false,\n onConfirm,\n onClose,\n}) {\n return (\n <Modal\n title={title}\n onClose={onClose}\n footer={\n <>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={onClose} disabled={busy}>\n 取消\n </button>\n <button\n type=\"button\"\n className={`skai-kb-btn ${danger ? 'skai-kb-btn-danger' : 'skai-kb-btn-primary'}`}\n onClick={onConfirm}\n disabled={busy}\n >\n {busy ? '处理中…' : confirmText}\n </button>\n </>\n }\n >\n <p className=\"skai-kb-confirm-text\">{message}</p>\n </Modal>\n )\n}\n","/** 全局 Toast(错误处理统一出口:ApiError 透出的服务端 msg 在此展示)\n * 经 createPortal 挂到 document.body + position:fixed——相对整个 DSH 窗口居中,\n * 而非插件标签页区域(与 Modal 同款挂载策略) */\nimport { createPortal } from 'react-dom'\nimport { useStore } from '../../store/create-store.js'\nimport { uiStore, dismissToast } from '../../store/ui-store.js'\n\nexport default function Toast() {\n const toasts = useStore(uiStore, (s) => s.toasts)\n if (!toasts.length) return null\n return createPortal(\n <div className=\"skai-kb-toast-layer\" role=\"status\" aria-live=\"polite\">\n {toasts.map((t) => (\n <div\n key={t.id}\n className={`skai-kb-toast skai-kb-toast-${t.type}`}\n onClick={() => dismissToast(t.id)}\n >\n {t.message}\n </div>\n ))}\n </div>,\n document.body,\n )\n}\n","/**\n * 插件自绘图形(简单书本 / 设置齿轮 Glyph,随包自带,避免依赖共享图标集)\n * 用途:引导页胶囊图标、标签页内页头、首页右上角设置入口\n */\nimport { createElement } from 'react'\n\n/** 等待转圈(16 viewBox 3/4 圆弧,stroke=currentColor;配合 .skai-kb-spin 旋转动画使用) */\nexport function SpinnerGlyph({ size = 13 }) {\n return createElement(\n 'svg',\n {\n className: 'skai-kb-spin',\n width: size,\n height: size,\n viewBox: '0 0 16 16',\n fill: 'none',\n 'aria-hidden': true,\n },\n createElement('circle', {\n cx: 8,\n cy: 8,\n r: 6,\n stroke: 'currentColor',\n 'stroke-opacity': 0.25,\n 'stroke-width': 2,\n }),\n createElement('path', {\n d: 'M14 8a6 6 0 0 0-6-6',\n stroke: 'currentColor',\n 'stroke-width': 2,\n 'stroke-linecap': 'round',\n }),\n )\n}\n\nexport function KnowledgeGlyph({ size = 20 }) {\n return createElement(\n 'svg',\n {\n width: size,\n height: size,\n viewBox: '0 0 20 20',\n fill: 'none',\n 'aria-hidden': true,\n },\n createElement('path', {\n d: 'M3 4.2C3 3.54 3.54 3 4.2 3H8a2.8 2.8 0 0 1 2 2.8V17a2.4 2.4 0 0 0-2.4-2.4H4.2A1.2 1.2 0 0 1 3 13.4V4.2Z',\n fill: 'currentColor',\n opacity: 0.55,\n }),\n createElement('path', {\n d: 'M17 4.2C17 3.54 16.46 3 15.8 3H12a2.8 2.8 0 0 0-2 2.8V17a2.4 2.4 0 0 1 2.4-2.4h3.4a1.2 1.2 0 0 0 1.2-1.2V4.2Z',\n fill: 'currentColor',\n }),\n )\n}\n\n/** 书本 + 加号(线性风格;「添加到知识库」动作图标,与宿主操作行线性图标同系列) */\nexport function BookPlusGlyph({ size = 15 }) {\n return createElement(\n 'svg',\n {\n width: size,\n height: size,\n viewBox: '0 0 24 24',\n fill: 'none',\n stroke: 'currentColor',\n strokeWidth: 1.8,\n strokeLinecap: 'round',\n strokeLinejoin: 'round',\n 'aria-hidden': true,\n },\n createElement('path', {\n d: 'M4 19.5V5a2.5 2.5 0 0 1 2.5-2.5H20V17H6.5A2.5 2.5 0 0 0 4 19.5Zm0 0A2.5 2.5 0 0 0 6.5 22H20',\n }),\n createElement('path', {\n d: 'M12 7.5v5M9.5 10h5',\n }),\n )\n}\n\n/** 书本 + 放大镜(线性风格;「引用知识库」动作图标,检索知识库语义,\n * 书本轮廓与 BookPlusGlyph 同款,与操作行线性图标同系列) */\nexport function BookSearchGlyph({ size = 15 }) {\n return createElement(\n 'svg',\n {\n width: size,\n height: size,\n viewBox: '0 0 24 24',\n fill: 'none',\n stroke: 'currentColor',\n strokeWidth: 1.8,\n strokeLinecap: 'round',\n strokeLinejoin: 'round',\n 'aria-hidden': true,\n },\n createElement('path', {\n d: 'M4 19.5V5a2.5 2.5 0 0 1 2.5-2.5H20V17H6.5A2.5 2.5 0 0 0 4 19.5Zm0 0A2.5 2.5 0 0 0 6.5 22H20',\n }),\n createElement('circle', { cx: 11.8, cy: 9.4, r: 2.7 }),\n createElement('path', {\n d: 'm14 11.6 2.3 2.3',\n }),\n )\n}\n\n/**\n * 操作小图标(与 CRM 插件 Glyph 同款几何:20 viewBox,fill=currentColor,随文字色着色)\n * P:路径表(按需补充);Glyph:通用单 path 图标渲染器\n */\nexport function Glyph({ size = 14, d, filled = true }) {\n return createElement(\n 'svg',\n {\n width: size,\n height: size,\n viewBox: '0 0 20 20',\n fill: 'none',\n 'aria-hidden': true,\n },\n createElement('path', {\n d,\n fill: filled ? 'currentColor' : 'none',\n stroke: filled ? 'none' : 'currentColor',\n strokeWidth: 1.5,\n }),\n )\n}\n\nexport const P = {\n plus: 'M10 4a.9.9 0 0 1 .9.9V9.1h4.2a.9.9 0 1 1 0 1.8H10.9v4.2a.9.9 0 1 1-1.8 0V10.9H4.9a.9.9 0 1 1 0-1.8h4.2V4.9A.9.9 0 0 1 10 4Z',\n refresh:\n 'M10 3.5a6.5 6.5 0 0 1 5.6 3.2l1.6-1v4.2h-4.2l1.4-1.4A4.7 4.7 0 0 0 10 5.3 4.7 4.7 0 0 0 5.3 10H3.5A6.5 6.5 0 0 1 10 3.5Zm-7.2 6.8h4.2l-1.4 1.4A4.7 4.7 0 0 0 10 14.7a4.7 4.7 0 0 0 4.7-4.7h1.8A6.5 6.5 0 0 1 4.4 13.3l-1.6 1V10.3Z',\n}\n\n/** 设置齿轮(线性风格;currentColor 随文字色,主题自适应) */\nexport function SettingsGlyph({ size = 20 }) {\n return createElement(\n 'svg',\n {\n width: size,\n height: size,\n viewBox: '0 0 20 20',\n fill: 'none',\n 'aria-hidden': true,\n },\n createElement('path', {\n d: 'M10 12.4a2.4 2.4 0 1 0 0-4.8 2.4 2.4 0 0 0 0 4.8Z',\n stroke: 'currentColor',\n strokeWidth: 1.5,\n }),\n createElement('path', {\n d: 'M16.32 12.24a1.42 1.42 0 0 0 .29 1.57l.05.05a1.72 1.72 0 1 1-2.43 2.43l-.05-.05a1.42 1.42 0 0 0-1.57-.29 1.42 1.42 0 0 0-.86 1.3v.14a1.72 1.72 0 0 1-3.44 0v-.08a1.42 1.42 0 0 0-.93-1.3 1.42 1.42 0 0 0-1.57.29l-.05.05a1.72 1.72 0 1 1-2.43-2.43l.05-.05a1.42 1.42 0 0 0 .29-1.57 1.42 1.42 0 0 0-1.3-.86h-.14a1.72 1.72 0 0 1 0-3.44h.08a1.42 1.42 0 0 0 1.3-.93 1.42 1.42 0 0 0-.29-1.57l-.05-.05A1.72 1.72 0 1 1 5.71 3.2l.05.05a1.42 1.42 0 0 0 1.57.29h.07a1.42 1.42 0 0 0 .86-1.3v-.14a1.72 1.72 0 0 1 3.44 0v.08a1.42 1.42 0 0 0 .86 1.3 1.42 1.42 0 0 0 1.57-.29l.05-.05a1.72 1.72 0 1 1 2.43 2.43l-.05.05a1.42 1.42 0 0 0-.29 1.57v.07a1.42 1.42 0 0 0 1.3.86h.14a1.72 1.72 0 0 1 0 3.44h-.08a1.42 1.42 0 0 0-1.3.86Z',\n stroke: 'currentColor',\n strokeWidth: 1.5,\n strokeLinejoin: 'round',\n }),\n )\n}\n\nexport default KnowledgeGlyph\n\n/**\n * 全屏 / 退出全屏(宿主 DSH 右侧边栏右上角同款 16×16 图标,path 数据逐字取自宿主渲染结果)\n * g 上 fill/stroke 均为 currentColor,随按钮文字色自适应主题\n */\nconst FULLSCREEN_PATHS = [\n 'M6.04798 2.13627V0.815964H5.99549L5.36158 0.817345V0.815964L3.39978 0.815274C3.01892 0.815274 2.67749 0.814821 2.39919 0.844967C2.10813 0.87655 1.80506 0.949512 1.52981 1.14949C1.3822 1.25681 1.25251 1.38652 1.14518 1.53412C0.945217 1.80935 0.872245 2.11246 0.840659 2.4035C0.810509 2.68178 0.810965 3.02324 0.810966 3.40409L0.811656 5.36589V5.9998L0.810966 6.05297L0.864137 6.05228H2.13196L2.18513 6.05297L2.18444 5.9998V5.36589L2.18513 3.40409C2.18513 2.99322 2.18631 2.73978 2.20653 2.55266C2.22499 2.38234 2.25273 2.34575 2.25556 2.34204C2.27837 2.31066 2.30635 2.28267 2.33774 2.25987C2.34207 2.25657 2.37978 2.22911 2.54835 2.21084C2.73548 2.19063 2.98893 2.18944 3.39978 2.18944L5.36158 2.18875L5.9948 2.18944H6.04867L6.04798 2.13627Z',\n 'M9.94031 13.86L9.94031 15.1803L9.99279 15.1803L10.6267 15.179L10.6267 15.1803L12.5885 15.181C12.9694 15.181 13.3108 15.1815 13.5891 15.1513C13.8801 15.1198 14.1832 15.0468 14.4585 14.8468C14.6061 14.7395 14.7358 14.6098 14.8431 14.4622C15.0431 14.187 15.116 13.8838 15.1476 13.5928C15.1778 13.3145 15.1773 12.9731 15.1773 12.5922L15.1766 10.6304L15.1766 9.9965L15.1773 9.94333L15.1241 9.94402L13.8563 9.94402L13.8032 9.94333L13.8038 9.9965L13.8038 10.6304L13.8032 12.5922C13.8032 13.0031 13.802 13.2565 13.7817 13.4437C13.7633 13.614 13.7355 13.6506 13.7327 13.6543C13.7099 13.6856 13.6819 13.7136 13.6505 13.7364C13.6462 13.7397 13.6085 13.7672 13.4399 13.7855C13.2528 13.8057 12.9993 13.8069 12.5885 13.8069L10.6267 13.8076L9.99348 13.8069L9.93962 13.8069L9.94031 13.86Z',\n 'M13.8568 6.05243H15.1771V5.99995L15.1757 5.36604H15.1771L15.1778 3.40423C15.1778 3.02337 15.1783 2.68194 15.1481 2.40365C15.1165 2.11259 15.0436 1.80952 14.8436 1.53427C14.7363 1.38666 14.6066 1.25697 14.459 1.14964C14.1837 0.949672 13.8806 0.8767 13.5896 0.845114C13.3113 0.814965 12.9698 0.815421 12.589 0.815421L10.6272 0.816112H9.99329L9.94011 0.815421L9.9408 0.868592V2.13641L9.94011 2.18958L9.99329 2.18889H10.6272L12.589 2.18958C12.9999 2.18958 13.2533 2.19077 13.4404 2.21099C13.6107 2.22944 13.6473 2.25719 13.651 2.26002C13.6824 2.28282 13.7104 2.31081 13.7332 2.34219C13.7365 2.34653 13.764 2.38424 13.7822 2.5528C13.8025 2.73993 13.8037 2.99339 13.8037 3.40423L13.8043 5.36604L13.8037 5.99926V6.05312L13.8568 6.05243Z',\n 'M2.12951 9.94389L0.809205 9.94389L0.809205 9.99637L0.810586 10.6303L0.809205 10.6303L0.808514 12.5921C0.808514 12.9729 0.808061 13.3144 0.838207 13.5927C0.86979 13.8837 0.942753 14.1868 1.14273 14.4621C1.25005 14.6097 1.37976 14.7394 1.52736 14.8467C1.80259 15.0467 2.1057 15.1196 2.39674 15.1512C2.67502 15.1814 3.01648 15.1809 3.39733 15.1809L5.35913 15.1802L5.99304 15.1802L6.04621 15.1809L6.04552 15.1277L6.04552 13.8599L6.04621 13.8067L5.99304 13.8074L5.35913 13.8074L3.39733 13.8067C2.98646 13.8067 2.73302 13.8056 2.5459 13.7853C2.37559 13.7669 2.33899 13.7391 2.33528 13.7363C2.3039 13.7135 2.27591 13.6855 2.25311 13.6541C2.24981 13.6498 2.22235 13.6121 2.20408 13.4435C2.18387 13.2564 2.18268 13.0029 2.18268 12.5921L2.18199 10.6303L2.18268 9.99706L2.18268 9.9432L2.12951 9.94389Z',\n]\n\nconst FULLSCREEN_EXIT_PATHS = [\n 'M10.698 0.379607H9.43015L9.37698 0.378916L9.37767 0.432087V1.066L9.37698 4.0277C9.37698 4.40856 9.37653 4.74998 9.40667 5.02828C9.43826 5.31934 9.51053 5.62311 9.71051 5.89835C9.81779 6.04587 9.94762 6.1757 10.0951 6.28298C10.3704 6.48296 10.6741 6.55523 10.9652 6.58682C11.2435 6.61696 11.5849 6.61651 11.9658 6.61651L14.9275 6.61582H15.5614L15.6146 6.61651L15.6139 6.56334V5.29552L15.6146 5.24235L15.5614 5.24304H14.9275L11.9658 5.24235C11.5545 5.24235 11.3009 5.24191 11.1137 5.22163C10.9443 5.20329 10.9078 5.17501 10.9038 5.17191C10.8724 5.14911 10.8444 5.12112 10.8216 5.08974C10.8185 5.08566 10.7902 5.04908 10.7719 4.87982C10.7516 4.69263 10.7511 4.439 10.7511 4.0277L10.7505 1.066V0.432087L10.7511 0.378916L10.698 0.379607Z',\n 'M5.29031 15.6167L6.55813 15.6167L6.6113 15.6174L6.61061 15.5642L6.61061 14.9303L6.6113 11.9686C6.6113 11.5878 6.61176 11.2463 6.58161 10.968C6.55003 10.677 6.47775 10.3732 6.27777 10.098C6.17049 9.95045 6.04067 9.82062 5.89315 9.71334C5.6179 9.51336 5.31413 9.44109 5.02307 9.40951C4.74478 9.37936 4.40335 9.37981 4.02249 9.37981L1.06079 9.3805L0.426879 9.3805L0.373708 9.37981L0.374398 9.43298L0.374398 10.7008L0.373708 10.754L0.426879 10.7533L1.06079 10.7533L4.02249 10.754C4.43379 10.754 4.68742 10.7544 4.87461 10.7747C5.04393 10.793 5.08047 10.8213 5.08453 10.8244C5.11591 10.8472 5.1439 10.8752 5.1667 10.9066C5.16982 10.9107 5.19808 10.9472 5.21642 11.1165C5.2367 11.3037 5.23714 11.5573 5.23714 11.9686L5.23783 14.9303L5.23783 15.5642L5.23714 15.6174L5.29031 15.6167Z',\n]\n\nfunction hostIcon(paths, size) {\n return createElement(\n 'svg',\n {\n width: size,\n height: size,\n viewBox: '0 0 16 16',\n fill: 'none',\n 'aria-hidden': true,\n style: { display: 'block' },\n },\n createElement(\n 'g',\n { fill: 'currentColor', stroke: 'currentColor', strokeWidth: 0.105646, strokeLinecap: 'square' },\n paths.map((d) => createElement('path', { key: d.slice(0, 24), d })),\n ),\n )\n}\n\n/** 全屏(进入全屏态按钮;默认 12px 与弹窗关闭按钮 ✕ 字号一致) */\nexport function FullscreenGlyph({ size = 12 }) {\n return hostIcon(FULLSCREEN_PATHS, size)\n}\n\n/** 退出全屏(还原态按钮;默认 12px 与弹窗关闭按钮 ✕ 字号一致) */\nexport function FullscreenExitGlyph({ size = 12 }) {\n return hostIcon(FULLSCREEN_EXIT_PATHS, size)\n}\n","/**\n * 用户管理 REST(对应后端 /kb/user/*;查看与操作仅限管理员,me 为状态门禁豁免接口)\n */\nimport request from '../core/request.js'\n\n/**\n * 当前登录用户平台状态(待审核/禁用时前端据此展示全局横幅)\n * @returns {Promise<{ uid: number, status: number, status_text: string }>}\n */\nexport function getMe() {\n return request.get('/user/me')\n}\n\n/**\n * 用户列表(仅管理员)\n * @param {{ status?: number, keyword?: string, page?: number, limit?: number }} params\n * @returns {Promise<{ list: Array<{ uid: number, masked_mobile: string, status: number, review_time: number, review_uid: number, create_time: number, update_time: number, is_admin: boolean }>, total: number, page: number, limit: number, pending_count: number }>}\n */\nexport function listUsers(params = {}) {\n return request.get('/user/list', params)\n}\n\n/**\n * 正常状态用户选项列表(知识库「添加成员 → 从用户列表选择」用;非管理员可调)\n * @param {{ keyword?: string, page?: number, limit?: number }} params\n * @returns {Promise<{ list: Array<{ uid: number, masked_mobile: string }>, total: number, page: number, limit: number }>}\n */\nexport function listUserOptions(params = {}) {\n return request.get('/user/options', params)\n}\n\n/**\n * 用户概览统计(首页「用户数」卡片;仅管理员)\n * @returns {Promise<{ user_count: number, pending_count: number }>} pending_count=待审核用户数\n */\nexport function getUserStats() {\n return request.get('/user/stats')\n}\n\n/**\n * 查询新用户默认审核模式(仅管理员)\n * @returns {Promise<{ mode: number }>} 0=无需审核(默认)/ 1=需审核\n */\nexport function getReviewConfig() {\n return request.get('/user/review-config')\n}\n\n/**\n * 切换新用户默认审核模式(仅管理员;仅影响之后首次验签的新用户,不影响存量用户状态)\n * @param {0|1} mode\n */\nexport function setReviewConfig(mode) {\n return request.put('/user/review-config', { mode })\n}\n\n/** 审核通过(待审核 → 正常;仅管理员;管理员不可被操作) */\nexport function reviewUser(uid) {\n return request.post(`/user/${uid}/review`)\n}\n\n/** 禁用(待审核/正常 → 禁用,同步吊销其全部插件 Token;仅管理员) */\nexport function disableUser(uid) {\n return request.post(`/user/${uid}/disable`)\n}\n\n/** 启用(禁用 → 正常;仅管理员) */\nexport function enableUser(uid) {\n return request.post(`/user/${uid}/enable`)\n}\n\n/**\n * 删除用户(仅管理员;物理删除状态记录与成员权限/待激活授权,保留其创建的知识库\n * 与文档,悬空所有者由管理员经「修改所有者」接管;用户再次登录视为新用户)\n */\nexport function deleteUser(uid) {\n return request.delete(`/user/${uid}`)\n}\n","/**\n * 首页(知识库列表标签页正文)\n *\n * - 知识库概览统计(文档数 / 向量块数 / MCP 开启数,由列表聚合)\n * - 知识库列表:名称/标签过滤、分页、置顶优先;卡片「文档」打开知识库详情标签页\n * - 添加知识库(所有登录用户);编辑/归档/置顶/重建向量按角色展示\n * - 设置入口(打开「设置」标签页:后端服务器地址 + 管理员)\n *\n * 导经 tab.actions.openTab(kind, { params }) 由宿主标签页系统承载:\n * 打开知识库详情 = 新标签页;本页面不维护内嵌路由。\n */\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { useStore } from '../../store/create-store.js'\nimport {\n kbStore,\n setKbList,\n setKbKeyword,\n setKbTagFilter,\n upsertKb,\n removeKbLocally,\n setStats,\n} from '../../store/kb-store.js'\nimport { setKbName } from '../../store/title-store.js'\nimport { toast, toastError } from '../../store/ui-store.js'\nimport { listKb, createKb, updateKb, archiveKb, pinKb } from '../../api/kb.js'\nimport { rebuildVector } from '../../api/task.js'\nimport { adminExists } from '../../api/auth.js'\nimport { subscribe as subscribeServerConfig, getApiBase, whenReady } from '../../core/server-config.js'\nimport { formatTime } from '../../utils/file-type.js'\nimport KbCard from '../../components/kb/KbCard.jsx'\nimport KbFormModal from '../../components/kb/KbFormModal.jsx'\nimport ConfirmDialog from '../../components/common/ConfirmDialog.jsx'\nimport Toast from '../../components/common/Toast.jsx'\nimport { SettingsGlyph } from '../../components/common/icons.jsx'\nimport { getUserStats } from '../../api/user.js'\n\n/**\n * @param {object} props\n * @param {{ openKb: (kbId: number, opts?: { view?: string }) => void, openSettings: () => void }} props.nav\n * 标签页导航(DSH 路径经 tab.actions.openTab 注入;standalone 路径内部路由实现)\n */\nexport default function HomePage({ nav }) {\n const list = useStore(kbStore, (s) => s.list)\n const total = useStore(kbStore, (s) => s.total)\n const page = useStore(kbStore, (s) => s.page)\n const limit = useStore(kbStore, (s) => s.limit)\n const keyword = useStore(kbStore, (s) => s.keyword)\n const tagFilter = useStore(kbStore, (s) => s.tagFilter)\n const stats = useStore(kbStore, (s) => s.stats)\n const [isSysadmin, setIsSysadmin] = useState(false)\n const [userStats, setUserStats] = useState(null) // 管理员用户概览 { count, pending }(非管理员 null)\n const [creating, setCreating] = useState(false)\n const [editing, setEditing] = useState(null)\n const [archiving, setArchiving] = useState(null)\n const [busy, setBusy] = useState(false)\n\n const reload = useCallback(\n (p = page) => {\n listKb({ keyword, tag: tagFilter, page: p, limit })\n .then((data) => {\n const kbList = data?.list || []\n setKbList(kbList, data?.total || 0, p, limit)\n kbList.forEach((k) => setKbName(k.id, k.name))\n })\n .catch(toastError)\n },\n [keyword, tagFilter, page, limit],\n )\n\n // 首次加载等待服务器配置解析完成:浏览器刷新后云配置异步到达,基址就绪前\n // 发起请求会被 request 拦截误报「请先在设置页配置服务器信息」。\n // readyRef 放行后续关键词/标签变化触发的重载\n const readyRef = useRef(false)\n useEffect(() => {\n let cancelled = false\n whenReady().then(() => {\n if (cancelled) return\n readyRef.current = true\n reload(1)\n })\n return () => {\n cancelled = true\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n useEffect(() => {\n if (!readyRef.current) return\n reload(1)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [keyword, tagFilter])\n\n // 概览统计(全量聚合,独立于分页列表)+ 标签页名称预热(同样等配置就绪)\n const loadStats = useCallback(() => {\n let cancelled = false\n listKb({ page: 1, limit: 100 })\n .then((data) => {\n if (cancelled) return\n const kbList = data && data.list ? data.list : []\n const docTotal = kbList.reduce((sum, k) => sum + (k.doc_count || 0), 0)\n const mcpOn = kbList.filter((k) => k.enable_mcp).length\n const lastUpdate = kbList.reduce((max, k) => Math.max(max, k.update_time || 0), 0)\n setStats({ kbCount: kbList.length, docTotal, mcpOn, lastUpdate })\n kbList.forEach((k) => setKbName(k.id, k.name))\n })\n .catch((e) => !cancelled && toastError(e))\n return () => {\n cancelled = true\n }\n }, [])\n\n const loadAdminState = useCallback(() => {\n let cancelled = false\n adminExists()\n .then((data) => {\n if (cancelled) return\n const isAdmin = Boolean(data && data.is_admin)\n setIsSysadmin(isAdmin)\n // 管理员额外拉取用户概览(用户数 + 待审核气泡;非管理员无此统计权限)\n if (isAdmin) {\n getUserStats()\n .then((res) => {\n if (!cancelled) {\n setUserStats({ count: Number(res?.user_count) || 0, pending: Number(res?.pending_count) || 0 })\n }\n })\n .catch(() => !cancelled && setUserStats(null))\n } else {\n setUserStats(null)\n }\n })\n .catch(() => !cancelled && setIsSysadmin(false))\n return () => {\n cancelled = true\n }\n }, [])\n\n useEffect(() => {\n let cancelled = false\n whenReady().then(() => {\n if (cancelled) return\n loadStats()\n loadAdminState()\n })\n return () => {\n cancelled = true\n }\n }, [loadStats, loadAdminState])\n\n // DSH 启动自动生效:服务器配置经用户中心云持久化异步到达(或切换服务器),\n // 基址就绪后自动重载列表 / 统计 / 管理员状态,页面无需手动刷新\n useEffect(() => {\n let prev = getApiBase()\n const off = subscribeServerConfig(() => {\n const cur = getApiBase()\n if (cur === prev) return\n prev = cur\n if (!cur) return\n reload(1)\n loadStats()\n loadAdminState()\n })\n return off\n }, [reload, loadStats, loadAdminState])\n\n const submitPin = (kb) => {\n setBusy(true)\n pinKb(kb.id, !kb.pinned)\n .then(() => {\n upsertKb({ ...kb, pinned: kb.pinned ? 0 : 1 })\n toast(kb.pinned ? '已取消置顶' : '已置顶,该知识库将排在列表最前', 'success')\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const submitCreate = (data) => {\n setBusy(true)\n createKb(data)\n .then(() => {\n toast('知识库已创建', 'success')\n setCreating(false)\n reload(1)\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const submitEdit = (data) => {\n setBusy(true)\n updateKb(editing.id, data)\n .then((kb) => {\n const merged = kb || { ...editing, ...data }\n upsertKb(merged)\n setKbName(merged.id, merged.name)\n toast('已保存', 'success')\n setEditing(null)\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const submitArchive = () => {\n setBusy(true)\n archiveKb(archiving.id)\n .then(() => {\n removeKbLocally(archiving.id)\n toast('知识库已归档', 'success')\n setArchiving(null)\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const submitRebuild = (kb) => {\n setBusy(true)\n rebuildVector(kb.id)\n .then((res) => {\n toast(`已提交向量重建任务${res?.task_id ? `(#${res.task_id})` : ''}`, 'success')\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const totalPages = Math.max(1, Math.ceil(total / limit))\n\n return (\n <div className=\"skai-kb-page\">\n {/* 页头(固定):左侧标题与说明介绍,右上角设置入口 */}\n <div className=\"skai-kb-home-head\">\n <div className=\"skai-kb-home-head-main\">\n <div className=\"skai-kb-detail-title\">知识库</div>\n <div className=\"skai-kb-home-desc\">\n 集中管理文档与成员权限:上传文档自动解析、分块并向量化,DSH 智能体经 MCP\n 实时检索引用;支持按成员配置查看 / 编辑 / 管理权限,可创建多个知识库按业务隔离。\n </div>\n </div>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={() => nav.openSettings()}>\n <SettingsGlyph size={14} />\n 设置\n </button>\n </div>\n\n <div className=\"skai-kb-page-scroll\">\n {/* 概览统计 */}\n <div className=\"skai-kb-stat-grid\">\n <div className=\"skai-kb-stat-card\">\n <div className=\"skai-kb-stat-num\">{stats ? stats.kbCount : '-'}</div>\n <div className=\"skai-kb-stat-label\">知识库</div>\n </div>\n <div className=\"skai-kb-stat-card\">\n <div className=\"skai-kb-stat-num\">{stats ? stats.docTotal : '-'}</div>\n <div className=\"skai-kb-stat-label\">文档总数</div>\n </div>\n {isSysadmin ? (\n <div className=\"skai-kb-stat-card\">\n <div className=\"skai-kb-stat-num\">\n {userStats ? userStats.count : '-'}\n {userStats && userStats.pending > 0 ? (\n <span\n className=\"skai-kb-badge skai-kb-badge-amber skai-kb-stat-badge\"\n title={`${userStats.pending} 个用户待审核,前往设置页「用户管理」处理`}\n >\n {userStats.pending} 待审核\n </span>\n ) : null}\n </div>\n <div className=\"skai-kb-stat-label\">用户数</div>\n </div>\n ) : null}\n <div className=\"skai-kb-stat-card\">\n <div className=\"skai-kb-stat-num\">{stats ? stats.mcpOn : '-'}</div>\n <div className=\"skai-kb-stat-label\">开启 MCP 检索</div>\n </div>\n </div>\n <div className=\"skai-kb-sub\" style={{ marginBottom: 10 }}>\n 最后更新:{stats ? formatTime(stats.lastUpdate) : '-'}\n </div>\n\n {/* 工具栏:搜索 / 标签 / 添加知识库 */}\n <div className=\"skai-kb-toolbar\">\n <input\n className=\"skai-kb-input skai-kb-search\"\n value={keyword}\n placeholder=\"搜索知识库名称\"\n onChange={(e) => setKbKeyword(e.target.value)}\n />\n <input\n className=\"skai-kb-input\"\n style={{ maxWidth: 110 }}\n value={tagFilter}\n placeholder=\"标签过滤\"\n onChange={(e) => setKbTagFilter(e.target.value)}\n />\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-primary\"\n onClick={() => setCreating(true)}\n >\n 添加知识库\n </button>\n </div>\n\n {/* 知识库列表 */}\n {list.length === 0 ? (\n <div className=\"skai-kb-empty\">\n <p>暂无可访问的知识库</p>\n <p className=\"skai-kb-empty-sub\">创建知识库后即可上传文档、管理成员权限</p>\n </div>\n ) : (\n <div className=\"skai-kb-card-list\">\n {list.map((kb) => (\n <KbCard\n key={kb.id}\n kb={kb}\n isAdmin={kb.my_role === 1}\n isSysadmin={isSysadmin}\n onOpen={(k) => nav.openKb(k.id)}\n onOpenPermission={(k) => nav.openKb(k.id, { view: 'permission' })}\n onEdit={(k) => setEditing(k)}\n onArchive={(k) => setArchiving(k)}\n onRebuild={submitRebuild}\n onPin={submitPin}\n />\n ))}\n </div>\n )}\n\n {/* 分页 */}\n {totalPages > 1 ? (\n <div className=\"skai-kb-pagination\">\n <span>\n 第 {page} / {totalPages} 页 · 共 {total} 个\n </span>\n <div className=\"skai-kb-pagination-btns\">\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm\"\n disabled={page <= 1}\n onClick={() => reload(page - 1)}\n >\n 上一页\n </button>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm\"\n disabled={page >= totalPages}\n onClick={() => reload(page + 1)}\n >\n 下一页\n </button>\n </div>\n </div>\n ) : null}\n </div>\n\n {/* 弹窗 */}\n {creating ? (\n <KbFormModal busy={busy} onSubmit={submitCreate} onClose={() => setCreating(false)} />\n ) : null}\n {editing ? (\n <KbFormModal initial={editing} busy={busy} onSubmit={submitEdit} onClose={() => setEditing(null)} />\n ) : null}\n {archiving ? (\n <ConfirmDialog\n title=\"归档知识库\"\n message={`确定归档「${archiving.name}」吗?归档后 MCP 不可检索,历史数据保留。`}\n confirmText=\"归档\"\n busy={busy}\n onConfirm={submitArchive}\n onClose={() => setArchiving(null)}\n />\n ) : null}\n <Toast />\n </div>\n )\n}\n","/**\n * 目录(文件夹)域状态:当前知识库目录树、当前浏览目录\n * currentId 语义与后端一致:0=根目录\n */\nimport { createStore } from './create-store.js'\n\nexport const initialFolderState = {\n kbId: null,\n tree: [], // 服务端嵌套树:[{ id, parent_id, name, sort_order, children }]\n currentId: 0, // 当前浏览目录(0=根目录)\n}\n\n/** 稳定空树引用:selector 在 kbId 不匹配时必须返回同一引用,避免 useSyncExternalStore 死循环 */\nexport const EMPTY_TREE = []\n\nexport const folderStore = createStore(initialFolderState)\n\n/** 拉取目录树后整体回填(切库/结构变更后调用) */\nexport function setFolderTree(kbId, tree) {\n folderStore.setState((s) => ({\n kbId,\n tree: tree || [],\n // 换库回到根目录;同库结构变更保持当前目录\n currentId: s.kbId === kbId ? s.currentId : 0,\n }))\n}\n\nexport function setCurrentFolder(id) {\n folderStore.setState({ currentId: id || 0 })\n}\n\n/**\n * HTML5 DnD 拖拽源上下文(模块级共享:dragover 阶段 dataTransfer.getData 不可读)\n * type: 'folder' | 'doc';id: 拖拽对象 id;parentId: 目录的父目录(0=顶层)\n */\nexport const dragCtx = { type: null, id: null, parentId: 0 }\n\n/** 在树中定位某父目录下的同级节点数组(parentId=0 返回顶层) */\nexport function siblingsOf(tree, parentId) {\n if (!parentId) return tree\n for (const node of tree || []) {\n if (node.id === parentId) return node.children || []\n const deep = siblingsOf(node.children, parentId)\n if (deep) return deep\n }\n return null\n}\n","/**\n * 目录(文件夹)管理 REST(对应后端 /kb/kb/:id/folder/*)\n */\nimport request from '../core/request.js'\n\n/** 目录树(全量;节点含 children 嵌套) */\nexport function getFolderTree(kbId) {\n return request.get(`/kb/${kbId}/folder/tree`)\n}\n\n/** 新建目录(parentId 缺省/0 = 顶层) */\nexport function createFolder(kbId, name, parentId = 0) {\n return request.post(`/kb/${kbId}/folder/create`, { name, parent_id: parentId || 0 })\n}\n\n/** 重命名目录 */\nexport function renameFolder(kbId, folderId, name) {\n return request.put(`/kb/${kbId}/folder/${folderId}/update`, { name })\n}\n\n/** 目录同级拖拽排序(parent_id + 有序 folder_id 数组整批提交) */\nexport function reorderFolders(kbId, parentId, folderIds) {\n return request.post(`/kb/${kbId}/folder/reorder`, { parent_id: parentId || 0, folder_ids: folderIds })\n}\n\n/** 删除目录(软删;仅空目录) */\nexport function deleteFolder(kbId, folderId) {\n return request.delete(`/kb/${kbId}/folder/${folderId}`)\n}\n","/**\n * 当前 uid 在知识库内的角色与按钮级权限\n * 角色由后端列表接口随知识库返回(my_role),前端只做渲染拦截(无权限按钮隐藏)\n * 真实鉴权以后端为准:不可见即不可操作,后端仍会做权限校验兜底\n *\n * @param {number|undefined} kbId 知识库 id;缺省时取列表内最高角色\n * @returns {{ role, isAdmin, isEditor, canEdit, canManage, canUpload }}\n */\nimport { useMemo } from 'react'\nimport { useStore } from '../store/create-store.js'\nimport { kbStore, ROLE } from '../store/kb-store.js'\n\nexport function useKbPermission(kbId) {\n const list = useStore(kbStore, (s) => s.list)\n const role = useMemo(() => {\n if (kbId == null) return list.reduce((min, k) => Math.min(min, k.my_role ?? ROLE.READONLY), 99)\n const kb = list.find((k) => k.id === kbId)\n return kb ? kb.my_role : ROLE.READONLY\n }, [list, kbId])\n return {\n role,\n isAdmin: role === ROLE.ADMIN,\n isEditor: role === ROLE.EDITOR,\n canEdit: role === ROLE.ADMIN || role === ROLE.EDITOR,\n canManage: role === ROLE.ADMIN,\n canUpload: role === ROLE.ADMIN || role === ROLE.EDITOR,\n }\n}\n","/**\n * 任务进度轮询(文档解析/向量化状态实时刷新统一入口)\n * 页面禁止自写 setInterval:统一收敛到本 hook(自动清理、标签页隐藏时暂停)\n *\n * @param {() => boolean} enabled 是否继续轮询(返回 false 自动停止)\n * @param {() => Promise<void>} tick 轮询回调(内部自行取数与回填 store)\n * @param {number} [interval] 轮询间隔毫秒(默认 3000)\n */\nimport { useRef, useEffect } from 'react'\n\nexport function useTaskPolling(enabled, tick, interval = 3000) {\n const tickRef = useRef(tick)\n tickRef.current = tick\n const enabledRef = useRef(enabled)\n enabledRef.current = enabled\n useEffect(() => {\n if (!enabled) return undefined\n let stopped = false\n let timer = null\n const run = async () => {\n if (stopped || document.hidden) {\n schedule()\n return\n }\n try {\n await tickRef.current()\n } catch {}\n schedule()\n }\n const schedule = () => {\n if (stopped) return\n timer = setTimeout(run, interval)\n }\n run()\n return () => {\n stopped = true\n if (timer) clearTimeout(timer)\n }\n }, [enabled, interval])\n}\n","/**\n * 文档检索栏:文档名称 + 文本关键词检索、按标签过滤\n * (PG 全文关键词检索在当前知识库内进行,由后端完成)\n */\nexport default function DocSearchBar({ keyword, tag, onKeyword, onTag, children }) {\n return (\n <div className=\"skai-kb-toolbar\">\n <input\n className=\"skai-kb-input skai-kb-search\"\n value={keyword}\n placeholder=\"搜索文档名称与文本内容\"\n onChange={(e) => onKeyword(e.target.value)}\n />\n <input\n className=\"skai-kb-input\"\n style={{ maxWidth: 110 }}\n value={tag}\n placeholder=\"标签过滤\"\n onChange={(e) => onTag(e.target.value)}\n />\n {children}\n </div>\n )\n}\n","/** 文档状态徽标:待解析→解析中→向量化中→已就绪→解析失败 */\nimport { DOC_STATUS_LABEL } from '../../store/doc-store.js'\n\nconst STATUS_STYLE = {\n 0: 'skai-kb-badge-gray',\n 1: 'skai-kb-badge-blue',\n 2: 'skai-kb-badge-amber',\n 3: 'skai-kb-badge-green',\n 4: 'skai-kb-badge-red',\n}\n\nexport default function DocStatusBadge({ status }) {\n return (\n <span className={`skai-kb-badge ${STATUS_STYLE[status] || 'skai-kb-badge-gray'}`}>\n {DOC_STATUS_LABEL[status] || '未知'}\n </span>\n )\n}\n","/**\n * 目录树组件(知识库详情页左栏)\n *\n * - 根目录虚拟节点(id=0)+ 服务端嵌套树渲染,点击切换当前浏览目录\n * - 编辑者/所有者:新建子目录(节点悬停 + / 树头「新建目录」)、重命名(✎)、\n * 删除空目录(✕,后端校验非空目录拒绝)\n * - 拖拽:目录同级拖拽排序(跨级不允许,spec 仅同级顺序调整);\n * 文档列表拖入目录节点/根目录 → 移动文档(onDropDoc 回调由页面处理)\n */\nimport { useCallback, useState } from 'react'\nimport { useStore } from '../../store/create-store.js'\nimport { folderStore, setCurrentFolder, dragCtx, siblingsOf, EMPTY_TREE } from '../../store/folder-store.js'\nimport { createFolder, renameFolder, reorderFolders, deleteFolder } from '../../api/folder.js'\nimport { toast, toastError } from '../../store/ui-store.js'\nimport Modal from '../common/Modal.jsx'\nimport ConfirmDialog from '../common/ConfirmDialog.jsx'\n\nexport default function FolderTree({ kbId, canEdit, onTreeChange, onDropDoc }) {\n const tree = useStore(folderStore, (s) => (s.kbId === kbId ? s.tree : EMPTY_TREE))\n const currentId = useStore(folderStore, (s) => (s.kbId === kbId ? s.currentId : 0))\n const [expanded, setExpanded] = useState({ 0: true })\n // 拖拽悬停态:{ key: 'f<id>' | 'root', pos: 'before' | 'after' | 'in' }\n const [dragOver, setDragOver] = useState(null)\n const [creating, setCreating] = useState(null) // { parentId, parentLabel }\n const [renaming, setRenaming] = useState(null) // { id, name }\n const [removing, setRemoving] = useState(null) // node\n const [newName, setNewName] = useState('')\n const [busy, setBusy] = useState(false)\n\n const toggleExpand = useCallback((id) => {\n setExpanded((prev) => ({ ...prev, [id]: !prev[id] }))\n }, [])\n\n /** 目录同级排序:拖拽插入到 target 前/后,整批提交新顺序 */\n const reorderTo = useCallback(\n (srcNode, targetNode, pos) => {\n const siblings = siblingsOf(tree, targetNode.parent_id) || []\n const ids = siblings.map((n) => n.id).filter((id) => id !== srcNode.id)\n let idx = ids.indexOf(targetNode.id)\n if (idx < 0) return\n if (pos === 'after') idx += 1\n ids.splice(idx, 0, srcNode.id)\n reorderFolders(kbId, targetNode.parent_id, ids)\n .then(() => onTreeChange())\n .catch(toastError)\n },\n [kbId, tree, onTreeChange],\n )\n\n const onDragOverNode = (e, node) => {\n if (!dragCtx.type || !canEdit) return\n e.preventDefault()\n e.dataTransfer.dropEffect = 'move'\n const key = `f${node.id}`\n if (dragCtx.type === 'doc') {\n setDragOver({ key, pos: 'in' })\n return\n }\n // 目录:仅同级排序;根目录层级(parent_id 相同)显示插入线\n if (dragCtx.id === node.id) return\n const siblings = siblingsOf(tree, node.parent_id) || []\n if (!siblings.some((n) => n.id === dragCtx.id)) return\n const rect = e.currentTarget.getBoundingClientRect()\n const pos = e.clientY - rect.top < rect.height / 2 ? 'before' : 'after'\n setDragOver({ key, pos })\n }\n\n const onDragOverRoot = (e) => {\n if (!dragCtx.type || !canEdit) return\n e.preventDefault()\n e.dataTransfer.dropEffect = 'move'\n if (dragCtx.type === 'doc') {\n setDragOver({ key: 'root', pos: 'in' })\n return\n }\n // 顶层目录排序:拖到根节点 = 移到顶层末尾\n if (dragCtx.type === 'folder' && dragCtx.parentId === 0 && dragCtx.id !== 0) {\n setDragOver({ key: 'root', pos: 'in' })\n }\n }\n\n const onDropNode = (e, node) => {\n e.preventDefault()\n const over = dragOver\n setDragOver(null)\n if (!dragCtx.type || !canEdit) return\n if (dragCtx.type === 'doc') {\n if (dragCtx.id != null) onDropDoc?.(dragCtx.id, node.id)\n return\n }\n if (dragCtx.type === 'folder' && over && over.pos !== 'in') {\n const src = findNode(tree, dragCtx.id)\n if (src) reorderTo(src, node, over.pos)\n }\n }\n\n const onDropRoot = (e) => {\n e.preventDefault()\n setDragOver(null)\n if (!dragCtx.type || !canEdit) return\n if (dragCtx.type === 'doc') {\n if (dragCtx.id != null) onDropDoc?.(dragCtx.id, 0)\n return\n }\n if (dragCtx.type === 'folder' && dragCtx.parentId === 0) {\n const siblings = tree.map((n) => n.id).filter((id) => id !== dragCtx.id)\n siblings.push(dragCtx.id)\n reorderFolders(kbId, 0, siblings)\n .then(() => onTreeChange())\n .catch(toastError)\n }\n }\n\n const submitCreate = () => {\n if (!newName.trim()) {\n toastError(new Error('请输入目录名称'))\n return\n }\n setBusy(true)\n createFolder(kbId, newName.trim(), creating.parentId)\n .then(() => {\n setExpanded((prev) => ({ ...prev, [creating.parentId]: true }))\n toast('目录已创建', 'success')\n setCreating(null)\n setNewName('')\n onTreeChange()\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const submitRename = () => {\n if (!newName.trim()) {\n toastError(new Error('请输入目录名称'))\n return\n }\n setBusy(true)\n renameFolder(kbId, renaming.id, newName.trim())\n .then(() => {\n toast('目录已重命名', 'success')\n setRenaming(null)\n setNewName('')\n onTreeChange()\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const submitDelete = () => {\n setBusy(true)\n deleteFolder(kbId, removing.id)\n .then(() => {\n toast('目录已删除', 'success')\n if (currentId === removing.id) setCurrentFolder(removing.parent_id || 0)\n setRemoving(null)\n onTreeChange()\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const nodeCls = (key, extra) => {\n let cls = `skai-kb-folder-item ${extra || ''}`\n if (dragOver && dragOver.key === key) cls += ` skai-kb-drop-${dragOver.pos}`\n return cls\n }\n\n const renderNode = (node, depth) => {\n const hasChildren = (node.children || []).length > 0\n const isOpen = !!expanded[node.id]\n const active = currentId === node.id\n return (\n <div key={node.id} className=\"skai-kb-folder-branch\">\n <div\n className={nodeCls(`f${node.id}`, active ? 'is-active' : '')}\n style={{ paddingLeft: 6 + depth * 14 }}\n onClick={() => setCurrentFolder(node.id)}\n draggable={canEdit}\n onDragStart={(e) => {\n dragCtx.type = 'folder'\n dragCtx.id = node.id\n dragCtx.parentId = node.parent_id\n e.dataTransfer.effectAllowed = 'move'\n e.dataTransfer.setData('text/plain', String(node.id))\n }}\n onDragEnd={() => {\n dragCtx.type = null\n setDragOver(null)\n }}\n onDragOver={(e) => onDragOverNode(e, node)}\n onDragLeave={() => setDragOver((prev) => (prev && prev.key === `f${node.id}` ? null : prev))}\n onDrop={(e) => onDropNode(e, node)}\n role=\"treeitem\"\n aria-selected={active}\n tabIndex={0}\n onKeyDown={(e) => e.key === 'Enter' && setCurrentFolder(node.id)}\n >\n <span\n className={`skai-kb-folder-arrow ${hasChildren ? '' : 'is-leaf'}`}\n onClick={(e) => {\n if (hasChildren) {\n e.stopPropagation()\n toggleExpand(node.id)\n }\n }}\n >\n {hasChildren ? (isOpen ? '▾' : '▸') : ''}\n </span>\n <span className=\"skai-kb-folder-icon\">📁</span>\n <span className=\"skai-kb-folder-name\" title={node.name}>\n {node.name}\n </span>\n {canEdit ? (\n <span className=\"skai-kb-folder-actions\" onClick={(e) => e.stopPropagation()}>\n <button\n type=\"button\"\n className=\"skai-kb-folder-act\"\n title=\"新建子目录\"\n onClick={() => {\n setNewName('')\n setCreating({ parentId: node.id, parentLabel: node.name })\n }}\n >\n +\n </button>\n <button\n type=\"button\"\n className=\"skai-kb-folder-act\"\n title=\"重命名\"\n onClick={() => {\n setNewName(node.name)\n setRenaming(node)\n }}\n >\n ✎\n </button>\n <button\n type=\"button\"\n className=\"skai-kb-folder-act is-danger\"\n title=\"删除(仅空目录)\"\n onClick={() => setRemoving(node)}\n >\n ✕\n </button>\n </span>\n ) : null}\n </div>\n {hasChildren && isOpen ? (\n <div className=\"skai-kb-folder-children\">{node.children.map((c) => renderNode(c, depth + 1))}</div>\n ) : null}\n </div>\n )\n }\n\n return (\n <div className=\"skai-kb-folder-tree\">\n <div className=\"skai-kb-folder-head\">\n <span className=\"skai-kb-folder-head-title\">目录</span>\n {canEdit ? (\n <button\n type=\"button\"\n className=\"skai-kb-folder-act\"\n title=\"新建顶层目录\"\n onClick={() => {\n setNewName('')\n setCreating({ parentId: 0, parentLabel: '根目录' })\n }}\n >\n + 新建\n </button>\n ) : null}\n </div>\n <div className=\"skai-kb-folder-body\" role=\"tree\">\n {/* 根目录虚拟节点:未归目录文档兜底展示 + 文档拖入目标 */}\n <div\n className={nodeCls('root', currentId === 0 ? 'is-active' : '')}\n onClick={() => setCurrentFolder(0)}\n onDragOver={onDragOverRoot}\n onDragLeave={() => setDragOver((prev) => (prev && prev.key === 'root' ? null : prev))}\n onDrop={onDropRoot}\n role=\"treeitem\"\n aria-selected={currentId === 0}\n tabIndex={0}\n onKeyDown={(e) => e.key === 'Enter' && setCurrentFolder(0)}\n >\n <span className=\"skai-kb-folder-icon\">🗂</span>\n <span className=\"skai-kb-folder-name\">根目录</span>\n </div>\n {tree.map((node) => renderNode(node, 1))}\n </div>\n\n {creating ? (\n <Modal\n title={`新建子目录 · ${creating.parentLabel}`}\n onClose={() => setCreating(null)}\n footer={\n <>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={() => setCreating(null)} disabled={busy}>\n 取消\n </button>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-primary\" onClick={submitCreate} disabled={busy}>\n 创建\n </button>\n </>\n }\n >\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">目录名称 *</span>\n <input\n className=\"skai-kb-input\"\n value={newName}\n maxLength={64}\n autoFocus\n placeholder=\"同级目录内名称唯一\"\n onChange={(e) => setNewName(e.target.value)}\n onKeyDown={(e) => e.key === 'Enter' && submitCreate()}\n />\n </div>\n </Modal>\n ) : null}\n\n {renaming ? (\n <Modal\n title=\"重命名目录\"\n onClose={() => setRenaming(null)}\n footer={\n <>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={() => setRenaming(null)} disabled={busy}>\n 取消\n </button>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-primary\" onClick={submitRename} disabled={busy}>\n 保存\n </button>\n </>\n }\n >\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">目录名称 *</span>\n <input\n className=\"skai-kb-input\"\n value={newName}\n maxLength={64}\n autoFocus\n onChange={(e) => setNewName(e.target.value)}\n onKeyDown={(e) => e.key === 'Enter' && submitRename()}\n />\n </div>\n </Modal>\n ) : null}\n\n {removing ? (\n <ConfirmDialog\n title=\"删除目录\"\n message={`确定删除目录「${removing.name}」吗?仅允许删除空目录(无子目录且无文档)。`}\n confirmText=\"删除\"\n busy={busy}\n onConfirm={submitDelete}\n onClose={() => setRemoving(null)}\n />\n ) : null}\n </div>\n )\n}\n\n/** 在树中按 id 查找节点 */\nfunction findNode(tree, id) {\n for (const node of tree || []) {\n if (node.id === id) return node\n const deep = findNode(node.children, id)\n if (deep) return deep\n }\n return null\n}\n","/**\n * 移动文档到目录弹窗(列表「移动」按钮入口)\n * 目录树平铺展示(缩进表层级),含根目录;选中后调 moveDoc\n */\nimport { useMemo, useState } from 'react'\nimport { moveDoc } from '../../api/doc.js'\nimport { useStore } from '../../store/create-store.js'\nimport { folderStore, EMPTY_TREE } from '../../store/folder-store.js'\nimport { toast, toastError } from '../../store/ui-store.js'\nimport Modal from '../common/Modal.jsx'\n\nexport default function MoveDocModal({ kbId, doc, excludeFolderId, onDone, onClose }) {\n const tree = useStore(folderStore, (s) => (s.kbId === kbId ? s.tree : EMPTY_TREE))\n const [targetId, setTargetId] = useState(0)\n const [busy, setBusy] = useState(false)\n\n /** 树平铺(深度缩进),移动中排除当前所在目录 */\n const options = useMemo(() => {\n const out = []\n const walk = (nodes, depth) => {\n for (const n of nodes || []) {\n if (n.id !== excludeFolderId) out.push({ id: n.id, name: n.name, depth })\n walk(n.children, depth + 1)\n }\n }\n walk(tree, 1)\n return out\n }, [tree, excludeFolderId])\n\n const submit = () => {\n setBusy(true)\n moveDoc(kbId, doc.id, targetId)\n .then(() => {\n toast(`已移动到「${targetId === 0 ? '根目录' : options.find((o) => o.id === targetId)?.name || '根目录'}」`, 'success')\n onDone?.()\n onClose?.()\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n return (\n <Modal\n title={`移动文档 · ${doc.name}`}\n onClose={onClose}\n footer={\n <>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={onClose} disabled={busy}>\n 取消\n </button>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-primary\" onClick={submit} disabled={busy}>\n 移动\n </button>\n </>\n }\n >\n <div className=\"skai-kb-move-list\" role=\"listbox\" aria-label=\"目标目录\">\n <button\n type=\"button\"\n className={`skai-kb-move-item ${targetId === 0 ? 'is-active' : ''}`}\n onClick={() => setTargetId(0)}\n >\n 🗂 根目录\n </button>\n {options.map((o) => (\n <button\n key={o.id}\n type=\"button\"\n className={`skai-kb-move-item ${targetId === o.id ? 'is-active' : ''}`}\n style={{ paddingLeft: 8 + o.depth * 14 }}\n onClick={() => setTargetId(o.id)}\n >\n 📁 {o.name}\n </button>\n ))}\n </div>\n </Modal>\n )\n}\n","/**\n * 拖拽上传区(md/txt/pdf/docx/图片,单文件)\n * 上传动作由父组件执行:本组件只负责选文件与格式校验\n */\nimport { useRef, useState } from 'react'\nimport { isSupportedFile, formatSize } from '../../utils/file-type.js'\n\nexport function UploadDropzone({ onPick }) {\n const inputRef = useRef(null)\n const [dragOver, setDragOver] = useState(false)\n const [error, setError] = useState('')\n const pick = (file) => {\n setError('')\n if (!file) return\n if (!isSupportedFile(file.name)) {\n setError('仅支持 md / txt / pdf / docx / 表格 / PPT / 图片文件')\n return\n }\n onPick(file)\n }\n return (\n <div>\n <div\n className=\"skai-kb-dropzone\"\n role=\"button\"\n tabIndex={0}\n aria-label=\"上传文档\"\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: 88,\n cursor: 'pointer',\n textAlign: 'center',\n borderColor: dragOver ? 'var(--skai-kb-primary)' : undefined,\n }}\n onDragOver={(e) => {\n e.preventDefault()\n setDragOver(true)\n }}\n onDragLeave={() => setDragOver(false)}\n onDrop={(e) => {\n e.preventDefault()\n setDragOver(false)\n pick(e.dataTransfer.files && e.dataTransfer.files[0])\n }}\n onClick={() => inputRef.current?.click()}\n onKeyDown={(e) => e.key === 'Enter' && inputRef.current?.click()}\n >\n <div style={{ color: dragOver ? 'var(--skai-kb-primary)' : 'var(--skai-kb-text-sub)' }}>\n 拖拽文件到此处,或点击选择文件\n </div>\n <div className=\"skai-kb-sub\">支持 md / txt / pdf / docx / xlsx / csv / pptx / 图片,单文件上传</div>\n <input\n ref={inputRef}\n type=\"file\"\n accept=\".md,.txt,.pdf,.docx,.xlsx,.xlsm,.csv,.pptx,.jpg,.jpeg,.png,.webp,.bmp,.gif\"\n style={{ display: 'none' }}\n onChange={(e) => {\n pick(e.target.files && e.target.files[0])\n e.target.value = ''\n }}\n />\n </div>\n {error ? <div className=\"skai-kb-field-error\">{error}</div> : null}\n </div>\n )\n}\n\n/** 已选文件摘要 */\nexport function PickedFileMeta({ file }) {\n if (!file) return null\n return (\n <div className=\"skai-kb-sub\" style={{ marginTop: 4 }}>\n 已选择:{file.name}({formatSize(file.size)})\n </div>\n )\n}\n","/**\n * 分段配置表单:块大小 / 重叠长度(知识库默认 + 单文档覆盖)\n * 单文档覆盖为高级选项:留空表示使用知识库默认配置\n */\nimport { useState } from 'react'\nimport { validateChunkSize, validateChunkOverlap } from '../../utils/validator.js'\n\nexport default function ChunkConfigForm({ initial = {}, advanced = false, onChange }) {\n const [chunkSize, setChunkSize] = useState(initial.chunk_size ?? '')\n const [chunkOverlap, setChunkOverlap] = useState(initial.chunk_overlap ?? '')\n const [error, setError] = useState('')\n const emit = (size, overlap) => {\n let msg = ''\n if (size !== '') msg = validateChunkSize(size)\n if (!msg && overlap !== '') msg = validateChunkOverlap(overlap, size || 4000)\n setError(msg)\n if (msg) return\n onChange({\n chunk_size: size === '' ? null : Number(size),\n chunk_overlap: overlap === '' ? null : Number(overlap),\n })\n }\n return (\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">\n {advanced ? '分段覆盖配置(留空使用知识库默认)' : '分段配置(块大小 / 重叠长度)'}\n </span>\n <div className=\"skai-kb-field-row\">\n <input\n className=\"skai-kb-input\"\n type=\"number\"\n min={100}\n max={4000}\n value={chunkSize}\n placeholder=\"块大小(100-4000)\"\n aria-label=\"块大小\"\n onChange={(e) => {\n setChunkSize(e.target.value)\n emit(e.target.value, chunkOverlap)\n }}\n />\n <input\n className=\"skai-kb-input\"\n type=\"number\"\n min={0}\n max={500}\n value={chunkOverlap}\n placeholder=\"重叠长度(0-500)\"\n aria-label=\"重叠长度\"\n onChange={(e) => {\n setChunkOverlap(e.target.value)\n emit(chunkSize, e.target.value)\n }}\n />\n </div>\n {error ? <div className=\"skai-kb-field-error\">{error}</div> : null}\n </div>\n )\n}\n","/**\n * 版本快照时间线:查看历史文本版本、回滚(回滚自动触发重新向量化)\n */\nimport { formatTime } from '../../utils/file-type.js'\n\nexport default function VersionTimeline({ versions = [], currentVersion, canEdit, onPreview, onRollback, busy }) {\n if (!versions.length) {\n return (\n <div className=\"skai-kb-empty\">\n <p>暂无历史版本</p>\n </div>\n )\n }\n return (\n <ul className=\"skai-kb-timeline\">\n {versions.map((v) => (\n <li key={v.version_no}>\n <div className=\"skai-kb-row-between\">\n <span className=\"skai-kb-title\">\n v{v.version_no}\n {v.version_no === currentVersion ? (\n <span className=\"skai-kb-tag\" style={{ marginLeft: 6 }}>\n 当前\n </span>\n ) : null}\n </span>\n <span className=\"skai-kb-sub\">{formatTime(v.create_time)}</span>\n </div>\n <div className=\"skai-kb-row\" style={{ marginTop: 4 }}>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-sm\" onClick={() => onPreview(v)}>\n 查看内容\n </button>\n {canEdit && v.version_no !== currentVersion ? (\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-sm\" disabled={busy} onClick={() => onRollback(v)}>\n 回滚到此版本\n </button>\n ) : null}\n </div>\n </li>\n ))}\n </ul>\n )\n}\n","/**\n * 成员公开资料批量获取(权限配置成员列表展示昵称/头像/脱敏手机号)\n *\n * 数据源:用户中心开放接口 window.SHIKEAI_GET_MEMBER_INFO(按 uid 批量查询,\n * 云端 member/batch_info 手机号服务端脱敏,明文不出服务端);仅用于展示,\n * 不作为可信身份。接口未挂载(用户中心未安装或为旧版本)时不发请求,\n * 列表回退展示 (#uid)。\n *\n * 会话级缓存:uid → 资料,切换知识库/成员去重后只拉取未缓存过的 uid\n */\nimport { useMemo, useState, useEffect } from 'react'\n\nconst infoCache = new Map()\n\n/**\n * 按手机号查询会员 uid(添加管理员/成员前解析目标身份用)\n * 数据源:用户中心开放接口 window.SHIKEAI_GET_MEMBER_UID_BY_MOBILE(云端\n * member/uid_by_mobile 精确匹配,命中返回 { uid, nickname, avatar, mobile },\n * mobile 为脱敏值);接口未挂载(用户中心为旧版本)、未命中、游客态或请求\n * 失败时返回 null,调用方按「未注册」回退到手机号 md5 待激活授权\n * @param {string} mobile 11 位大陆手机号\n * @returns {Promise<{uid:number|string, nickname:string, avatar:string, mobile:string}|null>}\n */\nexport function findMemberByMobile(mobile) {\n const query = typeof window !== 'undefined' ? window.SHIKEAI_GET_MEMBER_UID_BY_MOBILE : null\n if (typeof query !== 'function') return Promise.resolve(null)\n return Promise.resolve()\n .then(() => query(mobile))\n .then((data) => (data && Number(data.uid) > 0 ? data : null))\n .catch(() => null)\n}\n\nfunction buildInfoMap(uidList) {\n const map = {}\n uidList.forEach((uid) => {\n const info = infoCache.get(Number(uid))\n if (info) map[String(uid)] = info\n })\n return map\n}\n\n/**\n * @param {number[]} uids 成员 uid 列表\n * @returns {{ infoMap: Record<string, {uid:number|string, nickname:string, avatar:string, mobile:string}> }}\n */\nexport function useMemberInfo(uids = []) {\n const uidKey = useMemo(\n () => [...new Set(uids.map(Number).filter((uid) => uid > 0))].sort((a, b) => a - b).join(','),\n [uids],\n )\n const [infoMap, setInfoMap] = useState(() => buildInfoMap(uidKey ? uidKey.split(',') : []))\n useEffect(() => {\n const uidList = uidKey ? uidKey.split(',') : []\n setInfoMap(buildInfoMap(uidList))\n if (!uidList.length) return\n const fetchInfo = typeof window !== 'undefined' ? window.SHIKEAI_GET_MEMBER_INFO : null\n if (typeof fetchInfo !== 'function') return\n const missing = uidList.filter((uid) => !infoCache.has(Number(uid)))\n if (!missing.length) return\n let cancelled = false\n fetchInfo(missing)\n .then((data) => {\n if (cancelled || !data) return\n Object.values(data).forEach((info) => {\n const uid = Number(info && info.uid)\n if (uid) infoCache.set(uid, info)\n })\n setInfoMap(buildInfoMap(uidList))\n })\n .catch(() => {})\n return () => {\n cancelled = true\n }\n }, [uidKey])\n return { infoMap }\n}\n","/**\n * 成员列表:头像/昵称/脱敏手机号(用户中心开放接口批量获取,仅展示)、\n * 所有者/编辑者/只读标识、移除成员(所有者操作)\n * 成员资料拉取失败或用户中心未提供接口时回退 (#uid) 展示;\n * 待激活行(按手机号预添加、目标用户尚未登录过)显示脱敏手机号与撤销按钮\n */\nimport { useMemberInfo } from '../../hooks/use-member-info.js'\nimport { ROLE_LABEL } from '../../store/kb-store.js'\nimport { formatTime } from '../../utils/file-type.js'\n\nexport default function MemberList({ members = [], isAdmin, canManage, onRoleChange, onRemove, busy }) {\n const { infoMap } = useMemberInfo(members.filter((m) => m.uid).map((m) => m.uid))\n if (!members.length) {\n return (\n <div className=\"skai-kb-empty\">\n <p>暂无成员</p>\n </div>\n )\n }\n return (\n <div>\n {members.map((m) => {\n // 待激活行:无 uid,以手机号脱敏串标识\n if (m.pending) {\n return (\n <div key={`pending-${m.pending_id}`} className=\"skai-kb-member-row\">\n <span className=\"skai-kb-member-avatar skai-kb-member-avatar-fallback\" aria-hidden=\"true\">\n 📱\n </span>\n <div className=\"skai-kb-member-main\">\n <span className=\"skai-kb-member-name\">{m.masked_mobile || '未激活手机号'}</span>\n <span className=\"skai-kb-sub\">待激活:该用户登录知识库后自动生效</span>\n </div>\n <span className=\"skai-kb-badge skai-kb-badge-gray\">{ROLE_LABEL[m.role] || '只读'}</span>\n <span className=\"skai-kb-sub\">{formatTime(m.create_time)}</span>\n {canManage ? (\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm skai-kb-btn-ghost-danger\"\n disabled={busy}\n onClick={() => onRemove(m)}\n >\n 撤销\n </button>\n ) : null}\n </div>\n )\n }\n const info = infoMap[String(m.uid)]\n const nickname = (info?.nickname || m.nickname || '').trim()\n const initial = nickname ? nickname.slice(0, 1).toUpperCase() : '#'\n return (\n <div key={m.uid} className=\"skai-kb-member-row\">\n {info?.avatar ? (\n <img className=\"skai-kb-member-avatar\" src={info.avatar} alt=\"\" />\n ) : (\n <span className=\"skai-kb-member-avatar skai-kb-member-avatar-fallback\" aria-hidden=\"true\">\n {initial}\n </span>\n )}\n <div className=\"skai-kb-member-main\">\n <span className=\"skai-kb-member-name\">\n {nickname ? `${nickname} ` : ''}(UID:{m.uid})\n </span>\n {info?.mobile ? <span className=\"skai-kb-member-mobile\">{info.mobile}</span> : null}\n </div>\n {isAdmin ? (\n <select\n className=\"skai-kb-select\"\n style={{ width: 96, flex: 'none' }}\n value={m.role}\n disabled={busy}\n onChange={(e) => onRoleChange(m, Number(e.target.value))}\n aria-label={`修改成员 ${m.uid} 角色`}\n >\n <option value={1}>{ROLE_LABEL[1]}</option>\n <option value={2}>{ROLE_LABEL[2]}</option>\n <option value={3}>{ROLE_LABEL[3]}</option>\n </select>\n ) : (\n <span className={`skai-kb-badge ${m.role === 1 ? 'skai-kb-badge-blue' : 'skai-kb-badge-gray'}`}>\n {ROLE_LABEL[m.role] || '只读'}\n </span>\n )}\n <span className=\"skai-kb-sub\">{formatTime(m.create_time)}</span>\n {canManage ? (\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm skai-kb-btn-ghost-danger\"\n disabled={busy}\n onClick={() => onRemove(m)}\n >\n 移除\n </button>\n ) : null}\n </div>\n )\n })}\n </div>\n )\n}\n","/**\n * 添加成员弹窗:两种方式(所有者操作)\n * - 按手机号:目标用户登录过 → 即时生效;未登录过 → 落待激活授权,其登录后自动补全 uid 生效\n * - 从用户列表选择:候选为平台「正常」状态用户(头像/昵称/脱敏手机号),支持按\n * uid / 昵称 / 手机号片段搜索、多选(已在知识库中的用户禁选)、批量授权\n */\nimport { useEffect, useMemo, useState } from 'react'\nimport Modal from '../common/Modal.jsx'\nimport { ROLE_LABEL } from '../../store/kb-store.js'\nimport { validateMobile } from '../../utils/validator.js'\nimport { listUserOptions } from '../../api/user.js'\nimport { useMemberInfo } from '../../hooks/use-member-info.js'\nimport { toastError } from '../../store/ui-store.js'\n\n/** 候选拉取上限(正常用户全量,前端过滤 + 分页:昵称数据在用户中心,无法库内搜索) */\nconst FETCH_LIMIT = 500\nconst PAGE_SIZE = 8\n\nexport default function MemberGrantModal({ busy, onSubmit, onClose, existingUids = [] }) {\n const [mode, setMode] = useState('mobile') // mobile=按手机号 | pick=从用户列表选择\n const [mobile, setMobile] = useState('')\n const [role, setRole] = useState(2)\n const [error, setError] = useState('')\n\n // 选择模式:候选(正常状态用户全量)→ 前端按 uid/昵称/手机号过滤 → 分页\n const [keyword, setKeyword] = useState('')\n const [options, setOptions] = useState([])\n const [loaded, setLoaded] = useState(false)\n const [page, setPage] = useState(1)\n const [pickedUids, setPickedUids] = useState([]) // 多选:候选 uid 列表(保持点选顺序)\n const existing = useMemo(() => new Set(existingUids.map(Number)), [existingUids])\n const { infoMap } = useMemberInfo(mode === 'pick' ? options.map((u) => u.uid) : [])\n\n useEffect(() => {\n if (mode !== 'pick' || loaded) return\n let cancelled = false\n listUserOptions({ keyword: '', page: 1, limit: FETCH_LIMIT })\n .then((data) => {\n if (cancelled) return\n setOptions(data?.list || [])\n setLoaded(true)\n })\n .catch((e) => {\n if (!cancelled) toastError(e)\n })\n return () => {\n cancelled = true\n }\n }, [mode, loaded])\n\n /** 候选手机号展示值:插件库 masked_mobile 优先,用户中心公开资料 mobile 兜底(均为脱敏值) */\n const mobileOf = (u) => u.masked_mobile || infoMap[String(u.uid)]?.mobile || ''\n\n /** 手机号片段匹配:所见即所搜(脱敏串 includes);输入完整 11 位明文号码时\n * 按脱敏串「前 3 位 + 后 4 位」比对(脱敏中间段无法匹配,属数据边界) */\n const mobileMatch = (masked, kw) => {\n if (!masked) return false\n if (masked.toLowerCase().includes(kw)) return true\n if (/^\\d{11}$/.test(kw)) return masked.slice(0, 3) === kw.slice(0, 3) && masked.slice(-4) === kw.slice(-4)\n return false\n }\n\n /** 过滤:uid / 昵称 / 脱敏手机号(昵称、兜底手机号来自用户中心公开资料) */\n const filtered = useMemo(() => {\n const kw = keyword.trim().toLowerCase()\n if (!kw) return options\n return options.filter((u) => {\n if (String(u.uid).includes(kw)) return true\n if (mobileMatch(mobileOf(u), kw)) return true\n const nickname = (infoMap[String(u.uid)]?.nickname || '').toLowerCase()\n return nickname.includes(kw)\n })\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [options, keyword, infoMap])\n\n const totalPages = Math.max(1, Math.ceil(filtered.length / PAGE_SIZE))\n const safePage = Math.min(page, totalPages)\n const pageItems = filtered.slice((safePage - 1) * PAGE_SIZE, safePage * PAGE_SIZE)\n\n const togglePick = (u) => {\n if (existing.has(Number(u.uid))) return\n setPickedUids((prev) => (prev.includes(u.uid) ? prev.filter((x) => x !== u.uid) : [...prev, u.uid]))\n }\n\n const submit = () => {\n if (mode === 'mobile') {\n const msg = validateMobile(mobile)\n if (msg) {\n setError(msg)\n return\n }\n onSubmit({ mobile: String(mobile).replace(/[\\s-]/g, ''), role })\n return\n }\n if (!pickedUids.length) {\n setError('请先从列表中选择用户(支持多选)')\n return\n }\n onSubmit({ uids: pickedUids, role })\n }\n\n return (\n <Modal\n title=\"添加成员\"\n onClose={onClose}\n footer={\n <>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={onClose} disabled={busy}>\n 取消\n </button>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-primary\" onClick={submit} disabled={busy}>\n {busy\n ? '添加中…'\n : mode === 'pick' && pickedUids.length\n ? `添加(已选 ${pickedUids.length} 人)`\n : '添加'}\n </button>\n </>\n }\n >\n {/* 添加方式切换 */}\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">添加方式</span>\n <div className=\"skai-kb-row-actions\">\n <button\n type=\"button\"\n className={`skai-kb-btn skai-kb-btn-sm ${mode === 'mobile' ? 'skai-kb-btn-primary' : ''}`}\n onClick={() => {\n setMode('mobile')\n setError('')\n }}\n >\n 按手机号\n </button>\n <button\n type=\"button\"\n className={`skai-kb-btn skai-kb-btn-sm ${mode === 'pick' ? 'skai-kb-btn-primary' : ''}`}\n onClick={() => {\n setMode('pick')\n setPickedUids([])\n setError('')\n }}\n >\n 从用户列表选择\n </button>\n </div>\n </div>\n\n {mode === 'mobile' ? (\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">成员手机号 *</span>\n <input\n className=\"skai-kb-input\"\n value={mobile}\n inputMode=\"tel\"\n maxLength={13}\n placeholder=\"11 位大陆手机号,如 13812345678\"\n onChange={(e) => setMobile(e.target.value)}\n />\n </div>\n ) : (\n <>\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">选择用户 *</span>\n <input\n className=\"skai-kb-input\"\n value={keyword}\n placeholder=\"搜索 uid、昵称或手机号片段\"\n onChange={(e) => {\n setKeyword(e.target.value)\n setPage(1)\n }}\n />\n </div>\n\n {/* 已选 chips(可移除) */}\n {pickedUids.length ? (\n <div className=\"skai-kb-picked-chips\">\n {pickedUids.map((uid) => {\n const info = infoMap[String(uid)]\n const nickname = (info?.nickname || '').trim()\n return (\n <span key={uid} className=\"skai-kb-picked-chip\">\n {info?.avatar ? <img className=\"skai-kb-picked-chip-avatar\" src={info.avatar} alt=\"\" /> : null}\n <span className=\"skai-kb-picked-chip-text\">{nickname || `uid ${uid}`}</span>\n <button\n type=\"button\"\n className=\"skai-kb-picked-chip-remove\"\n aria-label={`移除 ${nickname || uid}`}\n onClick={() => setPickedUids((prev) => prev.filter((x) => x !== uid))}\n >\n ×\n </button>\n </span>\n )\n })}\n </div>\n ) : null}\n\n <div className=\"skai-kb-user-pick-list\" role=\"listbox\" aria-label=\"用户候选列表\" aria-multiselectable=\"true\">\n {!loaded ? (\n <div className=\"skai-kb-sub\">加载中…</div>\n ) : pageItems.length === 0 ? (\n <div className=\"skai-kb-sub\">\n {options.length ? '无匹配用户' : '暂无候选用户(仅展示「正常」状态用户)'}\n </div>\n ) : (\n pageItems.map((u) => {\n const uidNum = Number(u.uid)\n const inKb = existing.has(uidNum)\n const checked = pickedUids.includes(u.uid)\n const info = infoMap[String(u.uid)]\n const nickname = (info?.nickname || '').trim()\n const initial = nickname ? nickname.slice(0, 1).toUpperCase() : '#'\n const mobileView = u.masked_mobile || info?.mobile || '手机号未知'\n return (\n <button\n key={u.uid}\n type=\"button\"\n role=\"option\"\n aria-selected={checked}\n disabled={inKb}\n className={`skai-kb-user-pick-item ${checked ? 'skai-kb-user-pick-item-active' : ''} ${inKb ? 'skai-kb-user-pick-item-disabled' : ''}`}\n onClick={() => togglePick(u)}\n >\n <span className={`skai-kb-pick-check ${checked ? 'skai-kb-pick-check-on' : ''}`} aria-hidden=\"true\">\n {checked ? '✓' : ''}\n </span>\n <span className=\"skai-kb-row\" style={{ minWidth: 0, flex: 1 }}>\n {info?.avatar ? (\n <img className=\"skai-kb-member-avatar\" src={info.avatar} alt=\"\" />\n ) : (\n <span className=\"skai-kb-member-avatar skai-kb-member-avatar-fallback\" aria-hidden=\"true\">\n {initial}\n </span>\n )}\n <span style={{ minWidth: 0 }}>\n <span className=\"skai-kb-user-pick-nickname\">\n {nickname || '用户'}(uid {u.uid})\n </span>\n <span className=\"skai-kb-sub\" style={{ display: 'block', padding: 0 }}>\n {mobileView}\n </span>\n </span>\n </span>\n {inKb ? <span className=\"skai-kb-badge skai-kb-badge-gray\">已在知识库</span> : null}\n </button>\n )\n })\n )}\n </div>\n {totalPages > 1 ? (\n <div className=\"skai-kb-row-actions\" style={{ marginTop: 6 }}>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm\"\n disabled={safePage <= 1}\n onClick={() => setPage((p) => Math.max(1, p - 1))}\n >\n 上一页\n </button>\n <span className=\"skai-kb-sub\">\n {safePage} / {totalPages} · 共 {filtered.length} 人\n </span>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm\"\n disabled={safePage >= totalPages}\n onClick={() => setPage((p) => p + 1)}\n >\n 下一页\n </button>\n </div>\n ) : null}\n </>\n )}\n\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">角色</span>\n <select className=\"skai-kb-select\" value={role} onChange={(e) => setRole(Number(e.target.value))}>\n <option value={2}>{ROLE_LABEL[2]}(上传、新增、修改文档)</option>\n <option value={3}>{ROLE_LABEL[3]}(查看文档、预览)</option>\n <option value={1}>{ROLE_LABEL[1]}(全部管理权限)</option>\n </select>\n </div>\n <div className=\"skai-kb-sub\">\n {mode === 'mobile'\n ? '通过手机号添加:已注册用户直接添加生效;尚未注册的用户会先创建待激活授权,其注册并登录知识库后自动成为成员'\n : '从列表选择:仅展示「正常」状态用户,可多选批量添加;已在知识库中的用户不可重复添加'}\n </div>\n {error ? <div className=\"skai-kb-field-error\">{error}</div> : null}\n </Modal>\n )\n}\n","/**\n * 知识库成员权限配置弹窗(知识库详情页内打开)\n * 成员列表、角色管理(所有者);权限变更实时写 PG,\n * 后端同步失效 Redis 权限缓存(cache:kb_perm:{uid})\n */\nimport { useCallback, useEffect, useState } from 'react'\nimport Modal from '../common/Modal.jsx'\nimport ConfirmDialog from '../common/ConfirmDialog.jsx'\nimport MemberList from './MemberList.jsx'\nimport MemberGrantModal from './MemberGrantModal.jsx'\nimport { listPermission, grantPermission, revokePermission, revokePendingPermission } from '../../api/kb.js'\nimport { findMemberByMobile } from '../../hooks/use-member-info.js'\nimport { toast, toastError } from '../../store/ui-store.js'\n\nexport default function PermissionModal({ kbId, kbName, isAdmin, onClose }) {\n const [members, setMembers] = useState([])\n const [granting, setGranting] = useState(false)\n const [removing, setRemoving] = useState(null)\n const [busy, setBusy] = useState(false)\n\n const reload = useCallback(() => {\n if (kbId == null) return\n listPermission(kbId)\n .then((data) => setMembers(data?.list || []))\n .catch(toastError)\n }, [kbId])\n\n useEffect(() => {\n reload()\n }, [reload])\n\n const submitGrant = (data) => {\n setBusy(true)\n // 从用户列表选择(多选):逐个按 uid 授权,allSettled 聚合成败\n if (data.uids?.length) {\n Promise.allSettled(data.uids.map((uid) => grantPermission(kbId, { uid: Number(uid), role: data.role })))\n .then((results) => {\n const ok = results.filter((r) => r.status === 'fulfilled').length\n const fail = results.length - ok\n if (ok) toast(`已添加 ${ok} 名成员${fail ? `,${fail} 名失败` : ''}`, fail ? 'info' : 'success')\n if (fail) toast(`${fail} 名用户添加失败,请重试`, 'error')\n if (!fail) setGranting(false)\n reload()\n })\n .finally(() => setBusy(false))\n return\n }\n // 从用户列表选择(单个,兼容):直接按 uid 授权\n if (data.uid) {\n grantPermission(kbId, { uid: Number(data.uid), role: data.role })\n .then(() => {\n toast('成员已添加', 'success')\n setGranting(false)\n reload()\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n return\n }\n // 按手机号添加:先经用户中心按手机号解析 uid:已注册 → 直接按 uid 授权;\n // 未注册(或用户中心接口不可用)→ 回退手机号 md5 待激活授权\n findMemberByMobile(data.mobile)\n .then((member) => {\n if (member) {\n const label = member.nickname ? `${member.nickname}(uid ${member.uid})` : `uid ${member.uid}`\n return grantPermission(kbId, { uid: Number(member.uid), role: data.role }).then(() => {\n toast(`已添加成员 ${label}`, 'success')\n setGranting(false)\n reload()\n })\n }\n return grantPermission(kbId, { mobile: data.mobile, role: data.role }).then((res) => {\n toast(\n res?.pending\n ? '该手机号尚未注册,已创建待激活授权,其注册登录后自动生效'\n : '成员已添加',\n 'success',\n )\n setGranting(false)\n reload()\n })\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const changeRole = (m, role) => {\n setBusy(true)\n grantPermission(kbId, { uid: m.uid, role })\n .then(() => {\n toast('角色已更新', 'success')\n reload()\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const submitRemove = () => {\n setBusy(true)\n // 待激活行:撤销预授权;正式成员:移除授权\n const req = removing.pending\n ? revokePendingPermission(kbId, removing.pending_id)\n : revokePermission(kbId, removing.uid)\n req\n .then(() => {\n toast(removing.pending ? '已撤销待激活授权' : '成员已移除', 'success')\n setRemoving(null)\n reload()\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n return (\n <>\n <Modal\n title={`成员权限 · ${kbName || `知识库 #${kbId}`}`}\n onClose={onClose}\n footer={\n isAdmin ? (\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-primary\"\n onClick={() => setGranting(true)}\n >\n 添加成员\n </button>\n ) : null\n }\n >\n {!isAdmin ? (\n <div className=\"skai-kb-sub\" style={{ marginBottom: 6 }}>\n 仅所有者可管理成员与角色\n </div>\n ) : null}\n <MemberList\n members={members}\n isAdmin={isAdmin}\n canManage={isAdmin}\n onRoleChange={changeRole}\n onRemove={setRemoving}\n busy={busy}\n />\n </Modal>\n {granting ? (\n <MemberGrantModal\n busy={busy}\n existingUids={members.map((m) => m.uid).filter((uid) => Number(uid) > 0)}\n onSubmit={submitGrant}\n onClose={() => setGranting(false)}\n />\n ) : null}\n {removing ? (\n <ConfirmDialog\n title={removing.pending ? '撤销待激活授权' : '移除成员'}\n message={\n removing.pending\n ? `确定撤销手机号 ${removing.masked_mobile || ''} 的待激活授权吗?撤销后该手机号登录将不再自动获得权限。`\n : `确定移除成员 #${removing.uid} 吗?移除后其将无法访问该知识库。`\n }\n confirmText={removing.pending ? '撤销' : '移除'}\n busy={busy}\n onConfirm={submitRemove}\n onClose={() => setRemoving(null)}\n />\n ) : null}\n </>\n )\n}\n","/**\n * 知识库详情页(独立标签页正文,params: { kbId })\n *\n * - 页头:知识库名称 / 角色 / MCP 状态;返回列表、权限配置、编辑、重建向量\n * - 文档列表:名称+文本关键词检索、标签过滤、分页;点击文档打开「文档详情」标签页\n * - 添加文档:拖拽/单文件上传(md/txt/pdf/docx),标签与分段覆盖配置\n * - 解析/向量化状态轮询(use-task-polling);失败重解析\n * - 知识库成员权限配置(弹窗,所有者)\n */\nimport { useCallback, useEffect, useState } from 'react'\nimport { useStore } from '../../store/create-store.js'\nimport {\n docStore,\n setDocList,\n setDocKeyword,\n setDocTagFilter,\n setDocPage,\n patchDocStatus,\n} from '../../store/doc-store.js'\nimport { folderStore, setFolderTree, setCurrentFolder, dragCtx, EMPTY_TREE } from '../../store/folder-store.js'\nimport { kbStore, upsertKb } from '../../store/kb-store.js'\nimport { setDocName, setKbName } from '../../store/title-store.js'\nimport { toast, toastError } from '../../store/ui-store.js'\nimport {\n listDocs,\n uploadDoc,\n deleteDoc,\n reparseDoc,\n listDocVersions,\n rollbackDoc,\n moveDoc,\n reorderDocs,\n} from '../../api/doc.js'\nimport { getFolderTree } from '../../api/folder.js'\nimport { listKb, updateKb } from '../../api/kb.js'\nimport { rebuildVector } from '../../api/task.js'\nimport { useKbPermission } from '../../hooks/use-kb-permission.js'\nimport { useTaskPolling } from '../../hooks/use-task-polling.js'\nimport { formatTime, EXT_LABEL, extOf } from '../../utils/file-type.js'\nimport { ROLE_LABEL } from '../../store/kb-store.js'\nimport DocSearchBar from '../../components/doc/DocSearchBar.jsx'\nimport DocStatusBadge from '../../components/doc/DocStatusBadge.jsx'\nimport FolderTree from '../../components/doc/FolderTree.jsx'\nimport MoveDocModal from '../../components/doc/MoveDocModal.jsx'\nimport { UploadDropzone, PickedFileMeta } from '../../components/doc/UploadDropzone.jsx'\nimport ChunkConfigForm from '../../components/doc/ChunkConfigForm.jsx'\nimport VersionTimeline from '../../components/doc/VersionTimeline.jsx'\nimport TagPicker from '../../components/kb/TagPicker.jsx'\nimport KbFormModal from '../../components/kb/KbFormModal.jsx'\nimport Modal from '../../components/common/Modal.jsx'\nimport ConfirmDialog from '../../components/common/ConfirmDialog.jsx'\nimport PermissionModal from '../../components/permission/PermissionModal.jsx'\nimport Toast from '../../components/common/Toast.jsx'\n\n/**\n * @param {object} props\n * @param {number} props.kbId 知识库 id(导航参数)\n * @param {string} [props.view] 导航视图提示('permission' 时自动打开权限配置)\n * @param {{ openDoc: (kbId: number, docId: number) => void, openHome: () => void }} props.nav\n */\nexport default function KbDetailPage({ kbId, view, nav }) {\n const kb = useStore(kbStore, (s) => s.list.find((k) => k.id === kbId))\n const list = useStore(docStore, (s) => s.list)\n const total = useStore(docStore, (s) => s.total)\n const page = useStore(docStore, (s) => s.page)\n const limit = useStore(docStore, (s) => s.limit)\n const keyword = useStore(docStore, (s) => s.keyword)\n const tagFilter = useStore(docStore, (s) => s.tagFilter)\n // 当前浏览目录(0=根目录);文档列表按目录过滤\n const folderTree = useStore(folderStore, (s) => (s.kbId === kbId ? s.tree : EMPTY_TREE))\n const currentFolderId = useStore(folderStore, (s) => (s.kbId === kbId ? s.currentId : 0))\n const { canEdit, canManage, isAdmin } = useKbPermission(kbId)\n const [uploading, setUploading] = useState(false)\n const [pickedFile, setPickedFile] = useState(null)\n const [uploadTags, setUploadTags] = useState([])\n const [uploadChunk, setUploadChunk] = useState({ chunk_size: null, chunk_overlap: null })\n const [uploadFolderId, setUploadFolderId] = useState(0)\n const [deleting, setDeleting] = useState(null)\n const [moving, setMoving] = useState(null)\n const [dragOverDocId, setDragOverDocId] = useState(null)\n const [menuDocId, setMenuDocId] = useState(null) // 卡片右上角「操作」下拉当前打开的文档 id\n const [versionsOf, setVersionsOf] = useState(null)\n const [versions, setVersions] = useState([])\n const [editing, setEditing] = useState(false)\n const [permissionOpen, setPermissionOpen] = useState(false)\n const [busy, setBusy] = useState(false)\n\n /** 文档列表加载(防串库:仅当返回仍属于当前 kbId 时回填;按当前目录递归列出其子树全部文档) */\n const reload = useCallback(\n (p = page) => {\n if (kbId == null) return\n listDocs(kbId, { keyword, tag: tagFilter, folderId: currentFolderId, recursive: true, page: p, limit })\n .then((data) => {\n const docList = data?.list || []\n setDocList(kbId, docList, data?.total || 0, p, limit)\n docList.forEach((d) => setDocName(kbId, d.id, d.name))\n })\n .catch(toastError)\n },\n [kbId, keyword, tagFilter, page, limit, currentFolderId],\n )\n\n /** 目录树加载(进入页面/结构变更后) */\n const reloadTree = useCallback(() => {\n if (kbId == null) return\n getFolderTree(kbId)\n .then((tree) => setFolderTree(kbId, tree || []))\n .catch(toastError)\n }, [kbId])\n\n // 切换知识库(新开/重新导航标签页)重置筛选并拉取列表 + 目录树\n useEffect(() => {\n setDocKeyword('')\n setDocTagFilter('')\n setDocPage(1)\n setCurrentFolder(0)\n reloadTree()\n reload(1)\n }, [kbId])\n\n useEffect(() => {\n reload(1)\n }, [keyword, tagFilter, currentFolderId])\n\n // 知识库元信息缺失时(直接打开详情标签页)拉一次列表补齐 + 标签页名称\n useEffect(() => {\n if (kb || kbId == null) return\n listKb({ page: 1, limit: 100 })\n .then((data) => {\n const kbList = data?.list || []\n const found = kbList.find((k) => k.id === kbId)\n if (found) {\n upsertKb(found)\n setKbName(found.id, found.name)\n }\n })\n .catch(() => {})\n }, [kb, kbId])\n\n // 解析中/向量化中的文档自动轮询刷新\n useTaskPolling(\n kbId != null && list.some((d) => d.status === 0 || d.status === 1 || d.status === 2),\n async () => {\n const data = await listDocs(kbId, { page, limit, keyword, tag: tagFilter })\n const docList = data?.list || []\n setDocList(kbId, docList, data?.total || 0, page, limit)\n docList.forEach((d) => setDocName(kbId, d.id, d.name))\n },\n )\n\n // 导航参数 view=permission:打开权限配置弹窗(每次重新导航都会步进 revision,\n // 以 revision 为依赖保证同参数再次导航也能弹出)\n useEffect(() => {\n if (view === 'permission' && isAdmin) setPermissionOpen(true)\n }, [view, kbId, isAdmin])\n\n const submitUpload = () => {\n if (!pickedFile) {\n toastError(new Error('请先选择文件'))\n return\n }\n setBusy(true)\n uploadDoc({\n kbId,\n file: pickedFile,\n tags: uploadTags,\n chunkSize: uploadChunk.chunk_size || '',\n chunkOverlap: uploadChunk.chunk_overlap || '',\n folderId: uploadFolderId,\n })\n .then(() => {\n toast('文档已上传,开始解析', 'success')\n setUploading(false)\n setPickedFile(null)\n setUploadTags([])\n setUploadChunk({ chunk_size: null, chunk_overlap: null })\n // 上传目标目录即当前浏览目录(默认),列表同步刷新\n reload(1)\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n /** 文档拖入目录树节点 → 移动到目标目录(0=根目录) */\n const submitDropMove = (docId, folderId) => {\n moveDoc(kbId, docId, folderId)\n .then(() => {\n toast(`已移动到「${folderId === 0 ? '根目录' : folderLabel(folderTree, folderId)}」`, 'success')\n reload(page)\n })\n .catch(toastError)\n }\n\n /** 文档拖拽排序(同目录内;drop 到目标文档前/后,整批提交该目录顺序;递归列表跨目录拖拽仅提示) */\n const submitDocReorder = (srcDoc, targetDoc, pos) => {\n if (srcDoc.id === targetDoc.id) return\n if ((srcDoc.folder_id || 0) !== (targetDoc.folder_id || 0)) {\n toast('跨目录调整请把文档拖到左侧目录树的目标目录', 'info')\n return\n }\n const ids = list\n .filter((d) => (d.folder_id || 0) === (srcDoc.folder_id || 0))\n .map((d) => d.id)\n .filter((id) => id !== srcDoc.id)\n let idx = ids.indexOf(targetDoc.id)\n if (idx < 0) return\n if (pos === 'after') idx += 1\n ids.splice(idx, 0, srcDoc.id)\n reorderDocs(kbId, srcDoc.folder_id || 0, ids)\n .then(() => reload(page))\n .catch(toastError)\n }\n\n const openVersions = (doc) => {\n setVersionsOf(doc)\n setVersions([])\n listDocVersions(kbId, doc.id)\n .then((data) => setVersions(data?.list || []))\n .catch(toastError)\n }\n\n const submitRollback = (v) => {\n setBusy(true)\n rollbackDoc(kbId, versionsOf.id, v.version_no)\n .then(() => {\n toast(`已回滚到 v${v.version_no},正在重新向量化`, 'success')\n setVersionsOf(null)\n reload(page)\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const submitDelete = () => {\n setBusy(true)\n deleteDoc(kbId, deleting.id)\n .then(() => {\n toast('文档已删除', 'success')\n setDeleting(null)\n reload(page)\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const submitReparse = (doc) => {\n reparseDoc(kbId, doc.id)\n .then(() => {\n patchDocStatus(doc.id, { status: 0 })\n toast('已提交重新解析', 'success')\n })\n .catch(toastError)\n }\n\n const submitRebuild = () => {\n setBusy(true)\n rebuildVector(kbId)\n .then((res) => {\n toast(`已提交向量重建任务${res?.task_id ? `(#${res.task_id})` : ''}`, 'success')\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n if (kbId == null) {\n return (\n <div className=\"skai-kb-page\">\n <div className=\"skai-kb-empty\">\n <p>缺少知识库参数</p>\n <p className=\"skai-kb-empty-sub\">请从首页的知识库列表进入</p>\n <div className=\"skai-kb-row\" style={{ justifyContent: 'center', marginTop: 10 }}>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-sm\" onClick={() => nav.openHome()}>\n 返回首页\n </button>\n </div>\n </div>\n <Toast />\n </div>\n )\n }\n\n const totalPages = Math.max(1, Math.ceil(total / limit))\n\n return (\n <div className=\"skai-kb-page\">\n {/* 页头(固定) */}\n <div className=\"skai-kb-detail-head\">\n <div className=\"skai-kb-row-between\">\n <div className=\"skai-kb-row\" style={{ minWidth: 0 }}>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm skai-kb-back\"\n onClick={() => nav.openHome()}\n title=\"返回知识库列表\"\n >\n ‹ 列表\n </button>\n <span className=\"skai-kb-detail-title\" title={kb ? kb.name : ''}>\n {kb ? kb.name : `知识库 #${kbId}`}\n </span>\n <span className={`skai-kb-badge ${kb?.my_role === 1 || kb?.my_role === 5 ? 'skai-kb-badge-blue' : 'skai-kb-badge-gray'}`}>\n {ROLE_LABEL[kb?.my_role] || '只读'}\n </span>\n {kb ? (\n <span className={`skai-kb-badge ${kb.enable_mcp ? 'skai-kb-badge-green' : 'skai-kb-badge-gray'}`}>\n {kb.enable_mcp ? 'MCP 开' : 'MCP 关'}\n </span>\n ) : null}\n </div>\n <div className=\"skai-kb-row\">\n {isAdmin ? (\n <>\n <button\n type=\"button\"\n className=\"skai-kb-btn\"\n onClick={() => setPermissionOpen(true)}\n >\n 权限配置\n </button>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={() => setEditing(true)}>\n 编辑\n </button>\n <button type=\"button\" className=\"skai-kb-btn\" disabled={busy} onClick={submitRebuild}>\n 重建向量\n </button>\n </>\n ) : null}\n </div>\n </div>\n </div>\n\n {/* 滚动区:目录树 + 文档工具栏 + 列表 + 分页 */}\n <div className=\"skai-kb-page-scroll\">\n <div className=\"skai-kb-doc-layout\">\n {/* 左栏:目录树 */}\n <FolderTree\n kbId={kbId}\n canEdit={canEdit}\n onTreeChange={reloadTree}\n onDropDoc={submitDropMove}\n />\n\n {/* 右栏:文档区 */}\n <div className=\"skai-kb-doc-main\">\n {/* 文档工具栏 */}\n <DocSearchBar keyword={keyword} tag={tagFilter} onKeyword={setDocKeyword} onTag={setDocTagFilter}>\n {canEdit ? (\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-primary\"\n onClick={() => {\n setUploadFolderId(currentFolderId)\n setUploading(true)\n }}\n >\n 添加文档\n </button>\n ) : null}\n </DocSearchBar>\n\n {/* 文档列表 */}\n {list.length === 0 ? (\n <div className=\"skai-kb-empty\">\n <p>暂无文档</p>\n <p className=\"skai-kb-empty-sub\">\n {canEdit ? '支持 md / txt / pdf / docx 上传,也可拖入左侧目录' : '支持 md / txt / pdf / docx'}\n </p>\n </div>\n ) : (\n <div className=\"skai-kb-card-list\">\n {list.map((doc, idx) => (\n <div\n key={doc.id}\n className={`skai-kb-card skai-kb-doc-item ${dragOverDocId === doc.id ? 'skai-kb-drop-in' : ''}`}\n onClick={() => nav.openDoc(kbId, doc.id)}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => e.key === 'Enter' && nav.openDoc(kbId, doc.id)}\n draggable={canEdit}\n onDragStart={(e) => {\n dragCtx.type = 'doc'\n dragCtx.id = doc.id\n e.dataTransfer.effectAllowed = 'move'\n e.dataTransfer.setData('text/plain', String(doc.id))\n }}\n onDragEnd={() => {\n dragCtx.type = null\n setDragOverDocId(null)\n }}\n onDragOver={(e) => {\n if (dragCtx.type !== 'doc' || dragCtx.id === doc.id || !canEdit) return\n e.preventDefault()\n e.dataTransfer.dropEffect = 'move'\n setDragOverDocId(doc.id)\n }}\n onDragLeave={() => setDragOverDocId((prev) => (prev === doc.id ? null : prev))}\n onDrop={(e) => {\n e.preventDefault()\n e.stopPropagation()\n const srcId = dragCtx.id\n dragCtx.type = null\n setDragOverDocId(null)\n const src = list.find((d) => d.id === srcId)\n if (src && src.id !== doc.id) {\n const rect = e.currentTarget.getBoundingClientRect()\n const pos = e.clientY - rect.top < rect.height / 2 ? 'before' : 'after'\n submitDocReorder(src, doc, pos)\n }\n }}\n data-idx={idx}\n >\n <div className=\"skai-kb-row-between\">\n <span className=\"skai-kb-title\" title={doc.name}>\n {doc.name}\n </span>\n <span className=\"skai-kb-doc-topbar\">\n <DocStatusBadge status={doc.status} />\n {canEdit ? (\n <span className=\"skai-kb-doc-menu-anchor\" onClick={(e) => e.stopPropagation()}>\n <button\n type=\"button\"\n className=\"skai-kb-doc-menu-trigger\"\n title=\"操作\"\n aria-expanded={menuDocId === doc.id}\n onClick={(e) => {\n e.stopPropagation()\n setMenuDocId(menuDocId === doc.id ? null : doc.id)\n }}\n >\n 操作\n <span className=\"skai-kb-caret\" aria-hidden=\"true\" />\n </button>\n {menuDocId === doc.id ? (\n <>\n <div className=\"skai-kb-menu-mask\" onClick={() => setMenuDocId(null)} />\n <div className=\"skai-kb-menu\" role=\"menu\">\n <button\n type=\"button\"\n className=\"skai-kb-menu-item\"\n role=\"menuitem\"\n onClick={() => {\n setMenuDocId(null)\n setMoving(doc)\n }}\n >\n 移动到…\n </button>\n {canManage ? (\n <button\n type=\"button\"\n className=\"skai-kb-menu-item is-danger\"\n role=\"menuitem\"\n onClick={() => {\n setMenuDocId(null)\n setDeleting(doc)\n }}\n >\n 删除\n </button>\n ) : null}\n </div>\n </>\n ) : null}\n </span>\n ) : null}\n </span>\n </div>\n <div className=\"skai-kb-kb-meta\">\n <span>{EXT_LABEL[extOf(doc.name)] || doc.file_type || '文件'}</span>\n <span>🕒 {formatTime(doc.update_time)}</span>\n {doc.chunk_count ? <span>🧩 {doc.chunk_count} 向量块</span> : null}\n {(doc.folder_id || 0) !== currentFolderId ? (\n <span title=\"来自下级目录\">📁 {folderLabel(folderTree, doc.folder_id)}</span>\n ) : null}\n </div>\n {doc.tags && doc.tags.length ? (\n <div style={{ marginTop: 4 }}>\n {doc.tags.map((t) => (\n <span key={t} className=\"skai-kb-tag\">\n {t}\n </span>\n ))}\n </div>\n ) : null}\n {doc.status === 4 && doc.error_msg ? (\n <div className=\"skai-kb-field-error\" style={{ marginTop: 4 }}>\n 失败原因:{doc.error_msg}\n </div>\n ) : null}\n {canEdit && doc.status === 4 ? (\n <div className=\"skai-kb-kb-actions\" onClick={(e) => e.stopPropagation()}>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm\"\n onClick={() => submitReparse(doc)}\n >\n 重新解析\n </button>\n </div>\n ) : null}\n </div>\n ))}\n </div>\n )}\n\n {/* 分页 */}\n {totalPages > 1 ? (\n <div className=\"skai-kb-pagination\">\n <span>\n 第 {page} / {totalPages} 页 · 共 {total} 篇\n </span>\n <div className=\"skai-kb-pagination-btns\">\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm\"\n disabled={page <= 1}\n onClick={() => {\n setDocPage(page - 1)\n reload(page - 1)\n }}\n >\n 上一页\n </button>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm\"\n disabled={page >= totalPages}\n onClick={() => {\n setDocPage(page + 1)\n reload(page + 1)\n }}\n >\n 下一页\n </button>\n </div>\n </div>\n ) : null}\n </div>\n </div>\n </div>\n\n {/* 上传文档弹窗 */}\n {uploading ? (\n <Modal\n title=\"添加文档\"\n onClose={() => setUploading(false)}\n footer={\n <>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={() => setUploading(false)} disabled={busy}>\n 取消\n </button>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-primary\"\n onClick={submitUpload}\n disabled={busy || !pickedFile}\n >\n {busy ? '上传中…' : '上传'}\n </button>\n </>\n }\n >\n <UploadDropzone onPick={setPickedFile} />\n <PickedFileMeta file={pickedFile} />\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">目标目录</span>\n <select\n className=\"skai-kb-input\"\n value={uploadFolderId}\n onChange={(e) => setUploadFolderId(Number(e.target.value))}\n >\n <option value={0}>根目录</option>\n {flattenFolderOptions(folderTree).map((o) => (\n <option key={o.id} value={o.id}>\n {' '.repeat(o.depth - 1)}\n {o.name}\n </option>\n ))}\n </select>\n <span className=\"skai-kb-field-hint\">默认为当前浏览的目录</span>\n </div>\n <div className=\"skai-kb-field\" style={{ marginTop: 8 }}>\n <span className=\"skai-kb-field-label\">标签</span>\n <TagPicker value={uploadTags} onChange={setUploadTags} />\n </div>\n <ChunkConfigForm advanced onChange={setUploadChunk} />\n </Modal>\n ) : null}\n\n {/* 历史版本弹窗 */}\n {versionsOf ? (\n <Modal title={`历史版本 · ${versionsOf.name}`} onClose={() => setVersionsOf(null)}>\n <VersionTimeline\n versions={versions}\n currentVersion={versionsOf.version_no}\n canEdit={canEdit}\n busy={busy}\n onPreview={() => toast('请在文档详情标签页查看内容', 'info')}\n onRollback={submitRollback}\n />\n </Modal>\n ) : null}\n\n {/* 移动文档弹窗 */}\n {moving ? (\n <MoveDocModal\n kbId={kbId}\n doc={moving}\n excludeFolderId={moving.folder_id || 0}\n onDone={() => reload(page)}\n onClose={() => setMoving(null)}\n />\n ) : null}\n\n {/* 删除文档确认 */}\n {deleting ? (\n <ConfirmDialog\n title=\"删除文档\"\n message={`确定删除「${deleting.name}」吗?删除后 MCP 检索将不再返回该文档。`}\n confirmText=\"删除\"\n busy={busy}\n onConfirm={submitDelete}\n onClose={() => setDeleting(null)}\n />\n ) : null}\n\n {/* 编辑知识库 */}\n {editing && kb ? (\n <KbFormModal\n initial={kb}\n busy={busy}\n onSubmit={(data) => {\n setBusy(true)\n updateKb(kbId, data)\n .then((updated) => {\n const merged = updated || { ...kb, ...data }\n upsertKb(merged)\n setKbName(merged.id, merged.name)\n toast('已保存', 'success')\n setEditing(false)\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }}\n onClose={() => setEditing(false)}\n />\n ) : null}\n\n {/* 权限配置弹窗 */}\n {permissionOpen ? (\n <PermissionModal kbId={kbId} kbName={kb?.name} isAdmin={isAdmin} onClose={() => setPermissionOpen(false)} />\n ) : null}\n <Toast />\n </div>\n )\n}\n\n/** 目录树平铺为下拉选项(depth 从 1 起,缩进用) */\nfunction flattenFolderOptions(tree) {\n const out = []\n const walk = (nodes, depth) => {\n for (const n of nodes || []) {\n out.push({ id: n.id, name: n.name, depth })\n walk(n.children, depth + 1)\n }\n }\n walk(tree, 1)\n return out\n}\n\n/** 按 id 查目录名称(toast 文案用) */\nfunction folderLabel(tree, folderId) {\n const found = flattenFolderOptions(tree).find((o) => o.id === folderId)\n return found ? found.name : `目录 #${folderId}`\n}\n","/**\n * 轻量 Markdown 渲染(无第三方依赖;文档详情页正文)\n *\n * - 文本一律作为 React 文本节点渲染(不经 dangerouslySetInnerHTML / innerHTML),\n * 文档内容中的 <script> 等片段只会原样展示,无注入面\n * - 块级:标题 #~######、围栏代码块 ```、引用 >、无序/有序列表、表格 |…|、\n * 分隔线 ---、段落\n * - 行内:`代码`、**粗体**、__粗体__、*斜体*、~~删除线~~、[链接](url)、\n * 、裸 http(s) 链接\n */\nimport { useMemo, Fragment } from 'react'\n\n/** 行内标记扫描:按优先级依次匹配,命中即递归处理内容 */\nconst INLINE_PATTERN =\n /(`[^`\\n]+`)|(\\*\\*[^*\\n]+\\*\\*)|(__[^_\\n]+__)|(\\*[^*\\n]+\\*)|(~~[^~\\n]+~~)|(!\\[[^\\]\\n]*\\]\\([^)\\s]+\\))|(\\[[^\\]\\n]+\\]\\([^)\\s]+\\))|(https?:\\/\\/[^\\s<>()[\\]]+)/g\n\n/** 递归渲染行内元素(key 前缀保证列表稳定;每次调用独立正则实例,避免递归串扰 lastIndex) */\nfunction renderInline(text, keyPrefix = 'i') {\n const re = new RegExp(INLINE_PATTERN.source, INLINE_PATTERN.flags)\n const nodes = []\n let last = 0\n let m\n let idx = 0\n while ((m = re.exec(text))) {\n if (m.index > last) nodes.push(text.slice(last, m.index))\n const tok = m[0]\n const key = `${keyPrefix}-${idx++}`\n if (tok.startsWith('`')) {\n nodes.push(\n <code key={key} className=\"skai-kb-md-code\">\n {tok.slice(1, -1)}\n </code>,\n )\n } else if (tok.startsWith('**') || tok.startsWith('__')) {\n nodes.push(<strong key={key}>{renderInline(tok.slice(2, -2), key)}</strong>)\n } else if (tok.startsWith('~~')) {\n nodes.push(<del key={key}>{renderInline(tok.slice(2, -2), key)}</del>)\n } else if (tok.startsWith('*')) {\n nodes.push(<em key={key}>{renderInline(tok.slice(1, -1), key)}</em>)\n } else if (tok.startsWith('![')) {\n const mm = /^!\\[([^\\]]*)\\]\\(([^)\\s]+)\\)$/.exec(tok)\n if (mm) {\n nodes.push(<img key={key} className=\"skai-kb-md-img\" src={mm[2]} alt={mm[1] || ''} loading=\"lazy\" />)\n } else {\n nodes.push(tok)\n }\n } else if (tok.startsWith('[')) {\n const mm = /^\\[([^\\]]+)\\]\\(([^)\\s]+)\\)$/.exec(tok)\n if (mm) {\n nodes.push(\n <a key={key} className=\"skai-kb-md-link\" href={mm[2]} target=\"_blank\" rel=\"noopener noreferrer\">\n {renderInline(mm[1], key)}\n </a>,\n )\n } else {\n nodes.push(tok)\n }\n } else {\n nodes.push(\n <a key={key} className=\"skai-kb-md-link\" href={tok} target=\"_blank\" rel=\"noopener noreferrer\">\n {tok}\n </a>,\n )\n }\n last = re.lastIndex\n }\n if (last < text.length) nodes.push(text.slice(last))\n return nodes\n}\n\n/** 表格行解析:| a | b | → ['a','b'](容忍首尾竖线缺失) */\nfunction splitTableRow(line) {\n return line\n .replace(/^\\s*\\|/, '')\n .replace(/\\|\\s*$/, '')\n .split('|')\n .map((c) => c.trim())\n}\n\nfunction isTableDivider(line) {\n return /^\\s*\\|?[\\s:-]*-[\\s:|-]*\\|?\\s*$/.test(line) && line.includes('-')\n}\n\n/** 块级解析:行数组 → React 元素数组 */\nfunction renderBlocks(lines, keyPrefix = 'b') {\n const blocks = []\n let i = 0\n let idx = 0\n const k = () => `${keyPrefix}-${idx++}`\n while (i < lines.length) {\n const line = lines[i]\n // 围栏代码块\n if (/^\\s*```/.test(line)) {\n const lang = line.replace(/^\\s*```/, '').trim()\n const buf = []\n i++\n while (i < lines.length && !/^\\s*```/.test(lines[i])) {\n buf.push(lines[i])\n i++\n }\n i++ // 跳过收尾 ```\n blocks.push(\n <pre key={k()} className=\"skai-kb-md-pre\" data-lang={lang || undefined}>\n <code>{buf.join('\\n')}</code>\n </pre>,\n )\n continue\n }\n // 标题\n const h = /^(#{1,6})\\s+(.*)$/.exec(line)\n if (h) {\n const level = h[1].length\n const content = renderInline(h[2].replace(/\\s+#+\\s*$/, ''), `${k()}-h`)\n const Tag = `h${Math.min(level + 1, 6)}` // 页内标题从 h2 起,避免抢标签页语义\n blocks.push(\n <Tag key={k()} className={`skai-kb-md-h skai-kb-md-h${level}`}>\n {content}\n </Tag>,\n )\n i++\n continue\n }\n // 分隔线\n if (/^\\s*(-{3,}|\\*{3,}|_{3,})\\s*$/.test(line)) {\n blocks.push(<hr key={k()} className=\"skai-kb-md-hr\" />)\n i++\n continue\n }\n // 引用(连续 > 行)\n if (/^\\s*>/.test(line)) {\n const buf = []\n while (i < lines.length && /^\\s*>/.test(lines[i])) {\n buf.push(lines[i].replace(/^\\s*>\\s?/, ''))\n i++\n }\n blocks.push(\n <blockquote key={k()} className=\"skai-kb-md-quote\">\n {renderBlocks(buf, `${k()}-q`)}\n </blockquote>,\n )\n continue\n }\n // 表格(表头行 + 分隔行)\n if (line.includes('|') && i + 1 < lines.length && isTableDivider(lines[i + 1]) && lines[i + 1].includes('|')) {\n const head = splitTableRow(line)\n i += 2\n const rows = []\n while (i < lines.length && lines[i].includes('|') && lines[i].trim() !== '') {\n rows.push(splitTableRow(lines[i]))\n i++\n }\n blocks.push(\n <div key={k()} className=\"skai-kb-md-table-wrap\">\n <table className=\"skai-kb-md-table\">\n <thead>\n <tr>\n {head.map((c, ci) => (\n <th key={ci}>{renderInline(c, `${k()}-th${ci}`)}</th>\n ))}\n </tr>\n </thead>\n <tbody>\n {rows.map((r, ri) => (\n <tr key={ri}>\n {r.map((c, ci) => (\n <td key={ci}>{renderInline(c, `${k()}-td${ri}-${ci}`)}</td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>,\n )\n continue\n }\n // 无序列表\n if (/^\\s*[-*+]\\s+/.test(line)) {\n const items = []\n while (i < lines.length && /^\\s*[-*+]\\s+/.test(lines[i])) {\n items.push(lines[i].replace(/^\\s*[-*+]\\s+/, ''))\n i++\n }\n blocks.push(\n <ul key={k()} className=\"skai-kb-md-ul\">\n {items.map((it, ii) => (\n <li key={ii}>{renderInline(it, `${k()}-li${ii}`)}</li>\n ))}\n </ul>,\n )\n continue\n }\n // 有序列表\n if (/^\\s*\\d+[.)]\\s+/.test(line)) {\n const items = []\n while (i < lines.length && /^\\s*\\d+[.)]\\s+/.test(lines[i])) {\n items.push(lines[i].replace(/^\\s*\\d+[.)]\\s+/, ''))\n i++\n }\n blocks.push(\n <ol key={k()} className=\"skai-kb-md-ol\">\n {items.map((it, ii) => (\n <li key={ii}>{renderInline(it, `${k()}-oli${ii}`)}</li>\n ))}\n </ol>,\n )\n continue\n }\n // 空行\n if (line.trim() === '') {\n i++\n continue\n }\n // 段落(连续非空、非特殊行合并;软换行以 <br/> 呈现)\n const buf = [line]\n i++\n while (\n i < lines.length &&\n lines[i].trim() !== '' &&\n !/^\\s*```/.test(lines[i]) &&\n !/^(#{1,6})\\s+/.test(lines[i]) &&\n !/^\\s*>/.test(lines[i]) &&\n !/^\\s*[-*+]\\s+/.test(lines[i]) &&\n !/^\\s*\\d+[.)]\\s+/.test(lines[i]) &&\n !/^\\s*(-{3,}|\\*{3,}|_{3,})\\s*$/.test(lines[i])\n ) {\n buf.push(lines[i])\n i++\n }\n blocks.push(\n <p key={k()} className=\"skai-kb-md-p\">\n {buf.map((ln, li) => (\n <Fragment key={li}>\n {li > 0 ? <br /> : null}\n {renderInline(ln, `${k()}-p${li}`)}\n </Fragment>\n ))}\n </p>,\n )\n }\n return blocks\n}\n\n/**\n * Markdown 渲染组件\n * @param {object} props\n * @param {string} props.text markdown 原文\n */\nexport default function Markdown({ text }) {\n const blocks = useMemo(() => renderBlocks(String(text || '').split(/\\r?\\n/)), [text])\n return <div className=\"skai-kb-md\">{blocks}</div>\n}\n","/**\n * Markdown 可视化编辑器(文档详情页正文区,组件内自管草稿状态)\n *\n * - 布局:工具栏 + 编辑区(默认「编辑」模式,占满父容器高度),可切换 仅编辑/分屏/仅预览;\n * - 工具栏:标题、加粗、斜体、删除线、行内代码、无序/有序列表、引用、代码块、\n * 表格、链接 —— 对选区包裹或行首插入前缀\n * - 保存:onSave(content, force);HTTP 409 冲突时由父级弹「放弃/覆盖」引导,\n * 覆盖重试时 force=true(本组件保持草稿不重置)\n * - 预览复用 Markdown 渲染组件(无 dangerouslySetInnerHTML,无注入面)\n */\nimport { useEffect, useRef, useState } from 'react'\nimport Markdown from '../markdown/Markdown.jsx'\nimport { SpinnerGlyph } from '../common/icons.jsx'\n\n/** 工具栏动作定义:wrap=选区包裹;line=行首前缀;block=整块插入 */\nconst TOOLBAR = [\n { label: 'H2', title: '标题', kind: 'line', arg: '## ' },\n { label: 'H3', title: '三级标题', kind: 'line', arg: '### ' },\n { label: 'B', title: '加粗', kind: 'wrap', arg: '**' },\n { label: 'I', title: '斜体', kind: 'wrap', arg: '*' },\n { label: 'S', title: '删除线', kind: 'wrap', arg: '~~' },\n { label: '‹›', title: '行内代码', kind: 'wrap', arg: '`' },\n { label: '• 列表', title: '无序列表', kind: 'line', arg: '- ' },\n { label: '1. 列表', title: '有序列表', kind: 'line', arg: '1. ' },\n { label: '❝ 引用', title: '引用', kind: 'line', arg: '> ' },\n {\n label: '{}. 代码块',\n title: '代码块',\n kind: 'block',\n arg: '\\n```\\n\\n```\\n',\n cursorOffset: -5, // 定位到首尾 ``` 之间的空行\n },\n {\n label: '▦ 表格',\n title: '表格',\n kind: 'block',\n arg: '\\n| 列1 | 列2 | 列3 |\\n| --- | --- | --- |\\n| | | |\\n',\n cursorOffset: -21,\n },\n { label: '🔗 链接', title: '链接', kind: 'wrap', arg: '[', suffix: '](https://)' },\n]\n\n/**\n * @param {object} props\n * @param {string} props.initial 进入编辑时的原文\n * @param {boolean} props.saving 保存中(禁用按钮)\n * @param {(content: string, force: boolean) => void} props.onSave\n * @param {() => void} props.onCancel\n * @param {((draft: string) => void) | undefined} props.onAIWrite AI 编写入口(传入时在视图切换行首渲染按钮,携带当前草稿)\n * @param {boolean} [props.aiRunning] AI 编写进行中(按钮禁用并显示进度文案)\n */\nexport default function MarkdownEditor({ initial, saving, onSave, onCancel, onAIWrite, aiRunning }) {\n const [draft, setDraft] = useState(initial)\n // 视图模式:split 分屏 / edit 仅编辑 / preview 仅预览\n const [viewMode, setViewMode] = useState('edit')\n const taRef = useRef(null)\n\n // 内容被外部重载(重新进入编辑)时重置草稿\n useEffect(() => setDraft(initial), [initial])\n\n /** 应用工具栏动作:wrap 包裹选区 / line 行首前缀 / block 插入整块 */\n const applyAction = (act) => {\n const ta = taRef.current\n if (!ta) return\n const { selectionStart: start, selectionEnd: end, value } = ta\n let next = value\n let cursor = end\n if (act.kind === 'wrap') {\n const sel = value.slice(start, end) || act.placeholder || ''\n const suffix = act.suffix || act.arg\n next = value.slice(0, start) + act.arg + sel + suffix + value.slice(end)\n cursor = start + act.arg.length + sel.length\n } else if (act.kind === 'line') {\n // 行首插入前缀(多行逐行加)\n const lineStart = value.lastIndexOf('\\n', start - 1) + 1\n const seg = value.slice(lineStart, end)\n const prefixed = seg\n .split('\\n')\n .map((ln) => (ln.trim() === '' && seg.includes('\\n') ? ln : act.arg + ln))\n .join('\\n')\n next = value.slice(0, lineStart) + prefixed + value.slice(end)\n cursor = lineStart + prefixed.length\n } else if (act.kind === 'block') {\n next = value.slice(0, end) + act.arg + value.slice(end)\n cursor = end + act.arg.length + (act.cursorOffset || 0)\n }\n setDraft(next)\n // 等状态回写后恢复焦点与选区\n requestAnimationFrame(() => {\n ta.focus()\n ta.setSelectionRange(cursor, cursor)\n })\n }\n\n const dirty = draft !== initial\n\n return (\n <div className={`skai-kb-editor ${viewMode}`}>\n <div className=\"skai-kb-editor-bar\">\n <div className=\"skai-kb-editor-tools\">\n {TOOLBAR.map((act) => (\n <button\n key={act.label}\n type=\"button\"\n className=\"skai-kb-editor-tool\"\n title={act.title}\n disabled={saving}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => applyAction(act)}\n >\n {act.label}\n </button>\n ))}\n </div>\n <div className=\"skai-kb-editor-modes\">\n {onAIWrite ? (\n <button\n type=\"button\"\n className=\"skai-kb-btn\"\n onClick={() => onAIWrite(draft)}\n disabled={aiRunning}\n title=\"AI 修改完善文档,结果回填编辑框\"\n >\n {aiRunning ? (\n <>\n <SpinnerGlyph />\n 编写中\n </>\n ) : (\n 'AI编写'\n )}\n </button>\n ) : null}\n <button\n type=\"button\"\n className={`skai-kb-editor-mode ${viewMode === 'edit' ? 'is-active' : ''}`}\n onClick={() => setViewMode('edit')}\n >\n 编辑\n </button>\n <button\n type=\"button\"\n className={`skai-kb-editor-mode ${viewMode === 'split' ? 'is-active' : ''}`}\n onClick={() => setViewMode('split')}\n >\n 分屏\n </button>\n <button\n type=\"button\"\n className={`skai-kb-editor-mode ${viewMode === 'preview' ? 'is-active' : ''}`}\n onClick={() => setViewMode('preview')}\n >\n 预览\n </button>\n {dirty ? <span className=\"skai-kb-editor-dirty\">未保存</span> : null}\n <button type=\"button\" className=\"skai-kb-btn\" onClick={onCancel} disabled={saving}>\n 取消\n </button>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-primary\"\n disabled={saving || !draft.trim()}\n onClick={() => onSave(draft, false)}\n >\n {saving ? '保存中…' : '保存'}\n </button>\n </div>\n </div>\n <div className={`skai-kb-editor-panes ${viewMode}`}>\n {viewMode !== 'preview' ? (\n <textarea\n ref={taRef}\n className=\"skai-kb-editor-input\"\n value={draft}\n spellCheck={false}\n placeholder=\"输入 Markdown 内容…\"\n onChange={(e) => setDraft(e.target.value)}\n onKeyDown={(e) => {\n // Cmd/Ctrl+B 加粗、Cmd/Ctrl+I 斜体、Cmd/Ctrl+S 保存\n if ((e.metaKey || e.ctrlKey) && !e.shiftKey) {\n const k = e.key.toLowerCase()\n if (k === 'b') {\n e.preventDefault()\n applyAction(TOOLBAR[2])\n } else if (k === 'i') {\n e.preventDefault()\n applyAction(TOOLBAR[3])\n } else if (k === 's') {\n e.preventDefault()\n if (!saving && draft.trim()) onSave(draft, false)\n }\n }\n // Tab 缩进两个空格\n if (e.key === 'Tab') {\n e.preventDefault()\n const ta = e.currentTarget\n const { selectionStart: s, selectionEnd: t, value } = ta\n setDraft(value.slice(0, s) + ' ' + value.slice(t))\n requestAnimationFrame(() => ta.setSelectionRange(s + 2, s + 2))\n }\n }}\n />\n ) : null}\n {viewMode !== 'edit' ? (\n <div className=\"skai-kb-editor-preview\">\n <Markdown text={draft} />\n </div>\n ) : null}\n </div>\n </div>\n )\n}\n","/**\n * 文档详情页(独立标签页正文,params: { kbId, docId },markdown 格式渲染)\n *\n * - 页头:文档名称 / 状态 / 类型 / 更新时间;返回知识库、引用文档到会话(输入框插入\n * 不可编辑引用 chip,降级纯文本/剪贴板)、历史版本、重新解析、删除(按角色展示)\n * - 正文:所有入库内容统一为 Markdown(上传时 pdf/docx 已由后端解析整理为 md),一律按 Markdown 渲染\n * (在线文本预览由后端解析后的文本承载)\n * - 版本:历史快照查看、回滚(回滚自动触发重新向量化)\n * - 编辑:重命名 / 标签 / 分段覆盖配置(编辑者与所有者)\n * - 在线编辑:「编辑内容」进入 Markdown 可视化编辑器(默认「编辑」模式 + 格式工具栏;所有文档\n * 上传时已由后端统一解析整理为 Markdown 存储),保存触发版本快照与重新解析/向量化,\n * updated_at 乐观校验冲突时引导放弃/覆盖\n */\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { useStore } from '../../store/create-store.js'\nimport { docStore, patchDocStatus } from '../../store/doc-store.js'\nimport { setDocName } from '../../store/title-store.js'\nimport { toast, toastError } from '../../store/ui-store.js'\nimport { ROLE_LABEL } from '../../store/kb-store.js'\nimport { kbStore } from '../../store/kb-store.js'\nimport {\n getDoc,\n getDocContent,\n listDocVersions,\n rollbackDoc,\n updateDoc,\n updateDocContent,\n deleteDoc,\n reparseDoc,\n} from '../../api/doc.js'\nimport { runAIWriteSession, insertSessionReference } from '../../core/dsh-agent.js'\nimport { buildDocReferenceInsert, refSerializeText } from '../../core/kb-trigger.js'\nimport { useKbPermission } from '../../hooks/use-kb-permission.js'\nimport { useTaskPolling } from '../../hooks/use-task-polling.js'\nimport { formatTime, EXT_LABEL, extOf } from '../../utils/file-type.js'\nimport DocStatusBadge from '../../components/doc/DocStatusBadge.jsx'\nimport MarkdownEditor from '../../components/doc/MarkdownEditor.jsx'\nimport ChunkConfigForm from '../../components/doc/ChunkConfigForm.jsx'\nimport VersionTimeline from '../../components/doc/VersionTimeline.jsx'\nimport TagPicker from '../../components/kb/TagPicker.jsx'\nimport Markdown from '../../components/markdown/Markdown.jsx'\nimport Modal from '../../components/common/Modal.jsx'\nimport ConfirmDialog from '../../components/common/ConfirmDialog.jsx'\nimport Toast from '../../components/common/Toast.jsx'\nimport { FullscreenGlyph, FullscreenExitGlyph, SpinnerGlyph } from '../../components/common/icons.jsx'\n\n/** AI 编写默认提示词(弹窗内可修改) */\nconst AI_WRITE_PROMPT_DEFAULT = '修改和完善文档并排版,保持内容不变,不额外增加原有文档没有的内容。'\n\n/**\n * @param {object} props\n * @param {number} props.kbId 知识库 id\n * @param {number} props.docId 文档 id\n * @param {{ openKb: (kbId: number) => void }} props.nav\n */\nexport default function DocDetailPage({ kbId, docId, nav }) {\n const kb = useStore(kbStore, (s) => s.list.find((k) => k.id === kbId))\n const listDoc = useStore(docStore, (s) => s.list.find((d) => d.id === docId))\n const { canEdit, canManage, isAdmin } = useKbPermission(kbId)\n const [meta, setMeta] = useState(null)\n const [content, setContent] = useState('')\n const [loading, setLoading] = useState(true)\n const [contentError, setContentError] = useState('')\n const [versionsOpen, setVersionsOpen] = useState(false)\n const [versionsFull, setVersionsFull] = useState(false) // 历史版本弹窗全屏态\n const [versions, setVersions] = useState([])\n const [editing, setEditing] = useState(false)\n const [editName, setEditName] = useState('')\n const [editTags, setEditTags] = useState([])\n const [editChunk, setEditChunk] = useState({ chunk_size: null, chunk_overlap: null })\n const [previewVersion, setPreviewVersion] = useState(null)\n const [previewFull, setPreviewFull] = useState(false) // 版本内容预览弹窗全屏态\n const [deleting, setDeleting] = useState(false)\n const [busy, setBusy] = useState(false)\n // 在线编辑(Markdown 可视化编辑)\n const [editorOpen, setEditorOpen] = useState(false)\n const [savingContent, setSavingContent] = useState(false)\n const [conflict, setConflict] = useState(null) // { content } 乐观锁冲突待决(放弃/覆盖)\n // AI 编写(编辑器工具栏入口 → 提示词弹窗 → 独立子会话 → assistant 消息全文回填草稿)\n const [aiOpen, setAiOpen] = useState(false)\n const [aiPrompt, setAiPrompt] = useState(AI_WRITE_PROMPT_DEFAULT)\n const [aiRunning, setAiRunning] = useState(false)\n const [aiSource, setAiSource] = useState('') // 本次 AI 编写的输入底稿(编辑器当前草稿)\n const aiAbandonRef = useRef(false) // 「取消等待」置位:不再接收本次结果写回\n\n /** 文档元数据:详情接口优先,失败回退列表缓存 */\n const loadMeta = useCallback(() => {\n if (kbId == null || docId == null) return Promise.resolve(null)\n return getDoc(kbId, docId)\n .then((doc) => {\n setMeta(doc)\n setDocName(kbId, docId, doc.name)\n return doc\n })\n .catch(() => {\n if (listDoc) {\n setMeta(listDoc)\n setDocName(kbId, docId, listDoc.name)\n return listDoc\n }\n return null\n })\n }, [kbId, docId, listDoc])\n\n /** 正文内容 */\n const loadContent = useCallback(\n (versionNo) => {\n if (kbId == null || docId == null) return\n setLoading(true)\n setContentError('')\n getDocContent(kbId, docId, versionNo)\n .then((data) => setContent((data && data.content) || ''))\n .catch((e) => setContentError(e.msg || e.message || '内容加载失败'))\n .finally(() => setLoading(false))\n },\n [kbId, docId],\n )\n\n useEffect(() => {\n setMeta(null)\n setContent('')\n aiAbandonRef.current = true // 切换文档:放弃在途 AI 结果写回\n setAiRunning(false)\n setPreviewVersion(null)\n setPreviewFull(false)\n setVersionsOpen(false)\n setVersionsFull(false)\n loadMeta().finally(() => loadContent())\n }, [kbId, docId])\n\n // 组件卸载:放弃在途 AI 结果写回\n useEffect(() => () => {\n aiAbandonRef.current = true\n }, [])\n\n // 解析中/向量化中状态轮询(仅元数据,正文在「已就绪」后手动/重新进入查看)\n useTaskPolling(\n meta != null && (meta.status === 0 || meta.status === 1 || meta.status === 2),\n async () => {\n const doc = await loadMeta()\n if (doc && doc.status === 3 && (meta?.status || 0) < 3) loadContent()\n },\n )\n\n const openVersions = () => {\n setVersionsOpen(true)\n setVersions([])\n listDocVersions(kbId, docId)\n // 接口返回裸数组(data 即版本列表;?.list 为历史误读导致列表恒空)\n .then((data) => setVersions(Array.isArray(data) ? data : data?.list || []))\n .catch(toastError)\n }\n\n const submitRollback = (v) => {\n setBusy(true)\n rollbackDoc(kbId, docId, v.version_no)\n .then(() => {\n toast(`已回滚到 v${v.version_no},正在重新向量化`, 'success')\n setVersionsOpen(false)\n setPreviewVersion(null)\n loadMeta().then((doc) => {\n if (doc && doc.status === 3) loadContent()\n })\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const openEdit = () => {\n setEditName(meta?.name || '')\n setEditTags(meta?.tags || [])\n setEditChunk({ chunk_size: meta?.chunk_size || null, chunk_overlap: meta?.chunk_overlap || null })\n setEditing(true)\n }\n\n const submitEdit = () => {\n if (!editName.trim()) {\n toastError(new Error('请输入文档名称'))\n return\n }\n setBusy(true)\n updateDoc(kbId, docId, {\n name: editName.trim(),\n tags: editTags,\n chunk_size: editChunk.chunk_size,\n chunk_overlap: editChunk.chunk_overlap,\n })\n .then(() => {\n toast('已保存,文档重新向量化中', 'success')\n setEditing(false)\n loadMeta().then((doc) => {\n if (doc && doc.status === 3) loadContent()\n })\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const submitDelete = () => {\n setBusy(true)\n deleteDoc(kbId, docId)\n .then(() => {\n toast('文档已删除', 'success')\n nav.openKb(kbId)\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const submitReparse = () => {\n reparseDoc(kbId, docId)\n .then(() => {\n patchDocStatus(docId, { status: 0 })\n if (meta) setMeta({ ...meta, status: 0 })\n toast('已提交重新解析', 'success')\n })\n .catch(toastError)\n }\n\n /** 在线编辑保存:版本快照 + 重新解析/向量化;409 冲突时引导放弃/覆盖 */\n const submitContent = (draft, force) => {\n setSavingContent(true)\n updateDocContent(kbId, docId, { content: draft, baseUpdatedAt: meta?.update_time, force })\n .then((res) => {\n setConflict(null)\n setEditorOpen(false)\n toast(`已保存${res?.version_no ?? ''},重新解析/向量化中`, 'success')\n loadMeta().then((doc) => {\n if (doc && doc.status === 3) loadContent()\n })\n })\n .catch((e) => {\n if (e?.code === 409 || /冲突/.test(e?.msg || e?.message || '')) {\n setConflict({ content: draft })\n } else {\n toastError(e)\n }\n })\n .finally(() => setSavingContent(false))\n }\n\n /** AI 编写:提示词 + 编辑器当前草稿提交独立子会话,assistant 消息全文回填草稿 */\n const submitAIWrite = () => {\n const prompt = aiPrompt.trim()\n if (!prompt) {\n toastError(new Error('请输入提示词'))\n return\n }\n if (!aiSource.trim()) {\n toastError(new Error('文档内容为空,无法 AI 编写'))\n return\n }\n const text = [\n '【知识库 AI 编写】请根据提示词修改和完善下面的文档并排版。',\n `提示词:${prompt}`,\n '直接输出修改后的完整 Markdown 文档全文(不是片段、不是说明文字,不要附加任何解释或前后缀)。',\n `文档原文(kb_id=${kbId},doc_id=${docId},名称:${meta?.name || ''}):`,\n '<<<DOC_START>>>',\n aiSource,\n '<<<DOC_END>>>',\n ].join('\\n')\n aiAbandonRef.current = false\n setAiRunning(true)\n runAIWriteSession({\n text,\n onDelta: () => {}, // 过程帧预留:当前 UI 以弹窗文案呈现进度\n })\n .then((full) => {\n if (aiAbandonRef.current) return // 用户已取消等待或切换文档:不写回\n setAiRunning(false)\n setAiOpen(false)\n setConflict(null)\n setContent(full) // initial 变化触发 MarkdownEditor 草稿重置\n toast('AI 编写完成,已替换到编辑框,请确认后保存', 'success')\n })\n .catch((e) => {\n if (aiAbandonRef.current) return\n setAiRunning(false)\n toastError(e)\n })\n }\n\n /** 打开 AI 编写弹窗:记录底稿并重置提示词(编写中重开仅查看进度,不重置) */\n const openAIWrite = (draft) => {\n if (!aiRunning) {\n setAiSource(typeof draft === 'string' && draft.trim() ? draft : content)\n setAiPrompt(AI_WRITE_PROMPT_DEFAULT)\n }\n setAiOpen(true)\n }\n\n /** 编写中取消等待:AI 会话继续在 DSH 侧完成,仅前端不再接收结果写回 */\n const cancelAIWrite = () => {\n aiAbandonRef.current = true\n setAiRunning(false)\n setAiOpen(false)\n }\n\n if (kbId == null || docId == null) {\n return (\n <div className=\"skai-kb-page\">\n <div className=\"skai-kb-empty\">\n <p>缺少文档参数</p>\n <p className=\"skai-kb-empty-sub\">请从知识库详情页的文档列表进入</p>\n </div>\n <Toast />\n </div>\n )\n }\n\n const doc = meta\n const ext = extOf(doc?.name || '')\n const needsParse = doc && doc.status !== 3\n\n return (\n <div className=\"skai-kb-page skai-kb-doc-detail\">\n {/* 页头 */}\n <div className=\"skai-kb-detail-head\">\n <div className=\"skai-kb-row-between\">\n <div className=\"skai-kb-row\" style={{ minWidth: 0 }}>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm skai-kb-back\"\n onClick={() => nav.openKb(kbId)}\n title=\"返回知识库详情\"\n >\n ‹ {kb ? kb.name : '知识库'}\n </button>\n <span className=\"skai-kb-detail-title\" title={doc?.name || ''}>\n {doc?.name || (loading ? '加载中…' : `文档 #${docId}`)}\n </span>\n {doc ? <DocStatusBadge status={doc.status} /> : null}\n </div>\n <div className=\"skai-kb-row\">\n {canEdit ? (\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-primary\"\n onClick={() => {\n setConflict(null)\n setEditorOpen(true)\n }}\n disabled={editorOpen}\n >\n 编辑内容\n </button>\n ) : null}\n {canEdit ? (\n <button type=\"button\" className=\"skai-kb-btn\" onClick={openEdit}>\n 编辑\n </button>\n ) : null}\n <button type=\"button\" className=\"skai-kb-btn\" onClick={openVersions}>\n 历史版本\n </button>\n {canEdit && doc && doc.status === 4 ? (\n <button type=\"button\" className=\"skai-kb-btn\" onClick={submitReparse}>\n 重新解析\n </button>\n ) : null}\n {canManage ? (\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-ghost-danger\"\n onClick={() => setDeleting(true)}\n >\n 删除\n </button>\n ) : null}\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-primary\"\n disabled={!doc || doc.status !== 3}\n title={!doc ? '文档加载中' : doc.status !== 3 ? '文档解析就绪后才能引用' : '把文档引用以 chip 形式插入 DSH 当前会话的输入框'}\n onClick={async () => {\n const item = { kbId, docId, docName: doc?.name || '' }\n try {\n const r = await insertSessionReference(buildDocReferenceInsert(item), refSerializeText(item))\n if (r.chip) {\n toast('已将文档引用 chip 插入当前会话输入框,请补充问题后发送', 'success', 3600)\n } else {\n toast('宿主不支持插入引用 chip,已写入引用文本,请直接发送或补充问题', 'success', 4200)\n }\n } catch (e) {\n // 降级:直写失败(无打开会话/通道不可用)时退回复制到剪贴板\n const prompt = refSerializeText(item)\n try {\n await navigator.clipboard.writeText(prompt)\n toast(`引用已复制,请粘贴到 DSH 会话发送(${e?.message || '直写失败'})`, 'success', 4200)\n } catch (_) {\n toast('剪贴板不可用,请手动复制引用到会话', 'error', 3600)\n }\n }\n }}\n >\n 引用文档到会话\n </button>\n </div>\n </div>\n <div className=\"skai-kb-sub\" style={{ textAlign: 'right' }}>\n {EXT_LABEL[ext] || doc?.file_type || '文件'} · 更新于 {formatTime(doc?.update_time)} ·\n 当前版本 v{doc?.version_no ?? '-'}\n {doc?.chunk_count ? ` · ${doc.chunk_count} 向量块` : ''}\n <span className={`skai-kb-badge ${isAdmin ? 'skai-kb-badge-blue' : 'skai-kb-badge-gray'}`} style={{ marginLeft: 6 }}>\n {ROLE_LABEL[kb?.my_role] || ''}\n </span>\n </div>\n {doc?.status === 4 && doc?.error_msg ? (\n <div className=\"skai-kb-field-error\">解析失败:{doc.error_msg}</div>\n ) : null}\n </div>\n\n {/* 正文(编辑模式:Markdown 可视化编辑器;浏览模式:渲染预览) */}\n <div className=\"skai-kb-md-wrap\">\n {editorOpen ? (\n <MarkdownEditor\n initial={content}\n saving={savingContent}\n onSave={submitContent}\n onAIWrite={openAIWrite}\n aiRunning={aiRunning}\n onCancel={() => {\n setEditorOpen(false)\n setConflict(null)\n }}\n />\n ) : needsParse ? (\n <div className=\"skai-kb-empty\">\n <p>文档尚未完成解析({doc?.status === 4 ? '解析失败' : '解析中/向量化中'})</p>\n <p className=\"skai-kb-empty-sub\">解析完成后即可在线预览全文;当前可在列表中跟踪任务状态</p>\n </div>\n ) : loading ? (\n <div className=\"skai-kb-empty\">\n <p>内容加载中…</p>\n </div>\n ) : contentError ? (\n <div className=\"skai-kb-empty\">\n <p>{contentError}</p>\n </div>\n ) : (\n /* 所有入库内容统一为 Markdown(上传时 pdf/docx 已解析整理),一律按 Markdown 渲染 */\n <Markdown text={content} />\n )}\n </div>\n\n {/* 历史版本弹窗(版本列表) */}\n {versionsOpen ? (\n <Modal\n title={`历史版本 · ${doc?.name || ''}`}\n width=\"680px\"\n fullscreen={versionsFull}\n escClose={previewVersion === null}\n onClose={() => {\n setVersionsOpen(false)\n setVersionsFull(false)\n setPreviewVersion(null)\n setPreviewFull(false)\n }}\n extraHead={\n <button\n type=\"button\"\n className=\"skai-kb-icon-btn\"\n data-tip={versionsFull ? '退出全屏' : '全屏'}\n aria-label={versionsFull ? '退出全屏' : '全屏'}\n onClick={() => setVersionsFull(!versionsFull)}\n >\n {versionsFull ? <FullscreenExitGlyph /> : <FullscreenGlyph />}\n </button>\n }\n >\n <VersionTimeline\n versions={versions}\n currentVersion={doc?.version_no}\n canEdit={canEdit}\n busy={busy}\n onPreview={(v) => setPreviewVersion(v.version_no)}\n onRollback={submitRollback}\n />\n </Modal>\n ) : null}\n\n {/* 版本内容预览弹窗(独立弹窗,叠于版本列表之上;列表弹窗保持打开) */}\n {versionsOpen && previewVersion !== null ? (\n <Modal\n title={`版本内容 v${previewVersion} · ${doc?.name || ''}`}\n width=\"680px\"\n fullscreen={previewFull}\n onClose={() => {\n setPreviewVersion(null)\n setPreviewFull(false)\n }}\n extraHead={\n <button\n type=\"button\"\n className=\"skai-kb-icon-btn\"\n data-tip={previewFull ? '退出全屏' : '全屏'}\n aria-label={previewFull ? '退出全屏' : '全屏'}\n onClick={() => setPreviewFull(!previewFull)}\n >\n {previewFull ? <FullscreenExitGlyph /> : <FullscreenGlyph />}\n </button>\n }\n >\n <VersionPreview kbId={kbId} docId={docId} versionNo={previewVersion} />\n </Modal>\n ) : null}\n\n {/* 编辑文档弹窗 */}\n {editing ? (\n <Modal\n title=\"编辑文档\"\n onClose={() => setEditing(false)}\n footer={\n <>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={() => setEditing(false)} disabled={busy}>\n 取消\n </button>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-primary\" onClick={submitEdit} disabled={busy}>\n {busy ? '保存中…' : '保存'}\n </button>\n </>\n }\n >\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">名称 *</span>\n <input\n className=\"skai-kb-input\"\n value={editName}\n maxLength={128}\n onChange={(e) => setEditName(e.target.value)}\n />\n </div>\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">标签</span>\n <TagPicker value={editTags} onChange={setEditTags} />\n </div>\n <ChunkConfigForm advanced initial={{ chunk_size: editChunk.chunk_size || '', chunk_overlap: editChunk.chunk_overlap || '' }} onChange={setEditChunk} />\n <div className=\"skai-kb-sub\">修改名称/分段配置后,文档将自动重新向量化</div>\n </Modal>\n ) : null}\n\n {/* AI 编写弹窗(提示词确认 → 智能体编写 → 结果回填 → 手动保存;编写中锁定,仅「取消等待」可关) */}\n {aiOpen ? (\n <Modal\n title=\"AI 编写\"\n locked={aiRunning}\n escClose={!aiRunning}\n onClose={aiRunning ? cancelAIWrite : () => setAiOpen(false)}\n footer={\n <>\n <button\n type=\"button\"\n className=\"skai-kb-btn\"\n onClick={aiRunning ? cancelAIWrite : () => setAiOpen(false)}\n >\n {aiRunning ? '取消等待' : '取消'}\n </button>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-primary\"\n onClick={submitAIWrite}\n disabled={aiRunning}\n >\n {aiRunning ? (\n <>\n <SpinnerGlyph />\n 编写中\n </>\n ) : (\n '确认'\n )}\n </button>\n </>\n }\n >\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">提示词</span>\n <textarea\n className=\"skai-kb-textarea\"\n rows={4}\n value={aiPrompt}\n disabled={aiRunning}\n onChange={(e) => setAiPrompt(e.target.value)}\n />\n </div>\n {aiRunning ? (\n <div className=\"skai-kb-sub\">\n AI 正在编写(可在 DSH 会话列表查看进度),完成后将自动替换到编辑框;「取消等待」不再接收本次结果\n </div>\n ) : (\n <div className=\"skai-kb-sub\">\n 确认后提示词将携带文档原文提交 DSH 智能体独立会话编写,完成后自动替换编辑框内容,保存仍需手动确认\n </div>\n )}\n </Modal>\n ) : null}\n\n {/* 保存冲突(updated_at 乐观校验):放弃或覆盖 */}\n {conflict ? (\n <ConfirmDialog\n title=\"保存冲突\"\n message=\"文档内容已被他人更新。选择「覆盖保存」以当前内容强制保存;选择「取消」返回编辑器(可自行放弃修改)。\"\n confirmText=\"覆盖保存\"\n danger={false}\n busy={savingContent}\n onConfirm={() => submitContent(conflict.content, true)}\n onClose={() => setConflict(null)}\n />\n ) : null}\n\n {/* 删除确认 */}\n {deleting ? (\n <ConfirmDialog\n title=\"删除文档\"\n message={`确定删除「${doc?.name || ''}」吗?删除后 MCP 检索将不再返回该文档。`}\n confirmText=\"删除\"\n busy={busy}\n onConfirm={submitDelete}\n onClose={() => setDeleting(false)}\n />\n ) : null}\n <Toast />\n </div>\n )\n}\n\n/** 历史版本内容预览(md 渲染 / 纯文本) */\nfunction VersionPreview({ kbId, docId, versionNo }) {\n const [text, setText] = useState('')\n const [error, setError] = useState('')\n const [loading, setLoading] = useState(true)\n useEffect(() => {\n setLoading(true)\n setError('')\n getDocContent(kbId, docId, versionNo)\n .then((data) => setText((data && data.content) || ''))\n .catch((e) => setError(e.msg || e.message || '版本内容加载失败'))\n .finally(() => setLoading(false))\n }, [kbId, docId, versionNo])\n if (loading) return <div className=\"skai-kb-empty\"><p>版本内容加载中…</p></div>\n if (error) return <div className=\"skai-kb-empty\"><p>{error}</p></div>\n return <Markdown text={text} />\n}\n","/**\n * 系统级 REST(对应后端 /kb/health 等免鉴权接口)\n */\nimport request from '../core/request.js'\n\n/** 健康检查:返回 { status: 'ok', version: '<后端发布版本>' }(免登录,不受平台状态门禁拦截) */\nexport function getHealth() {\n return request.get('/health', {}, { allowAnonymous: true })\n}\n","","/**\n * 插件元信息(供桌面基座加载校验)\n */\nimport { version } from '../package.json'\n\nexport const manifest = {\n /** 插件标识(基座内唯一) */\n id: 'knowledge',\n /** 插件名称 */\n name: '知识库',\n /** npm 作用域包名 */\n packageName: '@shikeai/knowledge',\n /** 版本:单一来源 frontend/package.json,构建时(tsdown/vite)自动内联,禁止在此手写第二份 */\n version,\n /** 功能描述 */\n description: '时刻AI平台桌面端知识库插件:知识管理(右侧 Sidebar 标签页:首页/知识库详情/文档详情/设置)、成员权限、MCP RAG 检索服务',\n /** 作者 */\n author: 'shikeai',\n /** 平台内置预装插件,不可卸载 */\n builtin: true,\n uninstallable: false,\n /** 权限声明 */\n permissions: [\n 'tab:right-sidebar', // 注册右侧 Sidebar 标签页类型(首页 / 知识库详情 / 文档详情 / 设置)\n 'event:shikeai-usercenter', // 监听用户中心登录态事件(login / logout / expired / user-update)\n 'global:window', // 只读访问 window.SHIKEAI_USER_INFO / SHIKEAI_GET_SIGN_CREDENTIAL /\n // SHIKEAI_GET/SET_MEMBER_CONFIG(服务器配置云持久化)\n //(不接触用户中心 Token,登录态经按需验签换发)\n ],\n /**\n * UI 形态:DSH 右侧 Sidebar 标签页体系(每个主要功能各为一个新标签页,\n * 经 tab.actions.openTab(kind, { params }) 打开)\n * - 首页 shikeai-knowledge-home:知识库列表 / 添加知识库 / 设置入口(引导页胶囊直达)\n * - 知识库详情 shikeai-knowledge-kb:文档列表 / 权限配置 / 添加文档(params: { kbId })\n * - 文档详情 shikeai-knowledge-doc:markdown 渲染 / 版本 / 复制文档提示语(params: { kbId, docId })\n * - 设置 shikeai-knowledge-settings:后端服务器地址 / 管理员\n * 无内置对话面板,全部交互在标签页内完成,无页面跳转刷新\n */\n ui: {\n renderMode: 'drawer',\n drawerPosition: 'right',\n entries: ['sidebar-right-knowledge'],\n tabs: ['shikeai-knowledge-home', 'shikeai-knowledge-kb', 'shikeai-knowledge-doc', 'shikeai-knowledge-settings'],\n },\n}\n\nexport default manifest\n","/**\n * 新增/编辑后端服务器弹窗:名称 + 服务器URL(仅协议 + 域名/IP 及端口)\n * 应用路径固定 /kb 由前端统一拼装,无需用户配置\n * 校验与写入统一走 core/server-config,失败在表单内展示错误\n * 保存成功回调 onSaved({ added, activated }):activated=新增服务器被自动设为当前\n * (新增首个服务器),当前服务器即知识库 MCP 接入点,宿主登记随之同步至 DSH\n */\nimport { useState } from 'react'\nimport Modal from '../common/Modal.jsx'\nimport { addServer, updateServer, getActiveServer, validateServerName, validateServerUrl } from '../../core/server-config.js'\n\nexport default function ServerFormModal({ initial, onClose, onSaved }) {\n const isEdit = Boolean(initial && initial.id)\n const [name, setName] = useState(initial?.name || '')\n const [apiBase, setApiBase] = useState(initial?.api_base || '')\n const [error, setError] = useState('')\n\n const submit = () => {\n const msg = validateServerName(name) || validateServerUrl(apiBase)\n if (msg) {\n setError(msg)\n return\n }\n if (isEdit) {\n const err = updateServer(initial.id, name, apiBase)\n if (err) {\n setError(err)\n return\n }\n onSaved({ added: false, activated: false })\n return\n }\n const prevActiveId = getActiveServer()?.id || ''\n const err = addServer(name, apiBase)\n if (err) {\n setError(err)\n return\n }\n onSaved({ added: true, activated: (getActiveServer()?.id || '') !== prevActiveId })\n }\n\n return (\n <Modal\n title={isEdit ? '编辑服务器' : '添加服务器'}\n onClose={onClose}\n footer={\n <>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={onClose}>\n 取消\n </button>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-primary\" onClick={submit}>\n 保存\n </button>\n </>\n }\n >\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">名称 *</span>\n <input\n className=\"skai-kb-input\"\n value={name}\n maxLength={32}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"如:开发环境 / 内网服务器\"\n />\n </div>\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">服务器 URL *</span>\n <input\n className=\"skai-kb-input\"\n value={apiBase}\n onChange={(e) => setApiBase(e.target.value)}\n placeholder=\"http://127.0.0.1:8081\"\n />\n <span className=\"skai-kb-sub\">支持 http/https,仅填服务器 IP/域名及端口,如 http://127.0.0.1:8081;应用路径 /kb 固定,无需配置</span>\n </div>\n {error ? <div className=\"skai-kb-field-error\">{error}</div> : null}\n </Modal>\n )\n}\n","/**\n * 添加管理员弹窗:手机号(仅管理员操作)\n * 目标用户登录过 → 即时生效;未登录过 → 落待激活授权,其登录后自动补全 uid 生效\n */\nimport { useState } from 'react'\nimport Modal from '../common/Modal.jsx'\nimport { validateMobile } from '../../utils/validator.js'\n\nexport default function AdminFormModal({ busy, onSubmit, onClose }) {\n const [mobile, setMobile] = useState('')\n const [error, setError] = useState('')\n const submit = () => {\n const msg = validateMobile(mobile)\n if (msg) {\n setError(msg)\n return\n }\n onSubmit({ mobile: String(mobile).replace(/[\\s-]/g, '') })\n }\n return (\n <Modal\n title=\"添加管理员\"\n onClose={onClose}\n footer={\n <>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={onClose} disabled={busy}>\n 取消\n </button>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-primary\" onClick={submit} disabled={busy}>\n {busy ? '添加中…' : '添加'}\n </button>\n </>\n }\n >\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">用户手机号 *</span>\n <input\n className=\"skai-kb-input\"\n value={mobile}\n inputMode=\"tel\"\n maxLength={13}\n placeholder=\"11 位大陆手机号,如 13812345678\"\n onChange={(e) => setMobile(e.target.value)}\n />\n </div>\n <div className=\"skai-kb-sub\">\n 通过手机号添加:已注册用户直接添加生效;尚未注册的用户会先创建待激活授权,\n 其注册并登录知识库后自动成为管理员\n </div>\n {error ? <div className=\"skai-kb-field-error\">{error}</div> : null}\n </Modal>\n )\n}\n","/**\n * 用户管理区块(设置页;仅管理员可见可操作,非管理员仅展示状态说明)\n *\n * - 用户列表:昵称(用户中心批量获取,仅展示)/ UID / 脱敏手机号 / 状态标签 /\n * 注册时间 / 最近审核信息;状态筛选(全部/待审核/正常/禁用)+ 关键词(UID 或\n * 手机号片段)+ 分页;管理员行标注「管理员」且不可被审核/禁用/删除\n * - 操作:审核通过(待审核→正常)、禁用(同步吊销其全部插件 Token)、启用\n * (禁用→正常)、删除(物理删除状态与授权,保留其知识库,悬空所有者由管理员\n * 经「修改所有者」接管);操作均写后端审计日志\n * - 新用户默认审核模式:需审核 / 无需审核(默认);切换仅影响之后首次验签的新用户\n */\nimport { useCallback, useEffect, useState } from 'react'\nimport {\n listUsers,\n getReviewConfig,\n setReviewConfig,\n reviewUser,\n disableUser,\n enableUser,\n deleteUser,\n} from '../../api/user.js'\nimport { toast, toastError } from '../../store/ui-store.js'\nimport { useMemberInfo } from '../../hooks/use-member-info.js'\nimport { formatTime } from '../../utils/file-type.js'\nimport ConfirmDialog from '../common/ConfirmDialog.jsx'\n\nconst PAGE_SIZE = 20\n\n/** 用户状态 → 展示文案与徽标色系(0 待审核 / 1 正常 / 2 禁用) */\nconst STATUS_VIEW = {\n 0: { text: '待审核', badge: 'skai-kb-badge-amber' },\n 1: { text: '正常', badge: 'skai-kb-badge-green' },\n 2: { text: '禁用', badge: 'skai-kb-badge-red' },\n}\n\nconst STATUS_FILTERS = [\n { value: -1, label: '全部' },\n { value: 0, label: '待审核' },\n { value: 1, label: '正常' },\n { value: 2, label: '禁用' },\n]\n\nexport default function UserManagePanel({ isAdmin }) {\n const [loading, setLoading] = useState(true)\n const [users, setUsers] = useState([])\n const [total, setTotal] = useState(0)\n const [pendingCount, setPendingCount] = useState(0)\n const [status, setStatus] = useState(-1)\n const [keyword, setKeyword] = useState('')\n const [page, setPage] = useState(1)\n const [mode, setMode] = useState(null) // null 加载中;0 无需审核;1 需审核\n const [modeBusy, setModeBusy] = useState(false)\n const [busy, setBusy] = useState(false)\n const [confirm, setConfirm] = useState(null) // { action, user }\n // 用户公开资料(昵称/头像/脱敏手机号,用户中心批量获取,仅展示不作为可信身份)\n const { infoMap } = useMemberInfo(users.map((u) => u.uid))\n\n const reload = useCallback(() => {\n if (!isAdmin) {\n setLoading(false)\n return\n }\n setLoading(true)\n listUsers({ status, keyword: keyword.trim() || undefined, page, limit: PAGE_SIZE })\n .then((res) => {\n setUsers(Array.isArray(res?.list) ? res.list : [])\n setTotal(Number(res?.total) || 0)\n setPendingCount(Number(res?.pending_count) || 0)\n })\n .catch(toastError)\n .finally(() => setLoading(false))\n }, [isAdmin, status, keyword, page])\n\n useEffect(reload, [reload])\n\n useEffect(() => {\n if (!isAdmin) return\n getReviewConfig()\n .then((res) => setMode(Number(res?.mode) === 1 ? 1 : 0))\n .catch(() => setMode(0))\n }, [isAdmin])\n\n const switchMode = (next) => {\n if (modeBusy || next === mode) return\n setModeBusy(true)\n setReviewConfig(next)\n .then(() => {\n setMode(next)\n toast(next === 1 ? '已开启需审核:新用户首次进入知识库将处于待审核状态' : '已关闭审核:新用户首次进入即为正常状态', 'success')\n })\n .catch(toastError)\n .finally(() => setModeBusy(false))\n }\n\n const runAction = () => {\n const { action, user } = confirm\n setBusy(true)\n action(user.uid)\n .then(() => {\n toast('操作成功', 'success')\n setConfirm(null)\n reload()\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const totalPages = Math.max(1, Math.ceil(total / PAGE_SIZE))\n const canPrev = page > 1\n const canNext = page < totalPages\n\n if (!isAdmin) {\n return (\n <section className=\"skai-kb-panel\" aria-label=\"用户管理\">\n <div className=\"skai-kb-panel-head\">\n <h3>用户管理</h3>\n </div>\n <div className=\"skai-kb-sub\">用户管理仅管理员可用:审核新用户、禁用/启用账号、删除用户与配置新用户审核模式。</div>\n </section>\n )\n }\n\n return (\n <section className=\"skai-kb-panel\" aria-label=\"用户管理\">\n <div className=\"skai-kb-panel-head\">\n <h3>\n 用户管理\n {pendingCount > 0 ? <span className=\"skai-kb-badge skai-kb-badge-amber\">{pendingCount} 待审核</span> : null}\n </h3>\n </div>\n\n {/* 新用户默认审核模式 */}\n <div className=\"skai-kb-user-review-mode\">\n <span className=\"skai-kb-sub\" style={{ padding: 0 }}>\n 新用户默认审核模式(仅影响之后首次进入的新用户,不影响存量用户)\n </span>\n <div className=\"skai-kb-row-actions\">\n <button\n type=\"button\"\n className={`skai-kb-btn skai-kb-btn-sm ${mode === 1 ? 'skai-kb-btn-primary' : ''}`}\n disabled={mode === null || modeBusy}\n onClick={() => switchMode(1)}\n >\n 需审核\n </button>\n <button\n type=\"button\"\n className={`skai-kb-btn skai-kb-btn-sm ${mode === 0 ? 'skai-kb-btn-primary' : ''}`}\n disabled={mode === null || modeBusy}\n onClick={() => switchMode(0)}\n >\n 无需审核\n </button>\n </div>\n </div>\n\n {/* 筛选与关键词 */}\n <div className=\"skai-kb-user-toolbar\">\n <div className=\"skai-kb-row-actions\">\n {STATUS_FILTERS.map((f) => (\n <button\n key={f.value}\n type=\"button\"\n className={`skai-kb-btn skai-kb-btn-sm ${status === f.value ? 'skai-kb-btn-primary' : ''}`}\n onClick={() => {\n setStatus(f.value)\n setPage(1)\n }}\n >\n {f.label}\n </button>\n ))}\n </div>\n <input\n className=\"skai-kb-input skai-kb-user-search\"\n placeholder=\"搜索 UID 或手机号片段\"\n value={keyword}\n onChange={(e) => {\n setKeyword(e.target.value)\n setPage(1)\n }}\n />\n </div>\n\n {/* 用户列表 */}\n <ul className=\"skai-kb-server-list\">\n {loading ? (\n <li className=\"skai-kb-sub\">加载中…</li>\n ) : !users.length ? (\n <li className=\"skai-kb-empty skai-kb-empty-sub\">暂无符合条件的用户</li>\n ) : (\n users.map((u) => {\n const info = infoMap[String(u.uid)]\n const nickname = (info?.nickname || '').trim()\n const initial = nickname ? nickname.slice(0, 1).toUpperCase() : '#'\n const view = STATUS_VIEW[u.status] || { text: '未知', badge: 'skai-kb-badge-gray' }\n return (\n <li key={u.uid} className=\"skai-kb-server-item\">\n <span className=\"skai-kb-row\" style={{ minWidth: 0, flex: 1 }}>\n {info?.avatar ? (\n <img className=\"skai-kb-member-avatar\" src={info.avatar} alt=\"\" />\n ) : (\n <span className=\"skai-kb-member-avatar skai-kb-member-avatar-fallback\" aria-hidden=\"true\">\n {initial}\n </span>\n )}\n <span style={{ minWidth: 0 }}>\n <span className=\"skai-kb-server-name\">\n {nickname ? `${nickname} ` : ''}(UID:{u.uid})\n </span>\n <span className=\"skai-kb-sub\" style={{ display: 'block', padding: 0 }}>\n {u.masked_mobile || info?.mobile || '手机号未知'} · 进入于 {formatTime(u.create_time)}\n {u.review_time ? ` · 最近操作 ${formatTime(u.review_time)}` : ''}\n </span>\n </span>\n </span>\n {u.is_admin ? (\n <span className=\"skai-kb-badge skai-kb-badge-blue\">管理员</span>\n ) : (\n <>\n <span className={`skai-kb-badge ${view.badge}`}>{view.text}</span>\n <div className=\"skai-kb-row-actions\">\n {u.status === 0 ? (\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm\"\n disabled={busy}\n onClick={() => setConfirm({ action: reviewUser, user: u, title: '审核通过', message: `确定审核通过 uid ${u.uid} 吗?通过后该用户即可正常使用知识库全部功能。`, confirmText: '通过' })}\n >\n 审核\n </button>\n ) : null}\n {u.status === 2 ? (\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm\"\n disabled={busy}\n onClick={() => setConfirm({ action: enableUser, user: u, title: '启用用户', message: `确定启用 uid ${u.uid} 吗?启用后该用户恢复为正常状态。`, confirmText: '启用' })}\n >\n 启用\n </button>\n ) : null}\n {u.status !== 2 ? (\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm\"\n disabled={busy}\n onClick={() => setConfirm({ action: disableUser, user: u, title: '禁用用户', message: `确定禁用 uid ${u.uid} 吗?禁用后该用户全部业务功能立即不可用,其登录状态将被吊销。`, confirmText: '禁用' })}\n >\n 禁用\n </button>\n ) : null}\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm skai-kb-btn-ghost-danger\"\n disabled={busy}\n onClick={() => setConfirm({ action: deleteUser, user: u, title: '删除用户', message: `确定删除 uid ${u.uid} 吗?将移除其用户状态与全部成员授权(保留其创建的知识库,悬空所有者可经「修改所有者」接管);该用户再次登录将视为新用户。`, confirmText: '删除', danger: true })}\n >\n 删除\n </button>\n </div>\n </>\n )}\n </li>\n )\n })\n )}\n </ul>\n\n {/* 分页 */}\n {total > PAGE_SIZE ? (\n <div className=\"skai-kb-pagination\">\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-sm\" disabled={!canPrev || busy} onClick={() => setPage((p) => p - 1)}>\n 上一页\n </button>\n <span className=\"skai-kb-sub\" style={{ padding: 0 }}>\n 第 {page} / {totalPages} 页 · 共 {total} 人\n </span>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-sm\" disabled={!canNext || busy} onClick={() => setPage((p) => p + 1)}>\n 下一页\n </button>\n </div>\n ) : null}\n\n {confirm ? (\n <ConfirmDialog\n title={confirm.title}\n message={confirm.message}\n confirmText={confirm.confirmText}\n danger={confirm.danger}\n busy={busy}\n onConfirm={runAction}\n onClose={() => setConfirm(null)}\n />\n ) : null}\n </section>\n )\n}\n","/**\n * 设置页(独立标签页正文;布局对齐 CRM 设置页:页头 + panel 区块 + 行操作)\n *\n * - 页头:标题「设置」+ 右上角「添加服务器」主操作\n * - 服务器配置:多服务器增删改切(云持久化 knowledge.servers / knowledge.serverActive),\n * 当前服务器即 REST 基址与知识库 MCP 接入点,变更经 auth.subscribe 链路自动同步宿主\n * - 管理员:全局角色(昵称/uid/脱敏手机号/添加时间,资料经用户中心批量获取仅展示);\n * 管理员可添加、删除其他管理员(最后一个管理员不可删除);尚无任何管理员时可将\n * 当前登录用户初始化为管理员(首次部署「添加管理员」流程)\n * - 智能体(MCP)同步状态:宿主配置自检 + 手动重新自检 + 接入点展示\n * - 账号信息:当前用户角色与 UID(仅展示)\n */\nimport { useCallback, useEffect, useState } from 'react'\nimport {\n getServers,\n getActiveServer,\n setActiveServer,\n removeServer,\n isCloudPersistAvailable,\n subscribe,\n} from '../../core/server-config.js'\nimport { syncHostMcpAuth, checkHostMcpReady, getUserInfo } from '../../core/auth.js'\nimport { getHealth } from '../../api/system.js'\nimport { manifest } from '../../manifest.js'\nimport { resetServerScopedStores } from '../../store/reset.js'\nimport { toast, toastError } from '../../store/ui-store.js'\nimport {\n adminExists,\n initAdmin,\n listAdmins,\n addAdminByUid,\n addAdminByMobile,\n removeAdminPending,\n removeAdmin,\n} from '../../api/auth.js'\nimport { formatTime } from '../../utils/file-type.js'\nimport { getMe } from '../../api/user.js'\nimport { useMemberInfo, findMemberByMobile } from '../../hooks/use-member-info.js'\nimport ServerFormModal from '../../components/settings/ServerFormModal.jsx'\nimport AdminFormModal from '../../components/settings/AdminFormModal.jsx'\nimport UserManagePanel from '../../components/settings/UserManagePanel.jsx'\nimport ConfirmDialog from '../../components/common/ConfirmDialog.jsx'\nimport Toast from '../../components/common/Toast.jsx'\nimport { Glyph, P } from '../../components/common/icons.jsx'\n\n/** MCP 自检状态 → 展示文案与色系 */\nconst MCP_STATUS_VIEW = {\n ok: { text: '已就绪:智能体会话中可使用 mcp__knowledge__* 检索工具', tone: 'success' },\n 'mismatch-fixed': { text: '配置曾不一致,已重新同步;若反复出现请查看控制台 [knowledge] 日志', tone: 'warning' },\n 'no-endpoint': { text: '尚未配置服务器,配置后自动同步 MCP', tone: 'warning' },\n 'no-token': { text: '插件 Token 未就绪(未登录或验签失败),登录后自动恢复', tone: 'warning' },\n 'no-settings': { text: '宿主 settings 服务不可用(插件版本过旧或宿主未注入)', tone: 'danger' },\n 'no-namespace': { text: '宿主未注册 knowledge 命名空间(Host 半区未加载,重启 DSH 后重试)', tone: 'danger' },\n 'no-host': { text: '非浏览器环境', tone: 'neutral' },\n error: { text: '自检失败', tone: 'danger' },\n}\n/** 自检色系 → 知识库徽标类 */\nconst TONE_BADGE = {\n success: 'skai-kb-badge-green',\n warning: 'skai-kb-badge-amber',\n danger: 'skai-kb-badge-red',\n neutral: 'skai-kb-badge-gray',\n}\n\nexport default function SettingsPage() {\n const [, forceUpdate] = useState(0)\n const [editing, setEditing] = useState(null)\n const [removing, setRemoving] = useState(null)\n const [adminInfo, setAdminInfo] = useState({\n loading: true,\n exists: false,\n isAdmin: false,\n list: [],\n pending: [],\n })\n const [addingAdmin, setAddingAdmin] = useState(false)\n const [removingAdmin, setRemovingAdmin] = useState(null)\n const [removingPending, setRemovingPending] = useState(null)\n const [adminBusy, setAdminBusy] = useState(false)\n const [busy, setBusy] = useState(false)\n const servers = getServers()\n const active = getActiveServer()\n const activeBase = active ? active.api_base : ''\n const cloudOk = isCloudPersistAvailable()\n\n // 前后端版本一致性:/kb/health 暴露后端构建版本,与插件版本(frontend/package.json)比对。\n // 发布机制保证二者同源;此处用于部署侧升级遗漏时的可见告警(本地 dev 构建不告警)。\n const pluginVersion = String(manifest.version || '')\n const [backendVersion, setBackendVersion] = useState({ checking: false, version: '', error: '' })\n useEffect(() => {\n if (!activeBase) {\n setBackendVersion({ checking: false, version: '', error: '' })\n return undefined\n }\n let cancelled = false\n setBackendVersion({ checking: true, version: '', error: '' })\n getHealth()\n .then((health) => {\n if (!cancelled) {\n setBackendVersion({ checking: false, version: String(health?.version || ''), error: '' })\n }\n })\n .catch((error) => {\n if (!cancelled) {\n setBackendVersion({\n checking: false,\n version: '',\n error: (error && error.msg) || '无法获取后端版本',\n })\n }\n })\n return () => {\n cancelled = true\n }\n }, [activeBase])\n const backendVer = backendVersion.version\n const versionMismatch =\n Boolean(backendVer) &&\n backendVer !== 'dev' &&\n backendVer.replace(/^v/i, '') !== pluginVersion.replace(/^v/i, '')\n // 管理员公开资料(昵称/头像/脱敏手机号,用户中心批量获取,仅展示)\n const { infoMap } = useMemberInfo(adminInfo.list.map((m) => m.uid))\n\n useEffect(() => {\n const off = subscribe(() => forceUpdate((n) => n + 1))\n return off\n }, [])\n\n // 知识库 MCP 宿主配置自检:页面打开/配置变化即检查是否已在宿主就绪;\n // 值不一致自动重推修复;结构性问题给出可见原因(不再静默失败)\n const [mcpStatus, setMcpStatus] = useState({ checking: true, status: '', detail: '' })\n const runMcpCheck = useCallback(() => {\n setMcpStatus((s) => ({ ...s, checking: true }))\n return checkHostMcpReady()\n .then((res) => setMcpStatus({ checking: false, status: res.status, detail: res.detail || '' }))\n .catch((error) =>\n setMcpStatus({ checking: false, status: 'error', detail: (error && error.message) || '自检失败' }),\n )\n }, [])\n useEffect(() => {\n runMcpCheck()\n const off = subscribe(runMcpCheck)\n return () => {\n if (typeof off === 'function') off()\n }\n }, [runMcpCheck])\n\n const reloadAdmin = () => {\n setAdminInfo((s) => ({ ...s, loading: true }))\n Promise.all([adminExists(), listAdmins()])\n .then(([status, res]) =>\n setAdminInfo({\n loading: false,\n exists: Boolean(status?.exists),\n isAdmin: Boolean(status?.is_admin),\n list: Array.isArray(res?.list) ? res.list : [],\n pending: Array.isArray(res?.pending) ? res.pending : [],\n }),\n )\n .catch(() =>\n setAdminInfo({ loading: false, exists: false, isAdmin: false, list: [], pending: [] }),\n )\n }\n useEffect(reloadAdmin, [])\n\n // 自身平台状态(/user/me 豁免接口):待审核(0)/禁用(2)时隐藏「管理员」与「用户管理」区块——\n // 禁用用户换不到插件 Token,adminExists() 等请求被 40302 拦截会误判为「尚无管理员」,\n // 引导区块(添加我为管理员)对受限用户是误导性展示\n const [myStatus, setMyStatus] = useState(null) // null 未知;0 待审核;1 正常;2 禁用\n useEffect(() => {\n let cancelled = false\n getMe()\n .then((me) => !cancelled && setMyStatus(typeof me?.status === 'number' ? me.status : 1))\n .catch((error) => {\n // 被禁用户无有效 Token:getMe 经验签链路失败,40302/40301 错误码即自身状态\n if (!cancelled && error && error.code === 40302) setMyStatus(2)\n else if (!cancelled && error && error.code === 40301) setMyStatus(0)\n })\n return () => {\n cancelled = true\n }\n }, [])\n const statusRestricted = myStatus === 0 || myStatus === 2\n // 「管理员」区块仅两种情形展示:当前用户是平台管理员;或后端尚无任何管理员\n // (正常用户可见「认领首个管理员」引导,否则系统无法初始化)\n const showAdminSection = !statusRestricted && (!adminInfo.exists || adminInfo.isAdmin)\n\n const handleServerSaved = ({ added, activated }) => {\n setEditing(null)\n if (added && activated) {\n // 新增首个服务器自动激活:MCP 接入点变化,登记至宿主并清空上一服务器业务缓存\n resetServerScopedStores()\n syncHostMcpAuth()\n toast('服务器已添加并设为当前,知识库 MCP 接入点已同步至智能体', 'success')\n } else if (added) {\n toast('服务器已添加', 'success')\n } else {\n // 编辑当前服务器地址:宿主 MCP 配置随之更新\n syncHostMcpAuth()\n toast('已保存', 'success')\n }\n }\n\n const handleSwitch = (s) => {\n if (active && active.id === s.id) return\n setActiveServer(s.id)\n resetServerScopedStores()\n syncHostMcpAuth()\n toast(`已切换到「${s.name}」,业务数据将重新加载`, 'success')\n }\n\n const submitRemove = () => {\n const fallback = removing.id === (active && active.id)\n removeServer(removing.id)\n setRemoving(null)\n if (fallback) {\n resetServerScopedStores()\n syncHostMcpAuth()\n toast('已删除当前服务器,业务数据将重新加载', 'success')\n } else {\n toast('已删除', 'success')\n }\n }\n\n const handleInitAdmin = () => {\n setBusy(true)\n initAdmin()\n .then(() => {\n toast('已将当前用户设为管理员', 'success')\n })\n .catch(toastError)\n .finally(() => {\n setBusy(false)\n // 成功或「管理员已存在」等场景统一回查,及时纠正陈旧的界面状态\n reloadAdmin()\n })\n }\n\n const handleAddAdmin = ({ mobile }) => {\n setAdminBusy(true)\n // 先经用户中心按手机号解析 uid:已注册 → 直接按 uid 添加;\n // 未注册(或用户中心接口不可用)→ 回退手机号 md5 待激活授权\n findMemberByMobile(mobile)\n .then((member) => {\n if (member) {\n const label = member.nickname ? `${member.nickname}(uid ${member.uid})` : `uid ${member.uid}`\n return addAdminByUid(Number(member.uid)).then(() => {\n toast(`已添加管理员 ${label}`, 'success')\n setAddingAdmin(false)\n reloadAdmin()\n })\n }\n return addAdminByMobile(mobile).then((res) => {\n toast(\n res?.pending\n ? '该手机号尚未注册,已创建待激活授权,其注册登录后自动成为管理员'\n : '已添加管理员',\n 'success',\n )\n setAddingAdmin(false)\n reloadAdmin()\n })\n })\n .catch(toastError)\n .finally(() => setAdminBusy(false))\n }\n\n const handleRemovePending = () => {\n const target = removingPending\n setAdminBusy(true)\n removeAdminPending(target.id)\n .then(() => {\n toast(`已撤销手机号 ${target.masked_mobile || ''} 的待激活授权`, 'success')\n setRemovingPending(null)\n reloadAdmin()\n })\n .catch(toastError)\n .finally(() => setAdminBusy(false))\n }\n\n const handleRemoveAdmin = () => {\n const target = removingAdmin\n setAdminBusy(true)\n removeAdmin(target.uid)\n .then(() => {\n toast(`已删除管理员 uid ${target.uid}`, 'success')\n setRemovingAdmin(null)\n reloadAdmin()\n })\n .catch(toastError)\n .finally(() => setAdminBusy(false))\n }\n\n const mcpView =\n MCP_STATUS_VIEW[mcpStatus.status] ||\n (mcpStatus.checking ? { text: '自检中…', tone: 'neutral' } : { text: '未知状态', tone: 'neutral' })\n // 当前用户展示信息(公开资料只读,不作为可信身份)\n const meInfo = getUserInfo()\n const meUid = Number(meInfo?.uid ?? meInfo?.member_id ?? meInfo?.memberId) || 0\n\n return (\n <div className=\"skai-kb-page\">\n <header className=\"skai-kb-page-head\">\n <h2 className=\"skai-kb-page-title\">设置</h2>\n <div className=\"skai-kb-page-actions\">\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-primary\"\n onClick={() => setEditing({ id: '', name: '', api_base: '' })}\n >\n <Glyph size={12} d={P.plus} />\n 添加服务器\n </button>\n </div>\n </header>\n\n <div className=\"skai-kb-page-scroll\">\n {/* 服务器配置 */}\n <section className=\"skai-kb-panel\" aria-label=\"服务器配置\">\n <div className=\"skai-kb-panel-head\">\n <h3>服务器配置</h3>\n <span className=\"skai-kb-muted\">当前服务器即接口基址与知识库 MCP 接入点</span>\n </div>\n {servers.length ? (\n <ul className=\"skai-kb-server-list\">\n {servers.map((s) => {\n const isActive = Boolean(active && active.id === s.id)\n return (\n <li key={s.id} className={`skai-kb-server-item ${isActive ? 'is-active' : ''}`}>\n <div className=\"skai-kb-server-info\">\n <span className=\"skai-kb-server-name\">\n {s.name}\n {isActive ? <span className=\"skai-kb-badge skai-kb-badge-green\">当前</span> : null}\n </span>\n <span className=\"skai-kb-server-url\">{s.api_base}</span>\n </div>\n <div className=\"skai-kb-row-actions\">\n {!isActive ? (\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-sm\" onClick={() => handleSwitch(s)}>\n 切换\n </button>\n ) : null}\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-sm\" onClick={() => setEditing(s)}>\n 编辑\n </button>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm skai-kb-btn-ghost-danger\"\n onClick={() => setRemoving(s)}\n >\n 删除\n </button>\n </div>\n </li>\n )\n })}\n </ul>\n ) : (\n <div className=\"skai-kb-empty skai-kb-empty-sub\">\n 尚未配置服务器。添加后即可使用知识库全部功能,并自动注册 mcp__knowledge__* 智能体工具。\n </div>\n )}\n {/* 前后端版本一致性(升级/部署遗漏时可见告警;dev 本地构建不提示) */}\n {activeBase ? (\n <div\n className=\"skai-kb-sub\"\n style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap', marginTop: 8 }}\n >\n <span>\n 后端版本:{backendVersion.checking ? '检测中…' : backendVersion.error || backendVer || '未知'}\n </span>\n <span className=\"skai-kb-muted\">插件版本:v{pluginVersion}</span>\n {versionMismatch ? (\n <span className=\"skai-kb-badge skai-kb-badge-amber\">\n 前后端版本不一致,请将镜像与插件升级到同一版本\n </span>\n ) : null}\n </div>\n ) : null}\n {!cloudOk ? (\n <div className=\"skai-kb-sub skai-kb-cloud-hint\">\n 当前为游客态或用户中心配置接口未就绪:服务器配置仅本次会话内有效,登录后自动云同步。\n </div>\n ) : null}\n </section>\n\n {/* 管理员(仅平台管理员可见;后端尚无管理员时对正常用户展示认领引导;\n 待审核/禁用用户不展示:无管理能力,请求亦被门禁拦截) */}\n {showAdminSection ? (\n <section className=\"skai-kb-panel\" aria-label=\"管理员\">\n <div className=\"skai-kb-panel-head\">\n <h3>管理员</h3>\n {adminInfo.isAdmin ? (\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-primary\"\n onClick={() => setAddingAdmin(true)}\n >\n + 添加管理员\n </button>\n ) : null}\n </div>\n <div className=\"skai-kb-sub\" style={{ marginBottom: 8 }}>\n 管理员为全局角色:拥有全部知识库的最高权限,并可管理其他管理员(添加、删除);最后一个管理员不可删除\n </div>\n <ul className=\"skai-kb-server-list\">\n {adminInfo.loading ? (\n <li className=\"skai-kb-sub\">状态查询中…</li>\n ) : !adminInfo.exists ? (\n <li className=\"skai-kb-row\" style={{ justifyContent: 'space-between', gap: 8 }}>\n <span className=\"skai-kb-sub\">后端尚无管理员,可将当前登录用户初始化为管理员</span>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-primary\"\n style={{ flex: 'none', width: 'auto' }}\n disabled={busy}\n onClick={handleInitAdmin}\n >\n {busy ? '提交中…' : '添加我为管理员'}\n </button>\n </li>\n ) : adminInfo.list.length ? (\n adminInfo.list.map((m) => {\n const info = infoMap[String(m.uid)]\n const nickname = (info?.nickname || '').trim()\n const initial = nickname ? nickname.slice(0, 1).toUpperCase() : '#'\n return (\n <li key={m.id} className=\"skai-kb-server-item\">\n <span className=\"skai-kb-row\" style={{ minWidth: 0, flex: 1 }}>\n {info?.avatar ? (\n <img className=\"skai-kb-member-avatar\" src={info.avatar} alt=\"\" />\n ) : (\n <span\n className=\"skai-kb-member-avatar skai-kb-member-avatar-fallback\"\n aria-hidden=\"true\"\n >\n {initial}\n </span>\n )}\n <span style={{ minWidth: 0 }}>\n <span className=\"skai-kb-server-name\">\n {nickname ? `${nickname} ` : ''}(UID:{m.uid})\n </span>\n <span className=\"skai-kb-sub\" style={{ display: 'block', padding: 0 }}>\n {info?.mobile ? `${info.mobile} · ` : ''}添加于 {formatTime(m.create_time)}\n </span>\n </span>\n </span>\n <span className=\"skai-kb-badge skai-kb-badge-blue\">管理员</span>\n {adminInfo.isAdmin ? (\n <div className=\"skai-kb-row-actions\">\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm skai-kb-btn-ghost-danger\"\n disabled={adminBusy}\n onClick={() => setRemovingAdmin(m)}\n >\n 删除\n </button>\n </div>\n ) : null}\n </li>\n )\n })\n ) : (\n <li className=\"skai-kb-sub\">后端已存在管理员(由部署时初始化产生)</li>\n )}\n {/* 待激活授权(手机号预添加管理员、对方尚未登录激活) */}\n {adminInfo.pending.map((p) => (\n <li key={`pending-${p.id}`} className=\"skai-kb-server-item\">\n <span className=\"skai-kb-row\" style={{ minWidth: 0, flex: 1 }}>\n <span\n className=\"skai-kb-member-avatar skai-kb-member-avatar-fallback\"\n aria-hidden=\"true\"\n >\n ?\n </span>\n <span style={{ minWidth: 0 }}>\n <span className=\"skai-kb-server-name\">{p.masked_mobile || '未激活手机号'}</span>\n <span className=\"skai-kb-sub\" style={{ display: 'block', padding: 0 }}>\n 发起于 {formatTime(p.create_time)} · 对方登录知识库后自动激活为管理员\n </span>\n </span>\n </span>\n <span className=\"skai-kb-badge\">待激活</span>\n {adminInfo.isAdmin ? (\n <div className=\"skai-kb-row-actions\">\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm skai-kb-btn-ghost-danger\"\n disabled={adminBusy}\n onClick={() => setRemovingPending(p)}\n >\n 撤销\n </button>\n </div>\n ) : null}\n </li>\n ))}\n {!adminInfo.isAdmin && adminInfo.list.length ? (\n <li className=\"skai-kb-sub\">管理员由现有管理员管理;如需变更权限,请联系任一管理员</li>\n ) : null}\n </ul>\n </section>\n ) : null}\n\n {/* 用户管理(仅管理员可见可操作:状态审核/禁用/启用/删除 + 新用户审核模式) */}\n {!statusRestricted && adminInfo.isAdmin ? <UserManagePanel isAdmin /> : null}\n\n {/* 智能体(MCP)同步状态 */}\n <section className=\"skai-kb-panel\" aria-label=\"MCP 同步状态\">\n <div className=\"skai-kb-panel-head\">\n <h3>智能体(MCP)同步状态</h3>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm\"\n disabled={mcpStatus.checking}\n onClick={runMcpCheck}\n >\n <Glyph size={12} d={P.refresh} />\n 重新自检\n </button>\n </div>\n <div className=\"skai-kb-mcp-status\">\n <span className={`skai-kb-badge ${TONE_BADGE[mcpView.tone] || 'skai-kb-badge-gray'}`}>\n {mcpStatus.checking ? '检查中…' : mcpView.tone === 'success' ? '就绪' : '未就绪'}\n </span>\n <span className=\"skai-kb-mcp-text\">\n {mcpView.text}\n {mcpStatus.detail && mcpStatus.detail !== mcpView.text ? (\n <span className=\"skai-kb-muted\">({mcpStatus.detail})</span>\n ) : null}\n </span>\n </div>\n {active ? (\n <div className=\"skai-kb-sub\">\n 接入点:{active.api_base}/kb/mcp/v1 · 智能体经 mcp__knowledge__ 前缀工具检索知识库\n </div>\n ) : null}\n </section>\n\n {/* 账号信息 */}\n <section className=\"skai-kb-panel\" aria-label=\"账号信息\">\n <div className=\"skai-kb-panel-head\">\n <h3>账号信息</h3>\n </div>\n <div className=\"skai-kb-detail-list\">\n <div className=\"skai-kb-detail-row\">\n <span className=\"skai-kb-field-label\">角色</span>\n <span className=\"skai-kb-detail-text\">\n {adminInfo.loading ? '识别中…' : adminInfo.isAdmin ? '管理员' : '用户'}\n </span>\n </div>\n <div className=\"skai-kb-detail-row\">\n <span className=\"skai-kb-field-label\">用户 UID</span>\n <span className=\"skai-kb-detail-text\">{meUid || '—'}</span>\n </div>\n </div>\n </section>\n </div>\n\n {/* 弹窗 */}\n {editing ? (\n <ServerFormModal\n initial={editing.id ? editing : null}\n onClose={() => setEditing(null)}\n onSaved={handleServerSaved}\n />\n ) : null}\n {removing ? (\n <ConfirmDialog\n title=\"删除服务器\"\n message={`确定删除服务器「${removing.name}」吗?仅移除云端保存的该条配置,不影响后端数据。`}\n confirmText=\"删除\"\n danger\n onConfirm={submitRemove}\n onClose={() => setRemoving(null)}\n />\n ) : null}\n {addingAdmin ? (\n <AdminFormModal busy={adminBusy} onSubmit={handleAddAdmin} onClose={() => setAddingAdmin(false)} />\n ) : null}\n {removingAdmin ? (\n <ConfirmDialog\n title=\"删除管理员\"\n message={`确定删除管理员 uid ${removingAdmin.uid} 吗?该用户将立即失去全部知识库的管理权限;如需恢复可重新添加。`}\n confirmText=\"删除\"\n danger\n busy={adminBusy}\n onConfirm={handleRemoveAdmin}\n onClose={() => setRemovingAdmin(null)}\n />\n ) : null}\n {removingPending ? (\n <ConfirmDialog\n title=\"撤销待激活授权\"\n message={`确定撤销手机号 ${removingPending.masked_mobile || ''} 的待激活授权吗?撤销后该手机号登录将不再自动成为管理员。`}\n confirmText=\"撤销\"\n danger\n busy={adminBusy}\n onConfirm={handleRemovePending}\n onClose={() => setRemovingPending(null)}\n />\n ) : null}\n <Toast />\n </div>\n )\n}\n","/**\n * Standalone 应用壳(非 DSH 宿主):以内部状态模拟 DSH 标签页语义\n *\n * 同一套页面组件(HomePage / KbDetailPage / DocDetailPage / SettingsPage),\n * 导航回调 openKb / openDoc / openHome / openSettings 行为与 DSH 标签页一致:\n * 打开即「新标签页」(此处渲染为顶部页签栏,可切换可关闭),页面无感宿主差异。\n * DSH 真实环境由 slots/sidebar-right.js 经 tab.actions.openTab 承载同一语义。\n */\nimport { useCallback, useMemo, useState } from 'react'\nimport HomePage from '../pages/home/HomePage.jsx'\nimport KbDetailPage from '../pages/kb/KbDetailPage.jsx'\nimport DocDetailPage from '../pages/doc/DocDetailPage.jsx'\nimport SettingsPage from '../pages/settings/SettingsPage.jsx'\nimport { KnowledgeGlyph } from '../components/common/icons.jsx'\n\nlet seq = 0\n\n/** 打开一个内部标签页(同 kind 已存在时复用并更新参数,对齐 DSH 同类标签页去重语义) */\nfunction openTabIn(tabs, setTabs, kind, params, extra) {\n const payload = { ...(params || {}), ...(extra || {}) }\n const keyOf = (t) =>\n `${t.kind}:${t.kind === 'doc' ? `${t.params.kbId}:${t.params.docId}` : t.kind === 'kb' ? t.params.kbId : ''}`\n const targetKey = `${kind}:${kind === 'doc' ? `${payload.kbId}:${payload.docId}` : kind === 'kb' ? payload.kbId : ''}`\n setTabs((prev) => {\n const idx = prev.findIndex((t) => keyOf(t) === targetKey)\n if (idx >= 0) {\n const next = prev.slice()\n next[idx] = { ...next[idx], params: payload }\n return next\n }\n return [...prev, { id: ++seq, kind, params: payload }]\n })\n}\n\nconst KIND_LABEL = {\n home: '知识库',\n kb: '知识库详情',\n doc: '文档详情',\n settings: '知识库设置',\n}\n\nexport default function StandaloneApp() {\n const [tabs, setTabs] = useState([{ id: 0, kind: 'home', params: {} }])\n const [activeId, setActiveId] = useState(0)\n const active = tabs.find((t) => t.id === activeId) || tabs[0]\n\n const nav = useMemo(\n () => ({\n openHome: () => openTabIn(tabs, setTabs, 'home', {}),\n openSettings: () => openTabIn(tabs, setTabs, 'settings', {}),\n openKb: (kbId, opts) => openTabIn(tabs, setTabs, 'kb', { kbId }, { view: opts?.view || '' }),\n openDoc: (kbId, docId) => openTabIn(tabs, setTabs, 'doc', { kbId, docId }),\n }),\n [tabs],\n )\n\n const close = useCallback(\n (id) => {\n if (tabs.length <= 1) return\n const idx = tabs.findIndex((t) => t.id === id)\n const next = tabs.filter((t) => t.id !== id)\n setTabs(next)\n if (id === activeId) setActiveId(next[Math.max(0, idx - 1)].id)\n },\n [tabs, activeId],\n )\n\n return (\n <div className=\"skai-kb-root skai-kb-app skai-kb-standalone-inner\" role=\"region\" aria-label=\"知识库\">\n <header className=\"skai-kb-header\">\n <div className=\"skai-kb-header-title\">\n <KnowledgeGlyph size={16} />\n <span>知识库</span>\n </div>\n <nav className=\"skai-kb-nav\" aria-label=\"知识库页面导航\">\n {tabs.map((t) => (\n <span key={t.id} style={{ display: 'inline-flex', flex: 'none' }}>\n <button\n type=\"button\"\n className={`skai-kb-nav-btn ${t.id === active.id ? 'is-active' : ''}`}\n onClick={() => setActiveId(t.id)}\n >\n {KIND_LABEL[t.kind] || t.kind}\n </button>\n {tabs.length > 1 ? (\n <button\n type=\"button\"\n className=\"skai-kb-tab-close\"\n aria-label={`关闭 ${KIND_LABEL[t.kind] || t.kind}`}\n onClick={(e) => {\n e.stopPropagation()\n close(t.id)\n }}\n >\n ✕\n </button>\n ) : null}\n </span>\n ))}\n </nav>\n </header>\n <main className=\"skai-kb-body\">\n {active.kind === 'home' ? <HomePage nav={nav} /> : null}\n {active.kind === 'kb' ? (\n <KbDetailPage kbId={active.params.kbId} view={active.params.view} nav={nav} />\n ) : null}\n {active.kind === 'doc' ? (\n <DocDetailPage kbId={active.params.kbId} docId={active.params.docId} nav={nav} />\n ) : null}\n {active.kind === 'settings' ? <SettingsPage /> : null}\n </main>\n </div>\n )\n}\n","export default \"/* ============================================================\\n 时刻AI知识库插件样式(前缀 skai-kb-,不覆盖宿主样式)\\n - 0.8.0 起渲染于 DSH 右侧 Sidebar 标签页正文(首页 / 知识库详情 /\\n 文档详情 / 设置 各为一个标签页)与 standalone 调试台:\\n .skai-kb-page 声明 inline-size 容器查询(与 .skai-kb-app 同名 skai-kb),\\n 布局按容器宽度自适应,不依赖视口宽度(面板开合、拖宽均正确响应)\\n - 颜色全部取 DSH 官方主题令牌(--dsw-alias-*),随宿主\\n 浅色/深色主题自动切换;var() 兜底值仅供 standalone 预览\\n (无宿主令牌)使用\\n - z-index 使用适中值(≤35),禁止覆盖宿主设置菜单\\n ============================================================ */\\n\\n/* ---------- 主题令牌别名层(统一映射到 DSH 官方令牌) ----------\\n DSH 强调色语义(与常见设计系统相反,务必注意):\\n - --dsw-alias-brand-primary:亮色主题为深色(bluish-1000)、暗色主题为浅色\\n (bluish-50),即「反色强调」——主按钮填充随主题黑白互换\\n - --dsw-alias-label-primary-foreground:强调填充上的前景文字,恒与填充反相\\n (亮色=白、暗色=黑),是主按钮等强调填充上文字的正确取值。\\n (DSH 无 --dsw-alias-brand-text;此前误用导致暗色模式白底白字)\\n - --dsw-alias-link:正文链接色(亮 deepseek-500 / 暗 deepseek-400,恒为蓝) */\\n.skai-kb-root,\\n.skai-kb-modal-mask,\\n.skai-kb-toast-layer {\\n --skai-kb-bg: var(--dsw-alias-bg-base, #ffffff);\\n --skai-kb-bg-card: var(--dsw-alias-bg-layer-1, #ffffff);\\n --skai-kb-bg-soft: var(--dsw-alias-bg-layer-2, #f6f7f9);\\n --skai-kb-bg-hover: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, 0.04));\\n --skai-kb-mask: var(--dsw-alias-bg-mask-1, rgba(17, 19, 23, 0.5));\\n --skai-kb-border: var(--dsw-alias-border-l1, #e4e6eb);\\n --skai-kb-border-strong: var(--dsw-alias-border-l2, #d0d3d9);\\n --skai-kb-text: var(--dsw-alias-label-primary, #1f2329);\\n --skai-kb-text-sub: var(--dsw-alias-label-secondary, #8a8f99);\\n --skai-kb-text-caption: var(--dsw-alias-label-caption, #9ca1ab);\\n /* 知识库品牌青色:与 DSH 侧边栏标签页/引导页图标同色(#06b6d4) */\\n --skai-kb-primary: #06b6d4;\\n /* 强调填充上的文字(官方前景令牌:亮=白 / 暗=黑;无 token 环境兜底白色) */\\n --skai-kb-on-primary: var(--dsw-alias-label-primary-foreground, #ffffff);\\n /* 主按钮:品牌青色实心 + 白字(青色为高亮度色相,不适用深底反色公式),hover 提亮一档(与 CRM 一致) */\\n --skai-kb-btn-primary: var(--skai-kb-primary);\\n --skai-kb-primary-weak: color-mix(in srgb, var(--skai-kb-primary) 12%, transparent);\\n --skai-kb-danger: var(--dsw-alias-state-error-primary, #d83931);\\n --skai-kb-danger-weak: color-mix(in srgb, var(--skai-kb-danger) 12%, transparent);\\n --skai-kb-ok: var(--dsw-alias-state-success-primary, #2ea44f);\\n --skai-kb-ok-weak: color-mix(in srgb, var(--skai-kb-ok) 14%, transparent);\\n --skai-kb-warn: var(--dsw-alias-state-warn-primary, #d97706);\\n --skai-kb-warn-weak: color-mix(in srgb, var(--skai-kb-warn) 14%, transparent);\\n --skai-kb-link: var(--skai-kb-primary);\\n --skai-kb-shadow: 0 8px 24px rgba(31, 35, 41, 0.12);\\n font: inherit;\\n font-size: 13px;\\n line-height: 1.5;\\n color: var(--skai-kb-text);\\n background: var(--skai-kb-bg);\\n scrollbar-width: thin;\\n}\\n\\n/* 盒模型统一(与 CRM 一致):root 作用域内全部 border-box */\\n.skai-kb-root *,\\n.skai-kb-root *::before,\\n.skai-kb-root *::after,\\n.skai-kb-modal-mask *,\\n.skai-kb-modal-mask *::before,\\n.skai-kb-modal-mask *::after {\\n box-sizing: border-box;\\n}\\n\\n/* 原生 button 不继承字体,与 CRM 一致显式继承宿主字体 */\\n.skai-kb-root button,\\n.skai-kb-modal-mask button {\\n font-family: inherit;\\n}\\n\\n/* 深色模式(跟随系统 prefers-color-scheme,与 CRM 插件策略一致):\\n 宿主令牌存在时仍优先取宿主值(var 包裹),此处仅提供 standalone 兜底 */\\n@media (prefers-color-scheme: dark) {\\n .skai-kb-root,\\n .skai-kb-modal-mask,\\n .skai-kb-toast-layer {\\n --skai-kb-bg: var(--dsw-alias-bg-base, #1e1f22);\\n --skai-kb-bg-card: var(--dsw-alias-bg-layer-1, #1e1f22);\\n --skai-kb-bg-soft: var(--dsw-alias-bg-layer-2, #2a2b2e);\\n --skai-kb-bg-hover: var(--dsw-alias-interactive-bg-hover, rgba(255, 255, 255, 0.08));\\n --skai-kb-mask: rgba(0, 0, 0, 0.55);\\n --skai-kb-border: var(--dsw-alias-border-l1, #2c2d2f);\\n --skai-kb-border-strong: var(--dsw-alias-border-l2, #3a3d42);\\n --skai-kb-text: var(--dsw-alias-label-primary, #e8eaed);\\n --skai-kb-text-sub: var(--dsw-alias-label-secondary, #8b8f96);\\n --skai-kb-text-caption: var(--dsw-alias-label-caption, #6f747d);\\n --skai-kb-primary: #22d3ee;\\n --skai-kb-on-primary: var(--dsw-alias-label-primary-foreground, #10131a);\\n --skai-kb-btn-primary: #06b6d4;\\n --skai-kb-danger: var(--dsw-alias-state-error-primary, #f5564e);\\n --skai-kb-ok: var(--dsw-alias-state-success-primary, #46c26a);\\n --skai-kb-warn: var(--dsw-alias-state-warn-primary, #e8a23c);\\n --skai-kb-link: var(--skai-kb-primary);\\n --skai-kb-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);\\n }\\n}\\n\\n/* ---------- 布局骨架(容器查询基准) ---------- */\\n.skai-kb-app {\\n display: flex;\\n flex-direction: column;\\n height: 100%;\\n min-height: 0;\\n position: relative;\\n container-type: inline-size;\\n container-name: skai-kb;\\n}\\n\\n/* standalone 调试台挂载容器(模拟抽屉内 100% 高度) */\\n.skai-kb-standalone-inner {\\n height: 100%;\\n min-height: 0;\\n}\\n\\n/* ---------- DSH 标签页正文骨架 ----------\\n sidebar.right.pane.tab 正文:不滚动定位容器(弹窗/Toast 绝对定位收敛于此),\\n 内容滚动由 .skai-kb-page-scroll 承担(文档详情为 .skai-kb-md-wrap) */\\n.skai-kb-tab-root {\\n height: 100%;\\n min-height: 0;\\n display: flex;\\n flex-direction: column;\\n}\\n.skai-kb-page {\\n position: relative;\\n display: flex;\\n flex-direction: column;\\n gap: 12px;\\n height: 100%;\\n min-height: 0;\\n padding: 14px 16px;\\n overflow: hidden;\\n container-type: inline-size;\\n container-name: skai-kb;\\n}\\n.skai-kb-tab-root > .skai-kb-page {\\n flex: 1;\\n}\\n.skai-kb-page-scroll {\\n flex: 1;\\n min-height: 0;\\n overflow-y: auto;\\n display: flex;\\n flex-direction: column;\\n gap: 12px;\\n}\\n\\n.skai-kb-header {\\n display: flex;\\n flex-direction: column;\\n gap: 8px;\\n padding: 14px 16px 0;\\n flex: none;\\n}\\n.skai-kb-header-title {\\n display: flex;\\n align-items: center;\\n gap: 6px;\\n font-size: 15px;\\n font-weight: 600;\\n color: var(--skai-kb-text);\\n}\\n\\n/* 分区导航:窄容器横向滑动(不换行挤压),宽容器自然展开 */\\n.skai-kb-nav {\\n display: flex;\\n gap: 4px;\\n overflow-x: auto;\\n scrollbar-width: none;\\n padding-bottom: 8px;\\n border-bottom: 1px solid var(--skai-kb-border);\\n align-items: center;\\n}\\n.skai-kb-nav::-webkit-scrollbar {\\n display: none;\\n}\\n.skai-kb-nav-btn {\\n flex: none;\\n border: none;\\n background: transparent;\\n color: var(--skai-kb-text-sub);\\n padding: 4px 10px;\\n border-radius: 999px;\\n cursor: pointer;\\n font-size: 12px;\\n transition: background 0.15s ease, color 0.15s ease;\\n}\\n.skai-kb-nav-btn:hover {\\n background: var(--skai-kb-bg-hover);\\n color: var(--skai-kb-text);\\n}\\n.skai-kb-nav-btn.is-active {\\n background: var(--skai-kb-primary-weak);\\n color: var(--skai-kb-primary);\\n font-weight: 500;\\n}\\n.skai-kb-nav-btn:focus-visible {\\n outline: 2px solid var(--skai-kb-primary);\\n outline-offset: 1px;\\n}\\n/* standalone 页签关闭钮 */\\n.skai-kb-tab-close {\\n flex: none;\\n border: none;\\n background: transparent;\\n color: var(--skai-kb-text-caption);\\n cursor: pointer;\\n font-size: 10px;\\n padding: 2px 4px;\\n border-radius: 6px;\\n}\\n.skai-kb-tab-close:hover {\\n background: var(--skai-kb-bg-hover);\\n color: var(--skai-kb-danger);\\n}\\n\\n.skai-kb-body {\\n flex: 1;\\n min-height: 0;\\n overflow-y: auto;\\n padding: 14px 16px;\\n}\\n\\n/* ---------- 详情页头(知识库详情 / 文档详情标签页) ---------- */\\n.skai-kb-detail-head {\\n flex: none;\\n display: flex;\\n flex-direction: column;\\n gap: 4px;\\n padding-bottom: 8px;\\n}\\n.skai-kb-detail-title {\\n font-weight: 600;\\n font-size: 15px;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n.skai-kb-back {\\n flex: none;\\n width: auto;\\n min-width: 0;\\n}\\n\\n/* ---------- 首页页头(左侧说明介绍 + 右上角设置入口) ---------- */\\n.skai-kb-home-head {\\n flex: none;\\n display: flex;\\n align-items: flex-start;\\n justify-content: space-between;\\n gap: 10px;\\n padding-bottom: 10px;\\n}\\n.skai-kb-home-head-main {\\n min-width: 0;\\n display: flex;\\n flex-direction: column;\\n gap: 3px;\\n}\\n.skai-kb-home-desc {\\n font-size: 12px;\\n line-height: 1.6;\\n color: var(--skai-kb-text-sub);\\n /* 介绍信息完整展示:不截断,自动换行铺满全量文字 */\\n overflow-wrap: anywhere;\\n}\\n.skai-kb-home-head > .skai-kb-btn {\\n flex: none;\\n width: auto;\\n margin-top: 1px;\\n}\\n\\n/* ---------- 通用元素 ---------- */\\n.skai-kb-btn {\\n display: inline-flex;\\n align-items: center;\\n justify-content: center;\\n gap: 5px;\\n width: auto;\\n height: 30px;\\n padding: 0 12px;\\n border: 1px solid var(--skai-kb-border);\\n border-radius: 8px;\\n background: var(--skai-kb-bg-card);\\n color: var(--skai-kb-text);\\n cursor: pointer;\\n font-size: 12.5px;\\n white-space: nowrap;\\n transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;\\n}\\n.skai-kb-btn:hover:not(:disabled) {\\n background: var(--skai-kb-bg-soft);\\n}\\n.skai-kb-btn:focus-visible {\\n outline: 2px solid var(--skai-kb-primary);\\n outline-offset: 1px;\\n}\\n.skai-kb-btn:disabled {\\n opacity: 0.55;\\n cursor: not-allowed;\\n}\\n/* 等待转圈动画(SpinnerGlyph 专用) */\\n@keyframes skai-kb-spin {\\n to {\\n transform: rotate(360deg);\\n }\\n}\\n.skai-kb-spin {\\n animation: skai-kb-spin 0.8s linear infinite;\\n flex: none;\\n}\\n.skai-kb-btn-primary {\\n background: var(--skai-kb-btn-primary);\\n border-color: transparent;\\n color: #fff;\\n}\\n.skai-kb-btn-primary:hover:not(:disabled) {\\n background: var(--skai-kb-btn-primary);\\n filter: brightness(1.08);\\n}\\n.skai-kb-btn-danger {\\n background: var(--skai-kb-danger);\\n border-color: var(--skai-kb-danger);\\n color: #fff;\\n}\\n.skai-kb-btn-danger:hover:not(:disabled) {\\n background: var(--skai-kb-danger);\\n filter: brightness(1.05);\\n}\\n.skai-kb-btn-ghost-danger {\\n border-color: transparent;\\n background: transparent;\\n color: var(--skai-kb-danger);\\n}\\n.skai-kb-btn-ghost-danger:hover:not(:disabled) {\\n background: var(--skai-kb-danger-weak);\\n}\\n.skai-kb-btn-sm {\\n width: auto;\\n height: 26px;\\n padding: 0 9px;\\n font-size: 12px;\\n border-radius: 8px;\\n}\\n\\n.skai-kb-icon-btn {\\n position: relative;\\n display: inline-flex;\\n align-items: center;\\n justify-content: center;\\n width: 26px;\\n height: 26px;\\n padding: 0;\\n border: none;\\n background: transparent;\\n color: var(--skai-kb-text-sub);\\n cursor: pointer;\\n border-radius: 8px;\\n font-size: 12px;\\n}\\n.skai-kb-icon-btn:hover {\\n background: var(--skai-kb-bg-hover);\\n color: var(--skai-kb-text);\\n}\\n/* 悬停文字提示(CSS 实现,即时显示;按钮右上角对齐避免溢出弹窗) */\\n.skai-kb-icon-btn[data-tip]:hover::after {\\n content: attr(data-tip);\\n position: absolute;\\n top: calc(100% + 4px);\\n right: 0;\\n z-index: 30;\\n padding: 4px 8px;\\n border-radius: 6px;\\n background: var(--skai-kb-bg);\\n color: var(--skai-kb-text);\\n font-size: 12px;\\n line-height: 1.4;\\n white-space: nowrap;\\n pointer-events: none;\\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\\n}\\n\\n.skai-kb-input,\\n.skai-kb-select,\\n.skai-kb-textarea {\\n width: 100%;\\n padding: 5px 10px;\\n border: 1px solid var(--skai-kb-border);\\n border-radius: 8px;\\n background: var(--skai-kb-bg);\\n color: var(--skai-kb-text);\\n /* 原生表单控件不继承字体,与 CRM 一致显式继承 */\\n font: inherit;\\n font-size: 12.5px;\\n box-sizing: border-box;\\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\\n}\\n/* 下拉选择与 CRM 一致使用手型光标 */\\n.skai-kb-select {\\n cursor: pointer;\\n}\\n/* 单行输入控件与按钮(30px)同高 */\\n.skai-kb-input,\\n.skai-kb-select {\\n height: 30px;\\n}\\n.skai-kb-textarea {\\n min-height: 56px;\\n resize: vertical;\\n line-height: 1.6;\\n}\\n.skai-kb-input:focus,\\n.skai-kb-select:focus,\\n.skai-kb-textarea:focus {\\n outline: none;\\n border-color: var(--skai-kb-primary);\\n box-shadow: 0 0 0 2px var(--skai-kb-primary-weak);\\n}\\n.skai-kb-input::placeholder,\\n.skai-kb-textarea::placeholder {\\n color: var(--skai-kb-text-caption);\\n}\\n.skai-kb-field {\\n display: flex;\\n flex-direction: column;\\n gap: 4px;\\n margin-bottom: 10px;\\n}\\n.skai-kb-field-label {\\n font-size: 12px;\\n color: var(--skai-kb-text-sub);\\n}\\n.skai-kb-field-error {\\n font-size: 12px;\\n color: var(--skai-kb-danger);\\n}\\n.skai-kb-field-row {\\n display: flex;\\n gap: 8px;\\n}\\n.skai-kb-field-row > * {\\n flex: 1;\\n}\\n\\n.skai-kb-toolbar {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n margin-bottom: 10px;\\n flex-wrap: wrap;\\n flex: none;\\n}\\n.skai-kb-toolbar .skai-kb-search {\\n flex: 1;\\n min-width: 120px;\\n}\\n\\n.skai-kb-card {\\n border: 1px solid var(--skai-kb-border);\\n border-radius: 10px;\\n background: var(--skai-kb-bg-card);\\n padding: 10px 12px;\\n margin-bottom: 8px;\\n transition: border-color 0.15s ease, background 0.15s ease;\\n}\\n.skai-kb-card:hover {\\n border-color: var(--skai-kb-border-strong);\\n}\\n\\n/* 卡片列表:每行一个知识库卡片(纵向堆叠,占满整行宽度) */\\n.skai-kb-card-list {\\n display: flex;\\n flex-direction: column;\\n gap: 8px;\\n}\\n.skai-kb-card-list > .skai-kb-card {\\n margin-bottom: 0;\\n}\\n\\n.skai-kb-row {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n}\\n.skai-kb-row-between {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n gap: 8px;\\n}\\n.skai-kb-title {\\n font-weight: 600;\\n font-size: 13px;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n.skai-kb-sub {\\n padding: 7px 0 0 0;\\n font-size: 12px;\\n color: var(--skai-kb-text-sub);\\n /* 说明/介绍类文本完整展示:不截断省略,自动换行铺满全量文字 */\\n overflow-wrap: anywhere;\\n}\\n\\n.skai-kb-badge {\\n display: inline-flex;\\n align-items: center;\\n padding: 0 7px;\\n border-radius: 999px;\\n font-size: 11px;\\n line-height: 18px;\\n white-space: nowrap;\\n}\\n.skai-kb-badge-gray { background: var(--skai-kb-bg-soft); color: var(--skai-kb-text-sub); }\\n.skai-kb-badge-blue { background: var(--skai-kb-primary-weak); color: var(--skai-kb-primary); }\\n.skai-kb-badge-green { background: var(--skai-kb-ok-weak); color: var(--skai-kb-ok); }\\n.skai-kb-badge-amber { background: var(--skai-kb-warn-weak); color: var(--skai-kb-warn); }\\n.skai-kb-badge-red { background: var(--skai-kb-danger-weak); color: var(--skai-kb-danger); }\\n\\n.skai-kb-tag {\\n display: inline-block;\\n padding: 0 6px;\\n border-radius: 4px;\\n font-size: 11px;\\n line-height: 18px;\\n background: var(--skai-kb-bg-soft);\\n color: var(--skai-kb-text-sub);\\n margin-right: 4px;\\n}\\n\\n.skai-kb-empty {\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n justify-content: center;\\n gap: 6px;\\n text-align: center;\\n padding: 28px 16px;\\n color: var(--skai-kb-text-sub);\\n font-size: 13px;\\n}\\n.skai-kb-empty-sub {\\n font-size: 12px;\\n}\\n\\n.skai-kb-pagination {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n gap: 8px;\\n padding: 8px 0;\\n color: var(--skai-kb-text-sub);\\n font-size: 12px;\\n flex: none;\\n}\\n.skai-kb-pagination-btns {\\n display: flex;\\n gap: 8px;\\n}\\n\\n/* ---------- 设置页(对齐 CRM:页头 + panel 区块 + 行操作 + 详情列表) ---------- */\\n.skai-kb-page-head {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n gap: 10px;\\n flex-wrap: wrap;\\n flex: none;\\n}\\n.skai-kb-page-title {\\n display: inline-flex;\\n align-items: center;\\n gap: 6px;\\n margin: 0;\\n font-size: 15px;\\n font-weight: 600;\\n}\\n.skai-kb-page-title svg {\\n color: var(--skai-kb-primary);\\n}\\n.skai-kb-page-actions {\\n display: inline-flex;\\n align-items: center;\\n gap: 8px;\\n flex-wrap: wrap;\\n}\\n.skai-kb-panel {\\n display: flex;\\n flex-direction: column;\\n gap: 8px;\\n padding: 12px 14px;\\n border: 1px solid var(--skai-kb-border);\\n border-radius: 10px;\\n background: var(--skai-kb-bg-card);\\n}\\n.skai-kb-panel-head {\\n display: flex;\\n align-items: baseline;\\n justify-content: space-between;\\n gap: 8px;\\n flex-wrap: wrap;\\n}\\n.skai-kb-panel-head h3 {\\n margin: 0;\\n font-size: 13px;\\n font-weight: 600;\\n}\\n.skai-kb-panel-head .skai-kb-btn {\\n flex: none;\\n width: auto;\\n}\\n.skai-kb-muted {\\n color: var(--skai-kb-text-sub);\\n font-size: 12px;\\n}\\n.skai-kb-row-actions {\\n display: inline-flex;\\n align-items: center;\\n gap: 4px;\\n flex-wrap: wrap;\\n justify-content: flex-end;\\n}\\n.skai-kb-server-list {\\n display: flex;\\n flex-direction: column;\\n gap: 8px;\\n margin: 0;\\n padding: 0;\\n list-style: none;\\n}\\n.skai-kb-server-item {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n gap: 10px;\\n border: 1px solid var(--skai-kb-border);\\n border-radius: 8px;\\n background: var(--skai-kb-bg-card);\\n padding: 10px 12px;\\n transition: border-color 0.15s ease;\\n}\\n.skai-kb-server-item.is-active {\\n border-color: var(--skai-kb-primary);\\n background: var(--skai-kb-primary-weak);\\n}\\n.skai-kb-server-info {\\n display: flex;\\n flex-direction: column;\\n gap: 2px;\\n min-width: 0;\\n}\\n.skai-kb-server-name {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n font-weight: 500;\\n font-size: 13px;\\n}\\n.skai-kb-server-url {\\n margin-top: 2px;\\n font-size: 12px;\\n color: var(--skai-kb-text-sub);\\n word-break: break-all;\\n}\\n.skai-kb-mcp-status {\\n display: flex;\\n align-items: flex-start;\\n gap: 8px;\\n}\\n.skai-kb-mcp-text {\\n font-size: 12.5px;\\n line-height: 1.6;\\n}\\n.skai-kb-cloud-hint {\\n padding: 8px 10px;\\n border: 1px dashed var(--skai-kb-border);\\n border-radius: 8px;\\n}\\n.skai-kb-detail-list {\\n display: flex;\\n flex-direction: column;\\n}\\n.skai-kb-detail-row {\\n display: flex;\\n gap: 12px;\\n padding: 7px 0;\\n border-bottom: 1px dashed var(--skai-kb-border);\\n font-size: 12.5px;\\n}\\n.skai-kb-detail-row:last-child {\\n border-bottom: none;\\n}\\n.skai-kb-detail-row .skai-kb-field-label {\\n width: 92px;\\n flex-shrink: 0;\\n padding-top: 1px;\\n}\\n.skai-kb-detail-text {\\n flex: 1;\\n min-width: 0;\\n word-break: break-all;\\n white-space: pre-wrap;\\n}\\n\\n/* ---------- 用户管理(设置页区块:审核模式开关 / 筛选工具条 / 状态横幅) ---------- */\\n.skai-kb-user-review-mode {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n gap: 8px;\\n flex-wrap: wrap;\\n padding: 8px 10px;\\n border: 1px dashed var(--skai-kb-border);\\n border-radius: 8px;\\n margin-bottom: 10px;\\n}\\n.skai-kb-user-toolbar {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n gap: 8px;\\n flex-wrap: wrap;\\n margin-bottom: 8px;\\n}\\n\\n/* 添加成员弹窗「从用户列表选择」候选列表(弹窗内滚动,选中高亮) */\\n.skai-kb-user-pick-list {\\n display: flex;\\n flex-direction: column;\\n gap: 4px;\\n max-height: 200px;\\n overflow-y: auto;\\n border: 1px solid var(--skai-kb-border, #e5e7eb);\\n border-radius: 8px;\\n padding: 4px;\\n margin-bottom: 8px;\\n}\\n.skai-kb-user-pick-item {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n gap: 8px;\\n width: 100%;\\n padding: 6px 8px;\\n border: none;\\n border-radius: 6px;\\n background: transparent;\\n color: inherit;\\n font-size: 12.5px;\\n text-align: left;\\n cursor: pointer;\\n}\\n.skai-kb-user-pick-item:hover {\\n background: var(--skai-kb-hover, rgba(0, 0, 0, 0.04));\\n}\\n.skai-kb-user-pick-item-active,\\n.skai-kb-user-pick-item-active:hover {\\n background: var(--skai-kb-primary-soft, rgba(49, 92, 255, 0.1));\\n}\\n.skai-kb-user-pick-nickname {\\n display: block;\\n font-weight: 500;\\n}\\n/* 多选复选标记(行首圆角方框,选中品牌色) */\\n.skai-kb-pick-check {\\n flex: none;\\n width: 16px;\\n height: 16px;\\n border: 1px solid var(--skai-kb-border, #d1d5db);\\n border-radius: 4px;\\n font-size: 11px;\\n line-height: 14px;\\n text-align: center;\\n color: #fff;\\n}\\n.skai-kb-pick-check-on {\\n background: var(--skai-kb-primary, #17b0c8);\\n border-color: var(--skai-kb-primary, #17b0c8);\\n}\\n.skai-kb-user-pick-item-disabled,\\n.skai-kb-user-pick-item-disabled:hover {\\n opacity: 0.55;\\n cursor: not-allowed;\\n background: transparent;\\n}\\n/* 已选用户 chips(头像 + 昵称 + 移除) */\\n.skai-kb-picked-chips {\\n display: flex;\\n flex-wrap: wrap;\\n gap: 6px;\\n margin-bottom: 8px;\\n}\\n.skai-kb-picked-chip {\\n display: inline-flex;\\n align-items: center;\\n gap: 6px;\\n max-width: 100%;\\n padding: 3px 6px 3px 4px;\\n border: 1px solid var(--skai-kb-border, #e5e7eb);\\n border-radius: 999px;\\n background: var(--skai-kb-primary-soft, rgba(23, 176, 200, 0.08));\\n font-size: 12px;\\n}\\n.skai-kb-picked-chip-avatar {\\n width: 18px;\\n height: 18px;\\n border-radius: 50%;\\n object-fit: cover;\\n}\\n.skai-kb-picked-chip-text {\\n min-width: 0;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n.skai-kb-picked-chip-remove {\\n flex: none;\\n width: 16px;\\n height: 16px;\\n padding: 0;\\n border: none;\\n border-radius: 50%;\\n background: rgba(0, 0, 0, 0.08);\\n color: inherit;\\n font-size: 12px;\\n line-height: 16px;\\n cursor: pointer;\\n}\\n.skai-kb-picked-chip-remove:hover {\\n background: rgba(0, 0, 0, 0.16);\\n}\\n.skai-kb-user-search {\\n width: 200px;\\n height: 26px;\\n flex: none;\\n}\\n\\n/* ---------- 弹窗(Portal 挂 body,遮罩 fixed 铺满整个窗口并居中,与 CRM 同款;\\n 弹层根已纳入文件头部主题令牌作用域;z-index ≤35 不覆盖宿主设置菜单) ---------- */\\n.skai-kb-modal-mask {\\n position: fixed;\\n inset: 0;\\n z-index: 30;\\n background: var(--skai-kb-mask);\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n padding: 20px;\\n animation: skai-kb-fade-in 0.15s ease;\\n}\\n.skai-kb-modal {\\n width: 100%;\\n max-width: 520px;\\n max-height: 86%;\\n display: flex;\\n flex-direction: column;\\n background: var(--skai-kb-bg-card);\\n border-radius: 10px;\\n box-shadow: var(--skai-kb-shadow);\\n animation: skai-kb-pop-in 0.16s ease;\\n}\\n.skai-kb-modal.is-fullscreen {\\n max-width: none;\\n width: 100%;\\n max-height: 96%;\\n height: 96%;\\n}\\n.skai-kb-modal-head-actions {\\n display: inline-flex;\\n align-items: center;\\n gap: 2px;\\n flex: none;\\n}\\n.skai-kb-modal-head {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n gap: 8px;\\n padding: 12px 16px;\\n border-bottom: 1px solid var(--skai-kb-border);\\n flex: none;\\n}\\n.skai-kb-modal-title {\\n font-size: 14px;\\n font-weight: 600;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n.skai-kb-modal-body {\\n padding: 14px 16px;\\n overflow-y: auto;\\n}\\n.skai-kb-modal-foot {\\n display: flex;\\n align-items: center;\\n justify-content: flex-end;\\n gap: 8px;\\n padding: 10px 16px;\\n border-top: 1px solid var(--skai-kb-border);\\n flex: none;\\n}\\n.skai-kb-modal-foot .skai-kb-btn {\\n width: auto;\\n min-width: 72px;\\n}\\n.skai-kb-confirm-text {\\n margin: 0;\\n font-size: 13px;\\n line-height: 1.7;\\n}\\n\\n/* ---------- Toast(面板底 + 彩色描边样式,与 CRM 一致;z-index 34 宿主菜单避让约定内) ---------- */\\n.skai-kb-toast-layer {\\n /* createPortal 到 body + fixed:相对整个 DSH 窗口顶部居中(非插件标签页区域);\\n z-index 34 宿主菜单避让约定内 */\\n position: fixed;\\n left: 50%;\\n top: 18px;\\n transform: translateX(-50%);\\n z-index: 34;\\n display: flex;\\n flex-direction: column;\\n gap: 8px;\\n align-items: center;\\n pointer-events: none;\\n}\\n.skai-kb-toast {\\n pointer-events: auto;\\n max-width: 90%;\\n padding: 7px 14px;\\n border-radius: 999px;\\n font-size: 12.5px;\\n background: var(--skai-kb-bg-card);\\n border: 1px solid var(--skai-kb-border);\\n color: var(--skai-kb-text);\\n box-shadow: var(--skai-kb-shadow);\\n cursor: pointer;\\n word-break: break-all;\\n animation: skai-kb-toast-in 0.18s ease;\\n}\\n.skai-kb-toast-info { border-color: var(--skai-kb-primary); color: var(--skai-kb-primary); }\\n.skai-kb-toast-error { border-color: var(--skai-kb-danger); color: var(--skai-kb-danger); }\\n.skai-kb-toast-success { border-color: var(--skai-kb-ok); color: var(--skai-kb-ok); }\\n\\n/* ---------- 动画(与 CRM 同款节奏) ---------- */\\n@keyframes skai-kb-fade-in {\\n from { opacity: 0; }\\n to { opacity: 1; }\\n}\\n@keyframes skai-kb-pop-in {\\n from { opacity: 0; transform: translateY(8px) scale(0.98); }\\n to { opacity: 1; transform: translateY(0) scale(1); }\\n}\\n@keyframes skai-kb-toast-in {\\n from { opacity: 0; transform: translateY(-8px); }\\n to { opacity: 1; transform: translateY(0); }\\n}\\n\\n/* ---------- 概览统计(首页) ---------- */\\n.skai-kb-stat-grid {\\n display: grid;\\n grid-template-columns: repeat(2, minmax(0, 1fr));\\n gap: 10px;\\n margin-bottom: 4px;\\n}\\n.skai-kb-stat-card {\\n border: 1px solid var(--skai-kb-border);\\n border-radius: 10px;\\n background: var(--skai-kb-bg-card);\\n padding: 10px 12px;\\n}\\n.skai-kb-stat-num {\\n font-size: 18px;\\n font-weight: 600;\\n}\\n/* 统计卡内气泡(首页「用户数」待审核提示) */\\n.skai-kb-stat-badge {\\n margin-left: 8px;\\n vertical-align: 2px;\\n cursor: default;\\n}\\n.skai-kb-stat-label {\\n font-size: 12px;\\n color: var(--skai-kb-text-sub);\\n margin-top: 2px;\\n}\\n.skai-kb-quick-grid {\\n display: grid;\\n grid-template-columns: repeat(2, minmax(0, 1fr));\\n gap: 8px;\\n}\\n\\n/* ---------- 知识库卡片 ---------- */\\n.skai-kb-kb-meta {\\n display: flex;\\n gap: 12px;\\n margin-top: 6px;\\n font-size: 12px;\\n color: var(--skai-kb-text-sub);\\n flex-wrap: wrap;\\n}\\n.skai-kb-kb-actions {\\n display: flex;\\n gap: 6px;\\n margin-top: 8px;\\n flex-wrap: wrap;\\n}\\n.skai-kb-kb-actions .skai-kb-btn-sm {\\n flex: 1;\\n}\\n\\n/* ---------- 文档列表 ---------- */\\n.skai-kb-doc-item {\\n cursor: pointer;\\n}\\n\\n/* 文档卡片右上角「操作」下拉菜单(遮罩点击关闭;z-index ≤35 不覆盖宿主) */\\n.skai-kb-doc-topbar {\\n display: inline-flex;\\n align-items: center;\\n gap: 6px;\\n flex: none;\\n}\\n.skai-kb-doc-menu-anchor {\\n position: relative;\\n display: inline-flex;\\n}\\n.skai-kb-doc-menu-trigger {\\n display: inline-flex;\\n align-items: center;\\n gap: 4px;\\n line-height: 1;\\n border: none;\\n background: transparent;\\n color: var(--skai-kb-text-sub);\\n font-size: 12px;\\n padding: 2px 6px;\\n border-radius: 6px;\\n cursor: pointer;\\n}\\n/* CSS 三角下箭头:随 flex 垂直居中,字体字形对齐不可控故不用 ⌄ */\\n.skai-kb-caret {\\n width: 0;\\n height: 0;\\n border-left: 4px solid transparent;\\n border-right: 4px solid transparent;\\n border-top: 5px solid currentColor;\\n}\\n.skai-kb-doc-menu-trigger:hover {\\n background: var(--skai-kb-bg-hover);\\n color: var(--skai-kb-text);\\n}\\n.skai-kb-menu-mask {\\n position: fixed;\\n inset: 0;\\n z-index: 34;\\n}\\n.skai-kb-menu {\\n position: absolute;\\n top: 22px;\\n right: 0;\\n z-index: 35;\\n min-width: 104px;\\n padding: 4px;\\n background: var(--skai-kb-bg-card);\\n border: 1px solid var(--skai-kb-border-strong);\\n border-radius: 8px;\\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.14);\\n}\\n.skai-kb-menu-item {\\n display: block;\\n width: 100%;\\n text-align: left;\\n border: none;\\n background: transparent;\\n color: var(--skai-kb-text);\\n font-size: 12px;\\n padding: 6px 10px;\\n border-radius: 6px;\\n cursor: pointer;\\n white-space: nowrap;\\n}\\n.skai-kb-menu-item:hover {\\n background: var(--skai-kb-bg-hover);\\n}\\n.skai-kb-menu-item.is-danger {\\n color: var(--skai-kb-danger);\\n}\\n.skai-kb-menu-item.is-danger:hover {\\n background: var(--skai-kb-danger-weak);\\n}\\n\\n.skai-kb-pre {\\n white-space: pre-wrap;\\n word-break: break-word;\\n background: var(--skai-kb-bg-soft);\\n border: 1px solid var(--skai-kb-border);\\n border-radius: 8px;\\n padding: 8px 10px;\\n max-height: 260px;\\n overflow-y: auto;\\n font-size: 12px;\\n margin: 0;\\n}\\n\\n/* ---------- 文档详情正文 ---------- */\\n.skai-kb-doc-detail {\\n gap: 8px;\\n}\\n.skai-kb-md-wrap {\\n flex: 1;\\n min-height: 0;\\n overflow-y: auto;\\n border: 1px solid var(--skai-kb-border);\\n border-radius: 10px;\\n background: var(--skai-kb-bg-card);\\n padding: 14px 16px;\\n}\\n\\n/* ---------- Markdown 渲染(文档详情正文;.skai-kb-md 作用域,不外溢) ---------- */\\n.skai-kb-md {\\n font-size: 13px;\\n line-height: 1.7;\\n word-break: break-word;\\n}\\n.skai-kb-md .skai-kb-md-h {\\n font-weight: 600;\\n line-height: 1.4;\\n margin: 14px 0 6px;\\n}\\n.skai-kb-md .skai-kb-md-h:first-child {\\n margin-top: 0;\\n}\\n.skai-kb-md .skai-kb-md-h1 { font-size: 18px; }\\n.skai-kb-md .skai-kb-md-h2 { font-size: 16px; }\\n.skai-kb-md .skai-kb-md-h3 { font-size: 15px; }\\n.skai-kb-md .skai-kb-md-h4,\\n.skai-kb-md .skai-kb-md-h5,\\n.skai-kb-md .skai-kb-md-h6 { font-size: 14px; }\\n.skai-kb-md .skai-kb-md-p {\\n margin: 6px 0;\\n}\\n.skai-kb-md .skai-kb-md-code {\\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\\n font-size: 12px;\\n background: var(--skai-kb-bg-soft);\\n border: 1px solid var(--skai-kb-border);\\n border-radius: 4px;\\n padding: 0 4px;\\n}\\n.skai-kb-md .skai-kb-md-pre {\\n background: var(--skai-kb-bg-soft);\\n border: 1px solid var(--skai-kb-border);\\n border-radius: 8px;\\n padding: 10px 12px;\\n overflow-x: auto;\\n font-size: 12px;\\n line-height: 1.6;\\n margin: 8px 0;\\n white-space: pre;\\n}\\n.skai-kb-md .skai-kb-md-pre code {\\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\\n background: transparent;\\n border: none;\\n padding: 0;\\n}\\n.skai-kb-md .skai-kb-md-quote {\\n margin: 8px 0;\\n padding: 4px 12px;\\n border-left: 3px solid var(--skai-kb-border-strong);\\n color: var(--skai-kb-text-sub);\\n background: var(--skai-kb-bg-soft);\\n border-radius: 0 8px 8px 0;\\n}\\n.skai-kb-md .skai-kb-md-ul,\\n.skai-kb-md .skai-kb-md-ol {\\n margin: 6px 0;\\n padding-left: 22px;\\n}\\n.skai-kb-md .skai-kb-md-li {\\n margin: 2px 0;\\n}\\n.skai-kb-md .skai-kb-md-link {\\n color: var(--skai-kb-link);\\n text-decoration: none;\\n}\\n.skai-kb-md .skai-kb-md-link:hover {\\n text-decoration: underline;\\n}\\n.skai-kb-md .skai-kb-md-img {\\n max-width: 100%;\\n border-radius: 8px;\\n border: 1px solid var(--skai-kb-border);\\n}\\n.skai-kb-md .skai-kb-md-hr {\\n border: none;\\n border-top: 1px solid var(--skai-kb-border);\\n margin: 12px 0;\\n}\\n.skai-kb-md .skai-kb-md-table-wrap {\\n overflow-x: auto;\\n margin: 8px 0;\\n}\\n.skai-kb-md .skai-kb-md-table {\\n border-collapse: collapse;\\n font-size: 12px;\\n min-width: 60%;\\n}\\n.skai-kb-md .skai-kb-md-table th,\\n.skai-kb-md .skai-kb-md-table td {\\n border: 1px solid var(--skai-kb-border);\\n padding: 4px 10px;\\n text-align: left;\\n}\\n.skai-kb-md .skai-kb-md-table th {\\n background: var(--skai-kb-bg-soft);\\n font-weight: 600;\\n}\\n\\n/* ---------- 时间线(文档版本) ---------- */\\n.skai-kb-timeline {\\n list-style: none;\\n margin: 0;\\n padding: 0 0 0 14px;\\n border-left: 2px solid var(--skai-kb-border);\\n}\\n.skai-kb-timeline li {\\n position: relative;\\n padding: 0 0 12px 10px;\\n}\\n.skai-kb-timeline li::before {\\n content: '';\\n position: absolute;\\n left: -20px;\\n top: 4px;\\n width: 8px;\\n height: 8px;\\n border-radius: 50%;\\n background: var(--skai-kb-primary);\\n}\\n\\n/* ---------- 文档上传 ---------- */\\n.skai-kb-dropzone {\\n border: 1px dashed var(--skai-kb-border-strong);\\n border-radius: 8px;\\n padding: 12px;\\n}\\n\\n/* ---------- 成员权限 ---------- */\\n.skai-kb-member-row {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n padding: 6px 0;\\n border-bottom: 1px solid var(--skai-kb-border);\\n}\\n.skai-kb-member-row:last-child {\\n border-bottom: none;\\n}\\n.skai-kb-member-avatar {\\n width: 30px;\\n height: 30px;\\n border-radius: 50%;\\n flex: none;\\n object-fit: cover;\\n background: var(--skai-kb-bg-soft);\\n}\\n.skai-kb-member-avatar-fallback {\\n display: inline-flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 13px;\\n font-weight: 500;\\n color: var(--skai-kb-primary);\\n background: var(--skai-kb-primary-weak);\\n}\\n.skai-kb-member-main {\\n flex: 1;\\n min-width: 0;\\n display: flex;\\n flex-direction: column;\\n gap: 1px;\\n}\\n.skai-kb-member-name {\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n.skai-kb-member-mobile {\\n font-size: 12px;\\n color: var(--skai-kb-text-sub);\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n\\n/* ============================================================\\n 宽容器布局(DSH 标签页 / standalone 宽屏):按容器宽度自适应,\\n 与视口无关(面板开合、拖宽均正确响应)\\n ============================================================ */\\n@container skai-kb (min-width: 620px) {\\n /* 概览:统计四列 */\\n .skai-kb-stat-grid {\\n grid-template-columns: repeat(4, minmax(0, 1fr));\\n }\\n .skai-kb-quick-grid {\\n grid-template-columns: repeat(3, minmax(0, 1fr));\\n }\\n}\\n\\n@container skai-kb (min-width: 980px) {\\n /* 超宽容器:正文限宽保持可读性(卡片分列由基础网格自适应) */\\n .skai-kb-page-scroll,\\n .skai-kb-md-wrap {\\n max-width: 1080px;\\n }\\n}\\n\\n/* =======================================================================\\n 目录(文件夹)管理:目录树 + 文档列表布局 + 拖拽指示\\n ======================================================================= */\\n\\n/* 详情页两栏布局:左目录树 + 右文档区(窄容器降级为上下布局) */\\n.skai-kb-doc-layout {\\n display: flex;\\n gap: 10px;\\n align-items: stretch;\\n min-height: 0;\\n}\\n\\n.skai-kb-doc-main {\\n flex: 1;\\n min-width: 0;\\n display: flex;\\n flex-direction: column;\\n gap: 10px;\\n}\\n\\n/* 目录树面板 */\\n.skai-kb-folder-tree {\\n flex: none;\\n width: 168px;\\n display: flex;\\n flex-direction: column;\\n background: var(--skai-kb-bg-card, #fff);\\n border: 1px solid var(--skai-kb-border, #e5e7eb);\\n border-radius: 10px;\\n padding: 6px;\\n align-self: flex-start;\\n position: sticky;\\n top: 0;\\n}\\n\\n.skai-kb-folder-head {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n padding: 2px 6px 6px;\\n border-bottom: 1px solid var(--skai-kb-bg-soft, #f0f1f3);\\n margin-bottom: 4px;\\n}\\n\\n.skai-kb-folder-head-title {\\n font-size: 12px;\\n font-weight: 600;\\n color: var(--skai-kb-text-sub, #6b7280);\\n}\\n\\n.skai-kb-folder-body {\\n display: flex;\\n flex-direction: column;\\n gap: 1px;\\n overflow-y: auto;\\n max-height: 320px;\\n}\\n\\n.skai-kb-folder-item {\\n display: flex;\\n align-items: center;\\n gap: 4px;\\n padding: 4px 6px;\\n border-radius: 7px;\\n cursor: pointer;\\n font-size: 12.5px;\\n color: var(--skai-kb-text, #374151);\\n border: 1px dashed transparent;\\n user-select: none;\\n min-width: 0;\\n}\\n\\n.skai-kb-folder-item:hover {\\n background: var(--skai-kb-bg-hover, #f5f6f8);\\n}\\n\\n.skai-kb-folder-item.is-active {\\n background: var(--skai-kb-primary-weak, #eef4ff);\\n color: var(--skai-kb-primary, #2f6bff);\\n font-weight: 500;\\n}\\n\\n.skai-kb-folder-arrow {\\n flex: none;\\n width: 12px;\\n font-size: 10px;\\n color: var(--skai-kb-text-caption, #9ca3af);\\n text-align: center;\\n}\\n\\n.skai-kb-folder-arrow.is-leaf {\\n visibility: hidden;\\n}\\n\\n.skai-kb-folder-icon {\\n flex: none;\\n font-size: 12px;\\n}\\n\\n.skai-kb-folder-name {\\n flex: 1;\\n min-width: 0;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n\\n.skai-kb-folder-actions {\\n flex: none;\\n display: none;\\n gap: 2px;\\n}\\n\\n.skai-kb-folder-item:hover .skai-kb-folder-actions {\\n display: inline-flex;\\n}\\n\\n.skai-kb-folder-act {\\n border: 0;\\n background: transparent;\\n padding: 0 3px;\\n font-size: 11px;\\n line-height: 16px;\\n color: var(--skai-kb-text-caption, #9ca3af);\\n border-radius: 4px;\\n cursor: pointer;\\n}\\n\\n.skai-kb-folder-act:hover {\\n background: var(--skai-kb-bg-soft, #f0f1f3);\\n color: var(--skai-kb-primary, #2f6bff);\\n}\\n\\n.skai-kb-folder-act.is-danger:hover {\\n color: var(--skai-kb-danger, #e5484d);\\n}\\n\\n/* 目录树节点:文档拖入高亮(in)与同级排序插入线(before/after) */\\n.skai-kb-folder-item.skai-kb-drop-in {\\n border: 1px solid var(--skai-kb-primary, #2f6bff);\\n background: var(--skai-kb-primary-weak, #eef4ff);\\n}\\n\\n.skai-kb-folder-item.skai-kb-drop-before {\\n box-shadow: inset 0 2px 0 0 var(--skai-kb-primary, #2f6bff);\\n}\\n\\n.skai-kb-folder-item.skai-kb-drop-after {\\n box-shadow: inset 0 -2px 0 0 var(--skai-kb-primary, #2f6bff);\\n}\\n\\n/* 文档列表项:作为同目录排序 drop 目标时高亮 */\\n.skai-kb-doc-item.skai-kb-drop-in {\\n outline: 1.5px dashed var(--skai-kb-primary, #2f6bff);\\n outline-offset: -2px;\\n}\\n\\n/* 移动文档弹窗:目录选择列表 */\\n.skai-kb-move-list {\\n display: flex;\\n flex-direction: column;\\n gap: 2px;\\n max-height: 240px;\\n overflow-y: auto;\\n border: 1px solid var(--skai-kb-border, #e5e7eb);\\n border-radius: 8px;\\n padding: 4px;\\n}\\n\\n.skai-kb-move-item {\\n border: 0;\\n background: transparent;\\n text-align: left;\\n padding: 6px 8px;\\n font-size: 12.5px;\\n border-radius: 6px;\\n cursor: pointer;\\n color: var(--skai-kb-text, #374151);\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n\\n.skai-kb-move-item:hover {\\n background: var(--skai-kb-bg-hover, #f5f6f8);\\n}\\n\\n.skai-kb-move-item.is-active {\\n background: var(--skai-kb-primary-weak, #eef4ff);\\n color: var(--skai-kb-primary, #2f6bff);\\n font-weight: 500;\\n}\\n\\n/* =======================================================================\\n 文档在线编辑:Markdown 可视化编辑器(工具栏 + 双栏分屏)\\n ======================================================================= */\\n\\n.skai-kb-editor {\\n display: flex;\\n flex-direction: column;\\n gap: 8px;\\n height: 100%;\\n min-height: 320px;\\n}\\n\\n.skai-kb-editor-bar {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n gap: 8px;\\n flex-wrap: wrap;\\n}\\n\\n.skai-kb-editor-tools {\\n display: flex;\\n align-items: center;\\n gap: 2px;\\n flex-wrap: wrap;\\n}\\n\\n.skai-kb-editor-tool {\\n border: 1px solid var(--skai-kb-border, #e5e7eb);\\n background: var(--skai-kb-bg-card, #fff);\\n border-radius: 6px;\\n padding: 3px 7px;\\n font-size: 11.5px;\\n line-height: 16px;\\n color: var(--skai-kb-text, #374151);\\n cursor: pointer;\\n}\\n\\n.skai-kb-editor-tool:hover:not(:disabled) {\\n border-color: var(--skai-kb-primary, #2f6bff);\\n color: var(--skai-kb-primary, #2f6bff);\\n}\\n\\n.skai-kb-editor-tool:disabled {\\n opacity: 0.5;\\n cursor: not-allowed;\\n}\\n\\n.skai-kb-editor-modes {\\n display: flex;\\n align-items: center;\\n gap: 6px;\\n}\\n\\n.skai-kb-editor-mode {\\n border: 1px solid transparent;\\n background: transparent;\\n padding: 3px 8px;\\n font-size: 12px;\\n border-radius: 6px;\\n cursor: pointer;\\n color: var(--skai-kb-text-sub, #6b7280);\\n}\\n\\n.skai-kb-editor-mode.is-active {\\n background: var(--skai-kb-primary-weak, #eef4ff);\\n color: var(--skai-kb-primary, #2f6bff);\\n font-weight: 500;\\n}\\n\\n.skai-kb-editor-dirty {\\n font-size: 11px;\\n color: var(--skai-kb-warn, #d97706);\\n}\\n\\n/* 双栏分屏:编辑区 | 预览区(仅预览/仅编辑时单栏占满) */\\n.skai-kb-editor-panes {\\n display: flex;\\n gap: 8px;\\n flex: 1;\\n min-height: 0;\\n}\\n\\n.skai-kb-editor-input {\\n flex: 1;\\n min-width: 0;\\n min-height: 300px;\\n resize: vertical;\\n border: 1px solid var(--skai-kb-border, #e5e7eb);\\n border-radius: 10px;\\n padding: 10px 12px;\\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\\n font-size: 12.5px;\\n line-height: 1.6;\\n color: var(--skai-kb-text, #374151);\\n background: var(--skai-kb-bg-card, #fff);\\n}\\n\\n.skai-kb-editor-input:focus {\\n outline: none;\\n border-color: var(--skai-kb-primary, #2f6bff);\\n}\\n\\n/* 仅编辑模式:编辑框撑满父容器高度(取消最小高度下限与手动拉伸) */\\n.skai-kb-editor.edit .skai-kb-editor-input {\\n min-height: 0;\\n resize: none;\\n}\\n\\n.skai-kb-editor-preview {\\n flex: 1;\\n min-width: 0;\\n min-height: 300px;\\n border: 1px solid var(--skai-kb-border, #e5e7eb);\\n border-radius: 10px;\\n padding: 10px 12px;\\n overflow-y: auto;\\n background: var(--skai-kb-bg-soft, #fafafa);\\n}\\n\\n/* 窄容器:编辑器分屏改为上下堆叠 */\\n@container skai-kb (max-width: 560px) {\\n .skai-kb-doc-layout {\\n flex-direction: column;\\n }\\n\\n .skai-kb-folder-tree {\\n width: auto;\\n position: static;\\n }\\n\\n .skai-kb-folder-body {\\n flex-direction: row;\\n flex-wrap: wrap;\\n max-height: none;\\n }\\n\\n .skai-kb-editor-panes.split {\\n flex-direction: column;\\n }\\n\\n .skai-kb-editor-panes.split .skai-kb-editor-input,\\n .skai-kb-editor-panes.split .skai-kb-editor-preview {\\n min-height: 180px;\\n }\\n}\\n\\n/* ---------- 对话消息操作区「存入知识库」(conversation.chat.assistant-actions) ----------\\n 按钮渲染于宿主 AI 消息操作行(官方复制/点赞同款 28px 图标钮),颜色直接取\\n DSH 官方令牌(--dsw-alias-*,全局可达,随宿主浅/深色主题切换);\\n --skai-kb-* 别名仅作 standalone 兜底 */\\n.skai-kb-chat-save-btn {\\n width: 28px;\\n height: 28px;\\n display: inline-flex;\\n align-items: center;\\n justify-content: center;\\n padding: 6px;\\n color: var(--dsw-alias-label-tertiary, var(--skai-kb-text-caption, #9ca1ab));\\n background: none;\\n border: none;\\n border-radius: 28px;\\n cursor: pointer;\\n transition: color 0.15s, background 0.15s;\\n}\\n\\n.skai-kb-chat-save-btn:hover {\\n color: var(--dsw-alias-label-secondary, var(--skai-kb-text-sub, #8a8f99));\\n background: var(--dsw-alias-interactive-bg-hover, var(--skai-kb-bg-hover, rgba(0, 0, 0, 0.04)));\\n}\\n\\n.skai-kb-chat-save-preview {\\n display: flex;\\n flex-direction: column;\\n gap: 4px;\\n}\\n\\n.skai-kb-chat-save-preview-label {\\n font-size: 12px;\\n color: var(--skai-kb-text-caption);\\n}\\n\\n/* 保存方式切换(新建文档 / 覆盖已有文档):与弹窗按钮风格一致 */\\n.skai-kb-chat-save-modes {\\n display: flex;\\n gap: 8px;\\n}\\n.skai-kb-chat-save-hint {\\n display: block;\\n margin-top: 4px;\\n font-size: 12px;\\n color: var(--skai-kb-text-caption);\\n}\\n\\n.skai-kb-chat-save-preview pre {\\n max-height: 140px;\\n overflow: auto;\\n margin: 0;\\n padding: 8px 10px;\\n font-size: 12px;\\n line-height: 1.6;\\n white-space: pre-wrap;\\n word-break: break-word;\\n background: var(--skai-kb-bg-soft);\\n border-radius: 6px;\\n}\\n\\n\"","/**\n * 知识库插件 standalone 入口(非 DSH 宿主:静态托管 / vite 调试台)\n *\n * - install():样式注入 + 登录态事件 + 服务器配置加载(DSH client 半区共用)\n * - activate({ container }):挂载 StandaloneApp(内部导航壳:以内部状态模拟\n * DSH 标签页语义,同一套页面组件,openKb / openDoc / openSettings 行为一致)\n * - deactivate():卸载\n */\nimport { createRoot } from 'react-dom/client'\nimport { createElement } from 'react'\nimport StandaloneApp from './app/StandaloneApp.jsx'\nimport { initAuth, disposeAuth } from './core/auth.js'\nimport { initServerConfig } from './core/server-config.js'\nimport styles from './styles/knowledge.css?raw'\n\nlet styleEl = null\nlet root = null\nlet container = null\n\n/** 注入样式 + 初始化登录态/服务器配置(幂等) */\nexport function install() {\n if (typeof document === 'undefined') return\n if (!styleEl) {\n styleEl = document.createElement('style')\n styleEl.textContent = styles\n document.head.appendChild(styleEl)\n }\n initAuth()\n initServerConfig()\n}\n\n/** 挂载 standalone 应用 */\nexport function activate({ container: mountEl } = {}) {\n if (!mountEl) throw new Error('[knowledge] activate({ container }) 需要挂载容器')\n install()\n container = mountEl\n root = createRoot(mountEl)\n root.render(createElement(StandaloneApp))\n}\n\n/** 卸载 standalone 应用 */\nexport function deactivate() {\n if (root) {\n root.unmount()\n root = null\n }\n container = null\n}\n\n/** 移除样式与登录态监听(整插件停用时) */\nexport function uninstall() {\n deactivate()\n if (styleEl) {\n styleEl.remove()\n styleEl = null\n }\n disposeAuth()\n}\n\n/** DSH Client 半区入口(宿主加载 lib/client.js,不经本文件) */\nexport { apply, inject } from './client-entry.js'\n\nexport default { install, activate, deactivate, uninstall }\n","/**\n * 标签页正文与活标题(对齐 @deepseek-ai/dsh-client-ui-sidebar-right 插槽契约)\n *\n * 正文注册进 keyed 插槽 sidebar.right.pane.tab(key = 标签页类型 id),\n * 组件自动获得框架注入的 props.useTabInfo():读取 tab.navigation.params(打开时\n * 传入的 { kbId, docId } 等导航参数)、tab.actions.openTab(打开其他功能标签页)。\n * 每个「主要功能」各为一个标签页类型,经 kind 打开即新开标签页:\n * home 首页(知识库列表 / 添加知识库 / 设置入口,引导页胶囊直达)\n * kb 知识库详情(文档列表 / 权限配置 / 添加文档)\n * doc 文档详情(markdown 渲染 / 版本 / 复制文档提示语)\n * settings 设置(后端服务器地址 / 管理员)\n */\nimport { Component } from 'react'\nimport { KnowledgeGlyph } from '../components/common/icons.jsx'\nimport HomePage from '../pages/home/HomePage.jsx'\nimport KbDetailPage from '../pages/kb/KbDetailPage.jsx'\nimport DocDetailPage from '../pages/doc/DocDetailPage.jsx'\nimport SettingsPage from '../pages/settings/SettingsPage.jsx'\nimport { useStore } from '../store/create-store.js'\nimport { titleStore } from '../store/title-store.js'\n\n/** 标签页类型 id(keyed 插槽 key 域,跨插件唯一) */\nexport const TAB_TYPE = {\n home: '@shikeai/knowledge/home',\n kb: '@shikeai/knowledge/kb',\n doc: '@shikeai/knowledge/doc',\n settings: '@shikeai/knowledge/settings',\n}\n\n/** 打开类型(openTab 的 kind;kind 与类型 id 一一对应) */\nexport const TAB_KIND = {\n home: 'shikeai-knowledge-home',\n kb: 'shikeai-knowledge-kb',\n doc: 'shikeai-knowledge-doc',\n settings: 'shikeai-knowledge-settings',\n}\n\n/** 标签页类型定义表(sidebarRightTabs.register 输入;title 为打开时 chip 兜底文案) */\nexport function tabTypeDefinitions() {\n return [\n {\n id: TAB_TYPE.home,\n kind: TAB_KIND.home,\n priority: 'extension',\n title: () => '知识库',\n guide: [\n {\n id: 'knowledge-home',\n order: 20,\n title: () => '知识库',\n description: () => '知识库管理与 RAG 智能检索',\n icon: () => (\n <span style={{ color: '#06b6d4', display: 'inline-flex' }}>\n {KnowledgeGlyph({ size: 28 })}\n </span>\n ),\n },\n ],\n },\n { id: TAB_TYPE.kb, kind: TAB_KIND.kb, priority: 'extension', title: () => '知识库详情' },\n { id: TAB_TYPE.doc, kind: TAB_KIND.doc, priority: 'extension', title: () => '文档详情' },\n { id: TAB_TYPE.settings, kind: TAB_KIND.settings, priority: 'extension', title: () => '知识库设置' },\n ]\n}\n\n/** 统一导航实现:把 openTab 语义传给页面组件 */\nfunction makeNav(actions) {\n return {\n openHome: () => actions.openTab(TAB_KIND.home),\n openSettings: () => actions.openTab(TAB_KIND.settings),\n openKb: (kbId, opts) => actions.openTab(TAB_KIND.kb, { params: { kbId, view: opts?.view || '' } }),\n openDoc: (kbId, docId) => actions.openTab(TAB_KIND.doc, { params: { kbId, docId } }),\n }\n}\n\n/** 标签页根(主题令牌层 + 标签页正文骨架;页面组件与 standalone 完全共用) */\nfunction TabRoot({ children }) {\n return <div className=\"skai-kb-root skai-kb-tab-root\">{children}</div>\n}\n\n/**\n * 标签页正文自诊断边界:渲染期异常直接显示在正文区(含错误消息与组件栈),\n * 避免宿主错误边界把条目 abdicate 后只剩空白 pane 无从排查。\n * 注意:无法捕获 useTabInfo 工厂本身在 ContextualEntry 内的抛错(边界在框架层之外)。\n */\nclass TabBodyErrorBoundary extends Component {\n state = { error: null }\n\n static getDerivedStateFromError(error) {\n return { error }\n }\n\n componentDidCatch(error, info) {\n console.error('[shikeai-knowledge] 标签页正文渲染异常:', error, info?.componentStack)\n }\n\n render() {\n const { error } = this.state\n if (error) {\n return (\n <div className=\"skai-kb-root skai-kb-page\">\n <div className=\"skai-kb-empty\">\n <p>知识库标签页渲染出错</p>\n <p className=\"skai-kb-empty-sub\">{String(error && error.message ? error.message : error)}</p>\n {info_stack(error)}\n </div>\n </div>\n )\n }\n return this.props.children\n }\n}\n\n// getDerivedStateFromError 阶段拿不到 componentStack,改为在 componentDidCatch 记录;\n// 这里仅渲染错误消息主体(componentStack 经 console.error 输出)。\nfunction info_stack(error) {\n return error && error.stack ? (\n <pre className=\"skai-kb-pre\" style={{ marginTop: 8, textAlign: 'left' }}>{String(error.stack).slice(0, 800)}</pre>\n ) : null\n}\n\n/** 读取 tabInfo 并做防御:框架未注入 hook 时给出可读诊断而不是 TypeError 崩溃 */\nfunction useTabInfoSafe(props) {\n const readTabInfo = props && props.useTabInfo\n if (typeof readTabInfo !== 'function') {\n const keys = props ? Object.keys(props).join(', ') : '(无 props)'\n throw new Error(`知识库插件未收到框架注入的 useTabInfo hook(收到 props: ${keys})——检查 sidebar.right.pane.tab 座位声明`)\n }\n return readTabInfo()\n}\n\n/* ---------- 首页 ---------- */\n\n/** 首页活标题 chip:图标 + 「知识库」(对齐引导页胶囊图标) */\nexport function HomeTabTitle() {\n return (\n <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4 }}>\n <span style={{ color: '#06b6d4', display: 'inline-flex' }}>{KnowledgeGlyph({ size: 16 })}</span>\n 知识库\n </span>\n )\n}\n\nexport function HomeTabBody(props) {\n const { tab } = useTabInfoSafe(props)\n const nav = makeNav(tab.actions)\n return (\n <TabBodyErrorBoundary>\n <TabRoot>\n <HomePage nav={nav} />\n </TabRoot>\n </TabBodyErrorBoundary>\n )\n}\n\n/* ---------- 知识库详情 ---------- */\n\nexport function KbTabBody(props) {\n const { tab } = useTabInfoSafe(props)\n const nav = makeNav(tab.actions)\n const params = (tab && tab.navigation && tab.navigation.params) || {}\n return (\n <TabBodyErrorBoundary>\n <TabRoot>\n <KbDetailPage kbId={params.kbId} view={params.view || ''} nav={nav} />\n </TabRoot>\n </TabBodyErrorBoundary>\n )\n}\n\nexport function KbTabTitle(props) {\n const { tab } = props.useTabInfo()\n const kbNames = useStore(titleStore, (s) => s.kbNames)\n const params = tab.navigation.params || {}\n return kbNames[String(params.kbId)] || '知识库详情'\n}\n\n/* ---------- 文档详情 ---------- */\n\nexport function DocTabBody(props) {\n const { tab } = useTabInfoSafe(props)\n const nav = makeNav(tab.actions)\n const params = (tab && tab.navigation && tab.navigation.params) || {}\n return (\n <TabBodyErrorBoundary>\n <TabRoot>\n <DocDetailPage kbId={params.kbId} docId={params.docId} nav={nav} />\n </TabRoot>\n </TabBodyErrorBoundary>\n )\n}\n\nexport function DocTabTitle(props) {\n const { tab } = useTabInfoSafe(props)\n const docNames = useStore(titleStore, (s) => s.docNames)\n const params = (tab && tab.navigation && tab.navigation.params) || {}\n return docNames[`${params.kbId}:${params.docId}`] || '文档详情'\n}\n\n/* ---------- 设置 ---------- */\n\nexport function SettingsTabBody() {\n return (\n <TabBodyErrorBoundary>\n <TabRoot>\n <SettingsPage />\n </TabRoot>\n </TabBodyErrorBoundary>\n )\n}\n\nexport function SettingsTabTitle() {\n return '知识库设置'\n}\n\n/** 标签页正文名册(slots/sidebar-right.js 注册用) */\nexport function tabBodyRegistry() {\n return [\n { typeId: TAB_TYPE.home, Body: HomeTabBody, Title: HomeTabTitle },\n { typeId: TAB_TYPE.kb, Body: KbTabBody, Title: KbTabTitle },\n { typeId: TAB_TYPE.doc, Body: DocTabBody, Title: DocTabTitle },\n { typeId: TAB_TYPE.settings, Body: SettingsTabBody, Title: SettingsTabTitle },\n ]\n}\n","/**\n * 右侧 Sidebar 标签页注册(@deepseek-ai/dsh-client-ui-sidebar-right)\n *\n * - ctx.sidebarRightTabs.register({ id, kind, title, guide? }):声明标签页类型;\n * 仅首页类型声明 guide 条目(引导页胶囊直达),kb/doc/settings 由页面动作\n * openTab(kind, { params }) 打开(每个主要功能各一个新标签页)\n * - keyed 插槽 sidebar.right.pane.tab(key = 类型 id):标签页正文;\n * 组件自动获得 props.useTabInfo()(导航参数 / openTab 动作)\n * - keyed 插槽 sidebar.right.pane.tab.title:活标题 chip(知识库/文档加载后实时命名)\n * - ctx.slots.inject 内部等待插槽声明出现并管理注册 disposer,无需 effect 包裹注册本身\n */\nimport { tabTypeDefinitions, tabBodyRegistry } from '../app/tab-bodies.jsx'\n\n/**\n * 注册全部标签页类型、正文与活标题(client-entry apply 内调用,幂等)\n * @param {object} ctx client 半区 cordis ctx(含 sidebarRightTabs / slots)\n */\nexport function registerSidebarRightTabs(ctx) {\n // 标签页类型注册(每个类型一条注册,独立 effect 便于单点失败不影响其他类型)\n tabTypeDefinitions().forEach((def) => {\n ctx.effect(() => ctx.sidebarRightTabs.register(def), `shikeai-knowledge: tab type ${def.id}`)\n })\n\n // 正文与活标题(keyed 插槽按类型 id 分发;重复注册会抛错,effect 保证 dispose 清理)\n tabBodyRegistry().forEach(({ typeId, Body, Title }) => {\n ctx.effect(\n () =>\n ctx.slots.inject('sidebar.right.pane.tab', () =>\n ctx.slots.register({ name: 'sidebar.right.pane.tab', key: typeId }, Body),\n ),\n `shikeai-knowledge: tab body ${typeId}`,\n )\n if (Title) {\n ctx.effect(\n () =>\n ctx.slots.inject('sidebar.right.pane.tab.title', () =>\n ctx.slots.register({ name: 'sidebar.right.pane.tab.title', key: typeId }, Title),\n ),\n `shikeai-knowledge: tab title ${typeId}`,\n )\n }\n })\n}\n\nexport default registerSidebarRightTabs\n","/**\n * 知识库 MCP HTTP 客户端(client 半区直连,无状态 tools/call)\n *\n * - 与 REST(core/request.js)同源同鉴权:Authorization: Bearer <插件 Token>,\n * ensurePluginToken() 按需验签换发;后端 MCP Server(internal/mcp/server.go)的\n * tools/call 仅校验 Token、不要求 initialize 握手,客户端直发即可\n * - 401 兜底与 request.js 一致:静默清 Token → 重新验签 → 重放一次(仅一次)\n * - 未配置服务器(getMcpEndpoint() 为空串)直接抛错,不发请求\n * - 响应自适应 application/json 与 text/event-stream(后端当前返回 JSON,SSE 留兼容)\n * - 独立于 core/request.js:MCP 为 JSON-RPC 2.0 通道,响应非 {code,msg,data} 结构\n */\nimport { getMcpEndpoint } from '../core/server-config.js'\nimport { ensurePluginToken, invalidatePluginToken } from '../core/auth.js'\n\n/** 单次 RPC 超时(文档内容入库可能较大,取 30s) */\nconst MCP_TIMEOUT_MS = 30000\n\n/** MCP 调用错误(message 透出服务端 msg / JSON-RPC error.message,调用方统一读 .msg) */\nexport class McpError extends Error {\n constructor(message, code = 0) {\n super(message)\n this.name = 'McpError'\n this.code = code\n this.msg = message\n }\n}\n\nlet rpcSeq = 0\n\n/** 从 SSE 流解析出 id 匹配的 JSON-RPC 响应(读完即取消,不挂住连接) */\nasync function readSseMessage(res, wantId) {\n const reader = res.body.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n buffer += decoder.decode(value, { stream: true })\n let index\n while ((index = buffer.indexOf('\\n\\n')) >= 0) {\n const block = buffer.slice(0, index)\n buffer = buffer.slice(index + 2)\n for (const line of block.split('\\n')) {\n if (!line.startsWith('data:')) continue\n const data = line.slice(5).trim()\n if (!data) continue\n try {\n const message = JSON.parse(data)\n if (message.id === wantId) return message\n } catch {}\n }\n }\n }\n } finally {\n try {\n await reader.cancel()\n } catch {}\n }\n return null\n}\n\n/** 单次 tools/call RPC(不处理重试/重放;错误语义见 McpError.code:401=Token 失效) */\nasync function rpcOnce(url, token, name, args) {\n const id = ++rpcSeq\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), MCP_TIMEOUT_MS)\n let res\n try {\n res = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json, text/event-stream',\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({\n jsonrpc: '2.0',\n id,\n method: 'tools/call',\n params: { name, arguments: args || {} },\n }),\n signal: controller.signal,\n })\n } catch (error) {\n if (error && error.name === 'AbortError') throw new McpError('MCP 请求超时,请检查网络后重试')\n throw new McpError('网络连接失败,请检查内网后重试')\n } finally {\n clearTimeout(timer)\n }\n if (res.status === 401) throw new McpError('未登录或登录已失效', 401)\n if (!res.ok) {\n const text = await res.text().catch(() => '')\n throw new McpError(`MCP 请求异常(HTTP ${res.status})${text ? `:${text.slice(0, 200)}` : ''}`)\n }\n const contentType = res.headers.get('content-type') || ''\n const message = contentType.includes('text/event-stream')\n ? await readSseMessage(res, id)\n : await res.json().catch(() => null)\n if (!message) throw new McpError('MCP 响应解析失败')\n if (message.error) {\n throw new McpError(message.error.message || JSON.stringify(message.error), message.error.code || 0)\n }\n return message.result\n}\n\n/** content 数组转纯文本(text 项拼接;无 text 项时 JSON 兜底) */\nfunction textOfContent(content) {\n if (!Array.isArray(content)) return ''\n const texts = content.filter((item) => item && item.type === 'text').map((item) => item.text ?? '')\n if (texts.length) return texts.join('\\n')\n return content.length ? JSON.stringify(content) : ''\n}\n\n/**\n * 调用知识库 MCP 工具(tools/call,无状态;401 静默重验签重放一次)\n * @param {string} name 工具名(如 kb_doc_add)\n * @param {object} args 工具参数\n * @returns {Promise<object>} MCP result(isError 语义已在内部转为异常)\n */\nexport async function mcpCallTool(name, args, retried = false) {\n const url = getMcpEndpoint()\n if (!url) throw new McpError('请先在设置页配置服务器信息')\n let token\n try {\n token = await ensurePluginToken()\n } catch (error) {\n throw new McpError((error && error.message) || '请先在用户中心登录', 401)\n }\n let result\n try {\n result = await rpcOnce(url, token, name, args)\n } catch (error) {\n if (error instanceof McpError && error.code === 401 && !retried) {\n invalidatePluginToken()\n try {\n await ensurePluginToken()\n return await mcpCallTool(name, args, true)\n } catch {\n throw new McpError('请先在用户中心登录', 401)\n }\n }\n throw error\n }\n if (result && result.isError) throw new McpError(textOfContent(result.content) || '知识库工具执行失败')\n return result\n}\n\n/** 解包 MCP 工具结果为业务数据(structuredContent 优先,content[0].text JSON 兜底) */\nfunction unwrapToolData(result) {\n if (result?.structuredContent && typeof result.structuredContent === 'object') return result.structuredContent\n const text = textOfContent(result?.content)\n if (text) {\n try {\n return JSON.parse(text)\n } catch {}\n }\n return null\n}\n\n/**\n * 向知识库添加文档(MCP kb_doc_add;服务端解析/分块/向量化异步执行)\n * @param {object} p { kbId, docName, content, fileType?, tags?, folderId? }\n * @returns {Promise<{doc_id:number, task_id:number, hint?:string}>}\n */\nexport async function mcpAddDoc({ kbId, docName, content, fileType = 'md', tags, folderId }) {\n const result = await mcpCallTool('kb_doc_add', {\n kb_id: Number(kbId),\n doc_name: String(docName || ''),\n content: String(content || ''),\n file_type: fileType,\n ...(tags && tags.length ? { tags } : {}),\n ...(folderId ? { folder_id: Number(folderId) } : {}),\n })\n return unwrapToolData(result) || {}\n}\n","/**\n * 「存入知识库」图标按钮(DSH AI 消息操作区插槽组件 conversation.chat.assistant-actions)\n *\n * - props 契约(官方 dsh-client-ui-chat):owner 传 { messageId },session 作用域\n * 标准 props 注入 useChat(ChatSnapshot 选择器 hook);消息正文经 useChat 快照\n * 在 ChatNodeStore 中按 finalNode.messageId 匹配 assistant 节点取 text blocks\n * (LLM 回复本身就是 markdown,拼接原文即可;reasoning/工具块不入库)\n * - useStore 稳定快照约定:selector 返回快照本体(identity 稳定),文本派生走\n * useMemo,避免 getSnapshot 不稳定引发 React #185\n * - useChat 缺失或未命中时回退 DOM 纯文本抽取(保真度下降,仅兜底)\n * - 弹窗不挂 slot DOM(会话列 overflow 裁剪,模态不能挂进 slot——usercenter 先例):\n * Modal 自身 Portal 挂 body 固定层(z-index 30 ≤ 35,不覆盖宿主设置菜单),直接复用通用 Modal\n * - 按钮视觉对齐官方操作行(28px 图标钮,feedback 同款令牌)\n * - 提交走 MCP kb_doc_add(api/mcp.js),服务端解析/分块/向量化异步执行\n */\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport Modal from '../common/Modal.jsx'\nimport { BookPlusGlyph } from '../common/icons.jsx'\nimport { listKb } from '../../api/kb.js'\nimport { listDocs, updateDocContent } from '../../api/doc.js'\nimport { mcpAddDoc } from '../../api/mcp.js'\nimport { toast, toastError } from '../../store/ui-store.js'\n\n/** 按钮文案(DOM 兜底抽取时据此从克隆树中剔除按钮自身区域) */\nconst BTN_LABEL = '存入知识库'\n\n/**\n * 从 ChatSnapshot 提取指定 messageId 的 AI 回复 markdown 原文:\n * ChatNodeStore.values() 中 kind 'assistant-step' 且 data.finalNode.messageId\n * 匹配的节点,取其 blocks 的 text 项(跳过 reasoning/工具调用)以空行拼接\n */\nfunction extractTextFromChat(chat, messageId) {\n if (!chat || !messageId) return ''\n try {\n for (const node of chat.nodes.values()) {\n if (!node || node.kind !== 'assistant-step') continue\n const data = node.data\n if (!data || data.finalNode?.messageId !== messageId) continue\n return (data.blocks || [])\n .filter((b) => b && b.kind === 'text' && typeof b.text === 'string' && b.text.trim())\n .map((b) => b.text)\n .join('\\n\\n')\n .trim()\n }\n } catch {}\n return ''\n}\n\n/**\n * DOM 兜底:从操作区按钮向上找所在 turn 的 AI 回复正文(克隆后剔除\n * 按钮/图标等非正文节点)。宿主节点包裹层带 data-chat-turn=<turn>,\n * 取同 turn 的 assistant-step 节点文本\n */\nfunction extractFromDom(buttonEl) {\n if (!buttonEl || typeof document === 'undefined') return ''\n const tail = buttonEl.closest('[data-turn-tail]')\n const turnEl = tail?.closest('[data-chat-turn]') || buttonEl.closest('[data-chat-turn]')\n if (!turnEl) return ''\n const turn = turnEl.getAttribute('data-chat-turn')\n const scope = turn\n ? Array.from(document.querySelectorAll(`[data-chat-turn=\"${turn}\"]`)).find((el) =>\n (el.getAttribute('data-chat-flow-kind') || '').includes('assistant'),\n ) || turnEl.parentElement\n : turnEl.parentElement\n if (!scope) return ''\n const clone = scope.cloneNode(true)\n clone.querySelectorAll('button, svg, [aria-hidden=\"true\"]').forEach((el) => el.remove())\n if (clone.textContent.includes(BTN_LABEL)) {\n clone.querySelectorAll('span,div').forEach((el) => {\n if (!el.children.length && el.textContent.trim() === BTN_LABEL) el.remove()\n })\n }\n return (clone.innerText || clone.textContent || '').trim()\n}\n\n/** 默认文档名:首行语义摘要(≤24 字)+ 日期时间,避免重名 */\nfunction defaultDocName(text) {\n const firstLine = String(text).split('\\n').map((l) => l.trim()).find(Boolean) || ''\n const head = firstLine.replace(/[#*`>~[\\]]/g, '').slice(0, 24).trim() || '对话回复'\n const d = new Date()\n const pad = (n) => String(n).padStart(2, '0')\n return `${head}-${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}.md`\n}\n\n/**\n * 从 ChatSnapshot 提取会话最近指定的知识库文档:扫 user 消息文本中\n * 「kb_id[:=]N / doc_id[:=]N」标记(AI 编写与文档问答 prompt 均携带),\n * 取最后一条带 doc_id 的用户消息(最近上下文优先)。返回 { kbId, docId },未命中为 0\n */\nfunction extractKbDocRef(chat) {\n if (!chat || typeof chat.nodes?.values !== 'function') return { kbId: 0, docId: 0 }\n let ref = { kbId: 0, docId: 0 }\n try {\n for (const node of chat.nodes.values()) {\n if (!node || node.kind !== 'user' || !node.data) continue\n const text = (node.data.content || [])\n .map((b) => (b && typeof b.text === 'string' ? b.text : ''))\n .join('\\n')\n if (!text) continue\n const docM = text.match(/doc_id\\s*[:=:]\\s*(\\d+)/)\n if (docM) {\n const kbM = text.match(/kb_id\\s*[:=:]\\s*(\\d+)/)\n ref = { kbId: kbM ? Number(kbM[1]) : 0, docId: Number(docM[1]) }\n } else {\n const kbM = text.match(/kb_id\\s*[:=:]\\s*(\\d+)/)\n if (kbM && !ref.kbId) ref = { kbId: Number(kbM[1]), docId: 0 }\n }\n }\n } catch {}\n return ref\n}\n\nexport default function SaveToKbButton(props) {\n const { messageId, useChat } = props || {}\n const btnRef = useRef(null)\n const [open, setOpen] = useState(false)\n const [content, setContent] = useState('')\n const [kbs, setKbs] = useState([])\n const [kbLoaded, setKbLoaded] = useState(false)\n const [kbId, setKbId] = useState(0)\n const [docName, setDocName] = useState('')\n const [tags, setTags] = useState('')\n const [error, setError] = useState('')\n const [busy, setBusy] = useState(false)\n // 保存方式:create=新建文档(原有流程);overwrite=选择已有文档覆盖内容\n const [mode, setMode] = useState('create')\n const [docs, setDocs] = useState([])\n const [docsLoaded, setDocsLoaded] = useState(false)\n const [docId, setDocId] = useState(0)\n\n // 快照本体为 selector 结果(identity 稳定);文本派生在 useMemo 内完成\n const chat = typeof useChat === 'function' ? useChat((s) => s) : null\n const chatText = useMemo(() => extractTextFromChat(chat, messageId), [chat, messageId])\n // 会话最近指定的知识库文档(AI 编写/文档问答 prompt 的 kb_id/doc_id 标记)\n const kbDocRef = useMemo(() => extractKbDocRef(chat), [chat])\n // 数值化依赖:chat 快照流式更新会换本体,依赖原始 number 避免 effect 反复重拉\n const refKbId = kbDocRef.kbId\n const refDocId = kbDocRef.docId\n\n // 弹窗首次打开拉知识库列表(复用 REST listKb;失败 toast,不阻塞弹窗)。\n // 默认知识库优先选会话指定的(ref.kbId 在列表内),否则取列表首位\n useEffect(() => {\n if (!open || kbLoaded) return undefined\n let cancelled = false\n listKb({ page: 1, limit: 100 })\n .then((res) => {\n if (cancelled) return\n const list = (res && res.list) || []\n setKbs(list)\n const first = Number(list[0]?.id) || 0\n const refKb = kbDocRef.kbId && list.some((kb) => Number(kb.id) === kbDocRef.kbId) ? kbDocRef.kbId : 0\n setKbId((cur) => cur || refKb || first)\n setKbLoaded(true)\n })\n .catch((e) => {\n if (!cancelled) toastError(e)\n })\n return () => {\n cancelled = true\n }\n }, [open, kbLoaded, refKbId])\n\n // 覆盖模式:按所选知识库拉文档列表(切库重拉)。\n // 加载完成后若会话指定文档在该库中,则默认选中它\n useEffect(() => {\n if (!open || mode !== 'overwrite' || !kbId) return undefined\n let cancelled = false\n setDocsLoaded(false)\n setDocs([])\n setDocId(0)\n listDocs(kbId, { page: 1, limit: 200 })\n .then((res) => {\n if (cancelled) return\n const list = (res && res.list) || []\n setDocs(list)\n if (refDocId && list.some((d) => Number(d.id) === refDocId)) {\n setDocId(refDocId)\n }\n })\n .catch((e) => {\n if (!cancelled) toastError(e)\n })\n .finally(() => {\n if (!cancelled) setDocsLoaded(true)\n })\n return () => {\n cancelled = true\n }\n }, [open, mode, kbId, refDocId])\n\n function openModal() {\n const text = chatText || extractFromDom(btnRef.current)\n if (!text) {\n toast('未获取到消息内容,无法保存', 'error')\n return\n }\n setContent(text)\n setDocName(defaultDocName(text))\n setTags('')\n setError('')\n setMode('create')\n setOpen(true)\n }\n\n async function submit() {\n if (!kbId) {\n setError('请选择目标知识库')\n return\n }\n setBusy(true)\n setError('')\n try {\n if (mode === 'overwrite') {\n await submitOverwrite()\n } else {\n await submitCreate()\n }\n } finally {\n setBusy(false)\n }\n }\n\n /** 新建文档:MCP kb_doc_add(服务端解析/分块/向量化异步执行) */\n async function submitCreate() {\n if (!docName.trim()) {\n setError('请输入文档名称')\n return\n }\n try {\n const tagArr = tags.split(/[,,、\\s]+/).map((t) => t.trim()).filter(Boolean)\n const data = await mcpAddDoc({ kbId, docName: docName.trim(), content, tags: tagArr })\n toast(`已存入知识库(文档 ID ${data.doc_id ?? '?'}),解析与向量化异步执行中`, 'success', 4000)\n setOpen(false)\n } catch (e) {\n setError((e && (e.msg || e.message)) || '保存失败,请稍后重试')\n }\n }\n\n /**\n * 覆盖已有文档:REST updateDocContent(走编辑权限校验 + base_updated_at 乐观锁,\n * 原内容自动保留为历史版本快照);409 冲突时确认后强制覆盖\n */\n async function submitOverwrite() {\n if (!docId) {\n setError('请选择要覆盖的文档')\n return\n }\n const target = docs.find((d) => Number(d.id) === Number(docId))\n try {\n await updateDocContent(kbId, docId, { content, baseUpdatedAt: target?.update_time || 0 })\n toast(`已覆盖文档「${target?.name || docId}」,重新解析与向量化中`, 'success', 4000)\n setOpen(false)\n } catch (e) {\n const conflict = e?.code === 409 || /冲突/.test(e?.msg || e?.message || '')\n if (conflict && typeof window !== 'undefined' && window.confirm('该文档在此期间已被修改,是否强制覆盖?')) {\n try {\n await updateDocContent(kbId, docId, { content, baseUpdatedAt: target?.update_time || 0, force: true })\n toast(`已强制覆盖文档「${target?.name || docId}」,重新解析与向量化中`, 'success', 4000)\n setOpen(false)\n return\n } catch (e2) {\n setError((e2 && (e2.msg || e2.message)) || '覆盖失败,请稍后重试')\n return\n }\n }\n setError((e && (e.msg || e.message)) || '覆盖失败,请稍后重试')\n }\n }\n\n return (\n <>\n <button\n ref={btnRef}\n type=\"button\"\n className=\"skai-kb-chat-save-btn\"\n title={BTN_LABEL}\n aria-label={BTN_LABEL}\n onClick={openModal}\n >\n <BookPlusGlyph size={15} />\n </button>\n\n {open ? (\n <Modal\n title=\"存入知识库\"\n width={480}\n onClose={() => {\n if (!busy) setOpen(false)\n }}\n footer={\n <>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={() => setOpen(false)} disabled={busy}>\n 取消\n </button>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-primary\" onClick={submit} disabled={busy}>\n {busy ? '提交中…' : mode === 'overwrite' ? '覆盖' : '保存'}\n </button>\n </>\n }\n >\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">保存方式</span>\n <div className=\"skai-kb-chat-save-modes\">\n <button\n type=\"button\"\n className={`skai-kb-btn${mode === 'create' ? ' skai-kb-btn-primary' : ''}`}\n onClick={() => setMode('create')}\n disabled={busy}\n >\n 新建文档\n </button>\n <button\n type=\"button\"\n className={`skai-kb-btn${mode === 'overwrite' ? ' skai-kb-btn-primary' : ''}`}\n onClick={() => {\n setMode('overwrite')\n setError('')\n }}\n disabled={busy}\n >\n 覆盖已有文档\n </button>\n </div>\n </div>\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">目标知识库 *</span>\n <select className=\"skai-kb-select\" value={kbId} onChange={(e) => setKbId(Number(e.target.value) || 0)} disabled={busy}>\n {!kbLoaded ? <option value={0}>加载中…</option> : null}\n {kbLoaded && kbs.length === 0 ? <option value={0}>(无可用知识库,请先创建)</option> : null}\n {kbs.map((kb) => (\n <option key={kb.id} value={kb.id}>\n {kb.name}\n </option>\n ))}\n </select>\n </div>\n {mode === 'overwrite' ? (\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">选择要覆盖的文档 *</span>\n <select\n className=\"skai-kb-select\"\n value={docId}\n onChange={(e) => setDocId(Number(e.target.value) || 0)}\n disabled={busy || !docsLoaded || docs.length === 0}\n >\n {!docsLoaded ? <option value={0}>加载中…</option> : null}\n {docsLoaded && docs.length === 0 ? <option value={0}>(该知识库暂无文档)</option> : null}\n {docs.map((d) => (\n <option key={d.id} value={d.id}>\n {d.name}\n </option>\n ))}\n </select>\n <span className=\"skai-kb-chat-save-hint\">覆盖将替换文档全部内容,原内容自动保留为历史版本</span>\n </div>\n ) : (\n <>\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">文档名称 *</span>\n <input\n className=\"skai-kb-input\"\n value={docName}\n maxLength={120}\n onChange={(e) => setDocName(e.target.value)}\n placeholder=\"如:接口设计要点-20260101-1530.md\"\n disabled={busy}\n />\n </div>\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">业务标签(逗号分隔,可选)</span>\n <input\n className=\"skai-kb-input\"\n value={tags}\n onChange={(e) => setTags(e.target.value)}\n placeholder=\"如:对话纪要, 方案\"\n disabled={busy}\n />\n </div>\n </>\n )}\n <div className=\"skai-kb-chat-save-preview\">\n <span className=\"skai-kb-chat-save-preview-label\">内容预览(前 200 字)</span>\n <pre>\n {content.slice(0, 200)}\n {content.length > 200 ? '…' : ''}\n </pre>\n </div>\n {error ? <div className=\"skai-kb-field-error\">{error}</div> : null}\n </Modal>\n ) : null}\n </>\n )\n}\n","/**\n * 「引用知识库」图标按钮(DSH 输入区左侧工具行插槽 conversation.input.left)\n *\n * - props 契约(官方 dsh-client-ui-conversation,list/session 型插槽标准 props):\n * inputActions(官方输入动作面,唯一写入通道 setDraft(text))+ useInput\n * (InputState 快照选择器 hook,用于读取当前草稿)\n * - 交互链路:点击按钮 → 弹窗选择知识库 → 经 inputActions.setDraft 将\n * 引用提示语(含 kb_id 与名称)写入输入框 → 用户发送后由智能体据此\n * 调用 MCP kb_rag_query 检索该知识库(后端 mcp tools.go 已暴露该工具)\n * - 草稿保留:以「提示语 + 原问题」拼接,避免覆盖用户已输入内容\n * - 弹窗不挂 slot DOM(输入区 DOM 会被会话布局裁剪):Modal 自身 Portal 挂 body\n * 固定层(z-index 30 ≤ 35,不覆盖宿主设置菜单),直接复用通用 Modal\n * - 复用「存入知识库」按钮既有范式:同款 .skai-kb-chat-save-btn 图标钮样式、\n * 全局 toast;无新增 CSS/依赖\n */\nimport { useEffect, useState } from 'react'\nimport Modal from '../common/Modal.jsx'\nimport { BookSearchGlyph } from '../common/icons.jsx'\nimport { listKb } from '../../api/kb.js'\nimport { toast, toastError } from '../../store/ui-store.js'\n\nconst BTN_LABEL = '引用知识库'\n\n/**\n * 生成引用提示语:显式携带 kb_id 与名称,使智能体可稳定识别并调用\n * kb_rag_query(入参 kb_id/query 必填)。已有草稿时追加于提示语之后\n */\nfunction buildReference(kbId, kbName, draft) {\n const head = `请结合知识库(kb_id: ${kbId},名称:${kbName})回答我的问题`\n const q = String(draft || '').trim()\n return q ? `${head}:${q}` : `${head}:`\n}\n\nexport default function ReferenceKbButton(props) {\n const { useInput, inputActions } = props || {}\n const [open, setOpen] = useState(false)\n const [kbs, setKbs] = useState([])\n const [kbLoaded, setKbLoaded] = useState(false)\n const [kbId, setKbId] = useState(0)\n\n // 快照选择器返回字符串(identity 稳定,规避 React #185);草稿随输入实时更新\n const draft = typeof useInput === 'function' ? useInput((s) => s.draft) : ''\n\n // 弹窗首次打开拉知识库列表(复用 REST listKb;失败 toast,不阻塞弹窗)\n useEffect(() => {\n if (!open || kbLoaded) return undefined\n let cancelled = false\n listKb({ page: 1, limit: 100 })\n .then((res) => {\n if (cancelled) return\n const list = (res && res.list) || []\n setKbs(list)\n if (list.length) setKbId((cur) => cur || Number(list[0].id) || 0)\n setKbLoaded(true)\n })\n .catch((e) => {\n if (!cancelled) toastError(e)\n })\n return () => {\n cancelled = true\n }\n }, [open, kbLoaded])\n\n function openModal() {\n if (!inputActions || typeof inputActions.setDraft !== 'function') {\n toast('当前环境不支持写入输入框', 'error')\n return\n }\n setOpen(true)\n }\n\n function apply() {\n const kb = kbs.find((k) => Number(k.id) === Number(kbId))\n if (!kb) {\n toast('请选择知识库', 'error')\n return\n }\n inputActions.setDraft(buildReference(Number(kb.id), kb.name, draft))\n setOpen(false)\n }\n\n const selected = kbs.find((k) => Number(k.id) === Number(kbId)) || null\n\n return (\n <>\n <button\n type=\"button\"\n className=\"skai-kb-chat-save-btn\"\n title={BTN_LABEL}\n aria-label={BTN_LABEL}\n onClick={openModal}\n >\n <BookSearchGlyph size={15} />\n </button>\n\n {open ? (\n <Modal\n title=\"引用知识库\"\n width={480}\n onClose={() => setOpen(false)}\n footer={\n <>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={() => setOpen(false)}>\n 取消\n </button>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-primary\" onClick={apply}>\n 引用\n </button>\n </>\n }\n >\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">目标知识库 *</span>\n <select\n className=\"skai-kb-select\"\n value={kbId}\n onChange={(e) => setKbId(Number(e.target.value) || 0)}\n >\n {!kbLoaded ? <option value={0}>加载中…</option> : null}\n {kbLoaded && kbs.length === 0 ? <option value={0}>(无可用知识库,请先创建)</option> : null}\n {kbs.map((kb) => (\n <option key={kb.id} value={kb.id}>\n {kb.name}\n </option>\n ))}\n </select>\n </div>\n <div className=\"skai-kb-chat-save-preview\">\n <span className=\"skai-kb-chat-save-preview-label\">引用提示语预览</span>\n <pre>{buildReference(kbId || 0, selected ? selected.name : '', draft)}</pre>\n </div>\n </Modal>\n ) : null}\n </>\n )\n}\n","/**\n * DSH 对话 AI 消息操作区插槽注入(「存入知识库」图标按钮)\n *\n * - 插槽名 conversation.chat.assistant-actions(DSH 官方契约,dsh-client-ui-chat\n * 声明:kind 'list' / scope 'session',owner 传 { messageId };官方点赞点踩\n * (dsh-client-ui-message-feedback,order 10)走同一插槽,本入口 order 20 排其后\n * - list 型插槽注册:register 必选自有 id(独立 cell,fresh id 新增、复用 id 替换)\n * - 组件标准 props:sessionId 作用域插槽自动注入 useChat(ChatSnapshot 选择器\n * hook),消息正文由组件经 messageId 查 ChatNodeStore 得到(见 SaveToKbButton)\n * - ctx.slots.inject 内部等待插槽声明出现并管理注册 disposer\n */\nimport SaveToKbButton from '../components/chat/SaveToKbButton.jsx'\nimport ReferenceKbButton from '../components/chat/ReferenceKbButton.jsx'\n\n/** DSH AI 消息操作区插槽(官方 dsh-client-ui-chat 声明) */\nconst CHAT_ASSISTANT_ACTIONS_SLOT = 'conversation.chat.assistant-actions'\n\n/**\n * 注册 AI 消息操作区「存入知识库」入口(client-entry apply 内调用,幂等)\n * @param {object} ctx client 半区 cordis ctx(含 slots)\n */\nexport function registerChatMessageSlots(ctx) {\n ctx.effect(\n () =>\n ctx.slots.inject(CHAT_ASSISTANT_ACTIONS_SLOT, () =>\n ctx.slots.register(\n { name: CHAT_ASSISTANT_ACTIONS_SLOT, id: 'shikeai-knowledge-save-kb', order: 20 },\n SaveToKbButton,\n ),\n ),\n 'shikeai-knowledge: chat assistant-actions save-to-kb',\n )\n}\n\n/** DSH 输入区左侧工具行插槽(官方 dsh-client-ui-conversation 声明;list/session,无现有占用) */\nconst CONVERSATION_INPUT_LEFT_SLOT = 'conversation.input.left'\n\n/**\n * 注册输入区「引用知识库」入口(client-entry apply 内调用,幂等)\n * 选中知识库后经 inputActions.setDraft 将引用提示语写入输入框,\n * 由智能体据此调用 MCP kb_rag_query 检索对应知识库\n * @param {object} ctx client 半区 cordis ctx(含 slots)\n */\nexport function registerChatInputSlots(ctx) {\n ctx.effect(\n () =>\n ctx.slots.inject(CONVERSATION_INPUT_LEFT_SLOT, () =>\n ctx.slots.register(\n { name: CONVERSATION_INPUT_LEFT_SLOT, id: 'shikeai-knowledge-reference-kb', order: 30 },\n ReferenceKbButton,\n ),\n ),\n 'shikeai-knowledge: conversation input-left reference-kb',\n )\n}\n\nexport default registerChatMessageSlots\n","/**\n * DSH Web Client 半区入口(构建为 lib/client.js 的 ModuleLoader bundle)\n *\n * 挂载方式(DSH 右侧 Sidebar 标签页体系,每个主要功能各一个标签页):\n * - ctx.sidebarRightTabs.register:注册 4 个标签页类型\n * 首页 shikeai-knowledge-home(引导页胶囊直达;知识库列表/添加知识库/设置入口)\n * 知识库详情 shikeai-knowledge-kb(params: { kbId };文档列表/权限配置/添加文档)\n * 文档详情 shikeai-knowledge-doc(params: { kbId, docId };markdown 渲染)\n * 设置 shikeai-knowledge-settings(后端服务器地址/管理员)\n * - keyed 插槽 sidebar.right.pane.tab / sidebar.right.pane.tab.title:\n * 标签页正文与活标题(正文自动获得 props.useTabInfo())\n * - ctx.remote.settings:MCP 服务器配置经 knowledge namespace 同步宿主\n *\n * 登录态只读复用用户中心插件(按需验签换发插件自有 Token);无内置对话面板,\n * RAG 检索由 DSH 智能体经 MCP kb_rag_query 完成。非 DSH 宿主(standalone)\n * 不走本入口,走 index.js 的 activate()。\n */\nimport { setHostMcpContext } from './core/host-mcp-sync.js'\nimport { setHostContext, setSessionsContext } from './core/dsh-agent.js'\nimport { registerKbTriggerSource } from './core/kb-trigger.js'\nimport { install } from './index.js'\nimport { registerSidebarRightTabs } from './slots/sidebar-right.js'\nimport { registerChatInputSlots, registerChatMessageSlots } from './slots/chat-message.js'\n\n/** Client 服务依赖:slots(插槽注册)、sidebarRightTabs(标签页类型注册表)、remote.settings(MCP 配置同步宿主)、remote.session(AI 编写会话通道)、sessions(list 快照 current = 当前打开的会话 + scope(id) 取 session 域 ctx 写输入框)、inputTriggers(@知识库 触发源注册) */\nexport const inject = ['slots', 'sidebarRightTabs', 'remote', 'remote.settings', 'remote.session', 'sessions', 'inputTriggers']\n\nexport function apply(ctx) {\n setHostMcpContext(ctx)\n setHostContext(ctx)\n setSessionsContext(ctx.sessions)\n\n // 样式注入 + 登录态事件绑定 + 服务器配置加载(与 standalone 路径共用)\n install()\n\n // 右侧 Sidebar 标签页类型 + 正文 + 活标题\n registerSidebarRightTabs(ctx)\n\n // 对话消息操作区「存入知识库」入口(MCP kb_doc_add 入库)\n registerChatMessageSlots(ctx)\n\n // 输入区「引用知识库」入口(写入引用提示语,触发 MCP kb_rag_query 检索)\n registerChatInputSlots(ctx)\n\n // `@知识库` 输入触发源:候选列文档,选中插入不可编辑 reference chip\n // (发送时经 serialize 序列化为 kb_id/doc_id 结构化标记)\n const disposeKbTrigger = registerKbTriggerSource(ctx)\n\n // fiber dispose(generation 切换 / 插件停用):撤销宿主 MCP / 会话通道 ctx 引用\n if (typeof ctx.effect === 'function') {\n ctx.effect(\n () => () => {\n setHostMcpContext(null)\n setHostContext(null)\n setSessionsContext(null)\n disposeKbTrigger()\n },\n 'shikeai-knowledge: client dispose',\n )\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"client.js","names":["hostCtx","useSyncExternalStore","createPortal","useState","useState","createPortal","createElement","useState","useCallback","useRef","subscribeServerConfig","useMemo","useRef","useState","useCallback","useState","useMemo","useRef","useState","useState","useMemo","useState","PAGE_SIZE","useState","useMemo","useState","useCallback","useState","useCallback","Fragment","useMemo","useState","useRef","useState","useRef","useCallback","useState","useState","useState","useState","useCallback","useState","useCallback","styles","Component","BTN_LABEL","useRef","useState","useMemo","useState"],"sources":["../src/core/host-mcp-sync.js","../src/core/dsh-agent.js","../src/core/server-config.js","../src/core/config.js","../src/core/session.js","../src/store/create-store.js","../src/store/ui-store.js","../src/store/kb-store.js","../src/store/doc-store.js","../src/store/title-store.js","../src/store/reset.js","../src/core/auth.js","../src/core/request.js","../src/api/kb.js","../src/api/doc.js","../src/core/kb-trigger.js","../src/api/task.js","../src/api/auth.js","../src/utils/file-type.js","../src/components/kb/KbCard.jsx","../src/components/common/Modal.jsx","../src/utils/validator.js","../src/components/kb/TagPicker.jsx","../src/components/kb/KbFormModal.jsx","../src/components/common/ConfirmDialog.jsx","../src/components/common/Toast.jsx","../src/components/common/icons.jsx","../src/api/user.js","../src/pages/home/HomePage.jsx","../src/store/folder-store.js","../src/api/folder.js","../src/hooks/use-kb-permission.js","../src/hooks/use-task-polling.js","../src/components/doc/DocSearchBar.jsx","../src/components/doc/DocStatusBadge.jsx","../src/components/doc/FolderTree.jsx","../src/components/doc/MoveDocModal.jsx","../src/components/doc/UploadDropzone.jsx","../src/components/doc/ChunkConfigForm.jsx","../src/components/doc/VersionTimeline.jsx","../src/hooks/use-member-info.js","../src/components/permission/MemberList.jsx","../src/components/permission/MemberGrantModal.jsx","../src/components/permission/PermissionModal.jsx","../src/pages/kb/KbDetailPage.jsx","../src/components/markdown/Markdown.jsx","../src/components/doc/MarkdownEditor.jsx","../src/pages/doc/DocDetailPage.jsx","../src/api/modelconfig.js","../src/api/health.js","../package.json","../src/manifest.js","../src/components/settings/ServerFormModal.jsx","../src/components/settings/AdminFormModal.jsx","../src/components/settings/ModelServiceModal.jsx","../src/components/settings/ModelConfigHelpModal.jsx","../src/components/settings/UserManagePanel.jsx","../src/pages/settings/SettingsPage.jsx","../src/app/StandaloneApp.jsx","../src/styles/knowledge.css?raw","../src/index.js","../src/app/tab-bodies.jsx","../src/slots/sidebar-right.js","../src/api/mcp.js","../src/components/chat/SaveToKbButton.jsx","../src/components/chat/ReferenceKbButton.jsx","../src/slots/chat-message.js","../src/client-entry.js"],"sourcesContent":["/**\n * DSH 宿主 MCP 配置同步(settings 活配置通道;仅 DSH client 半区生效)\n *\n * 数据链路(namespace 'knowledge' 由 Host 半区 apply 经 settings.register 注册):\n * 1. 本模块经远程 settingsController 的 settings.mutate('knowledge', ...) 把设置页\n * 当前服务器的接入点与插件 Token 写入该 namespace(远程面仅 describe/mutate——\n * register 仅宿主侧可用,勿再尝试 client 侧兜底注册)\n * 2. 用户层持久化到 ~/.dsh/settings.yaml(重启不丢);Host 半区 scope.watch 在提交\n * 变更后以新值 createMcp 重建连接并重新注册工具\n * → 智能体会话出现 mcp__knowledge__<skill> 工具\n *\n * - 推送时机:auth.syncHostMcpAuth() 的全部时机(首次验签换发、401 刷新、\n * 登录/退出/失效,以及设置页当前服务器变化:新增首个服务器自动激活、切换、\n * 编辑、删除兜底激活)\n * - 幂等:先 describe 读取 namespace 当前值与 revision,目标未变化时跳过写入\n * - 清除:删除服务器/退出登录(mcp_endpoint 为空串)时写入空 {url:'', token:''}\n * 覆盖宿主残留配置(否则重启后 Host 仍会拿旧值建连);Host 半区对空 url 仅销毁连接\n * - 启动竞态:client 半区就绪早于 Host 半区 apply(describe 查不到 namespace)\n * 时,单次延时重试;仍查不到则留诊断日志,等待下次推送时机\n * - standalone / 无 ctx 环境(注入 remote 服务缺失)自动空操作\n */\n\n/** knowledge settings 命名空间(与 Host 半区 host-entry.js 的 MCP_SETTINGS_NS 同名) */\nconst MCP_NS = 'knowledge'\n\n/** 启动竞态的单次重试延时(毫秒):等待 Host 半区 apply 完成 namespace 注册 */\nconst RETRY_DELAY_MS = 2000\n\n/** 单次重试定时器(新推送到达时清掉旧定时器,避免叠加) */\nlet retryTimer = null\n\n/**\n * 从 describe 视图取 knowledge 行(兼容宿主字段命名差异:\n * namespaces/list 顶层键 + 行内 ns/name/key/id/namespace 任一字段)\n */\nfunction findNamespaceRow(view) {\n const list = Array.isArray(view?.namespaces)\n ? view.namespaces\n : Array.isArray(view?.list)\n ? view.list\n : Array.isArray(view)\n ? view\n : []\n const row = list.find(\n (n) =>\n n &&\n (n.ns === MCP_NS || n.name === MCP_NS || n.key === MCP_NS || n.id === MCP_NS || n.namespace === MCP_NS),\n )\n if (row) return row\n // 字段命名完全未知时的兜底判定:JSON 序列化包含性(仅能判定存在,值/revision 未知)\n try {\n if (view && JSON.stringify(view).includes(`\"${MCP_NS}\"`)) {\n return { ns: MCP_NS, value: {}, revision: undefined }\n }\n } catch {}\n return null\n}\n\n/** client 半区 cordis ctx(apply 时注入;standalone 为 null) */\nlet hostCtx = null\n\n/** 写入串行链(revision 依据时序递进,防止并发 mutate 互相覆盖) */\nlet pushChain = Promise.resolve()\n\n/** 注入 client 半区 ctx(client-entry apply 首行调用;dispose 时置 null) */\nexport function setHostMcpContext(ctx) {\n hostCtx = ctx || null\n if (!ctx && retryTimer) {\n clearTimeout(retryTimer)\n retryTimer = null\n }\n}\n\n/**\n * 把当前 MCP 服务器配置写入 knowledge namespace(fire-and-forget,串行化)\n * @param {object} payload auth.syncHostMcpAuth 的登记快照\n * { api_base, mcp_endpoint, server_name, token, updated_at }\n */\nexport function pushHostMcpConfig(payload) {\n if (!hostCtx || !payload) return\n // mcp_endpoint 为空串(删除服务器/退出登录)也要推送:写入空值清除宿主残留配置\n pushChain = pushChain.then(() => syncSettings(payload, false)).catch(() => {})\n}\n\n/** 同步一次(describe → 比对 → mutate);异常仅告警,不影响业务 */\nasync function syncSettings(payload, isRetry) {\n const ctx = hostCtx\n if (!ctx || typeof ctx.remote?.settings?.describe !== 'function') return\n const settings = ctx.remote.settings\n const desired = {\n url: payload.mcp_endpoint,\n token: payload.token || '',\n }\n try {\n const result = await settings.describe()\n if (!result || result.ok !== true) {\n console.warn('[knowledge] MCP 宿主 settings 读取失败', (result && result.error) || '')\n return\n }\n const view = result.value\n if (!view || view.writable === false) return\n const row = findNamespaceRow(view)\n\n if (!row) {\n // Host 半区 apply 未完成(启动竞态):单次延时重试;仍查不到则留诊断日志\n if (!isRetry) {\n if (retryTimer) clearTimeout(retryTimer)\n retryTimer = setTimeout(() => {\n retryTimer = null\n pushChain = pushChain.then(() => syncSettings(payload, true)).catch(() => {})\n }, RETRY_DELAY_MS)\n console.info(`[knowledge] describe 未查到 '${MCP_NS}' 命名空间(Host 半区可能尚未就绪),2s 后重试一次`)\n return\n }\n try {\n const raw = JSON.stringify(view)\n console.warn(\n `[knowledge] describe 仍未查到 '${MCP_NS}' 命名空间(namespaces 原始视图:${raw.length > 600 ? raw.slice(0, 600) + '…' : raw})。` +\n 'Host 半区未加载或版本过旧——请确认插件已启用并重启 DSH 后重试',\n )\n } catch {}\n return\n }\n\n const cur = row.value || {}\n if (cur.url === desired.url && cur.token === desired.token) return\n\n const res = await settings.mutate(\n MCP_NS,\n [{ op: 'set', path: [], value: desired }],\n row.revision,\n )\n if (!res || res.ok === false) console.warn('[knowledge] MCP 宿主配置写入未接受', (res && res.error) || '')\n } catch (error) {\n console.warn('[knowledge] MCP 宿主配置同步失败', error)\n }\n}\n\n/**\n * 自检宿主 MCP 配置状态(页面加载/刷新时由 auth.checkHostMcpReady 调用)\n * @returns {Promise<{status: string, url: string, hasToken: boolean, detail: string}>}\n * status:no-ctx(非 DSH 环境/插件未激活)| no-settings(宿主 settings 不可用)\n * | no-namespace(Host 半区未注册 knowledge)| registered(已注册,\n * url/hasToken 供调用方与期望值比对)\n */\nexport async function describeHostMcpStatus() {\n if (!hostCtx) {\n return { status: 'no-ctx', url: '', hasToken: false, detail: '非 DSH 宿主环境(standalone 模式无需宿主 MCP)' }\n }\n const settings = hostCtx.remote?.settings\n if (!settings || typeof settings.describe !== 'function') {\n return { status: 'no-settings', url: '', hasToken: false, detail: '宿主 settings 服务不可用(client 半区未获得 remote.settings 注入)' }\n }\n try {\n const result = await settings.describe()\n if (!result || result.ok !== true) {\n return { status: 'no-settings', url: '', hasToken: false, detail: `宿主 settings 读取失败:${(result && result.error) || '未知错误'}` }\n }\n const view = result.value\n if (!view || view.writable === false) {\n return { status: 'no-settings', url: '', hasToken: false, detail: '宿主 settings 不可写' }\n }\n const row = findNamespaceRow(view)\n if (!row) {\n return {\n status: 'no-namespace',\n url: '',\n hasToken: false,\n detail: `宿主未注册 ${MCP_NS} 命名空间(Host 半区未加载或版本过旧,重启 DSH 后重试)`,\n }\n }\n const cur = row.value || {}\n return { status: 'registered', url: cur.url || '', hasToken: Boolean(cur.token), detail: '' }\n } catch (error) {\n return { status: 'no-settings', url: '', hasToken: false, detail: `宿主 settings 异常:${(error && error.message) || error}` }\n }\n}\n","/**\n * DSH 智能体对接封装(knowledge 版)\n *\n * 插件不直接调用 LLM。AI 编写提交到 DSH 当前打开的会话(ctx.sessions.list\n * 快照 current):follow 订阅该会话流 → prompt 提交「提示词 + 文档原文」→\n * 从 durable 的 assistant/message 事件提取全文(seq 水位过滤历史事件)。\n * 文档内容由前端页面直接携带,不经 MCP 工具读取;结果直接从会话流取回。\n *\n * 宿主上下文由 client-entry apply 时经 setHostContext 注入;standalone\n * 环境未注入则抛可读错误。\n */\n\n/** client 半区注入的宿主上下文(client-entry apply 时注入;standalone 为 null) */\nlet hostCtx = null\n\n/** client 半区注入的 sessions 服务(ctx.sessions,list 快照 current = 当前打开的会话) */\nlet sessionsSvc = null\n\n/**\n * 注入 client 半区 ctx(client-entry apply 首行调用;dispose 时置 null)\n */\nexport function setHostContext(ctx) {\n hostCtx = ctx || null\n}\n\n/**\n * 注入宿主 sessions 服务(client-entry apply 时调用;dispose 时置 null)。\n * AI 编写提交到当前打开的会话:list 快照的 current 即 DSH 界面正在查看的会话 id\n */\nexport function setSessionsContext(svc) {\n sessionsSvc = svc || null\n}\n\n/** 解析当前打开的会话 id(sessions.list 快照 current);无打开会话返回 undefined */\nfunction resolveCurrentSessionId() {\n try {\n return sessionsSvc?.list?.getSnapshot?.()?.current\n } catch {\n return undefined\n }\n}\n\n/** 解析宿主 session 远程服务(ctx.remote.session,宿主 WebUI 会话面板同源) */\nfunction resolveSessionRemote() {\n const remote = hostCtx && hostCtx.remote\n const session = remote && remote.session\n if (session && typeof session.create === 'function' && typeof session.prompt === 'function' && typeof session.follow === 'function') {\n return session\n }\n return null\n}\n\n/**\n * 解析当前打开会话的输入 facade(SessionInput:setDraft/insertReference/state)。\n * 标准路径(对齐宿主 queue dock 内部用法):\n * sessions.scope(id) 取 session 域 ctx → actx.get('conversation') →\n * conversation.input.for(actx)(要求 session scope)\n * standalone 环境 / 无打开会话 / 通道不可用时抛错,由调用方降级(如剪贴板)\n */\nfunction resolveSessionInputFacade() {\n const sessions = hostCtx && hostCtx.sessions\n if (!sessions || typeof sessions.scope !== 'function') {\n throw new Error('当前宿主未提供会话通道')\n }\n const sessionId = resolveCurrentSessionId()\n if (!sessionId) {\n throw new Error('请先在 DSH 中打开一个会话')\n }\n const actx = sessions.scope(sessionId)\n if (!actx) {\n throw new Error(`会话 \"${sessionId}\" 未解析到作用域`)\n }\n const conversation = typeof actx.get === 'function' ? actx.get('conversation') : actx.conversation\n const facade = conversation && conversation.input && typeof conversation.input.for === 'function'\n ? conversation.input.for(actx)\n : null\n if (!facade || typeof facade.setDraft !== 'function') {\n throw new Error('当前会话输入通道不可用')\n }\n return facade\n}\n\n/** 读取 facade 当前草稿(clipboard 投影;读不到视同空串) */\nfunction readFacadeDraft(facade) {\n try {\n const snap = facade.state && typeof facade.state.getSnapshot === 'function' ? facade.state.getSnapshot() : null\n return snap && typeof snap.draft === 'string' ? snap.draft : ''\n } catch {\n return ''\n }\n}\n\n/**\n * 将提示语写入 DSH 当前打开会话的输入框。\n * 合并语义:输入框已有内容时**追加**(空行分隔 + 提示语,原内容保留不覆盖),\n * 为空时直接填入。宿主公开 API(SessionInput.setDraft 全量替换、InputState 无\n * 光标字段)不暴露光标位置,无法真插到光标处——末尾追加是 API 内唯一可靠路径。\n * standalone 环境 / 无打开会话 / 写入未生效时抛错,由调用方降级(如剪贴板)\n * @param {string} text 要填入输入框的提示语\n */\nexport async function setSessionDraft(text) {\n const facade = resolveSessionInputFacade()\n // 合并:已有草稿 → 末尾空行分隔追加;空 → 直填\n const current = readFacadeDraft(facade)\n const next = current.trim()\n ? (current.endsWith('\\n') ? current + '\\n' : current + '\\n\\n') + text\n : text\n facade.setDraft(next)\n // 生效校验:正常 facade 下 draft 状态应在数帧内反映写入内容\n await new Promise((resolve) => setTimeout(resolve, 80))\n let snap = null\n try {\n snap = facade.state && typeof facade.state.getSnapshot === 'function' ? facade.state.getSnapshot() : null\n } catch { /* inert facade 读态抛错视同未生效 */ }\n if (!snap || typeof snap.draft !== 'string' || snap.draft !== next) {\n throw new Error('未能写入会话输入框')\n }\n}\n\n/**\n * 向 DSH 当前打开会话的输入框插入一条结构化引用 chip(与 `@知识库` onPick\n * 插入的芯片同构,发送时经触发源 codec.serialize 序列化)。\n *\n * 流程:setDraft 末尾追加占位文本(placeholder,与 codec.serialize 输出一致)→\n * 等草稿状态落地取最新 draftRev → 定位占位在 detect 坐标的 span →\n * facade.insertReference 将该 span 替换为 chip 节点。\n * detect 坐标换算:芯片在 clipboard 投影(draft)展开为 label,在 detect 投影\n * 仅占 1 字符(U+FFFC),故 detect 末尾 = draft.length - Σ(occurrence.length - 1)。\n *\n * 降级语义(不抛错):宿主 facade 无 insertReference 方法(旧版本)或 span CAS\n * 未通过(phase 锁定/并发编辑)时,占位文本保留在输入框——纯文本形式仍可被\n * lexicon 装饰成 chip 样式、可被 AI 解析,返回 { chip:false };\n * 无会话/通道不可用仍抛错,由调用方走剪贴板兜底。\n *\n * @param {object} reference ReferenceInsert 形状 { source, ref, label, appearance?, clipboardText }\n * @param {string} placeholder 占位文本(chip 替换目标;降级时即最终纯文本引用)\n * @returns {Promise<{chip: boolean}>} 是否成功插入为 chip\n */\nexport async function insertSessionReference(reference, placeholder) {\n const facade = resolveSessionInputFacade()\n const ph = String(placeholder || '')\n if (!ph) throw new Error('引用占位文本为空')\n const current = readFacadeDraft(facade)\n // 占位写入:非空草稿末尾以空格衔接(insertReference 会自动在芯片后补分隔空格)\n const next = current ? (/\\s$/.test(current) ? current : current + ' ') + ph : ph\n if (typeof facade.insertReference !== 'function') {\n facade.setDraft(next) // 降级:纯文本引用(serialize 同形,可被 lexicon 装饰)\n return { chip: false }\n }\n facade.setDraft(next)\n // 等草稿状态落地(芯片替换需要最新 draftRev 做 span CAS)\n let snap = null\n for (let i = 0; i < 25; i++) {\n await new Promise((resolve) => setTimeout(resolve, 40))\n try {\n snap = facade.state && typeof facade.state.getSnapshot === 'function' ? facade.state.getSnapshot() : null\n } catch { snap = null }\n if (snap && typeof snap.draft === 'string' && snap.draft.includes(ph)) break\n }\n if (!snap || typeof snap.draft !== 'string' || !snap.draft.includes(ph)) {\n throw new Error('未能写入会话输入框')\n }\n // detect 坐标换算:已存芯片 clipboard 展开 label、detect 仅占 1 字符\n const chipDelta = (snap.occurrences || []).reduce((acc, o) => acc + Math.max((o.length || 1) - 1, 0), 0)\n const detectEnd = snap.draft.length - chipDelta\n const span = { start: Math.max(detectEnd - ph.length, 0), end: detectEnd, draftRev: snap.draftRev }\n let ok = false\n try {\n ok = facade.insertReference(reference, span) === true\n } catch { ok = false }\n return { chip: ok }\n}\n\n/**\n * 从 assistant/message 事件的 message.content 中提取全部 text block 拼接全文\n * @param {object} message AssistantMessage 形状 { role:'assistant', content: ContentBlock[] }\n * @returns {string} 纯文本全文(无 text block 时返回空串)\n */\nfunction extractMessageText(message) {\n if (!message || !Array.isArray(message.content)) return ''\n return message.content\n .filter((b) => b && b.type === 'text' && typeof b.text === 'string')\n .map((b) => b.text)\n .join('')\n}\n\n/**\n * 运行一次 AI 编写:提交到 DSH 当前打开的会话 → follow 订阅 → prompt 提交 →\n * 一直等到本轮 assistant 消息落定(turn/end)→ 返回全文。无整体超时;\n * 会话中断(interrupt/cancel)或 prompt 提交失败立即停止等待并抛错。\n *\n * @param {object} p\n * @param {string} p.text 完整意图文本(提示词 + 文档原文,由前端拼装)\n * @param {(delta: string) => void} [p.onDelta] 流式增量回调(尽力而为,仅用于进度展示;\n * 最终结果以 assistant/message 事件为准)\n * @returns {Promise<string>} AI 输出的完整文本\n */\nexport async function runAIWriteSession({ text, onDelta }) {\n const session = resolveSessionRemote()\n if (!session) {\n throw new Error('当前宿主未提供会话通道(ctx.remote.session),请在 DSH 环境中重试')\n }\n // 提交到当前打开的会话(DSH 界面正在查看的那个);无打开会话时报错,不另创建\n const sessionId = resolveCurrentSessionId()\n if (!sessionId) {\n throw new Error('请先在 DSH 中打开一个会话,再使用 AI 编写')\n }\n\n // follow 打开后再 prompt:保证不会漏掉本轮 assistant 消息事件\n const followStream = await session.follow(\n { address: { kind: 'session', sessionId }, assistantStream: true },\n undefined,\n )\n const iterator = followStream[Symbol.asyncIterator]()\n\n // 尽早关闭 follow 流(async generator return 触发宿主侧订阅清理)\n const cleanup = () => {\n try {\n iterator.return?.()\n } catch { /* 已结束则忽略 */ }\n }\n\n try {\n // 先提交(follow 已在位);prompt 返回 Receipt,不代表生成完成。\n // 不在循环内 await Receipt(queue 模式可能迟至 turn 结束才落定,会阻塞流消费导致丢帧);\n // 其 rejection 转 promptFailed 参与竞速,让循环立即退出快速失败\n const promptPromise = session.prompt({\n requestId: `skai-kb-aiw-${Date.now()}`,\n sessionId,\n mode: 'queue',\n content: [{ type: 'text', text }],\n })\n // 快速失败竞速分支:prompt reject 时立即打断流等待;\n // 成功后转为永不 settle 的 promise(不干扰后续竞速,只等流事件)\n const promptFailed = promptPromise.then(\n () => new Promise(() => {}),\n (e) => {\n throw e\n },\n )\n\n // ctx.remote.session 是 typert RPC 代理,follow 返回裸 wire 帧(SessionFollowFrame):\n // {type:'snapshot', records: SessionEventEntry[]} 打开基线(已有会话含全部历史)\n // {type:'event', event:{seq, type, data}} journal durable 事件(assistant/message、turn/end 在此)\n // {type:'assistant-stream', frame: SessionAssistantStreamFrame} assistant 流片段\n let latest = null // 最后一条 assistant/message 的全文\n let interrupted = false\n // 水位:follow 打开已有会话时基线含历史事件(旧 assistant/message、旧 turn/end),\n // seq <= watermark 的一律忽略,只吸收本次 prompt 产生的新事件\n let watermark = 0\n const absorb = (ev) => {\n if (!ev) return\n if (ev.seq != null && ev.seq <= watermark) return\n if (ev.type === 'assistant/message') {\n const data = ev.data || {}\n latest = extractMessageText(data.message)\n if (data.interrupted) interrupted = true\n } else if (ev.type === 'turn/end') {\n // 一轮落定:以 turn 为完成边界(多步场景取最后一轮的助手消息)\n if (ev.data?.reason?.kind === 'interrupted') interrupted = true\n }\n }\n for (;;) {\n // 等待流下一帧;prompt 提交失败时经 promptFailed 竞速立即抛错(无整体超时,\n // 一直等到会话 turn/end 或流关闭为止)\n const next = await Promise.race([iterator.next(), promptFailed])\n if (next.done) break\n const frame = next.value\n\n if (frame?.type === 'snapshot') {\n // 基线:只取最大 seq 作水位(旧事件不吸收,防止误回填历史消息)\n for (const record of frame.records || []) {\n const seq = record?.event?.seq\n if (typeof seq === 'number' && seq > watermark) watermark = seq\n }\n continue\n }\n if (frame?.type === 'event') {\n absorb(frame.event)\n if (frame.event?.type === 'turn/end' && frame.event.seq > watermark) break\n continue\n }\n if (frame?.type === 'assistant-stream' && onDelta) {\n // 过程帧:尽力提取增量文本供进度展示(chunk 为 provider 流片段,容错解析)\n const f = frame.frame\n if (f?.type === 'chunk' && f.chunk) {\n const c = f.chunk\n const piece = typeof c === 'string' ? c : typeof c.delta === 'string' ? c.delta : c.type === 'text' && typeof c.text === 'string' ? c.text : ''\n if (piece) onDelta(piece)\n }\n continue\n }\n // 其余未知帧忽略\n }\n\n if (interrupted) throw new Error('AI 输出被中断,未获得完整结果')\n if (!latest || !latest.trim()) {\n throw new Error('会话已结束但未收到 AI 文本结果')\n }\n return latest\n } finally {\n cleanup()\n }\n}\n","/**\n * 后端服务器配置(设置页数据源,用户中心配置项云持久化)\n *\n * - 支持配置多个 Go 后端服务器(名称 + 服务器URL),一键切换当前使用的服务器;\n * 服务器 URL 只含协议 + IP/端口(如 http://127.0.0.1:8081),应用路径固定\n * /kb 由前端统一拼装,无需用户配置\n * - REST(request.js)请求发往「当前服务器」;当前服务器同时作为 MCP 接入点\n * (getMcpEndpoint() = {服务器URL}/kb/mcp/v1),新增首个服务器自动激活 /\n * 切换 / 编辑 / 删除兜底激活时经 auth.syncHostMcpAuth() 把 MCP 服务器配置登记至宿主\n * (供 DSH 智能体注册并调用知识库 MCP Skill)\n * - 持久化:经用户中心配置开放接口(window.SHIKEAI_GET_MEMBER_CONFIG /\n * window.SHIKEAI_SET_MEMBER_CONFIG)按会员维度云存储(key 前缀 knowledge.),\n * 跨设备同步;本模块维护内存态镜像,getServers / getActiveServer / getApiBase\n * 同步读取(request / session 每次请求动态取值),写入即时生效并异步上云\n * - 游客态:云接口读取返回 null、保存返回 false,配置仅本次会话内有效(不落本地)\n * - 登录态变化(登录 / 退出 / 失效)自动重新拉取云端配置,实现账号隔离,\n * 防止跨账号配置残留\n * - 不内置默认地址——未配置/未选中服务器时 getApiBase() 返回空串,请求侧统一\n * 拦截并提示先配置服务器信息\n */\n\n/** 云配置键(用户中心约定「插件名.配置项名」前缀,value 均为字符串) */\nconst KEY_SERVERS = 'knowledge.servers'\nconst KEY_ACTIVE = 'knowledge.serverActive'\n\n/** 固定应用路径(前后端约定;服务器 URL 不含该前缀,request / session / MCP 端点统一拼装) */\nexport const APP_PATH = '/kb'\n\n/** 服务器配置内存态(云端镜像;同步读取源) */\nlet servers = []\nlet activeId = ''\n\n/** 加载请求序号(丢弃过期加载结果,防慢响应覆盖新配置) */\nlet loadSeq = 0\n/** 登录态事件是否已绑定 */\nlet authBound = false\n\nconst listeners = new Set()\nfunction emit() {\n listeners.forEach((fn) => {\n try {\n fn()\n } catch {}\n })\n}\n\nlet seq = 0\nfunction genId() {\n return `srv_${Date.now()}_${++seq}`\n}\n\n/** 云端列表数据清洗:仅保留结构完整的条目;api_base 归一为 origin(旧配置 /api 后缀自动收敛) */\nfunction sanitizeServers(raw) {\n if (!Array.isArray(raw)) return { list: [], changed: false }\n let changed = false\n const list = raw\n .filter((s) => s && typeof s === 'object' && s.id && s.name && s.api_base)\n .map((s) => {\n const base = normalizeApiBase(s.api_base)\n const apiBase = base || String(s.api_base)\n if (apiBase !== s.api_base) changed = true\n return {\n id: String(s.id),\n name: String(s.name),\n api_base: apiBase,\n created_at: Number(s.created_at) || 0,\n }\n })\n return { list, changed }\n}\n\n/** 应用云端配置到内存态(activeId 失效时置空,不自动兜底选择;归一发生变化时回写云端) */\nfunction applyCloud(list, activeRaw) {\n const { list: cleaned, changed } = sanitizeServers(list)\n servers = cleaned\n const id = typeof activeRaw === 'string' ? activeRaw : ''\n activeId = servers.some((s) => s.id === id) ? id : ''\n // 旧版本存量配置(api_base 带 /api 等应用路径后缀)归一为 origin 后回写云端,仅首次触发\n if (changed) persist()\n emit()\n}\n\n/**\n * 从用户中心云配置拉取服务器配置(幂等可重入)\n * 安装时与登录态变化(登录 / 退出 / 失效,账号隔离)时调用\n *\n * 启动自动生效保障(DSH 启动后已配置服务器无需手动操作即生效):\n * - 桥接就绪等待:用户中心 bundle 可能晚于本插件挂载 window 桥接(bundle 顺序\n * 变化时),有界轮询等待(250ms × 40 = 10s 上限),就绪后立即拉取\n * - 静默恢复重拉:DSH 启动时用户中心经 restoreSession 静默恢复会话(不派发\n * login 事件),恢复成功派发 user-update;本模块监听该事件重拉云端配置,\n * 覆盖「首拉时会话/后端未就绪」的瞬时失败\n * - 瞬时失败重试:已登录(SHIKEAI_USER_INFO 存在)但云端读取返回 null(网络\n * 异常等)时有界重试 3 次(间隔 1s);返回空对象(确实未配置)或游客态不重试\n */\nconst BRIDGE_POLL_INTERVAL = 250\nconst BRIDGE_POLL_MAX = 40\nconst FETCH_RETRY_MAX = 3\nconst FETCH_RETRY_INTERVAL = 1000\n\nfunction cloudBridgeReady() {\n return typeof window !== 'undefined' && typeof window.SHIKEAI_GET_MEMBER_CONFIG === 'function'\n}\n\n/** 首次加载完成标记与等待者(whenReady 用;登录态变化的后续重拉不再放行) */\nlet firstLoadDone = false\nlet firstLoadResolvers = []\n\nfunction settleFirstLoad() {\n if (firstLoadDone) return\n firstLoadDone = true\n const resolvers = firstLoadResolvers\n firstLoadResolvers = []\n resolvers.forEach((resolve) => resolve())\n}\n\nasync function loadFromCloud() {\n const reqSeq = ++loadSeq\n try {\n await pullFromCloud(reqSeq)\n } finally {\n // 仅最后一轮加载负责放行 whenReady(被新加载顶替时由新加载放行)\n if (reqSeq === loadSeq) settleFirstLoad()\n }\n}\n\nasync function pullFromCloud(reqSeq) {\n for (let i = 0; !cloudBridgeReady() && i < BRIDGE_POLL_MAX; i++) {\n await new Promise((resolve) => setTimeout(resolve, BRIDGE_POLL_INTERVAL))\n if (reqSeq !== loadSeq) return\n }\n if (!cloudBridgeReady() || reqSeq !== loadSeq) return\n for (let attempt = 1; attempt <= FETCH_RETRY_MAX; attempt++) {\n try {\n const data = await window.SHIKEAI_GET_MEMBER_CONFIG([KEY_SERVERS, KEY_ACTIVE])\n if (reqSeq !== loadSeq) return\n if (data == null) {\n // null = 游客态或云端读取失败:已登录(用户信息在)时按瞬时失败重试,\n // 游客态无配置可读,直接放弃\n const loggedIn = Boolean(window.SHIKEAI_USER_INFO)\n if (!loggedIn || attempt >= FETCH_RETRY_MAX) return\n await new Promise((resolve) => setTimeout(resolve, FETCH_RETRY_INTERVAL))\n if (reqSeq !== loadSeq) return\n continue\n }\n const raw = typeof data === 'object' ? data : {}\n let list = []\n try {\n list = raw[KEY_SERVERS] ? JSON.parse(raw[KEY_SERVERS]) : []\n } catch {\n list = []\n }\n applyCloud(list, raw[KEY_ACTIVE])\n return\n } catch {\n if (attempt >= FETCH_RETRY_MAX) return\n await new Promise((resolve) => setTimeout(resolve, FETCH_RETRY_INTERVAL))\n if (reqSeq !== loadSeq) return\n }\n }\n}\n\n/** 云端保存(fire-and-forget;游客态 / 失败仅告警,内存态修改不受影响) */\nfunction persist() {\n if (typeof window === 'undefined' || typeof window.SHIKEAI_SET_MEMBER_CONFIG !== 'function') return\n Promise.resolve(\n window.SHIKEAI_SET_MEMBER_CONFIG({\n [KEY_SERVERS]: JSON.stringify(servers),\n [KEY_ACTIVE]: activeId,\n }),\n )\n .then((ok) => {\n if (!ok) console.warn('[knowledge] 服务器配置云端保存失败(游客态或网络异常),本次修改仅会话内有效')\n })\n .catch(() => {})\n}\n\n/** 是否具备云持久化条件(用户中心配置接口已挂载且已登录);设置页提示用 */\nexport function isCloudPersistAvailable() {\n if (typeof window === 'undefined') return false\n return typeof window.SHIKEAI_SET_MEMBER_CONFIG === 'function' && Boolean(window.SHIKEAI_USER_INFO)\n}\n\n/** 安装:绑定用户中心登录态事件(登录 / 退出 / 失效 / 静默恢复成功)并首次加载(幂等) */\nexport function initServerConfig() {\n if (typeof window === 'undefined') return\n if (!authBound) {\n authBound = true\n // user-update:DSH 启动时用户中心静默恢复会话成功(restoreSession → refreshUser)\n // 的确切信号——首拉可能因会话/后端未就绪失败,该事件到达即重拉云端配置\n ;['shikeai-usercenter:login', 'shikeai-usercenter:logout', 'shikeai-usercenter:expired', 'shikeai-usercenter:user-update'].forEach((type) => {\n window.addEventListener(type, loadFromCloud)\n })\n }\n loadFromCloud()\n}\n\n/** URL 规范化:协议必须为 http/https,仅保留 origin(协议+域名/IP+端口,应用路径不随 URL 配置) */\nexport function normalizeApiBase(url) {\n const v = String(url || '').trim()\n if (!v) return ''\n let parsed\n try {\n parsed = new URL(v)\n } catch {\n return ''\n }\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') return ''\n return parsed.origin\n}\n\n/** 服务器 URL 校验:返回错误信息,空串表示通过 */\nexport function validateServerUrl(url) {\n const v = String(url || '').trim()\n if (!v) return '请输入服务器 URL'\n if (!normalizeApiBase(v)) return 'URL 格式不正确,需为 http(s)://IP:端口 形式(如 http://127.0.0.1:8081)'\n return ''\n}\n\n/** 服务器名称校验 */\nexport function validateServerName(name) {\n const v = String(name || '').trim()\n if (!v) return '请输入服务器名称'\n if (v.length > 32) return '服务器名称不能超过 32 字符'\n return ''\n}\n\n/** 获取服务器配置列表 */\nexport function getServers() {\n return servers\n}\n\n/** 获取当前选中的服务器(未选中或已失效时为 null) */\nexport function getActiveServer() {\n if (!activeId) return null\n return servers.find((s) => s.id === activeId) || null\n}\n\n/** 获取当前请求基址(request / session 动态读取;未配置服务器时返回空串,调用方须先拦截提示) */\nexport function getApiBase() {\n const active = getActiveServer()\n return (active && active.api_base) || ''\n}\n\n/**\n * 获取当前知识库 MCP 服务接入点(后端 POST {服务器URL}/kb/mcp/v1,JSON-RPC 2.0)。\n * 当前服务器变化(新增首个服务器自动激活 / 切换 / 编辑 / 删除兜底激活)时随之更新,\n * 经 auth.syncHostMcpAuth() 登记至 DSH 宿主,供智能体注册并调用知识库 MCP Skill;\n * 未配置服务器时返回空串。\n */\nexport function getMcpEndpoint() {\n const apiBase = getApiBase()\n return apiBase ? `${apiBase}${APP_PATH}/mcp/v1` : ''\n}\n\n/** 订阅配置变更(设置页刷新列表用) */\nexport function subscribe(fn) {\n listeners.add(fn)\n return () => listeners.delete(fn)\n}\n\n/**\n * 等待首次云端配置解析完成(启动自动生效用):resolve 后 getApiBase() 即为本轮\n * 加载的最终结果(已配置则基址就绪,未配置/游客态为空串)。\n * 页面首次加载用它避免在配置到达前发起请求,被 request 拦截误报\n * 「请先在设置页配置服务器信息」(浏览器刷新后云配置异步到达的窗口期)\n */\nexport function whenReady() {\n if (firstLoadDone) return Promise.resolve()\n return new Promise((resolve) => firstLoadResolvers.push(resolve))\n}\n\n/**\n * 新增服务器;名称或 URL 非法时返回错误信息(不改状态);无当前服务器时自动激活。\n * 自动激活(新增首个服务器)会经 subscribe 通知 auth 同步宿主:当前服务器即 MCP 接入点,\n * 知识库 MCP 服务器配置随登记流程写入 DSH。\n */\nexport function addServer(name, url) {\n const errMsg = validateServerName(name) || validateServerUrl(url)\n if (errMsg) return errMsg\n const apiBase = normalizeApiBase(url)\n if (servers.some((s) => s.api_base === apiBase)) return '该接口 URL 已存在'\n const id = genId()\n servers = [...servers, { id, name: name.trim(), api_base: apiBase, created_at: Date.now() }]\n if (!getActiveServer()) activeId = id\n emit()\n persist()\n return ''\n}\n\n/** 编辑服务器;id 非法时返回错误信息 */\nexport function updateServer(id, name, url) {\n const errMsg = validateServerName(name) || validateServerUrl(url)\n if (errMsg) return errMsg\n if (!servers.find((s) => s.id === id)) return '服务器不存在或已被删除'\n const apiBase = normalizeApiBase(url)\n if (servers.some((s) => s.id !== id && s.api_base === apiBase)) return '该接口 URL 已存在'\n servers = servers.map((s) => (s.id === id ? { ...s, name: name.trim(), api_base: apiBase } : s))\n emit()\n persist()\n return ''\n}\n\n/** 删除服务器;若删除的是当前服务器则自动激活首个剩余服务器(无则当前无服务器,请求将被拦截) */\nexport function removeServer(id) {\n const list = servers.filter((s) => s.id !== id)\n servers = list\n if (activeId === id) activeId = list.length > 0 ? list[0].id : ''\n emit()\n persist()\n return ''\n}\n\n/** 切换当前服务器 */\nexport function setActiveServer(id) {\n if (activeId === id) return\n activeId = servers.some((s) => s.id === id) ? id : ''\n emit()\n persist()\n}\n","/**\n * 运行时配置\n *\n * - 不内置默认后端地址:请求基址完全由设置页配置(server-config.getApiBase())。\n * 未配置/未选中服务器时 getApiBase() 返回空串,request / session 统一\n * 拦截并提示「请先在设置页配置服务器信息」,不发任何网络请求\n */\n\n/** 请求超时(毫秒);上传/大文档可单独放宽 */\nexport const REQUEST_TIMEOUT = 20000\n","/**\n * 插件会话验签换发/吊销(原生 fetch 直连,不走 request.js 以避免循环依赖)\n *\n * 插件不接触用户中心 Token:\n * - 换发:以用户中心 JS 验签接口(window.SHIKEAI_GET_SIGN_CREDENTIAL)返回的\n * sign + message 调 POST /kb/auth/verify,后端 Ed25519 公钥本地验签\n * (时间戳容差 + 一次性消费防重放)后签发插件自有 token(Redis 会话,非活跃过期)\n * - 吊销:用户中心登出/失效时调 POST /kb/auth/logout,后端删除会话\n * - 响应结构 { code, msg, data },code === 0 判定成功\n */\nimport { REQUEST_TIMEOUT } from './config.js'\nimport { getApiBase, APP_PATH } from './server-config.js'\n\nfunction timeoutController(ms) {\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), ms)\n return { controller, done: () => clearTimeout(timer) }\n}\n\n/**\n * 以用户中心验签数据(sign + message)换发插件自有 token\n * @param {string} sign Ed25519 签名(base64,来自用户中心 JS 验签接口)\n * @param {string} message 被签名明文(uid / 手机号md5 / 秒级时间戳)\n * @returns {Promise<{token: string, uid: number, mobile_md5?: string, expires_in: number}>}\n * @throws {Error} 携带服务端 msg(验签失败/已消费等)\n */\nexport async function exchangePluginToken(sign, message) {\n const apiBase = getApiBase()\n if (!apiBase) throw new Error('请先在设置页配置服务器信息')\n const { controller, done } = timeoutController(REQUEST_TIMEOUT)\n try {\n const res = await fetch(`${apiBase}${APP_PATH}/auth/verify`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ sign, message }),\n signal: controller.signal,\n })\n const body = await res.json().catch(() => null)\n if (body && typeof body === 'object' && body.code === 0 && body.data && body.data.token) return body.data\n const error = new Error((body && body.msg) || `换发插件 token 失败(HTTP ${res.status})`)\n error.code = (body && body.code) || res.status // 透传门禁码(40302 等),调用方据此去重提示\n throw error\n } catch (error) {\n if (error.name === 'AbortError') throw new Error('换发插件 token 超时,请检查网络后重试')\n throw error\n } finally {\n done()\n }\n}\n\n/**\n * 吊销插件 token(用户中心登出/失效回调;幂等,失败静默——后端会话有 TTL 兜底)\n * @param {string} pluginToken 插件自有 token\n */\nexport async function revokePluginToken(pluginToken) {\n if (!pluginToken || !getApiBase()) return\n const { controller, done } = timeoutController(REQUEST_TIMEOUT)\n try {\n await fetch(`${getApiBase()}${APP_PATH}/auth/logout`, {\n method: 'POST',\n headers: { Authorization: `Bearer ${pluginToken}` },\n signal: controller.signal,\n })\n } catch {\n } finally {\n done()\n }\n}\n","/**\n * 轻量状态容器(框架无关,供 React 与 core 层共用)\n *\n * 注意:useStore 的 selector 必须返回稳定引用(state 上的字段或原语),\n * 不要在 selector 中构造新对象,否则 useSyncExternalStore 会死循环。\n */\nimport { useSyncExternalStore } from 'react'\n\nexport function createStore(initialState) {\n let state = initialState\n const listeners = new Set()\n return {\n getState: () => state,\n setState(patch) {\n const next = typeof patch === 'function' ? patch(state) : patch\n state = { ...state, ...next }\n listeners.forEach((listener) => listener())\n },\n subscribe(listener) {\n listeners.add(listener)\n return () => listeners.delete(listener)\n },\n }\n}\n\n/** React 绑定:订阅 store 并按 selector 取快照(第三参为 SSR 服务端快照,与服务端一致) */\nexport function useStore(store, selector = (s) => s) {\n return useSyncExternalStore(store.subscribe, () => selector(store.getState()), () => selector(store.getState()))\n}\n","/**\n * 全局 UI 状态:Toast 提示(错误处理统一出口,禁止静默吞错)\n *\n * 0.8.0 起页面导航改由 DSH 右侧 Sidebar 标签页系统承载\n * (首页 / 知识库详情 / 文档详情 / 设置 各为一个标签页,\n * 经 tab.actions.openTab(kind, { params }) 打开),本 store 不再持有页面路由。\n */\nimport { createStore } from './create-store.js'\n\nconst initialUiState = {\n toasts: [],\n}\n\nexport const uiStore = createStore(initialUiState)\n\nlet toastSeq = 0\n/** 展示中的 toast 索引(key: type|message → {id, timer}):同文案去重,重置时长不叠加 */\nconst activeToasts = new Map()\n\n/** 全局 Toast 提示(错误处理统一出口,禁止静默吞错;同文案在展示中时不重复弹出) */\nexport function toast(message, type = 'info', duration = 2600) {\n const key = `${type}|${message}`\n const exist = activeToasts.get(key)\n if (exist) {\n if (exist.timer) clearTimeout(exist.timer)\n if (duration > 0) exist.timer = setTimeout(() => dismissToast(exist.id), duration)\n return exist.id\n }\n const id = ++toastSeq\n activeToasts.set(key, {\n id,\n timer: duration > 0 ? setTimeout(() => dismissToast(id), duration) : null,\n })\n uiStore.setState((s) => ({\n toasts: [...s.toasts, { id, message, type }],\n }))\n return id\n}\n\nexport function dismissToast(id) {\n for (const [key, t] of activeToasts) {\n if (t.id === id) {\n if (t.timer) clearTimeout(t.timer)\n activeToasts.delete(key)\n }\n }\n uiStore.setState((s) => ({ toasts: s.toasts.filter((t) => t.id !== id) }))\n}\n\n/** 错误 Toast 统一出口(ApiError 透出服务端 msg);\n * 用户状态门禁错误(40301 待审核 / 40302 禁用)同样走 Toast(同文案展示期内自动去重) */\nexport function toastError(error) {\n return toast((error && (error.msg || error.message)) || '操作失败', 'error', 3600)\n}\n","/**\n * 知识库域状态:列表、筛选、统计概览\n * 角色:1 所有者 / 2 编辑者 / 3 只读(与后端 smallint 对齐)\n */\nimport { createStore } from './create-store.js'\n\nexport const ROLE = { ADMIN: 1, EDITOR: 2, READONLY: 3 }\nexport const ROLE_LABEL = { 1: '所有者', 2: '编辑者', 3: '只读', 5: '管理员' }\n\nexport const initialKbState = {\n list: [],\n total: 0,\n page: 1,\n limit: 20,\n keyword: '',\n tagFilter: '',\n loaded: false,\n /** 统计概览(首页):知识库 / 文档 / 向量块统计 */\n stats: null,\n}\n\nexport const kbStore = createStore(initialKbState)\n\nexport function setKbList(list, total, page, limit) {\n kbStore.setState({\n list: list || [],\n total: total || 0,\n page,\n limit,\n loaded: true,\n })\n}\n\nexport function setKbKeyword(keyword) {\n kbStore.setState({ keyword, page: 1 })\n}\n\nexport function setKbTagFilter(tag) {\n kbStore.setState({ tagFilter: tag, page: 1 })\n}\n\nexport function upsertKb(kb) {\n kbStore.setState((s) => {\n const idx = s.list.findIndex((k) => k.id === kb.id)\n if (idx < 0) return { list: [kb, ...s.list] }\n const list = s.list.slice()\n list[idx] = kb\n return { list }\n })\n}\n\nexport function removeKbLocally(kbId) {\n kbStore.setState((s) => ({\n list: s.list.filter((k) => k.id !== kbId),\n total: Math.max(0, s.total - 1),\n }))\n}\n\nexport function setStats(stats) {\n kbStore.setState({ stats })\n}\n","/**\n * 文档域状态:当前知识库文档列表、筛选条件\n * 文档状态:0 待解析 / 1 解析中 / 2 向量化中 / 3 已就绪 / 4 解析失败\n */\nimport { createStore } from './create-store.js'\n\nexport const initialDocState = {\n kbId: null,\n list: [],\n total: 0,\n page: 1,\n limit: 20,\n keyword: '',\n tagFilter: '',\n}\n\nexport const DOC_STATUS_LABEL = {\n 0: '待解析',\n 1: '解析中',\n 2: '向量化中',\n 3: '已就绪',\n 4: '解析失败',\n}\n\nexport const docStore = createStore(initialDocState)\n\nexport function setDocList(kbId, list, total, page, limit) {\n docStore.setState({\n kbId,\n list: list || [],\n total,\n page,\n limit,\n })\n}\n\nexport function setDocKeyword(keyword) {\n docStore.setState({ keyword, page: 1 })\n}\n\nexport function setDocTagFilter(tag) {\n docStore.setState({ tagFilter: tag, page: 1 })\n}\n\nexport function setDocPage(page) {\n docStore.setState({ page })\n}\n\n/** 轮询回填:按文档 id 就地更新状态(不整表刷新,避免闪烁) */\nexport function patchDocStatus(docId, patch) {\n docStore.setState((s) => {\n const idx = s.list.findIndex((d) => d.id === docId)\n if (idx < 0) return null\n const list = s.list.slice()\n list[idx] = { ...list[idx], ...patch }\n return { list }\n })\n}\n","/**\n * 标签页标题注册表(sidebar.right.pane.tab.title 活标题数据源)\n *\n * DSH 右侧 Sidebar 标签页的 chip 文案在打开时由 title(address) 捕获;\n * 知识库详情 / 文档详情标签页打开时往往还不知道名称(只有 id 参数),\n * 因此由页面在数据到达后把 id → 名称写入本 store,标题组件经 useStore\n * 订阅展示实时名称,未知名时回退通用文案。\n */\nimport { createStore } from './create-store.js'\n\nconst titleStore = createStore({\n /** kbId(String) → 知识库名称 */\n kbNames: {},\n /** `${kbId}:${docId}` → 文档名称 */\n docNames: {},\n})\n\nexport function setKbName(kbId, name) {\n if (kbId == null || !name) return\n titleStore.setState((s) => {\n const key = String(kbId)\n if (s.kbNames[key] === name) return null\n return { kbNames: { ...s.kbNames, [key]: name } }\n })\n}\n\nexport function setDocName(kbId, docId, name) {\n if (kbId == null || docId == null || !name) return\n titleStore.setState((s) => {\n const key = `${kbId}:${docId}`\n if (s.docNames[key] === name) return null\n return { docNames: { ...s.docNames, [key]: name } }\n })\n}\n\nexport function getKbName(kbId) {\n if (kbId == null) return ''\n return titleStore.getState().kbNames[String(kbId)] || ''\n}\n\nexport function getDocName(kbId, docId) {\n if (kbId == null || docId == null) return ''\n return titleStore.getState().docNames[`${kbId}:${docId}`] || ''\n}\n\nexport function clearNames() {\n titleStore.setState({ kbNames: {}, docNames: {} })\n}\n\nexport { titleStore }\n","/**\n * 登出/失效/切换服务器统一复位(core/auth 调用,避免 store ↔ auth 循环依赖)\n */\nimport { uiStore } from './ui-store.js'\nimport { kbStore, initialKbState } from './kb-store.js'\nimport { docStore, initialDocState } from './doc-store.js'\nimport { clearNames } from './title-store.js'\n\n/** 清空本地状态并禁用全部操作(登录态只读复用,本地不存登录数据) */\nexport function resetAllStores() {\n uiStore.setState({ toasts: [] })\n kbStore.setState(initialKbState)\n docStore.setState(initialDocState)\n clearNames()\n}\n\n/**\n * 切换后端服务器后复位业务数据(Toast 保留,清空上一服务器的\n * 知识库列表、文档、统计概览与标签页名称缓存),各标签页重新拉取\n */\nexport function resetServerScopedStores() {\n kbStore.setState(initialKbState)\n docStore.setState(initialDocState)\n clearNames()\n}\n","/**\n * 登录态桥接(用户中心验签换发,插件不接触用户中心 Token)+ 插件会话管理\n *\n * - 登录态按需获取:仅请求需要登录态的后端接口时,调用用户中心 JS 验签接口\n * window.SHIKEAI_GET_SIGN_CREDENTIAL() 获取 sign + message(游客态返回 null),\n * 经 POST /kb/auth/verify 换取插件自有 Token;有效期内复用,不重复验签\n * - Token 持久化:localStorage skai_kb_token / skai_kb_uid,跨会话复用;\n * REST 与 MCP(Authorization: Bearer)同源携带\n * - 公开用户信息只读 window.SHIKEAI_USER_INFO(脱敏手机号、昵称、头像),仅用于展示\n * - 监听 shikeai-usercenter:login / logout / expired / user-update 四类事件同步登录态:\n * 登录重置本地 Token 待下次请求重新验签;登出/失效吊销后端会话并清空本地状态与业务缓存\n * - 事件错过兜底:初始化时校验 SHIKEAI_USER_INFO,游客态或账号与本地缓存不一致\n * 时按退出登录处理(切换账号防跨账号数据残留)\n * - 宿主同步:将当前后端服务器对应的 MCP 服务器配置(MCP 接入点 {服务器URL}/kb/mcp/v1、\n * 最新插件 Token)经 settings.mutate 写入 Host 半区注册的 knowledge\n * namespace(Host 半区 scope.watch 后自动销毁旧连接、重建 MCP 并重新注册\n * 工具);登录态页面加载即自动换发 Token 并同步(DSH 启动\n * 后 MCP 配置自动就绪),设置页新增首个服务器自动激活 / 切换 / 编辑 / 删除\n * 兜底激活时同步更新\n */\nimport { getActiveServer, getApiBase, getMcpEndpoint, subscribe } from './server-config.js'\nimport { exchangePluginToken, revokePluginToken } from './session.js'\nimport { describeHostMcpStatus, pushHostMcpConfig } from './host-mcp-sync.js'\nimport { resetAllStores } from '../store/reset.js'\n\n/** 插件自有 Token 持久化键(规范约定:skai_ 平台命名空间 + kb 业务域) */\nconst LS_TOKEN = 'skai_kb_token'\n/** Token 配套 uid(账号一致性兜底检测用) */\nconst LS_UID = 'skai_kb_uid'\n/** 旧版存储键(0.2.x 命名规范遗留),仅用于一次性迁移读取 */\nconst LEGACY_LS_TOKEN = 'skb_kb_token'\nconst LEGACY_LS_UID = 'skb_kb_uid'\n\nlet initialized = false\nlet disposed = false\n/** 插件自有 Token(内存缓存,懒恢复自 localStorage) */\nlet pluginToken = ''\n/** Token 配套 uid(0 = 未知) */\nlet cachedUid = 0\n/** 最近一次成功换发的 uid(跨清空保留,用于切换账号检测) */\nlet lastUid = 0\nlet hydrated = false\nlet exchangeInflight = null\nlet offServerConfig = null\n/** 已同步宿主的基址(变更即失效本地 Token:Token 与后端服务器绑定) */\nlet syncedApiBase = ''\n\nfunction hydrateOnce() {\n if (hydrated || typeof window === 'undefined') return\n hydrated = true\n try {\n if (!window.localStorage.getItem(LS_TOKEN) && window.localStorage.getItem(LEGACY_LS_TOKEN)) {\n window.localStorage.setItem(LS_TOKEN, window.localStorage.getItem(LEGACY_LS_TOKEN))\n if (window.localStorage.getItem(LEGACY_LS_UID)) {\n window.localStorage.setItem(LS_UID, window.localStorage.getItem(LEGACY_LS_UID))\n }\n window.localStorage.removeItem(LEGACY_LS_TOKEN)\n window.localStorage.removeItem(LEGACY_LS_UID)\n }\n pluginToken = window.localStorage.getItem(LS_TOKEN) || ''\n cachedUid = Number(window.localStorage.getItem(LS_UID)) || 0\n if (cachedUid) lastUid = cachedUid\n } catch {}\n}\n\nfunction persistLocalAuth(token, uid) {\n try {\n window.localStorage.setItem(LS_TOKEN, token)\n if (uid) window.localStorage.setItem(LS_UID, String(uid))\n } catch {}\n}\n\nfunction clearLocalAuth() {\n pluginToken = ''\n cachedUid = 0\n try {\n window.localStorage.removeItem(LS_TOKEN)\n window.localStorage.removeItem(LS_UID)\n } catch {}\n}\n\n/** 读取插件自有 Token(REST/MCP 鉴权头取值源;未换发时为空串) */\nexport function getPluginToken() {\n hydrateOnce()\n return pluginToken\n}\n\n/** 读取全局公开用户信息(只读,仅用于展示,不作为可信身份) */\nexport function getUserInfo() {\n if (typeof window === 'undefined') return null\n return window.SHIKEAI_USER_INFO || null\n}\n\n/** 是否已登录(用户中心已登录或本地仍持有有效插件 Token) */\nexport function isLoggedIn() {\n return Boolean(getPluginToken() || getUserInfo())\n}\n\n/** 调用用户中心 JS 验签接口(用户中心为唯一权威提供方);未挂载或游客态返回 null */\nasync function fetchSignCredential() {\n if (typeof window === 'undefined' || typeof window.SHIKEAI_GET_SIGN_CREDENTIAL !== 'function') return null\n try {\n return await window.SHIKEAI_GET_SIGN_CREDENTIAL()\n } catch {\n return null\n }\n}\n\n/**\n * 确保插件 Token 可用:已持有则直接返回;否则按需验签换发(并发请求去重)。\n * @returns {Promise<string>} 插件自有 Token\n * @throws {Error} 游客态(验签接口返回空)抛「请先在用户中心登录」;换发失败携带服务端 msg\n */\nexport function ensurePluginToken() {\n hydrateOnce()\n if (pluginToken) return Promise.resolve(pluginToken)\n if (!exchangeInflight) {\n exchangeInflight = (async () => {\n const cred = await fetchSignCredential()\n if (!cred || !cred.sign || !cred.message) {\n clearLocalAuth()\n resetAllStores()\n syncHostMcpAuth()\n notifyAuthChange('guest')\n const error = new Error('请先在用户中心登录')\n error.guest = true\n throw error\n }\n const data = await exchangePluginToken(cred.sign, cred.message)\n const uid = Number(data.uid) || 0\n if (lastUid && uid && lastUid !== uid) resetAllStores()\n if (uid) lastUid = uid\n pluginToken = data.token\n cachedUid = uid\n persistLocalAuth(pluginToken, uid)\n syncHostMcpAuth()\n return pluginToken\n })().finally(() => {\n exchangeInflight = null\n })\n }\n return exchangeInflight\n}\n\n/** 本地失效插件 Token(不清业务缓存;401 静默重验签前调用,下次请求重新换发) */\nexport function invalidatePluginToken() {\n pluginToken = ''\n cachedUid = 0\n exchangeInflight = null\n try {\n window.localStorage.removeItem(LS_TOKEN)\n window.localStorage.removeItem(LS_UID)\n } catch {}\n}\n\n/**\n * 将当前后端服务器对应的「知识库 MCP 服务器配置」同步至 DSH 宿主(settings 活配置\n * 通道,见 core/host-mcp-sync):经 mutate 把 {url, token} 写入 Host 半区注册的\n * knowledge namespace,由 dsh-settings-file provider 持久化到 ~/.dsh/settings.yaml\n * (重启不丢);Host 半区 scope.watch 值变化后自动销毁旧 MCP 连接、重建并重新注册\n * 工具(Token 换发 / 刷新后随 mutate 同步更新)。\n * 同步时机:页面加载(登录态且已配置当前服务器:云端配置到达即自动验签换发并\n * 同步,无需手动操作)、首次验签换发、401 重验签刷新、登录/退出/失效,以及当前\n * 服务器变化(设置页新增首个服务器自动激活、切换、编辑当前服务器地址、删除后\n * 兜底激活)。\n */\nexport function syncHostMcpAuth() {\n if (typeof window === 'undefined') return\n const active = getActiveServer()\n pushHostMcpConfig(\n Object.freeze({\n api_base: getApiBase(),\n mcp_endpoint: getMcpEndpoint(),\n server_name: active ? active.name : '',\n token: getPluginToken(),\n updated_at: Date.now(),\n }),\n )\n}\n\n/**\n * 页面加载/刷新自检:知识库 MCP 是否已在宿主配置就绪;未就绪时自动修复。\n * 链路:服务器已配置 + 已登录 → 确保插件 Token(换发成功即随链路推送宿主)→\n * 读取宿主 knowledge namespace 与期望值(当前接入点 + 插件 Token)比对,\n * 不一致(服务器切换/Token 换发后未同步)则重推一次;结构性问题\n * (namespace 未注册/settings 不可用)返回原因供页面可见化展示。\n * @returns {Promise<{status: string, detail: string}>}\n * ok | mismatch-fixed(已重推修复)| no-endpoint | no-token\n * | no-ctx | no-settings | no-namespace(后三者 detail 含可展示原因)\n */\nexport async function checkHostMcpReady() {\n if (typeof window === 'undefined') return { status: 'no-host', detail: '' }\n if (!getMcpEndpoint()) {\n return { status: 'no-endpoint', detail: '尚未配置知识库服务器(设置页配置后自动同步 MCP)' }\n }\n hydrateOnce()\n if (!pluginToken) {\n try {\n await ensurePluginToken()\n } catch (error) {\n return {\n status: 'no-token',\n detail: error && error.guest ? '请先在用户中心登录' : (error && error.message) || '插件 Token 换发失败',\n }\n }\n }\n const state = await describeHostMcpStatus()\n if (state.status === 'registered') {\n if (state.url === getMcpEndpoint() && state.hasToken) {\n return { status: 'ok', detail: '' }\n }\n // 值与期望不一致(namespace 刚由 client 自动注册为空值 / 服务器切换 /\n // Token 换发后未同步到宿主)→ 重推修复,推送链路完成后复核一次\n syncHostMcpAuth()\n for (let i = 0; i < 5; i++) {\n await new Promise((resolve) => setTimeout(resolve, 150))\n const after = await describeHostMcpStatus()\n if (after.status === 'registered' && after.url === getMcpEndpoint() && after.hasToken) {\n return { status: 'ok', detail: '' }\n }\n }\n return { status: 'mismatch-fixed', detail: '宿主 MCP 配置与当前服务器/登录态不一致,已重新同步(若反复出现请查看浏览器控制台 [knowledge] 日志)' }\n }\n return { status: state.status, detail: state.detail }\n}\n\n/** 账号切换统一处理:吊销旧会话 + 清本地态与业务缓存 + 清宿主残留 → 以新登录用户立即重验签换发并同步宿主 */\nfunction resyncForAccountSwitch() {\n const token = pluginToken\n clearLocalAuth()\n resetAllStores()\n syncHostMcpAuth()\n if (token) revokePluginToken(token)\n // 立即以新用户换发(用户中心事件派发时新会话已就绪):成功路径自动把新 Token 同步\n // 宿主 MCP,不留空窗、不等首个业务请求;失败(用户中心竞态/游客)保持空宿主配置,\n // 业务请求 401 时再兜底重验签\n ensurePluginToken().catch(() => {})\n notifyAuthChange('login')\n}\n\n/** 退出/失效统一处理:吊销后端会话(幂等)→ 清空本地登录态与业务缓存 → 同步宿主 */\nfunction handleExit(reason) {\n const token = pluginToken\n clearLocalAuth()\n resetAllStores()\n syncHostMcpAuth()\n revokePluginToken(token)\n notifyAuthChange(reason)\n}\n\n/** 用户中心 login 事件(含切换账号):按换号重同步(旧 Token 吊销 + 新用户立即换发) */\nfunction onLogin() {\n resyncForAccountSwitch()\n}\n\n/**\n * 用户资料更新(昵称/头像):只读同步广播刷新展示;\n * uid 变化(切换账号的用户中心实现可能仅派发 user-update 而非 logout+login)\n * 按换号重同步,否则插件 Token 与宿主 MCP 仍是旧用户身份(越权身份错位)\n */\nfunction onUserUpdate() {\n hydrateOnce()\n const info = getUserInfo()\n const uid = Number(info && (info.uid ?? info.member_id ?? info.memberId)) || 0\n if (lastUid && uid && lastUid !== uid) {\n resyncForAccountSwitch()\n return\n }\n notifyAuthChange('user-update')\n}\n\n/**\n * 初始化兜底:抽屉未打开期间可能错过全局事件——每次初始化校验\n * window.SHIKEAI_USER_INFO,游客态或账号与本地缓存不一致时按退出登录处理\n */\nfunction reconcileAuthState() {\n hydrateOnce()\n const info = getUserInfo()\n if (!info) {\n if (pluginToken) handleExit('logout')\n return\n }\n const currentUid = Number(info.uid ?? info.member_id ?? info.memberId) || 0\n if (pluginToken && cachedUid && currentUid && cachedUid !== currentUid) resyncForAccountSwitch()\n}\n\n/** 登录态变化广播(供 hooks 订阅刷新) */\nconst authListeners = new Set()\nexport function onAuthChange(listener) {\n authListeners.add(listener)\n return () => authListeners.delete(listener)\n}\n\nfunction notifyAuthChange(reason) {\n authListeners.forEach((fn) => {\n try {\n fn(reason)\n } catch {}\n })\n}\n\n/** 安装登录态事件监听(幂等;DSH client 与 standalone 路径共用) */\nexport function initAuth() {\n if (initialized || typeof window === 'undefined') return\n initialized = true\n disposed = false\n window.addEventListener('shikeai-usercenter:login', onLogin)\n window.addEventListener('shikeai-usercenter:logout', onLogoutHandler)\n window.addEventListener('shikeai-usercenter:expired', onExpiredHandler)\n window.addEventListener('shikeai-usercenter:user-update', onUserUpdate)\n syncedApiBase = getApiBase()\n offServerConfig = subscribe(() => {\n const apiBase = getApiBase()\n if (apiBase !== syncedApiBase) {\n // 仅当此前已有生效基址(内存态非空)才是真实的服务器切换——Token 与后端绑定\n // 须失效重验签;启动时云端配置首拉('' → X)属「采纳」:保留持久化 Token\n // (仍与该服务器绑定),避免误清后与用户中心静默恢复会话竞态时清空宿主配置\n const switched = Boolean(syncedApiBase)\n syncedApiBase = apiBase\n if (switched) invalidatePluginToken()\n syncHostMcpAuth()\n notifyAuthChange('server-switch')\n }\n // 启动自动生效:云端服务器配置到达(或用户中心静默恢复会话后重拉成功)即确保\n // 插件 Token 可用(过期自动重验签换发)并同步宿主 MCP 配置——DSH 启动后无需\n // 打开插件页面,已配置的知识库服务器与 MCP 检索即自动就绪\n if (getUserInfo() && getMcpEndpoint()) ensurePluginToken().catch(() => {})\n })\n reconcileAuthState()\n syncHostMcpAuth()\n}\n\n/** 卸载监听(client 半区 dispose / standalone deactivate 时调用) */\nexport function disposeAuth() {\n if (!initialized || disposed) return\n disposed = true\n window.removeEventListener('shikeai-usercenter:login', onLogin)\n window.removeEventListener('shikeai-usercenter:logout', onLogoutHandler)\n window.removeEventListener('shikeai-usercenter:expired', onExpiredHandler)\n window.removeEventListener('shikeai-usercenter:user-update', onUserUpdate)\n if (typeof offServerConfig === 'function') offServerConfig()\n offServerConfig = null\n initialized = false\n}\n\nfunction onLogoutHandler() {\n handleExit('logout')\n}\n\nfunction onExpiredHandler() {\n handleExit('expired')\n}\n","/**\n * REST 请求适配器(插件前端唯一出口,页面禁止直接 fetch / axios)\n *\n * - 请求前经 ensurePluginToken() 按需验签确保插件自有 Token(用户中心 sign+message\n * 换发),携带 Authorization: Bearer <插件 Token>\n * - 不内置默认地址:未配置服务器(getApiBase() 为空串)时直接抛\n * 「请先在设置页配置服务器信息」,不发任何网络请求\n * - 401 兜底:静默清除本地 Token → 重新验签换取新 Token → 重放原请求(仅一次);\n * 重验签仍失败(游客态/验签失效)时抛 401 由调用方引导登录\n * - 响应结构 { code, msg, data },code === 0 判定成功,返回 data\n * - 错误统一抛 ApiError(透出服务端 msg)\n */\nimport { getApiBase, APP_PATH } from './server-config.js'\nimport { REQUEST_TIMEOUT } from './config.js'\nimport { getPluginToken, isLoggedIn, ensurePluginToken, invalidatePluginToken } from './auth.js'\n\n/** 业务错误(携带 code 与服务端 msg,调用方统一以 error.msg 读取提示) */\nexport class ApiError extends Error {\n constructor(message, code = 0, data = null) {\n super(message)\n this.name = 'ApiError'\n this.code = code\n this.data = data\n this.msg = message\n }\n}\n\n/** 用户状态门禁专用错误码(后端 pkg/response 对应;管理员豁免,由服务端判定,\n * 前端经 toastError 以服务端 msg 提示) */\nexport const USER_STATUS_CODE = {\n PENDING: 40301,\n DISABLED: 40302,\n}\n\n/** 门禁命中后清空本地业务缓存(知识库列表/文档/目录树等):\n * DSH 标签页常驻不刷新,禁用后 store 旧快照会继续渲染首页数据,\n * 收到 40301/40302 时即时清空,各标签页随后的重新拉取仍会被门禁拦截(保持空态)。\n * 动态 import 避免 store ↔ core 循环依赖;重复调用幂等(setState 同一常量引用) */\nasync function resetBusinessStoresOnGate() {\n try {\n const { resetServerScopedStores } = await import('../store/reset.js')\n resetServerScopedStores()\n } catch {\n /* 清理失败不影响错误透出 */\n }\n}\n\nfunction withQuery(url, data) {\n const params = new URLSearchParams()\n Object.entries(data || {}).forEach(([key, value]) => {\n if (value !== undefined && value !== null) params.append(key, value)\n })\n const query = params.toString()\n return query ? `${url}?${query}` : url\n}\n\nfunction buildHeaders(hasBody) {\n const headers = {}\n const token = getPluginToken()\n if (token) headers.Authorization = `Bearer ${token}`\n if (hasBody && !(typeof FormData !== 'undefined' && hasBody instanceof FormData)) {\n headers['Content-Type'] = 'application/json'\n }\n return headers\n}\n\nasync function parseResponse(res) {\n let body = null\n try {\n body = await res.json()\n } catch {\n body = null\n }\n if (body && typeof body === 'object' && 'code' in body) {\n if (body.code === 0) return body.data\n if (body.code === USER_STATUS_CODE.PENDING || body.code === USER_STATUS_CODE.DISABLED) {\n void resetBusinessStoresOnGate()\n }\n throw new ApiError(body.msg || '请求失败', body.code, body.data)\n }\n if (res.status === 401) throw new ApiError('未登录或登录已失效', 401, null)\n throw new ApiError(`请求异常(HTTP ${res.status})`, res.status, null)\n}\n\nasync function doRequest(method, url, data = {}, options = {}, retried = false) {\n const apiBase = getApiBase()\n if (!apiBase) throw new ApiError('请先在设置页配置服务器信息', 0, null)\n if (!options.allowAnonymous) {\n if (!isLoggedIn()) throw new ApiError('请先在用户中心登录', 401, null)\n try {\n await ensurePluginToken()\n } catch (error) {\n throw error instanceof ApiError\n ? error\n : new ApiError(error.message || '登录状态校验失败', error.code || 401, null) // 保留门禁码(40301/40302)\n }\n }\n // 应用路径固定 /kb(服务器 URL 仅含协议+IP/端口,由前端统一拼装)\n let fullUrl = apiBase + APP_PATH + String(url)\n if (method === 'GET' || method === 'HEAD') fullUrl = withQuery(fullUrl, data)\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), options.timeout || REQUEST_TIMEOUT)\n try {\n return await parseResponse(\n await fetch(fullUrl, {\n method,\n headers: buildHeaders(options.body),\n body: options.body != null && method !== 'GET' && method !== 'HEAD' ? options.body : undefined,\n signal: controller.signal,\n }),\n )\n } catch (error) {\n if (error instanceof ApiError && error.code === 401) {\n if (!retried && !options.allowAnonymous) {\n invalidatePluginToken()\n try {\n await ensurePluginToken()\n return await doRequest(method, url, data, options, true)\n } catch {\n throw new ApiError('请先在用户中心登录', 401, null)\n }\n }\n throw error\n }\n if (error && error.name === 'AbortError') throw new ApiError('请求超时,请检查网络后重试', 0, null)\n // 业务错误(服务端已返回 {code, msg})原样透出,保留服务端 msg 供页面提示\n if (error instanceof ApiError) throw error\n throw new ApiError('网络连接失败,请检查内网后重试', 0, null)\n } finally {\n clearTimeout(timer)\n }\n}\n\n/** JSON 请求体封装 */\nfunction jsonBody(data) {\n return JSON.stringify(data || {})\n}\n\n/** 文件上传(multipart/form-data;extra 附加字段一并以 form 提交) */\nasync function upload(url, file, extra = {}, options = {}) {\n const form = new FormData()\n form.append('file', file, file.name || 'file')\n Object.entries(extra).forEach(([key, value]) => {\n if (value !== undefined && value !== null) form.append(key, value)\n })\n return doRequest('POST', url, {}, { ...options, body: form })\n}\n\nconst request = {\n get: (url, data, options) => doRequest('GET', url, data, options),\n post: (url, data, options) => doRequest('POST', url, {}, { ...options, body: jsonBody(data) }),\n put: (url, data, options) => doRequest('PUT', url, {}, { ...options, body: jsonBody(data) }),\n delete: (url, data, options) => doRequest('DELETE', url, {}, { ...options, body: data ? jsonBody(data) : null }),\n upload,\n}\n\nexport default request\n","/**\n * 知识库管理 REST(对应后端 /kb/kb/*)\n */\nimport request from '../core/request.js'\n\n/** 知识库列表(当前 uid 有权限的 + 公开的,置顶优先;keyword/tag 过滤 + 分页) */\nexport function listKb(params = {}) {\n return request.get('/kb/list', {\n keyword: params.keyword || '',\n tag: params.tag || '',\n page: params.page || 1,\n limit: params.limit || 20,\n })\n}\n\n/** 创建知识库:{ name, description, tags, enable_mcp, chunk_size, chunk_overlap } */\nexport function createKb(data) {\n return request.post('/kb/create', data)\n}\n\n/** 编辑知识库(含 MCP 检索开关、分段默认配置;所有者) */\nexport function updateKb(kbId, data) {\n return request.put(`/kb/${kbId}/update`, data)\n}\n\n/** 归档知识库(软删除;所有者) */\nexport function archiveKb(kbId) {\n return request.delete(`/kb/${kbId}/archive`)\n}\n\n/** 置顶 / 取消置顶知识库(管理员):{ pinned: boolean } */\nexport function pinKb(kbId, pinned) {\n return request.post(`/kb/${kbId}/pin`, { pinned: Boolean(pinned) })\n}\n\n/** 成员权限列表(所有者) */\nexport function listPermission(kbId) {\n return request.get(`/kb/${kbId}/permission`)\n}\n\n/**\n * 添加成员 / 修改角色:{ mobile?, uid, role }(所有者)。\n * 传 mobile 时按手机号添加:目标未登录过则落待激活授权,返回 { pending: boolean }\n */\nexport function grantPermission(kbId, data) {\n return request.post(`/kb/${kbId}/grant`, data)\n}\n\n/** 撤销待激活授权(所有者;pid=待激活记录 ID) */\nexport function revokePendingPermission(kbId, pid) {\n return request.delete(`/kb/${kbId}/pending/${pid}`)\n}\n\n/** 移除成员:{ uid }(所有者) */\nexport function revokePermission(kbId, uid) {\n return request.delete(`/kb/${kbId}/grant`, { uid })\n}\n","/**\n * 文档管理 REST(对应后端 /kb/kb/:id/doc/*)\n */\nimport request from '../core/request.js'\n\n/**\n * 上传文档(单文件,multipart)\n * @param {object} p { kbId, file, tags?, chunkSize?, chunkOverlap?, folderId? }\n */\nexport function uploadDoc({ kbId, file, tags, chunkSize, chunkOverlap, folderId }) {\n return request.upload(`/kb/${kbId}/doc/upload`, file, {\n tags: tags && tags.length ? JSON.stringify(tags) : '',\n chunk_size: chunkSize || '',\n chunk_overlap: chunkOverlap || '',\n folder_id: folderId || 0,\n })\n}\n\n/**\n * 文档列表(keyword 名称+文本检索、tag 过滤、folder_id 目录过滤、分页)\n * @param {number} [params.folderId] 缺省=全库;0=根目录;>0=指定目录\n * @param {boolean} [params.recursive] true=目录过滤展开为该目录及全部后代目录\n */\nexport function listDocs(kbId, params = {}) {\n return request.get(`/kb/${kbId}/doc/list`, {\n keyword: params.keyword || '',\n tag: params.tag || '',\n folder_id: params.folderId ?? '',\n recursive: params.recursive ? 1 : '',\n page: params.page || 1,\n limit: params.limit || 20,\n })\n}\n\n/** 文档元数据详情(GET /kb/:id/doc/:id) */\nexport function getDoc(kbId, docId) {\n return request.get(`/kb/${kbId}/doc/${docId}`)\n}\n\n/** 文档当前文本内容(在线预览;?version_no 可选历史版本) */\nexport function getDocContent(kbId, docId, versionNo) {\n return request.get(`/kb/${kbId}/doc/${docId}/content`, versionNo ? { version_no: versionNo } : {})\n}\n\n/** 历史版本列表 */\nexport function listDocVersions(kbId, docId) {\n return request.get(`/kb/${kbId}/doc/${docId}/versions`)\n}\n\n/** 回滚至历史版本(自动触发重新向量化) */\nexport function rollbackDoc(kbId, docId, versionNo) {\n return request.post(`/kb/${kbId}/doc/${docId}/rollback`, { version_no: versionNo })\n}\n\n/** 修改文档(重命名 / 标签 / 分段覆盖配置) */\nexport function updateDoc(kbId, docId, data) {\n return request.put(`/kb/${kbId}/doc/${docId}`, data)\n}\n\n/** 删除文档(软删) */\nexport function deleteDoc(kbId, docId) {\n return request.delete(`/kb/${kbId}/doc/${docId}`)\n}\n\n/** 失败文档重新解析(编辑者) */\nexport function reparseDoc(kbId, docId) {\n return request.post(`/kb/${kbId}/doc/${docId}/reparse`)\n}\n\n/** 移动文档到目标目录(folderId 0=根目录) */\nexport function moveDoc(kbId, docId, folderId) {\n return request.post(`/kb/${kbId}/doc/${docId}/move`, { folder_id: folderId || 0 })\n}\n\n/** 目录内文档拖拽排序(folderId + 有序 doc_id 数组整批提交) */\nexport function reorderDocs(kbId, folderId, docIds) {\n return request.post(`/kb/${kbId}/doc/reorder`, { folder_id: folderId || 0, doc_ids: docIds })\n}\n\n/**\n * 保存在线编辑内容(文本类文件;保存版本快照并触发重新解析/向量化)\n * @param {object} p { content, baseUpdatedAt, force? } baseUpdatedAt 为进入编辑时的 updated_at;\n * 冲突(HTTP 409)时由页面引导放弃/覆盖,覆盖传 force=true\n */\nexport function updateDocContent(kbId, docId, { content, baseUpdatedAt, force }) {\n return request.put(`/kb/${kbId}/doc/${docId}/content`, {\n content,\n base_updated_at: baseUpdatedAt || 0,\n force: !!force,\n })\n}\n","/**\n * DSH 输入框 `@` 触发源注册:`ctx.inputTriggers.registerSource(src)`(公开契约,\n * dsh-client-ui-input-trigger InputTriggerServiceContract)\n *\n * 用户在会话输入框敲 `@知识库` → 候选菜单列出全部知识库文档 → 选中后经\n * onPick 返回 { insert: ReferenceInsert },由宿主 pipeline 插入**不可编辑的\n * reference chip**(与 @file 引用同款块)。chip 发送时宿主逐个调用\n * serialize(ref) 序列化为模型文本(kb_id/doc_id 结构化标记),失败会阻断发送,\n * 保证语义不降级为纯文本。\n *\n * 生命周期:apply 注册 → 返回 disposer 由 client-entry 的 ctx.effect 撤销。\n */\nimport { listKb } from '../api/kb.js'\nimport { listDocs } from '../api/doc.js'\n\n/** 文档候选缓存(全部库 × 文档列表,30s TTL,避免每次敲 @ 都打 REST) */\nlet cache = null\nlet cacheAt = 0\nconst CACHE_TTL = 30 * 1000\n\n/** 触发源唯一 group 名(per-trigger 唯一,重复注册宿主会 throw) */\nexport const KB_TRIGGER_NAME = '知识库'\n\nasync function loadDocs() {\n if (cache && Date.now() - cacheAt < CACHE_TTL) return cache\n const kbRes = await listKb({ page: 1, limit: 100 })\n const kbs = (kbRes && kbRes.list) || []\n const pages = await Promise.all(\n kbs.map((kb) =>\n listDocs(kb.id, { page: 1, limit: 100 })\n .then((res) => ({ kb, docs: (res && res.list) || [] }))\n .catch(() => ({ kb, docs: [] })),\n ),\n )\n cache = pages.flatMap(({ kb, docs }) =>\n docs.map((d) => ({ kbId: Number(kb.id), kbName: kb.name, docId: Number(d.id), docName: d.name })),\n )\n cacheAt = Date.now()\n return cache\n}\n\n/** ref 编解码(source-owned opaque payload;JSON 数组 [kbId, docId, docName]) */\nexport function encodeRef(item) {\n return JSON.stringify([item.kbId, item.docId, item.docName])\n}\n\nfunction decodeRef(ref) {\n try {\n const [kbId, docId, docName] = JSON.parse(ref)\n return { kbId, docId, docName }\n } catch {\n return null\n }\n}\n\n/**\n * 引用整串 token:`文档名(kb_id:N,doc_id:M)`。lexicon 条目、serialize 输出(去 @)、\n * chip label 三者逐字一致且内部无空格——无论气泡走文本匹配还是 label 渲染,\n * 名称与 id 都整体进 chip,不产生游离括号文本\n */\nexport function refToken(item) {\n return `${item.docName}(kb_id:${item.kbId},doc_id:${item.docId})`\n}\n\n/** 剪贴板投影:`知识库文档:文档名(kb_id: N, doc_id: M)`(onPick 与 codec.clipboardText 共用) */\nfunction refClipboardText(item) {\n return `知识库文档:${item.docName}(kb_id: ${item.kbId}, doc_id: ${item.docId})`\n}\n\n/**\n * serialize 输出形式:`@文档名 (kb_id: N, doc_id: M)`。发送后消息文本经\n * lexicon 精确匹配装饰成 chip(@文件 同款);其后括号补 kb_id/doc_id 结构化标记,\n * 供 AI 解析调 MCP 工具与「存入知识库」覆盖模式默认选中。\n * 程序化插芯片(DocDetailPage 引用按钮)的占位文本同用此形式——芯片插入\n * 失败时退化为纯文本仍可被 lexicon 装饰、可被 AI 解析\n */\nexport function refSerializeText(item) {\n return `@${item.docName} (kb_id: ${item.kbId}, doc_id: ${item.docId})`\n}\n\n/**\n * 构造与 `@知识库` onPick 插入完全同构的 ReferenceInsert(供文档详情页\n * 「引用文档到会话」经 SessionInput facade.insertReference 程序化插入芯片)\n */\nexport function buildDocReferenceInsert(item) {\n return {\n source: KB_TRIGGER_NAME,\n ref: encodeRef(item),\n // chip 显示文本 = label,整串含 id\n label: refToken(item),\n appearance: 'file',\n clipboardText: refClipboardText(item),\n }\n}\n\n/**\n * 注册 `@知识库` 触发源。重复注册(宿主 duplicate throw)安全降级为 no-op。\n * @param {object} ctx client 半区 ctx(需可解出 inputTriggers 服务)\n * @returns {() => void} disposer(撤销注册;不可用时为 no-op)\n */\nexport function registerKbTriggerSource(ctx) {\n const svc = ctx && ctx.inputTriggers\n if (!svc || typeof svc.registerSource !== 'function') return () => {}\n try {\n const disposer = svc.registerSource({\n trigger: '@',\n name: KB_TRIGGER_NAME,\n order: 30,\n async candidates(_session, req) {\n const query = String((req && req.query) || '').trim().toLowerCase()\n const docs = await loadDocs()\n const hit = query\n ? docs.filter((d) => d.docName.toLowerCase().includes(query) || d.kbName.toLowerCase().includes(query))\n : docs\n return hit.slice(0, 30).map((d) => ({\n name: d.docName,\n description: `知识库:${d.kbName}`,\n section: d.kbName,\n value: encodeRef(d),\n }))\n },\n onPick(pick) {\n const value = pick && pick.candidate && typeof pick.candidate.value === 'string' ? pick.candidate.value : ''\n const item = decodeRef(value)\n if (!item) return 'handled'\n return { insert: buildDocReferenceInsert(item) }\n },\n /**\n * scope-birth 预热:拉全量文档填缓存,让 lexicon 尽早就绪\n * (发送后的消息文本要靠 lexicon 装饰回 chip 样式)\n */\n warm() {\n loadDocs().catch(() => {})\n },\n /**\n * plain-text reference decoration(同步热快照,禁止 fetch):\n * 渲染侧扫描消息文本中的 `@<name>` token,精确匹配 lexicon 即装饰成 chip\n * (与 @文件 发送后样式同机制)。undefined = 未热,不装饰\n */\n lexicon() {\n return cache ? cache.map((d) => d.docName) : undefined\n },\n /**\n * Reference codec(必须挂 codec 字段——发送时宿主经 roster 找 owner.codec.serialize,\n * 缺失报 \"slash: no serializer for reference source\"):\n * serialize 必须输出 `@<文档名>` token——发送后的消息文本经 lexicon\n * 精确匹配装饰成 chip(@文件 同款);其后括号补 kb_id/doc_id 结构化标记,\n * 供 AI 解析调 MCP 工具与「存入知识库」覆盖模式默认选中\n */\n codec: {\n clipboardText(ref) {\n const item = decodeRef(ref)\n return item ? refClipboardText(item) : '知识库文档(引用已失效)'\n },\n async serialize(ref) {\n const item = decodeRef(ref)\n if (!item) throw new Error('知识库引用已失效,请删除该引用后重试')\n return refSerializeText(item)\n },\n },\n })\n return typeof disposer === 'function' ? disposer : () => {}\n } catch (e) {\n // duplicate (trigger,name):多半是热重载后残留注册,忽略即可\n console.warn('[kb-trigger] 注册 @知识库 触发源失败(可能已注册):', e && e.message)\n return () => {}\n }\n}\n","/**\n * 任务查询 REST(对应后端 /kb/task/*;重建向量为所有者操作)\n */\nimport request from '../core/request.js'\n\n/** 重建知识库全量向量(所有者) */\nexport function rebuildVector(kbId) {\n return request.post(`/kb/${kbId}/rebuild-vector`)\n}\n","/**\n * 登录态与管理员 REST(对应后端 /kb/auth/*)\n */\nimport request from '../core/request.js'\n\n/**\n * 查询当前后端是否已存在管理员\n * @returns {Promise<{ exists: boolean, is_admin: boolean }>} 需登录态;is_admin=当前用户是否管理员\n */\nexport function adminExists() {\n return request.get('/auth/admin/exists')\n}\n\n/** 初始化第一个管理员(将当前登录用户设为管理员;仅当不存在时生效) */\nexport function initAdmin() {\n return request.post('/auth/init-admin')\n}\n\n/**\n * 查询管理员列表(需登录态;登录用户均可查看)\n * @returns {Promise<{ list: Array<{ id: number, uid: number, create_time: number, update_time: number }>, pending: Array<{ id: number, masked_mobile: string, create_time: number }> }>}\n * pending=待激活授权(按手机号预添加、目标用户尚未登录过)\n */\nexport function listAdmins() {\n return request.get('/auth/admin/list')\n}\n\n/**\n * 按 uid 添加管理员(仅管理员;uid 经用户中心手机号解析而来,即时生效)\n */\nexport function addAdminByUid(uid) {\n return request.post('/auth/admin/add', { uid })\n}\n\n/**\n * 按手机号添加管理员(仅管理员;目标未登录过知识库时落待激活授权)\n * @returns {Promise<{ pending: boolean }>} pending=true 表示创建的是待激活授权\n */\nexport function addAdminByMobile(mobile) {\n return request.post('/auth/admin/add', { mobile })\n}\n\n/** 撤销管理员待激活授权(仅管理员) */\nexport function removeAdminPending(pid) {\n return request.delete(`/auth/admin/pending/${pid}`)\n}\n\n/** 删除管理员(仅管理员;最后一个管理员不可删除) */\nexport function removeAdmin(uid) {\n return request.delete(`/auth/admin/${uid}`)\n}\n","/**\n * 文件类型工具:支持格式判定、隐藏文件过滤、大小格式化\n * 支持格式:md / txt / pdf / docx / 电子表格(xlsx/xlsm/csv)/ PPT(pptx)/\n * 图片(jpg/jpeg/png/webp/bmp/gif,走视觉模型 OCR 识别)\n */\n\nexport const SUPPORTED_EXTS = [\n '.md', '.txt', '.pdf', '.docx',\n '.xlsx', '.xlsm', '.csv', '.pptx',\n '.jpg', '.jpeg', '.png', '.webp', '.bmp', '.gif',\n]\n\nexport const EXT_LABEL = {\n '.md': 'Markdown',\n '.txt': '文本',\n '.pdf': 'PDF',\n '.docx': 'Word',\n '.xlsx': 'Excel',\n '.xlsm': 'Excel',\n '.csv': 'CSV',\n '.pptx': 'PPT',\n '.jpg': '图片',\n '.jpeg': '图片',\n '.png': '图片',\n '.webp': '图片',\n '.bmp': '图片',\n '.gif': '图片',\n}\n\n/** 是否支持解析的文件(按扩展名) */\nexport function isSupportedFile(name) {\n const ext = extOf(name)\n return SUPPORTED_EXTS.includes(ext)\n}\n\n/** 扩展名(小写,含点) */\nexport function extOf(name) {\n const base = String(name).split('/').pop() || ''\n const idx = base.lastIndexOf('.')\n return idx >= 0 ? base.slice(idx).toLowerCase() : ''\n}\n\n/** 字节大小格式化 */\nexport function formatSize(bytes) {\n const n = Number(bytes) || 0\n if (n < 1024) return `${n} B`\n if (n < 1048576) return `${(n / 1024).toFixed(1)} KB`\n return `${(n / 1024 / 1024).toFixed(2)} MB`\n}\n\n/** Unix 秒时间戳 → 本地时间文案 */\nexport function formatTime(sec) {\n if (!sec) return '-'\n const d = new Date(Number(sec) * 1000)\n const pad = (x) => String(x).padStart(2, '0')\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`\n}\n","/**\n * 知识库卡片:文档总数/向量块数/最后更新时间/MCP 开关 + 角色驱动的操作按钮\n * isSysadmin 为 true 时展示置顶/取消置顶(管理员专属能力)\n * onOpen 打开「知识库详情」标签页;onOpenPermission 打开详情页并弹出权限配置\n */\nimport { ROLE_LABEL } from '../../store/kb-store.js'\nimport { formatTime } from '../../utils/file-type.js'\n\nexport default function KbCard({\n kb,\n isAdmin,\n isSysadmin,\n onOpen,\n onOpenPermission,\n onEdit,\n onArchive,\n onRebuild,\n onPin,\n}) {\n return (\n <div className=\"skai-kb-card\">\n <div className=\"skai-kb-row-between\">\n <span className=\"skai-kb-title\" title={kb.name}>\n {kb.pinned ? '📌 ' : ''}\n {kb.name}\n </span>\n <span className={`skai-kb-badge ${kb.enable_mcp ? 'skai-kb-badge-green' : 'skai-kb-badge-gray'}`}>\n {kb.enable_mcp ? 'MCP 开' : 'MCP 关'}\n </span>\n </div>\n {kb.description ? (\n <div className=\"skai-kb-sub\" title={kb.description}>\n {kb.description}\n </div>\n ) : null}\n {kb.tags && kb.tags.length ? (\n <div style={{ marginTop: 4 }}>\n {kb.tags.map((t) => (\n <span key={t} className=\"skai-kb-tag\">\n {t}\n </span>\n ))}\n </div>\n ) : null}\n <div className=\"skai-kb-kb-meta\">\n <span>\n 📄 {kb.doc_count ?? 0} 文档\n </span>\n <span>\n 🧩 {kb.chunk_count ?? 0} 向量块\n </span>\n <span>🕒 {formatTime(kb.update_time)}</span>\n <span className={`skai-kb-badge ${kb.my_role === 1 || kb.my_role === 5 ? 'skai-kb-badge-blue' : 'skai-kb-badge-gray'}`}>\n {ROLE_LABEL[kb.my_role] || '只读'}\n </span>\n </div>\n <div className=\"skai-kb-kb-actions\">\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-sm skai-kb-btn-primary\" onClick={() => onOpen(kb)}>\n 文档\n </button>\n {isSysadmin ? (\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-sm\" onClick={() => onPin(kb)}>\n {kb.pinned ? '取消置顶' : '置顶'}\n </button>\n ) : null}\n {isAdmin ? (\n <>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-sm\" onClick={() => onOpenPermission(kb)}>\n 权限\n </button>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-sm\" onClick={() => onEdit(kb)}>\n 编辑\n </button>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-sm\" onClick={() => onRebuild(kb)}>\n 重建向量\n </button>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm skai-kb-btn-ghost-danger\"\n onClick={() => onArchive(kb)}\n >\n 归档\n </button>\n </>\n ) : null}\n </div>\n </div>\n )\n}\n","/**\n * 通用弹窗(createPortal 挂载 document.body;遮罩 fixed 铺满整个窗口并居中,与 CRM 同款范式;\n * z-index 30 ≤ 35 不覆盖宿主设置菜单;弹层根 .skai-kb-modal-mask 已纳入主题令牌作用域,\n * 脱离 .skai-kb-root 祖先后 var(--skai-kb-*) 仍可解析)\n * - width:自定义弹窗最大宽度(默认 520px);fullscreen=true 时铺满窗口(忽略 width)\n * - extraHead:头部标题右侧、关闭按钮左侧的操作区(如全屏切换按钮)\n * - escClose:Esc 关闭开关;多层弹窗叠加时底层弹窗传 false,保证 Esc 只关顶层\n * - locked:锁定态(如 AI 编写运行中)——遮罩点击不关闭、隐藏标题栏关闭按钮,\n * 配合 escClose=false 实现仅显式操作(如「取消等待」按钮)可关闭\n */\nimport { useLayoutEffect } from 'react'\nimport { createPortal } from 'react-dom'\n\nexport default function Modal({ title, onClose, children, footer, width, fullscreen = false, extraHead, escClose = true, locked = false }) {\n useLayoutEffect(() => {\n if (!escClose) return undefined\n const onKey = (e) => {\n if (e.key === 'Escape') onClose?.()\n }\n window.addEventListener('keydown', onKey)\n return () => window.removeEventListener('keydown', onKey)\n }, [onClose, escClose])\n\n return createPortal(\n <div\n className=\"skai-kb-modal-mask\"\n onMouseDown={(e) => e.target === e.currentTarget && !locked && onClose?.()}\n >\n <div\n className={`skai-kb-modal${fullscreen ? ' is-fullscreen' : ''}`}\n style={width && !fullscreen ? { maxWidth: width } : undefined}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={title}\n >\n <div className=\"skai-kb-modal-head\">\n <span className=\"skai-kb-modal-title\">{title}</span>\n <span className=\"skai-kb-modal-head-actions\">\n {extraHead}\n {!locked ? (\n <button type=\"button\" className=\"skai-kb-icon-btn\" aria-label=\"关闭\" onClick={onClose}>\n ✕\n </button>\n ) : null}\n </span>\n </div>\n <div className=\"skai-kb-modal-body\">{children}</div>\n {footer ? <div className=\"skai-kb-modal-foot\">{footer}</div> : null}\n </div>\n </div>,\n document.body,\n )\n}\n","/**\n * 表单校验:名称/标签校验、分块参数范围校验、uid 校验\n */\n\n/** 知识库名称:1-64 字符 */\nexport function validateKbName(name) {\n const v = String(name || '').trim()\n if (!v) return '请输入知识库名称'\n if (v.length > 64) return '知识库名称不能超过 64 字符'\n return ''\n}\n\n/** 标签解析与校验:逗号/空格分隔,去重,最多 20 个、单个 ≤ 32 字符 */\nexport function parseTags(input) {\n const raw = Array.isArray(input) ? input : String(input || '').split(/[,,\\s]+/)\n const seen = new Set()\n const tags = []\n for (let t of raw) {\n t = String(t).trim()\n if (!t || seen.has(t)) continue\n if (t.length > 32) return { tags: [], error: `标签「${t}」超过 32 字符` }\n seen.add(t)\n tags.push(t)\n if (tags.length >= 20) break\n }\n return { tags, error: '' }\n}\n\n/** 块大小范围:100-4000 字符 */\nexport function validateChunkSize(size) {\n const n = Number(size)\n if (!Number.isFinite(n)) return '块大小必须为数字'\n if (n < 100 || n > 4000) return '块大小范围为 100-4000'\n return ''\n}\n\n/** 重叠长度范围:0-500,且必须小于块大小 */\nexport function validateChunkOverlap(overlap, chunkSize) {\n const n = Number(overlap)\n if (!Number.isFinite(n)) return '重叠长度必须为数字'\n if (n < 0 || n > 500) return '重叠长度范围为 0-500'\n if (Number(chunkSize) && n >= Number(chunkSize)) return '重叠长度必须小于块大小'\n return ''\n}\n\n/** 中国大陆手机号:11 位,1 开头第二位 3-9(容忍空格/连字符分隔) */\nexport function validateMobile(mobile) {\n const v = String(mobile || '').replace(/[\\s-]/g, '')\n if (!/^1[3-9]\\d{9}$/.test(v)) return '手机号格式不正确(需为 11 位大陆手机号)'\n return ''\n}\n","/**\n * 业务标签选择器:输入 + 已有标签点击选择(逗号/空格分隔,去重)\n */\nimport { useState } from 'react'\nimport { parseTags } from '../../utils/validator.js'\n\nexport default function TagPicker({ value = [], onChange, placeholder = '输入标签后回车,逗号分隔' }) {\n const [input, setInput] = useState('')\n const commit = () => {\n const { tags, error } = parseTags(input)\n if (error) return\n onChange([...new Set([...(value || []), ...tags])].slice(0, 20))\n setInput('')\n }\n const remove = (tag) => onChange((value || []).filter((t) => t !== tag))\n return (\n <div>\n {value && value.length ? (\n <div style={{ marginBottom: 6 }}>\n {value.map((tag) => (\n <span\n key={tag}\n className=\"skai-kb-tag\"\n role=\"button\"\n tabIndex={0}\n onClick={() => remove(tag)}\n onKeyDown={(e) => e.key === 'Enter' && remove(tag)}\n title=\"点击移除\"\n >\n {tag} ✕\n </span>\n ))}\n </div>\n ) : null}\n <input\n className=\"skai-kb-input\"\n value={input}\n placeholder={placeholder}\n onChange={(e) => setInput(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === 'Enter') {\n e.preventDefault()\n commit()\n }\n }}\n onBlur={commit}\n />\n </div>\n )\n}\n","/**\n * 创建/编辑知识库弹窗:名称、描述、标签、MCP 检索开关、知识库级默认分段配置(所有者)\n */\nimport { useState } from 'react'\nimport Modal from '../common/Modal.jsx'\nimport TagPicker from './TagPicker.jsx'\nimport { validateKbName, validateChunkSize, validateChunkOverlap } from '../../utils/validator.js'\n\n/** 默认分段参数(与后端 config.yaml 默认值一致) */\nexport const DEFAULT_CHUNK_SIZE = 800\nexport const DEFAULT_CHUNK_OVERLAP = 100\n\nexport default function KbFormModal({ initial, busy = false, onSubmit, onClose }) {\n const isEdit = Boolean(initial && initial.id)\n const [name, setName] = useState(initial?.name || '')\n const [description, setDescription] = useState(initial?.description || '')\n const [tags, setTags] = useState(initial?.tags || [])\n const [enableMcp, setEnableMcp] = useState(initial ? Boolean(initial.enable_mcp) : true)\n const [chunkSize, setChunkSize] = useState(initial?.chunk_size || DEFAULT_CHUNK_SIZE)\n const [chunkOverlap, setChunkOverlap] = useState(initial?.chunk_overlap || DEFAULT_CHUNK_OVERLAP)\n const [error, setError] = useState('')\n\n const submit = () => {\n let msg = validateKbName(name)\n if (!msg) msg = validateChunkSize(chunkSize)\n if (!msg) msg = validateChunkOverlap(chunkOverlap, chunkSize)\n if (msg) {\n setError(msg)\n return\n }\n onSubmit({\n name: name.trim(),\n description: description.trim(),\n tags,\n enable_mcp: enableMcp ? 1 : 0,\n chunk_size: Number(chunkSize),\n chunk_overlap: Number(chunkOverlap),\n })\n }\n\n return (\n <Modal\n title={isEdit ? '编辑知识库' : '创建知识库'}\n onClose={onClose}\n footer={\n <>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={onClose} disabled={busy}>\n 取消\n </button>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-primary\" onClick={submit} disabled={busy}>\n {busy ? '保存中…' : '保存'}\n </button>\n </>\n }\n >\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">名称 *</span>\n <input\n className=\"skai-kb-input\"\n value={name}\n maxLength={64}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"知识库名称\"\n />\n </div>\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">描述</span>\n <textarea\n className=\"skai-kb-textarea\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n placeholder=\"知识库用途说明(可选)\"\n />\n </div>\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">业务标签</span>\n <TagPicker value={tags} onChange={setTags} />\n </div>\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">分段默认配置</span>\n <div className=\"skai-kb-field-row\">\n <input\n className=\"skai-kb-input\"\n type=\"number\"\n min={100}\n max={4000}\n value={chunkSize}\n onChange={(e) => setChunkSize(e.target.value)}\n placeholder=\"块大小\"\n aria-label=\"块大小\"\n />\n <input\n className=\"skai-kb-input\"\n type=\"number\"\n min={0}\n max={500}\n value={chunkOverlap}\n onChange={(e) => setChunkOverlap(e.target.value)}\n placeholder=\"重叠长度\"\n aria-label=\"重叠长度\"\n />\n </div>\n </div>\n <label className=\"skai-kb-row\" style={{ cursor: 'pointer' }}>\n <input type=\"checkbox\" checked={enableMcp} onChange={(e) => setEnableMcp(e.target.checked)} />\n <span>允许智能体通过 MCP 检索该知识库</span>\n </label>\n {error ? <div className=\"skai-kb-field-error\">{error}</div> : null}\n </Modal>\n )\n}\n","/** 危险操作确认弹窗(归档知识库 / 删除文档 / 移除成员等) */\nimport Modal from './Modal.jsx'\n\nexport default function ConfirmDialog({\n title = '确认操作',\n message,\n confirmText = '确认',\n danger = true,\n busy = false,\n onConfirm,\n onClose,\n}) {\n return (\n <Modal\n title={title}\n onClose={onClose}\n footer={\n <>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={onClose} disabled={busy}>\n 取消\n </button>\n <button\n type=\"button\"\n className={`skai-kb-btn ${danger ? 'skai-kb-btn-danger' : 'skai-kb-btn-primary'}`}\n onClick={onConfirm}\n disabled={busy}\n >\n {busy ? '处理中…' : confirmText}\n </button>\n </>\n }\n >\n <p className=\"skai-kb-confirm-text\">{message}</p>\n </Modal>\n )\n}\n","/** 全局 Toast(错误处理统一出口:ApiError 透出的服务端 msg 在此展示)\n * 经 createPortal 挂到 document.body + position:fixed——相对整个 DSH 窗口居中,\n * 而非插件标签页区域(与 Modal 同款挂载策略) */\nimport { createPortal } from 'react-dom'\nimport { useStore } from '../../store/create-store.js'\nimport { uiStore, dismissToast } from '../../store/ui-store.js'\n\nexport default function Toast() {\n const toasts = useStore(uiStore, (s) => s.toasts)\n if (!toasts.length) return null\n return createPortal(\n <div className=\"skai-kb-toast-layer\" role=\"status\" aria-live=\"polite\">\n {toasts.map((t) => (\n <div\n key={t.id}\n className={`skai-kb-toast skai-kb-toast-${t.type}`}\n onClick={() => dismissToast(t.id)}\n >\n {t.message}\n </div>\n ))}\n </div>,\n document.body,\n )\n}\n","/**\n * 插件自绘图形(简单书本 / 设置齿轮 Glyph,随包自带,避免依赖共享图标集)\n * 用途:引导页胶囊图标、标签页内页头、首页右上角设置入口\n */\nimport { createElement } from 'react'\n\n/** 等待转圈(16 viewBox 3/4 圆弧,stroke=currentColor;配合 .skai-kb-spin 旋转动画使用) */\nexport function SpinnerGlyph({ size = 13 }) {\n return createElement(\n 'svg',\n {\n className: 'skai-kb-spin',\n width: size,\n height: size,\n viewBox: '0 0 16 16',\n fill: 'none',\n 'aria-hidden': true,\n },\n createElement('circle', {\n cx: 8,\n cy: 8,\n r: 6,\n stroke: 'currentColor',\n 'stroke-opacity': 0.25,\n 'stroke-width': 2,\n }),\n createElement('path', {\n d: 'M14 8a6 6 0 0 0-6-6',\n stroke: 'currentColor',\n 'stroke-width': 2,\n 'stroke-linecap': 'round',\n }),\n )\n}\n\nexport function KnowledgeGlyph({ size = 20 }) {\n return createElement(\n 'svg',\n {\n width: size,\n height: size,\n viewBox: '0 0 20 20',\n fill: 'none',\n 'aria-hidden': true,\n },\n createElement('path', {\n d: 'M3 4.2C3 3.54 3.54 3 4.2 3H8a2.8 2.8 0 0 1 2 2.8V17a2.4 2.4 0 0 0-2.4-2.4H4.2A1.2 1.2 0 0 1 3 13.4V4.2Z',\n fill: 'currentColor',\n opacity: 0.55,\n }),\n createElement('path', {\n d: 'M17 4.2C17 3.54 16.46 3 15.8 3H12a2.8 2.8 0 0 0-2 2.8V17a2.4 2.4 0 0 1 2.4-2.4h3.4a1.2 1.2 0 0 0 1.2-1.2V4.2Z',\n fill: 'currentColor',\n }),\n )\n}\n\n/** 书本 + 加号(线性风格;「添加到知识库」动作图标,与宿主操作行线性图标同系列) */\nexport function BookPlusGlyph({ size = 15 }) {\n return createElement(\n 'svg',\n {\n width: size,\n height: size,\n viewBox: '0 0 24 24',\n fill: 'none',\n stroke: 'currentColor',\n strokeWidth: 1.8,\n strokeLinecap: 'round',\n strokeLinejoin: 'round',\n 'aria-hidden': true,\n },\n createElement('path', {\n d: 'M4 19.5V5a2.5 2.5 0 0 1 2.5-2.5H20V17H6.5A2.5 2.5 0 0 0 4 19.5Zm0 0A2.5 2.5 0 0 0 6.5 22H20',\n }),\n createElement('path', {\n d: 'M12 7.5v5M9.5 10h5',\n }),\n )\n}\n\n/** 书本 + 放大镜(线性风格;「引用知识库」动作图标,检索知识库语义,\n * 书本轮廓与 BookPlusGlyph 同款,与操作行线性图标同系列) */\nexport function BookSearchGlyph({ size = 15 }) {\n return createElement(\n 'svg',\n {\n width: size,\n height: size,\n viewBox: '0 0 24 24',\n fill: 'none',\n stroke: 'currentColor',\n strokeWidth: 1.8,\n strokeLinecap: 'round',\n strokeLinejoin: 'round',\n 'aria-hidden': true,\n },\n createElement('path', {\n d: 'M4 19.5V5a2.5 2.5 0 0 1 2.5-2.5H20V17H6.5A2.5 2.5 0 0 0 4 19.5Zm0 0A2.5 2.5 0 0 0 6.5 22H20',\n }),\n createElement('circle', { cx: 11.8, cy: 9.4, r: 2.7 }),\n createElement('path', {\n d: 'm14 11.6 2.3 2.3',\n }),\n )\n}\n\n/**\n * 操作小图标(与 CRM 插件 Glyph 同款几何:20 viewBox,fill=currentColor,随文字色着色)\n * P:路径表(按需补充);Glyph:通用单 path 图标渲染器\n */\nexport function Glyph({ size = 14, d, filled = true }) {\n return createElement(\n 'svg',\n {\n width: size,\n height: size,\n viewBox: '0 0 20 20',\n fill: 'none',\n 'aria-hidden': true,\n },\n createElement('path', {\n d,\n fill: filled ? 'currentColor' : 'none',\n stroke: filled ? 'none' : 'currentColor',\n strokeWidth: 1.5,\n }),\n )\n}\n\nexport const P = {\n plus: 'M10 4a.9.9 0 0 1 .9.9V9.1h4.2a.9.9 0 1 1 0 1.8H10.9v4.2a.9.9 0 1 1-1.8 0V10.9H4.9a.9.9 0 1 1 0-1.8h4.2V4.9A.9.9 0 0 1 10 4Z',\n refresh:\n 'M10 3.5a6.5 6.5 0 0 1 5.6 3.2l1.6-1v4.2h-4.2l1.4-1.4A4.7 4.7 0 0 0 10 5.3 4.7 4.7 0 0 0 5.3 10H3.5A6.5 6.5 0 0 1 10 3.5Zm-7.2 6.8h4.2l-1.4 1.4A4.7 4.7 0 0 0 10 14.7a4.7 4.7 0 0 0 4.7-4.7h1.8A6.5 6.5 0 0 1 4.4 13.3l-1.6 1V10.3Z',\n}\n\n/** 设置齿轮(线性风格;currentColor 随文字色,主题自适应) */\nexport function SettingsGlyph({ size = 20 }) {\n return createElement(\n 'svg',\n {\n width: size,\n height: size,\n viewBox: '0 0 20 20',\n fill: 'none',\n 'aria-hidden': true,\n },\n createElement('path', {\n d: 'M10 12.4a2.4 2.4 0 1 0 0-4.8 2.4 2.4 0 0 0 0 4.8Z',\n stroke: 'currentColor',\n strokeWidth: 1.5,\n }),\n createElement('path', {\n d: 'M16.32 12.24a1.42 1.42 0 0 0 .29 1.57l.05.05a1.72 1.72 0 1 1-2.43 2.43l-.05-.05a1.42 1.42 0 0 0-1.57-.29 1.42 1.42 0 0 0-.86 1.3v.14a1.72 1.72 0 0 1-3.44 0v-.08a1.42 1.42 0 0 0-.93-1.3 1.42 1.42 0 0 0-1.57.29l-.05.05a1.72 1.72 0 1 1-2.43-2.43l.05-.05a1.42 1.42 0 0 0 .29-1.57 1.42 1.42 0 0 0-1.3-.86h-.14a1.72 1.72 0 0 1 0-3.44h.08a1.42 1.42 0 0 0 1.3-.93 1.42 1.42 0 0 0-.29-1.57l-.05-.05A1.72 1.72 0 1 1 5.71 3.2l.05.05a1.42 1.42 0 0 0 1.57.29h.07a1.42 1.42 0 0 0 .86-1.3v-.14a1.72 1.72 0 0 1 3.44 0v.08a1.42 1.42 0 0 0 .86 1.3 1.42 1.42 0 0 0 1.57-.29l.05-.05a1.72 1.72 0 1 1 2.43 2.43l-.05.05a1.42 1.42 0 0 0-.29 1.57v.07a1.42 1.42 0 0 0 1.3.86h.14a1.72 1.72 0 0 1 0 3.44h-.08a1.42 1.42 0 0 0-1.3.86Z',\n stroke: 'currentColor',\n strokeWidth: 1.5,\n strokeLinejoin: 'round',\n }),\n )\n}\n\nexport default KnowledgeGlyph\n\n/**\n * 全屏 / 退出全屏(宿主 DSH 右侧边栏右上角同款 16×16 图标,path 数据逐字取自宿主渲染结果)\n * g 上 fill/stroke 均为 currentColor,随按钮文字色自适应主题\n */\nconst FULLSCREEN_PATHS = [\n 'M6.04798 2.13627V0.815964H5.99549L5.36158 0.817345V0.815964L3.39978 0.815274C3.01892 0.815274 2.67749 0.814821 2.39919 0.844967C2.10813 0.87655 1.80506 0.949512 1.52981 1.14949C1.3822 1.25681 1.25251 1.38652 1.14518 1.53412C0.945217 1.80935 0.872245 2.11246 0.840659 2.4035C0.810509 2.68178 0.810965 3.02324 0.810966 3.40409L0.811656 5.36589V5.9998L0.810966 6.05297L0.864137 6.05228H2.13196L2.18513 6.05297L2.18444 5.9998V5.36589L2.18513 3.40409C2.18513 2.99322 2.18631 2.73978 2.20653 2.55266C2.22499 2.38234 2.25273 2.34575 2.25556 2.34204C2.27837 2.31066 2.30635 2.28267 2.33774 2.25987C2.34207 2.25657 2.37978 2.22911 2.54835 2.21084C2.73548 2.19063 2.98893 2.18944 3.39978 2.18944L5.36158 2.18875L5.9948 2.18944H6.04867L6.04798 2.13627Z',\n 'M9.94031 13.86L9.94031 15.1803L9.99279 15.1803L10.6267 15.179L10.6267 15.1803L12.5885 15.181C12.9694 15.181 13.3108 15.1815 13.5891 15.1513C13.8801 15.1198 14.1832 15.0468 14.4585 14.8468C14.6061 14.7395 14.7358 14.6098 14.8431 14.4622C15.0431 14.187 15.116 13.8838 15.1476 13.5928C15.1778 13.3145 15.1773 12.9731 15.1773 12.5922L15.1766 10.6304L15.1766 9.9965L15.1773 9.94333L15.1241 9.94402L13.8563 9.94402L13.8032 9.94333L13.8038 9.9965L13.8038 10.6304L13.8032 12.5922C13.8032 13.0031 13.802 13.2565 13.7817 13.4437C13.7633 13.614 13.7355 13.6506 13.7327 13.6543C13.7099 13.6856 13.6819 13.7136 13.6505 13.7364C13.6462 13.7397 13.6085 13.7672 13.4399 13.7855C13.2528 13.8057 12.9993 13.8069 12.5885 13.8069L10.6267 13.8076L9.99348 13.8069L9.93962 13.8069L9.94031 13.86Z',\n 'M13.8568 6.05243H15.1771V5.99995L15.1757 5.36604H15.1771L15.1778 3.40423C15.1778 3.02337 15.1783 2.68194 15.1481 2.40365C15.1165 2.11259 15.0436 1.80952 14.8436 1.53427C14.7363 1.38666 14.6066 1.25697 14.459 1.14964C14.1837 0.949672 13.8806 0.8767 13.5896 0.845114C13.3113 0.814965 12.9698 0.815421 12.589 0.815421L10.6272 0.816112H9.99329L9.94011 0.815421L9.9408 0.868592V2.13641L9.94011 2.18958L9.99329 2.18889H10.6272L12.589 2.18958C12.9999 2.18958 13.2533 2.19077 13.4404 2.21099C13.6107 2.22944 13.6473 2.25719 13.651 2.26002C13.6824 2.28282 13.7104 2.31081 13.7332 2.34219C13.7365 2.34653 13.764 2.38424 13.7822 2.5528C13.8025 2.73993 13.8037 2.99339 13.8037 3.40423L13.8043 5.36604L13.8037 5.99926V6.05312L13.8568 6.05243Z',\n 'M2.12951 9.94389L0.809205 9.94389L0.809205 9.99637L0.810586 10.6303L0.809205 10.6303L0.808514 12.5921C0.808514 12.9729 0.808061 13.3144 0.838207 13.5927C0.86979 13.8837 0.942753 14.1868 1.14273 14.4621C1.25005 14.6097 1.37976 14.7394 1.52736 14.8467C1.80259 15.0467 2.1057 15.1196 2.39674 15.1512C2.67502 15.1814 3.01648 15.1809 3.39733 15.1809L5.35913 15.1802L5.99304 15.1802L6.04621 15.1809L6.04552 15.1277L6.04552 13.8599L6.04621 13.8067L5.99304 13.8074L5.35913 13.8074L3.39733 13.8067C2.98646 13.8067 2.73302 13.8056 2.5459 13.7853C2.37559 13.7669 2.33899 13.7391 2.33528 13.7363C2.3039 13.7135 2.27591 13.6855 2.25311 13.6541C2.24981 13.6498 2.22235 13.6121 2.20408 13.4435C2.18387 13.2564 2.18268 13.0029 2.18268 12.5921L2.18199 10.6303L2.18268 9.99706L2.18268 9.9432L2.12951 9.94389Z',\n]\n\nconst FULLSCREEN_EXIT_PATHS = [\n 'M10.698 0.379607H9.43015L9.37698 0.378916L9.37767 0.432087V1.066L9.37698 4.0277C9.37698 4.40856 9.37653 4.74998 9.40667 5.02828C9.43826 5.31934 9.51053 5.62311 9.71051 5.89835C9.81779 6.04587 9.94762 6.1757 10.0951 6.28298C10.3704 6.48296 10.6741 6.55523 10.9652 6.58682C11.2435 6.61696 11.5849 6.61651 11.9658 6.61651L14.9275 6.61582H15.5614L15.6146 6.61651L15.6139 6.56334V5.29552L15.6146 5.24235L15.5614 5.24304H14.9275L11.9658 5.24235C11.5545 5.24235 11.3009 5.24191 11.1137 5.22163C10.9443 5.20329 10.9078 5.17501 10.9038 5.17191C10.8724 5.14911 10.8444 5.12112 10.8216 5.08974C10.8185 5.08566 10.7902 5.04908 10.7719 4.87982C10.7516 4.69263 10.7511 4.439 10.7511 4.0277L10.7505 1.066V0.432087L10.7511 0.378916L10.698 0.379607Z',\n 'M5.29031 15.6167L6.55813 15.6167L6.6113 15.6174L6.61061 15.5642L6.61061 14.9303L6.6113 11.9686C6.6113 11.5878 6.61176 11.2463 6.58161 10.968C6.55003 10.677 6.47775 10.3732 6.27777 10.098C6.17049 9.95045 6.04067 9.82062 5.89315 9.71334C5.6179 9.51336 5.31413 9.44109 5.02307 9.40951C4.74478 9.37936 4.40335 9.37981 4.02249 9.37981L1.06079 9.3805L0.426879 9.3805L0.373708 9.37981L0.374398 9.43298L0.374398 10.7008L0.373708 10.754L0.426879 10.7533L1.06079 10.7533L4.02249 10.754C4.43379 10.754 4.68742 10.7544 4.87461 10.7747C5.04393 10.793 5.08047 10.8213 5.08453 10.8244C5.11591 10.8472 5.1439 10.8752 5.1667 10.9066C5.16982 10.9107 5.19808 10.9472 5.21642 11.1165C5.2367 11.3037 5.23714 11.5573 5.23714 11.9686L5.23783 14.9303L5.23783 15.5642L5.23714 15.6174L5.29031 15.6167Z',\n]\n\nfunction hostIcon(paths, size) {\n return createElement(\n 'svg',\n {\n width: size,\n height: size,\n viewBox: '0 0 16 16',\n fill: 'none',\n 'aria-hidden': true,\n style: { display: 'block' },\n },\n createElement(\n 'g',\n { fill: 'currentColor', stroke: 'currentColor', strokeWidth: 0.105646, strokeLinecap: 'square' },\n paths.map((d) => createElement('path', { key: d.slice(0, 24), d })),\n ),\n )\n}\n\n/** 全屏(进入全屏态按钮;默认 12px 与弹窗关闭按钮 ✕ 字号一致) */\nexport function FullscreenGlyph({ size = 12 }) {\n return hostIcon(FULLSCREEN_PATHS, size)\n}\n\n/** 退出全屏(还原态按钮;默认 12px 与弹窗关闭按钮 ✕ 字号一致) */\nexport function FullscreenExitGlyph({ size = 12 }) {\n return hostIcon(FULLSCREEN_EXIT_PATHS, size)\n}\n","/**\n * 用户管理 REST(对应后端 /kb/user/*;查看与操作仅限管理员,me 为状态门禁豁免接口)\n */\nimport request from '../core/request.js'\n\n/**\n * 当前登录用户平台状态(待审核/禁用时前端据此展示全局横幅)\n * @returns {Promise<{ uid: number, status: number, status_text: string }>}\n */\nexport function getMe() {\n return request.get('/user/me')\n}\n\n/**\n * 用户列表(仅管理员)\n * @param {{ status?: number, keyword?: string, page?: number, limit?: number }} params\n * @returns {Promise<{ list: Array<{ uid: number, masked_mobile: string, status: number, review_time: number, review_uid: number, create_time: number, update_time: number, is_admin: boolean }>, total: number, page: number, limit: number, pending_count: number }>}\n */\nexport function listUsers(params = {}) {\n return request.get('/user/list', params)\n}\n\n/**\n * 正常状态用户选项列表(知识库「添加成员 → 从用户列表选择」用;非管理员可调)\n * @param {{ keyword?: string, page?: number, limit?: number }} params\n * @returns {Promise<{ list: Array<{ uid: number, masked_mobile: string }>, total: number, page: number, limit: number }>}\n */\nexport function listUserOptions(params = {}) {\n return request.get('/user/options', params)\n}\n\n/**\n * 用户概览统计(首页「用户数」卡片;仅管理员)\n * @returns {Promise<{ user_count: number, pending_count: number }>} pending_count=待审核用户数\n */\nexport function getUserStats() {\n return request.get('/user/stats')\n}\n\n/**\n * 查询新用户默认审核模式(仅管理员)\n * @returns {Promise<{ mode: number }>} 0=无需审核(默认)/ 1=需审核\n */\nexport function getReviewConfig() {\n return request.get('/user/review-config')\n}\n\n/**\n * 切换新用户默认审核模式(仅管理员;仅影响之后首次验签的新用户,不影响存量用户状态)\n * @param {0|1} mode\n */\nexport function setReviewConfig(mode) {\n return request.put('/user/review-config', { mode })\n}\n\n/** 审核通过(待审核 → 正常;仅管理员;管理员不可被操作) */\nexport function reviewUser(uid) {\n return request.post(`/user/${uid}/review`)\n}\n\n/** 禁用(待审核/正常 → 禁用,同步吊销其全部插件 Token;仅管理员) */\nexport function disableUser(uid) {\n return request.post(`/user/${uid}/disable`)\n}\n\n/** 启用(禁用 → 正常;仅管理员) */\nexport function enableUser(uid) {\n return request.post(`/user/${uid}/enable`)\n}\n\n/**\n * 删除用户(仅管理员;物理删除状态记录与成员权限/待激活授权,保留其创建的知识库\n * 与文档,悬空所有者由管理员经「修改所有者」接管;用户再次登录视为新用户)\n */\nexport function deleteUser(uid) {\n return request.delete(`/user/${uid}`)\n}\n","/**\n * 首页(知识库列表标签页正文)\n *\n * - 知识库概览统计(文档数 / 向量块数 / MCP 开启数,由列表聚合)\n * - 知识库列表:名称/标签过滤、分页、置顶优先;卡片「文档」打开知识库详情标签页\n * - 添加知识库(所有登录用户);编辑/归档/置顶/重建向量按角色展示\n * - 设置入口(打开「设置」标签页:后端服务器地址 + 管理员)\n *\n * 导经 tab.actions.openTab(kind, { params }) 由宿主标签页系统承载:\n * 打开知识库详情 = 新标签页;本页面不维护内嵌路由。\n */\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { useStore } from '../../store/create-store.js'\nimport {\n kbStore,\n setKbList,\n setKbKeyword,\n setKbTagFilter,\n upsertKb,\n removeKbLocally,\n setStats,\n} from '../../store/kb-store.js'\nimport { setKbName } from '../../store/title-store.js'\nimport { toast, toastError } from '../../store/ui-store.js'\nimport { listKb, createKb, updateKb, archiveKb, pinKb } from '../../api/kb.js'\nimport { rebuildVector } from '../../api/task.js'\nimport { adminExists } from '../../api/auth.js'\nimport { subscribe as subscribeServerConfig, getApiBase, whenReady } from '../../core/server-config.js'\nimport { formatTime } from '../../utils/file-type.js'\nimport KbCard from '../../components/kb/KbCard.jsx'\nimport KbFormModal from '../../components/kb/KbFormModal.jsx'\nimport ConfirmDialog from '../../components/common/ConfirmDialog.jsx'\nimport Toast from '../../components/common/Toast.jsx'\nimport { SettingsGlyph } from '../../components/common/icons.jsx'\nimport { getUserStats } from '../../api/user.js'\n\n/**\n * @param {object} props\n * @param {{ openKb: (kbId: number, opts?: { view?: string }) => void, openSettings: () => void }} props.nav\n * 标签页导航(DSH 路径经 tab.actions.openTab 注入;standalone 路径内部路由实现)\n */\nexport default function HomePage({ nav }) {\n const list = useStore(kbStore, (s) => s.list)\n const total = useStore(kbStore, (s) => s.total)\n const page = useStore(kbStore, (s) => s.page)\n const limit = useStore(kbStore, (s) => s.limit)\n const keyword = useStore(kbStore, (s) => s.keyword)\n const tagFilter = useStore(kbStore, (s) => s.tagFilter)\n const stats = useStore(kbStore, (s) => s.stats)\n const [isSysadmin, setIsSysadmin] = useState(false)\n const [userStats, setUserStats] = useState(null) // 管理员用户概览 { count, pending }(非管理员 null)\n const [creating, setCreating] = useState(false)\n const [editing, setEditing] = useState(null)\n const [archiving, setArchiving] = useState(null)\n const [busy, setBusy] = useState(false)\n\n const reload = useCallback(\n (p = page) => {\n listKb({ keyword, tag: tagFilter, page: p, limit })\n .then((data) => {\n const kbList = data?.list || []\n setKbList(kbList, data?.total || 0, p, limit)\n kbList.forEach((k) => setKbName(k.id, k.name))\n })\n .catch(toastError)\n },\n [keyword, tagFilter, page, limit],\n )\n\n // 首次加载等待服务器配置解析完成:浏览器刷新后云配置异步到达,基址就绪前\n // 发起请求会被 request 拦截误报「请先在设置页配置服务器信息」。\n // readyRef 放行后续关键词/标签变化触发的重载\n const readyRef = useRef(false)\n useEffect(() => {\n let cancelled = false\n whenReady().then(() => {\n if (cancelled) return\n readyRef.current = true\n reload(1)\n })\n return () => {\n cancelled = true\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n useEffect(() => {\n if (!readyRef.current) return\n reload(1)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [keyword, tagFilter])\n\n // 概览统计(全量聚合,独立于分页列表)+ 标签页名称预热(同样等配置就绪)\n const loadStats = useCallback(() => {\n let cancelled = false\n listKb({ page: 1, limit: 100 })\n .then((data) => {\n if (cancelled) return\n const kbList = data && data.list ? data.list : []\n const docTotal = kbList.reduce((sum, k) => sum + (k.doc_count || 0), 0)\n const mcpOn = kbList.filter((k) => k.enable_mcp).length\n const lastUpdate = kbList.reduce((max, k) => Math.max(max, k.update_time || 0), 0)\n setStats({ kbCount: kbList.length, docTotal, mcpOn, lastUpdate })\n kbList.forEach((k) => setKbName(k.id, k.name))\n })\n .catch((e) => !cancelled && toastError(e))\n return () => {\n cancelled = true\n }\n }, [])\n\n const loadAdminState = useCallback(() => {\n let cancelled = false\n adminExists()\n .then((data) => {\n if (cancelled) return\n const isAdmin = Boolean(data && data.is_admin)\n setIsSysadmin(isAdmin)\n // 管理员额外拉取用户概览(用户数 + 待审核气泡;非管理员无此统计权限)\n if (isAdmin) {\n getUserStats()\n .then((res) => {\n if (!cancelled) {\n setUserStats({ count: Number(res?.user_count) || 0, pending: Number(res?.pending_count) || 0 })\n }\n })\n .catch(() => !cancelled && setUserStats(null))\n } else {\n setUserStats(null)\n }\n })\n .catch(() => !cancelled && setIsSysadmin(false))\n return () => {\n cancelled = true\n }\n }, [])\n\n useEffect(() => {\n let cancelled = false\n whenReady().then(() => {\n if (cancelled) return\n loadStats()\n loadAdminState()\n })\n return () => {\n cancelled = true\n }\n }, [loadStats, loadAdminState])\n\n // DSH 启动自动生效:服务器配置经用户中心云持久化异步到达(或切换服务器),\n // 基址就绪后自动重载列表 / 统计 / 管理员状态,页面无需手动刷新\n useEffect(() => {\n let prev = getApiBase()\n const off = subscribeServerConfig(() => {\n const cur = getApiBase()\n if (cur === prev) return\n prev = cur\n if (!cur) return\n reload(1)\n loadStats()\n loadAdminState()\n })\n return off\n }, [reload, loadStats, loadAdminState])\n\n const submitPin = (kb) => {\n setBusy(true)\n pinKb(kb.id, !kb.pinned)\n .then(() => {\n upsertKb({ ...kb, pinned: kb.pinned ? 0 : 1 })\n toast(kb.pinned ? '已取消置顶' : '已置顶,该知识库将排在列表最前', 'success')\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const submitCreate = (data) => {\n setBusy(true)\n createKb(data)\n .then(() => {\n toast('知识库已创建', 'success')\n setCreating(false)\n reload(1)\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const submitEdit = (data) => {\n setBusy(true)\n updateKb(editing.id, data)\n .then((kb) => {\n const merged = kb || { ...editing, ...data }\n upsertKb(merged)\n setKbName(merged.id, merged.name)\n toast('已保存', 'success')\n setEditing(null)\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const submitArchive = () => {\n setBusy(true)\n archiveKb(archiving.id)\n .then(() => {\n removeKbLocally(archiving.id)\n toast('知识库已归档', 'success')\n setArchiving(null)\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const submitRebuild = (kb) => {\n setBusy(true)\n rebuildVector(kb.id)\n .then((res) => {\n toast(`已提交向量重建任务${res?.task_id ? `(#${res.task_id})` : ''}`, 'success')\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const totalPages = Math.max(1, Math.ceil(total / limit))\n\n return (\n <div className=\"skai-kb-page\">\n {/* 页头(固定):左侧标题与说明介绍,右上角设置入口 */}\n <div className=\"skai-kb-home-head\">\n <div className=\"skai-kb-home-head-main\">\n <div className=\"skai-kb-detail-title\">知识库</div>\n <div className=\"skai-kb-home-desc\">\n 集中管理文档与成员权限:上传文档自动解析、分块并向量化,DSH 智能体经 MCP\n 实时检索引用;支持按成员配置查看 / 编辑 / 管理权限,可创建多个知识库按业务隔离。\n </div>\n </div>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={() => nav.openSettings()}>\n <SettingsGlyph size={14} />\n 设置\n </button>\n </div>\n\n <div className=\"skai-kb-page-scroll\">\n {/* 概览统计 */}\n <div className=\"skai-kb-stat-grid\">\n <div className=\"skai-kb-stat-card\">\n <div className=\"skai-kb-stat-num\">{stats ? stats.kbCount : '-'}</div>\n <div className=\"skai-kb-stat-label\">知识库</div>\n </div>\n <div className=\"skai-kb-stat-card\">\n <div className=\"skai-kb-stat-num\">{stats ? stats.docTotal : '-'}</div>\n <div className=\"skai-kb-stat-label\">文档总数</div>\n </div>\n {isSysadmin ? (\n <div className=\"skai-kb-stat-card\">\n <div className=\"skai-kb-stat-num\">\n {userStats ? userStats.count : '-'}\n {userStats && userStats.pending > 0 ? (\n <span\n className=\"skai-kb-badge skai-kb-badge-amber skai-kb-stat-badge\"\n title={`${userStats.pending} 个用户待审核,前往设置页「用户管理」处理`}\n >\n {userStats.pending} 待审核\n </span>\n ) : null}\n </div>\n <div className=\"skai-kb-stat-label\">用户数</div>\n </div>\n ) : null}\n <div className=\"skai-kb-stat-card\">\n <div className=\"skai-kb-stat-num\">{stats ? stats.mcpOn : '-'}</div>\n <div className=\"skai-kb-stat-label\">开启 MCP 检索</div>\n </div>\n </div>\n <div className=\"skai-kb-sub\" style={{ marginBottom: 10 }}>\n 最后更新:{stats ? formatTime(stats.lastUpdate) : '-'}\n </div>\n\n {/* 工具栏:搜索 / 标签 / 添加知识库 */}\n <div className=\"skai-kb-toolbar\">\n <input\n className=\"skai-kb-input skai-kb-search\"\n value={keyword}\n placeholder=\"搜索知识库名称\"\n onChange={(e) => setKbKeyword(e.target.value)}\n />\n <input\n className=\"skai-kb-input\"\n style={{ maxWidth: 110 }}\n value={tagFilter}\n placeholder=\"标签过滤\"\n onChange={(e) => setKbTagFilter(e.target.value)}\n />\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-primary\"\n onClick={() => setCreating(true)}\n >\n 添加知识库\n </button>\n </div>\n\n {/* 知识库列表 */}\n {list.length === 0 ? (\n <div className=\"skai-kb-empty\">\n <p>暂无可访问的知识库</p>\n <p className=\"skai-kb-empty-sub\">创建知识库后即可上传文档、管理成员权限</p>\n </div>\n ) : (\n <div className=\"skai-kb-card-list\">\n {list.map((kb) => (\n <KbCard\n key={kb.id}\n kb={kb}\n isAdmin={kb.my_role === 1}\n isSysadmin={isSysadmin}\n onOpen={(k) => nav.openKb(k.id)}\n onOpenPermission={(k) => nav.openKb(k.id, { view: 'permission' })}\n onEdit={(k) => setEditing(k)}\n onArchive={(k) => setArchiving(k)}\n onRebuild={submitRebuild}\n onPin={submitPin}\n />\n ))}\n </div>\n )}\n\n {/* 分页 */}\n {totalPages > 1 ? (\n <div className=\"skai-kb-pagination\">\n <span>\n 第 {page} / {totalPages} 页 · 共 {total} 个\n </span>\n <div className=\"skai-kb-pagination-btns\">\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm\"\n disabled={page <= 1}\n onClick={() => reload(page - 1)}\n >\n 上一页\n </button>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm\"\n disabled={page >= totalPages}\n onClick={() => reload(page + 1)}\n >\n 下一页\n </button>\n </div>\n </div>\n ) : null}\n </div>\n\n {/* 弹窗 */}\n {creating ? (\n <KbFormModal busy={busy} onSubmit={submitCreate} onClose={() => setCreating(false)} />\n ) : null}\n {editing ? (\n <KbFormModal initial={editing} busy={busy} onSubmit={submitEdit} onClose={() => setEditing(null)} />\n ) : null}\n {archiving ? (\n <ConfirmDialog\n title=\"归档知识库\"\n message={`确定归档「${archiving.name}」吗?归档后 MCP 不可检索,历史数据保留。`}\n confirmText=\"归档\"\n busy={busy}\n onConfirm={submitArchive}\n onClose={() => setArchiving(null)}\n />\n ) : null}\n <Toast />\n </div>\n )\n}\n","/**\n * 目录(文件夹)域状态:当前知识库目录树、当前浏览目录\n * currentId 语义与后端一致:0=根目录\n */\nimport { createStore } from './create-store.js'\n\nexport const initialFolderState = {\n kbId: null,\n tree: [], // 服务端嵌套树:[{ id, parent_id, name, sort_order, children }]\n currentId: 0, // 当前浏览目录(0=根目录)\n}\n\n/** 稳定空树引用:selector 在 kbId 不匹配时必须返回同一引用,避免 useSyncExternalStore 死循环 */\nexport const EMPTY_TREE = []\n\nexport const folderStore = createStore(initialFolderState)\n\n/** 拉取目录树后整体回填(切库/结构变更后调用) */\nexport function setFolderTree(kbId, tree) {\n folderStore.setState((s) => ({\n kbId,\n tree: tree || [],\n // 换库回到根目录;同库结构变更保持当前目录\n currentId: s.kbId === kbId ? s.currentId : 0,\n }))\n}\n\nexport function setCurrentFolder(id) {\n folderStore.setState({ currentId: id || 0 })\n}\n\n/**\n * HTML5 DnD 拖拽源上下文(模块级共享:dragover 阶段 dataTransfer.getData 不可读)\n * type: 'folder' | 'doc';id: 拖拽对象 id;parentId: 目录的父目录(0=顶层)\n */\nexport const dragCtx = { type: null, id: null, parentId: 0 }\n\n/** 在树中定位某父目录下的同级节点数组(parentId=0 返回顶层) */\nexport function siblingsOf(tree, parentId) {\n if (!parentId) return tree\n for (const node of tree || []) {\n if (node.id === parentId) return node.children || []\n const deep = siblingsOf(node.children, parentId)\n if (deep) return deep\n }\n return null\n}\n","/**\n * 目录(文件夹)管理 REST(对应后端 /kb/kb/:id/folder/*)\n */\nimport request from '../core/request.js'\n\n/** 目录树(全量;节点含 children 嵌套) */\nexport function getFolderTree(kbId) {\n return request.get(`/kb/${kbId}/folder/tree`)\n}\n\n/** 新建目录(parentId 缺省/0 = 顶层) */\nexport function createFolder(kbId, name, parentId = 0) {\n return request.post(`/kb/${kbId}/folder/create`, { name, parent_id: parentId || 0 })\n}\n\n/** 重命名目录 */\nexport function renameFolder(kbId, folderId, name) {\n return request.put(`/kb/${kbId}/folder/${folderId}/update`, { name })\n}\n\n/** 目录同级拖拽排序(parent_id + 有序 folder_id 数组整批提交) */\nexport function reorderFolders(kbId, parentId, folderIds) {\n return request.post(`/kb/${kbId}/folder/reorder`, { parent_id: parentId || 0, folder_ids: folderIds })\n}\n\n/** 删除目录(软删;仅空目录) */\nexport function deleteFolder(kbId, folderId) {\n return request.delete(`/kb/${kbId}/folder/${folderId}`)\n}\n","/**\n * 当前 uid 在知识库内的角色与按钮级权限\n * 角色由后端列表接口随知识库返回(my_role),前端只做渲染拦截(无权限按钮隐藏)\n * 真实鉴权以后端为准:不可见即不可操作,后端仍会做权限校验兜底\n *\n * @param {number|undefined} kbId 知识库 id;缺省时取列表内最高角色\n * @returns {{ role, isAdmin, isEditor, canEdit, canManage, canUpload }}\n */\nimport { useMemo } from 'react'\nimport { useStore } from '../store/create-store.js'\nimport { kbStore, ROLE } from '../store/kb-store.js'\n\nexport function useKbPermission(kbId) {\n const list = useStore(kbStore, (s) => s.list)\n const role = useMemo(() => {\n if (kbId == null) return list.reduce((min, k) => Math.min(min, k.my_role ?? ROLE.READONLY), 99)\n const kb = list.find((k) => k.id === kbId)\n return kb ? kb.my_role : ROLE.READONLY\n }, [list, kbId])\n return {\n role,\n isAdmin: role === ROLE.ADMIN,\n isEditor: role === ROLE.EDITOR,\n canEdit: role === ROLE.ADMIN || role === ROLE.EDITOR,\n canManage: role === ROLE.ADMIN,\n canUpload: role === ROLE.ADMIN || role === ROLE.EDITOR,\n }\n}\n","/**\n * 任务进度轮询(文档解析/向量化状态实时刷新统一入口)\n * 页面禁止自写 setInterval:统一收敛到本 hook(自动清理、标签页隐藏时暂停)\n *\n * @param {() => boolean} enabled 是否继续轮询(返回 false 自动停止)\n * @param {() => Promise<void>} tick 轮询回调(内部自行取数与回填 store)\n * @param {number} [interval] 轮询间隔毫秒(默认 3000)\n */\nimport { useRef, useEffect } from 'react'\n\nexport function useTaskPolling(enabled, tick, interval = 3000) {\n const tickRef = useRef(tick)\n tickRef.current = tick\n const enabledRef = useRef(enabled)\n enabledRef.current = enabled\n useEffect(() => {\n if (!enabled) return undefined\n let stopped = false\n let timer = null\n const run = async () => {\n if (stopped || document.hidden) {\n schedule()\n return\n }\n try {\n await tickRef.current()\n } catch {}\n schedule()\n }\n const schedule = () => {\n if (stopped) return\n timer = setTimeout(run, interval)\n }\n run()\n return () => {\n stopped = true\n if (timer) clearTimeout(timer)\n }\n }, [enabled, interval])\n}\n","/**\n * 文档检索栏:文档名称 + 文本关键词检索、按标签过滤\n * (PG 全文关键词检索在当前知识库内进行,由后端完成)\n */\nexport default function DocSearchBar({ keyword, tag, onKeyword, onTag, children }) {\n return (\n <div className=\"skai-kb-toolbar\">\n <input\n className=\"skai-kb-input skai-kb-search\"\n value={keyword}\n placeholder=\"搜索文档名称与文本内容\"\n onChange={(e) => onKeyword(e.target.value)}\n />\n <input\n className=\"skai-kb-input\"\n style={{ maxWidth: 110 }}\n value={tag}\n placeholder=\"标签过滤\"\n onChange={(e) => onTag(e.target.value)}\n />\n {children}\n </div>\n )\n}\n","/** 文档状态徽标:待解析→解析中→向量化中→已就绪→解析失败 */\nimport { DOC_STATUS_LABEL } from '../../store/doc-store.js'\n\nconst STATUS_STYLE = {\n 0: 'skai-kb-badge-gray',\n 1: 'skai-kb-badge-blue',\n 2: 'skai-kb-badge-amber',\n 3: 'skai-kb-badge-green',\n 4: 'skai-kb-badge-red',\n}\n\nexport default function DocStatusBadge({ status }) {\n return (\n <span className={`skai-kb-badge ${STATUS_STYLE[status] || 'skai-kb-badge-gray'}`}>\n {DOC_STATUS_LABEL[status] || '未知'}\n </span>\n )\n}\n","/**\n * 目录树组件(知识库详情页左栏)\n *\n * - 根目录虚拟节点(id=0)+ 服务端嵌套树渲染,点击切换当前浏览目录\n * - 编辑者/所有者:新建子目录(节点悬停 + / 树头「新建目录」)、重命名(✎)、\n * 删除空目录(✕,后端校验非空目录拒绝)\n * - 拖拽:目录同级拖拽排序(跨级不允许,spec 仅同级顺序调整);\n * 文档列表拖入目录节点/根目录 → 移动文档(onDropDoc 回调由页面处理)\n */\nimport { useCallback, useState } from 'react'\nimport { useStore } from '../../store/create-store.js'\nimport { folderStore, setCurrentFolder, dragCtx, siblingsOf, EMPTY_TREE } from '../../store/folder-store.js'\nimport { createFolder, renameFolder, reorderFolders, deleteFolder } from '../../api/folder.js'\nimport { toast, toastError } from '../../store/ui-store.js'\nimport Modal from '../common/Modal.jsx'\nimport ConfirmDialog from '../common/ConfirmDialog.jsx'\n\nexport default function FolderTree({ kbId, canEdit, onTreeChange, onDropDoc }) {\n const tree = useStore(folderStore, (s) => (s.kbId === kbId ? s.tree : EMPTY_TREE))\n const currentId = useStore(folderStore, (s) => (s.kbId === kbId ? s.currentId : 0))\n const [expanded, setExpanded] = useState({ 0: true })\n // 拖拽悬停态:{ key: 'f<id>' | 'root', pos: 'before' | 'after' | 'in' }\n const [dragOver, setDragOver] = useState(null)\n const [creating, setCreating] = useState(null) // { parentId, parentLabel }\n const [renaming, setRenaming] = useState(null) // { id, name }\n const [removing, setRemoving] = useState(null) // node\n const [newName, setNewName] = useState('')\n const [busy, setBusy] = useState(false)\n\n const toggleExpand = useCallback((id) => {\n setExpanded((prev) => ({ ...prev, [id]: !prev[id] }))\n }, [])\n\n /** 目录同级排序:拖拽插入到 target 前/后,整批提交新顺序 */\n const reorderTo = useCallback(\n (srcNode, targetNode, pos) => {\n const siblings = siblingsOf(tree, targetNode.parent_id) || []\n const ids = siblings.map((n) => n.id).filter((id) => id !== srcNode.id)\n let idx = ids.indexOf(targetNode.id)\n if (idx < 0) return\n if (pos === 'after') idx += 1\n ids.splice(idx, 0, srcNode.id)\n reorderFolders(kbId, targetNode.parent_id, ids)\n .then(() => onTreeChange())\n .catch(toastError)\n },\n [kbId, tree, onTreeChange],\n )\n\n const onDragOverNode = (e, node) => {\n if (!dragCtx.type || !canEdit) return\n e.preventDefault()\n e.dataTransfer.dropEffect = 'move'\n const key = `f${node.id}`\n if (dragCtx.type === 'doc') {\n setDragOver({ key, pos: 'in' })\n return\n }\n // 目录:仅同级排序;根目录层级(parent_id 相同)显示插入线\n if (dragCtx.id === node.id) return\n const siblings = siblingsOf(tree, node.parent_id) || []\n if (!siblings.some((n) => n.id === dragCtx.id)) return\n const rect = e.currentTarget.getBoundingClientRect()\n const pos = e.clientY - rect.top < rect.height / 2 ? 'before' : 'after'\n setDragOver({ key, pos })\n }\n\n const onDragOverRoot = (e) => {\n if (!dragCtx.type || !canEdit) return\n e.preventDefault()\n e.dataTransfer.dropEffect = 'move'\n if (dragCtx.type === 'doc') {\n setDragOver({ key: 'root', pos: 'in' })\n return\n }\n // 顶层目录排序:拖到根节点 = 移到顶层末尾\n if (dragCtx.type === 'folder' && dragCtx.parentId === 0 && dragCtx.id !== 0) {\n setDragOver({ key: 'root', pos: 'in' })\n }\n }\n\n const onDropNode = (e, node) => {\n e.preventDefault()\n const over = dragOver\n setDragOver(null)\n if (!dragCtx.type || !canEdit) return\n if (dragCtx.type === 'doc') {\n if (dragCtx.id != null) onDropDoc?.(dragCtx.id, node.id)\n return\n }\n if (dragCtx.type === 'folder' && over && over.pos !== 'in') {\n const src = findNode(tree, dragCtx.id)\n if (src) reorderTo(src, node, over.pos)\n }\n }\n\n const onDropRoot = (e) => {\n e.preventDefault()\n setDragOver(null)\n if (!dragCtx.type || !canEdit) return\n if (dragCtx.type === 'doc') {\n if (dragCtx.id != null) onDropDoc?.(dragCtx.id, 0)\n return\n }\n if (dragCtx.type === 'folder' && dragCtx.parentId === 0) {\n const siblings = tree.map((n) => n.id).filter((id) => id !== dragCtx.id)\n siblings.push(dragCtx.id)\n reorderFolders(kbId, 0, siblings)\n .then(() => onTreeChange())\n .catch(toastError)\n }\n }\n\n const submitCreate = () => {\n if (!newName.trim()) {\n toastError(new Error('请输入目录名称'))\n return\n }\n setBusy(true)\n createFolder(kbId, newName.trim(), creating.parentId)\n .then(() => {\n setExpanded((prev) => ({ ...prev, [creating.parentId]: true }))\n toast('目录已创建', 'success')\n setCreating(null)\n setNewName('')\n onTreeChange()\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const submitRename = () => {\n if (!newName.trim()) {\n toastError(new Error('请输入目录名称'))\n return\n }\n setBusy(true)\n renameFolder(kbId, renaming.id, newName.trim())\n .then(() => {\n toast('目录已重命名', 'success')\n setRenaming(null)\n setNewName('')\n onTreeChange()\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const submitDelete = () => {\n setBusy(true)\n deleteFolder(kbId, removing.id)\n .then(() => {\n toast('目录已删除', 'success')\n if (currentId === removing.id) setCurrentFolder(removing.parent_id || 0)\n setRemoving(null)\n onTreeChange()\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const nodeCls = (key, extra) => {\n let cls = `skai-kb-folder-item ${extra || ''}`\n if (dragOver && dragOver.key === key) cls += ` skai-kb-drop-${dragOver.pos}`\n return cls\n }\n\n const renderNode = (node, depth) => {\n const hasChildren = (node.children || []).length > 0\n const isOpen = !!expanded[node.id]\n const active = currentId === node.id\n return (\n <div key={node.id} className=\"skai-kb-folder-branch\">\n <div\n className={nodeCls(`f${node.id}`, active ? 'is-active' : '')}\n style={{ paddingLeft: 6 + depth * 14 }}\n onClick={() => setCurrentFolder(node.id)}\n draggable={canEdit}\n onDragStart={(e) => {\n dragCtx.type = 'folder'\n dragCtx.id = node.id\n dragCtx.parentId = node.parent_id\n e.dataTransfer.effectAllowed = 'move'\n e.dataTransfer.setData('text/plain', String(node.id))\n }}\n onDragEnd={() => {\n dragCtx.type = null\n setDragOver(null)\n }}\n onDragOver={(e) => onDragOverNode(e, node)}\n onDragLeave={() => setDragOver((prev) => (prev && prev.key === `f${node.id}` ? null : prev))}\n onDrop={(e) => onDropNode(e, node)}\n role=\"treeitem\"\n aria-selected={active}\n tabIndex={0}\n onKeyDown={(e) => e.key === 'Enter' && setCurrentFolder(node.id)}\n >\n <span\n className={`skai-kb-folder-arrow ${hasChildren ? '' : 'is-leaf'}`}\n onClick={(e) => {\n if (hasChildren) {\n e.stopPropagation()\n toggleExpand(node.id)\n }\n }}\n >\n {hasChildren ? (isOpen ? '▾' : '▸') : ''}\n </span>\n <span className=\"skai-kb-folder-icon\">📁</span>\n <span className=\"skai-kb-folder-name\" title={node.name}>\n {node.name}\n </span>\n {canEdit ? (\n <span className=\"skai-kb-folder-actions\" onClick={(e) => e.stopPropagation()}>\n <button\n type=\"button\"\n className=\"skai-kb-folder-act\"\n title=\"新建子目录\"\n onClick={() => {\n setNewName('')\n setCreating({ parentId: node.id, parentLabel: node.name })\n }}\n >\n +\n </button>\n <button\n type=\"button\"\n className=\"skai-kb-folder-act\"\n title=\"重命名\"\n onClick={() => {\n setNewName(node.name)\n setRenaming(node)\n }}\n >\n ✎\n </button>\n <button\n type=\"button\"\n className=\"skai-kb-folder-act is-danger\"\n title=\"删除(仅空目录)\"\n onClick={() => setRemoving(node)}\n >\n ✕\n </button>\n </span>\n ) : null}\n </div>\n {hasChildren && isOpen ? (\n <div className=\"skai-kb-folder-children\">{node.children.map((c) => renderNode(c, depth + 1))}</div>\n ) : null}\n </div>\n )\n }\n\n return (\n <div className=\"skai-kb-folder-tree\">\n <div className=\"skai-kb-folder-head\">\n <span className=\"skai-kb-folder-head-title\">目录</span>\n {canEdit ? (\n <button\n type=\"button\"\n className=\"skai-kb-folder-act\"\n title=\"新建顶层目录\"\n onClick={() => {\n setNewName('')\n setCreating({ parentId: 0, parentLabel: '根目录' })\n }}\n >\n + 新建\n </button>\n ) : null}\n </div>\n <div className=\"skai-kb-folder-body\" role=\"tree\">\n {/* 根目录虚拟节点:未归目录文档兜底展示 + 文档拖入目标 */}\n <div\n className={nodeCls('root', currentId === 0 ? 'is-active' : '')}\n onClick={() => setCurrentFolder(0)}\n onDragOver={onDragOverRoot}\n onDragLeave={() => setDragOver((prev) => (prev && prev.key === 'root' ? null : prev))}\n onDrop={onDropRoot}\n role=\"treeitem\"\n aria-selected={currentId === 0}\n tabIndex={0}\n onKeyDown={(e) => e.key === 'Enter' && setCurrentFolder(0)}\n >\n <span className=\"skai-kb-folder-icon\">🗂</span>\n <span className=\"skai-kb-folder-name\">根目录</span>\n </div>\n {tree.map((node) => renderNode(node, 1))}\n </div>\n\n {creating ? (\n <Modal\n title={`新建子目录 · ${creating.parentLabel}`}\n onClose={() => setCreating(null)}\n footer={\n <>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={() => setCreating(null)} disabled={busy}>\n 取消\n </button>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-primary\" onClick={submitCreate} disabled={busy}>\n 创建\n </button>\n </>\n }\n >\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">目录名称 *</span>\n <input\n className=\"skai-kb-input\"\n value={newName}\n maxLength={64}\n autoFocus\n placeholder=\"同级目录内名称唯一\"\n onChange={(e) => setNewName(e.target.value)}\n onKeyDown={(e) => e.key === 'Enter' && submitCreate()}\n />\n </div>\n </Modal>\n ) : null}\n\n {renaming ? (\n <Modal\n title=\"重命名目录\"\n onClose={() => setRenaming(null)}\n footer={\n <>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={() => setRenaming(null)} disabled={busy}>\n 取消\n </button>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-primary\" onClick={submitRename} disabled={busy}>\n 保存\n </button>\n </>\n }\n >\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">目录名称 *</span>\n <input\n className=\"skai-kb-input\"\n value={newName}\n maxLength={64}\n autoFocus\n onChange={(e) => setNewName(e.target.value)}\n onKeyDown={(e) => e.key === 'Enter' && submitRename()}\n />\n </div>\n </Modal>\n ) : null}\n\n {removing ? (\n <ConfirmDialog\n title=\"删除目录\"\n message={`确定删除目录「${removing.name}」吗?仅允许删除空目录(无子目录且无文档)。`}\n confirmText=\"删除\"\n busy={busy}\n onConfirm={submitDelete}\n onClose={() => setRemoving(null)}\n />\n ) : null}\n </div>\n )\n}\n\n/** 在树中按 id 查找节点 */\nfunction findNode(tree, id) {\n for (const node of tree || []) {\n if (node.id === id) return node\n const deep = findNode(node.children, id)\n if (deep) return deep\n }\n return null\n}\n","/**\n * 移动文档到目录弹窗(列表「移动」按钮入口)\n * 目录树平铺展示(缩进表层级),含根目录;选中后调 moveDoc\n */\nimport { useMemo, useState } from 'react'\nimport { moveDoc } from '../../api/doc.js'\nimport { useStore } from '../../store/create-store.js'\nimport { folderStore, EMPTY_TREE } from '../../store/folder-store.js'\nimport { toast, toastError } from '../../store/ui-store.js'\nimport Modal from '../common/Modal.jsx'\n\nexport default function MoveDocModal({ kbId, doc, excludeFolderId, onDone, onClose }) {\n const tree = useStore(folderStore, (s) => (s.kbId === kbId ? s.tree : EMPTY_TREE))\n const [targetId, setTargetId] = useState(0)\n const [busy, setBusy] = useState(false)\n\n /** 树平铺(深度缩进),移动中排除当前所在目录 */\n const options = useMemo(() => {\n const out = []\n const walk = (nodes, depth) => {\n for (const n of nodes || []) {\n if (n.id !== excludeFolderId) out.push({ id: n.id, name: n.name, depth })\n walk(n.children, depth + 1)\n }\n }\n walk(tree, 1)\n return out\n }, [tree, excludeFolderId])\n\n const submit = () => {\n setBusy(true)\n moveDoc(kbId, doc.id, targetId)\n .then(() => {\n toast(`已移动到「${targetId === 0 ? '根目录' : options.find((o) => o.id === targetId)?.name || '根目录'}」`, 'success')\n onDone?.()\n onClose?.()\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n return (\n <Modal\n title={`移动文档 · ${doc.name}`}\n onClose={onClose}\n footer={\n <>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={onClose} disabled={busy}>\n 取消\n </button>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-primary\" onClick={submit} disabled={busy}>\n 移动\n </button>\n </>\n }\n >\n <div className=\"skai-kb-move-list\" role=\"listbox\" aria-label=\"目标目录\">\n <button\n type=\"button\"\n className={`skai-kb-move-item ${targetId === 0 ? 'is-active' : ''}`}\n onClick={() => setTargetId(0)}\n >\n 🗂 根目录\n </button>\n {options.map((o) => (\n <button\n key={o.id}\n type=\"button\"\n className={`skai-kb-move-item ${targetId === o.id ? 'is-active' : ''}`}\n style={{ paddingLeft: 8 + o.depth * 14 }}\n onClick={() => setTargetId(o.id)}\n >\n 📁 {o.name}\n </button>\n ))}\n </div>\n </Modal>\n )\n}\n","/**\n * 拖拽上传区(md/txt/pdf/docx/图片,单文件)\n * 上传动作由父组件执行:本组件只负责选文件与格式校验\n */\nimport { useRef, useState } from 'react'\nimport { isSupportedFile, formatSize } from '../../utils/file-type.js'\n\nexport function UploadDropzone({ onPick }) {\n const inputRef = useRef(null)\n const [dragOver, setDragOver] = useState(false)\n const [error, setError] = useState('')\n const pick = (file) => {\n setError('')\n if (!file) return\n if (!isSupportedFile(file.name)) {\n setError('仅支持 md / txt / pdf / docx / 表格 / PPT / 图片文件')\n return\n }\n onPick(file)\n }\n return (\n <div>\n <div\n className=\"skai-kb-dropzone\"\n role=\"button\"\n tabIndex={0}\n aria-label=\"上传文档\"\n style={{\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: 88,\n cursor: 'pointer',\n textAlign: 'center',\n borderColor: dragOver ? 'var(--skai-kb-primary)' : undefined,\n }}\n onDragOver={(e) => {\n e.preventDefault()\n setDragOver(true)\n }}\n onDragLeave={() => setDragOver(false)}\n onDrop={(e) => {\n e.preventDefault()\n setDragOver(false)\n pick(e.dataTransfer.files && e.dataTransfer.files[0])\n }}\n onClick={() => inputRef.current?.click()}\n onKeyDown={(e) => e.key === 'Enter' && inputRef.current?.click()}\n >\n <div style={{ color: dragOver ? 'var(--skai-kb-primary)' : 'var(--skai-kb-text-sub)' }}>\n 拖拽文件到此处,或点击选择文件\n </div>\n <div className=\"skai-kb-sub\">支持 md / txt / pdf / docx / xlsx / csv / pptx / 图片,单文件上传</div>\n <input\n ref={inputRef}\n type=\"file\"\n accept=\".md,.txt,.pdf,.docx,.xlsx,.xlsm,.csv,.pptx,.jpg,.jpeg,.png,.webp,.bmp,.gif\"\n style={{ display: 'none' }}\n onChange={(e) => {\n pick(e.target.files && e.target.files[0])\n e.target.value = ''\n }}\n />\n </div>\n {error ? <div className=\"skai-kb-field-error\">{error}</div> : null}\n </div>\n )\n}\n\n/** 已选文件摘要 */\nexport function PickedFileMeta({ file }) {\n if (!file) return null\n return (\n <div className=\"skai-kb-sub\" style={{ marginTop: 4 }}>\n 已选择:{file.name}({formatSize(file.size)})\n </div>\n )\n}\n","/**\n * 分段配置表单:块大小 / 重叠长度(知识库默认 + 单文档覆盖)\n * 单文档覆盖为高级选项:留空表示使用知识库默认配置\n */\nimport { useState } from 'react'\nimport { validateChunkSize, validateChunkOverlap } from '../../utils/validator.js'\n\nexport default function ChunkConfigForm({ initial = {}, advanced = false, onChange }) {\n const [chunkSize, setChunkSize] = useState(initial.chunk_size ?? '')\n const [chunkOverlap, setChunkOverlap] = useState(initial.chunk_overlap ?? '')\n const [error, setError] = useState('')\n const emit = (size, overlap) => {\n let msg = ''\n if (size !== '') msg = validateChunkSize(size)\n if (!msg && overlap !== '') msg = validateChunkOverlap(overlap, size || 4000)\n setError(msg)\n if (msg) return\n onChange({\n chunk_size: size === '' ? null : Number(size),\n chunk_overlap: overlap === '' ? null : Number(overlap),\n })\n }\n return (\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">\n {advanced ? '分段覆盖配置(留空使用知识库默认)' : '分段配置(块大小 / 重叠长度)'}\n </span>\n <div className=\"skai-kb-field-row\">\n <input\n className=\"skai-kb-input\"\n type=\"number\"\n min={100}\n max={4000}\n value={chunkSize}\n placeholder=\"块大小(100-4000)\"\n aria-label=\"块大小\"\n onChange={(e) => {\n setChunkSize(e.target.value)\n emit(e.target.value, chunkOverlap)\n }}\n />\n <input\n className=\"skai-kb-input\"\n type=\"number\"\n min={0}\n max={500}\n value={chunkOverlap}\n placeholder=\"重叠长度(0-500)\"\n aria-label=\"重叠长度\"\n onChange={(e) => {\n setChunkOverlap(e.target.value)\n emit(chunkSize, e.target.value)\n }}\n />\n </div>\n {error ? <div className=\"skai-kb-field-error\">{error}</div> : null}\n </div>\n )\n}\n","/**\n * 版本快照时间线:查看历史文本版本、回滚(回滚自动触发重新向量化)\n */\nimport { formatTime } from '../../utils/file-type.js'\n\nexport default function VersionTimeline({ versions = [], currentVersion, canEdit, onPreview, onRollback, busy }) {\n if (!versions.length) {\n return (\n <div className=\"skai-kb-empty\">\n <p>暂无历史版本</p>\n </div>\n )\n }\n return (\n <ul className=\"skai-kb-timeline\">\n {versions.map((v) => (\n <li key={v.version_no}>\n <div className=\"skai-kb-row-between\">\n <span className=\"skai-kb-title\">\n v{v.version_no}\n {v.version_no === currentVersion ? (\n <span className=\"skai-kb-tag\" style={{ marginLeft: 6 }}>\n 当前\n </span>\n ) : null}\n </span>\n <span className=\"skai-kb-sub\">{formatTime(v.create_time)}</span>\n </div>\n <div className=\"skai-kb-row\" style={{ marginTop: 4 }}>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-sm\" onClick={() => onPreview(v)}>\n 查看内容\n </button>\n {canEdit && v.version_no !== currentVersion ? (\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-sm\" disabled={busy} onClick={() => onRollback(v)}>\n 回滚到此版本\n </button>\n ) : null}\n </div>\n </li>\n ))}\n </ul>\n )\n}\n","/**\n * 成员公开资料批量获取(权限配置成员列表展示昵称/头像/脱敏手机号)\n *\n * 数据源:用户中心开放接口 window.SHIKEAI_GET_MEMBER_INFO(按 uid 批量查询,\n * 云端 member/batch_info 手机号服务端脱敏,明文不出服务端);仅用于展示,\n * 不作为可信身份。接口未挂载(用户中心未安装或为旧版本)时不发请求,\n * 列表回退展示 (#uid)。\n *\n * 会话级缓存:uid → 资料,切换知识库/成员去重后只拉取未缓存过的 uid\n */\nimport { useMemo, useState, useEffect } from 'react'\n\nconst infoCache = new Map()\n\n/**\n * 按手机号查询会员 uid(添加管理员/成员前解析目标身份用)\n * 数据源:用户中心开放接口 window.SHIKEAI_GET_MEMBER_UID_BY_MOBILE(云端\n * member/uid_by_mobile 精确匹配,命中返回 { uid, nickname, avatar, mobile },\n * mobile 为脱敏值);接口未挂载(用户中心为旧版本)、未命中、游客态或请求\n * 失败时返回 null,调用方按「未注册」回退到手机号 md5 待激活授权\n * @param {string} mobile 11 位大陆手机号\n * @returns {Promise<{uid:number|string, nickname:string, avatar:string, mobile:string}|null>}\n */\nexport function findMemberByMobile(mobile) {\n const query = typeof window !== 'undefined' ? window.SHIKEAI_GET_MEMBER_UID_BY_MOBILE : null\n if (typeof query !== 'function') return Promise.resolve(null)\n return Promise.resolve()\n .then(() => query(mobile))\n .then((data) => (data && Number(data.uid) > 0 ? data : null))\n .catch(() => null)\n}\n\nfunction buildInfoMap(uidList) {\n const map = {}\n uidList.forEach((uid) => {\n const info = infoCache.get(Number(uid))\n if (info) map[String(uid)] = info\n })\n return map\n}\n\n/**\n * @param {number[]} uids 成员 uid 列表\n * @returns {{ infoMap: Record<string, {uid:number|string, nickname:string, avatar:string, mobile:string}> }}\n */\nexport function useMemberInfo(uids = []) {\n const uidKey = useMemo(\n () => [...new Set(uids.map(Number).filter((uid) => uid > 0))].sort((a, b) => a - b).join(','),\n [uids],\n )\n const [infoMap, setInfoMap] = useState(() => buildInfoMap(uidKey ? uidKey.split(',') : []))\n useEffect(() => {\n const uidList = uidKey ? uidKey.split(',') : []\n setInfoMap(buildInfoMap(uidList))\n if (!uidList.length) return\n const fetchInfo = typeof window !== 'undefined' ? window.SHIKEAI_GET_MEMBER_INFO : null\n if (typeof fetchInfo !== 'function') return\n const missing = uidList.filter((uid) => !infoCache.has(Number(uid)))\n if (!missing.length) return\n let cancelled = false\n fetchInfo(missing)\n .then((data) => {\n if (cancelled || !data) return\n Object.values(data).forEach((info) => {\n const uid = Number(info && info.uid)\n if (uid) infoCache.set(uid, info)\n })\n setInfoMap(buildInfoMap(uidList))\n })\n .catch(() => {})\n return () => {\n cancelled = true\n }\n }, [uidKey])\n return { infoMap }\n}\n","/**\n * 成员列表:头像/昵称/脱敏手机号(用户中心开放接口批量获取,仅展示)、\n * 所有者/编辑者/只读标识、移除成员(所有者操作)\n * 成员资料拉取失败或用户中心未提供接口时回退 (#uid) 展示;\n * 待激活行(按手机号预添加、目标用户尚未登录过)显示脱敏手机号与撤销按钮\n */\nimport { useMemberInfo } from '../../hooks/use-member-info.js'\nimport { ROLE_LABEL } from '../../store/kb-store.js'\nimport { formatTime } from '../../utils/file-type.js'\n\nexport default function MemberList({ members = [], isAdmin, canManage, onRoleChange, onRemove, busy }) {\n const { infoMap } = useMemberInfo(members.filter((m) => m.uid).map((m) => m.uid))\n if (!members.length) {\n return (\n <div className=\"skai-kb-empty\">\n <p>暂无成员</p>\n </div>\n )\n }\n return (\n <div>\n {members.map((m) => {\n // 待激活行:无 uid,以手机号脱敏串标识\n if (m.pending) {\n return (\n <div key={`pending-${m.pending_id}`} className=\"skai-kb-member-row\">\n <span className=\"skai-kb-member-avatar skai-kb-member-avatar-fallback\" aria-hidden=\"true\">\n 📱\n </span>\n <div className=\"skai-kb-member-main\">\n <span className=\"skai-kb-member-name\">{m.masked_mobile || '未激活手机号'}</span>\n <span className=\"skai-kb-sub\">待激活:该用户登录知识库后自动生效</span>\n </div>\n <span className=\"skai-kb-badge skai-kb-badge-gray\">{ROLE_LABEL[m.role] || '只读'}</span>\n <span className=\"skai-kb-sub\">{formatTime(m.create_time)}</span>\n {canManage ? (\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm skai-kb-btn-ghost-danger\"\n disabled={busy}\n onClick={() => onRemove(m)}\n >\n 撤销\n </button>\n ) : null}\n </div>\n )\n }\n const info = infoMap[String(m.uid)]\n const nickname = (info?.nickname || m.nickname || '').trim()\n const initial = nickname ? nickname.slice(0, 1).toUpperCase() : '#'\n return (\n <div key={m.uid} className=\"skai-kb-member-row\">\n {info?.avatar ? (\n <img className=\"skai-kb-member-avatar\" src={info.avatar} alt=\"\" />\n ) : (\n <span className=\"skai-kb-member-avatar skai-kb-member-avatar-fallback\" aria-hidden=\"true\">\n {initial}\n </span>\n )}\n <div className=\"skai-kb-member-main\">\n <span className=\"skai-kb-member-name\">\n {nickname ? `${nickname} ` : ''}(UID:{m.uid})\n </span>\n {info?.mobile ? <span className=\"skai-kb-member-mobile\">{info.mobile}</span> : null}\n </div>\n {isAdmin ? (\n <select\n className=\"skai-kb-select\"\n style={{ width: 96, flex: 'none' }}\n value={m.role}\n disabled={busy}\n onChange={(e) => onRoleChange(m, Number(e.target.value))}\n aria-label={`修改成员 ${m.uid} 角色`}\n >\n <option value={1}>{ROLE_LABEL[1]}</option>\n <option value={2}>{ROLE_LABEL[2]}</option>\n <option value={3}>{ROLE_LABEL[3]}</option>\n </select>\n ) : (\n <span className={`skai-kb-badge ${m.role === 1 ? 'skai-kb-badge-blue' : 'skai-kb-badge-gray'}`}>\n {ROLE_LABEL[m.role] || '只读'}\n </span>\n )}\n <span className=\"skai-kb-sub\">{formatTime(m.create_time)}</span>\n {canManage ? (\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm skai-kb-btn-ghost-danger\"\n disabled={busy}\n onClick={() => onRemove(m)}\n >\n 移除\n </button>\n ) : null}\n </div>\n )\n })}\n </div>\n )\n}\n","/**\n * 添加成员弹窗:两种方式(所有者操作)\n * - 按手机号:目标用户登录过 → 即时生效;未登录过 → 落待激活授权,其登录后自动补全 uid 生效\n * - 从用户列表选择:候选为平台「正常」状态用户(头像/昵称/脱敏手机号),支持按\n * uid / 昵称 / 手机号片段搜索、多选(已在知识库中的用户禁选)、批量授权\n */\nimport { useEffect, useMemo, useState } from 'react'\nimport Modal from '../common/Modal.jsx'\nimport { ROLE_LABEL } from '../../store/kb-store.js'\nimport { validateMobile } from '../../utils/validator.js'\nimport { listUserOptions } from '../../api/user.js'\nimport { useMemberInfo } from '../../hooks/use-member-info.js'\nimport { toastError } from '../../store/ui-store.js'\n\n/** 候选拉取上限(正常用户全量,前端过滤 + 分页:昵称数据在用户中心,无法库内搜索) */\nconst FETCH_LIMIT = 500\nconst PAGE_SIZE = 8\n\nexport default function MemberGrantModal({ busy, onSubmit, onClose, existingUids = [] }) {\n const [mode, setMode] = useState('mobile') // mobile=按手机号 | pick=从用户列表选择\n const [mobile, setMobile] = useState('')\n const [role, setRole] = useState(2)\n const [error, setError] = useState('')\n\n // 选择模式:候选(正常状态用户全量)→ 前端按 uid/昵称/手机号过滤 → 分页\n const [keyword, setKeyword] = useState('')\n const [options, setOptions] = useState([])\n const [loaded, setLoaded] = useState(false)\n const [page, setPage] = useState(1)\n const [pickedUids, setPickedUids] = useState([]) // 多选:候选 uid 列表(保持点选顺序)\n const existing = useMemo(() => new Set(existingUids.map(Number)), [existingUids])\n const { infoMap } = useMemberInfo(mode === 'pick' ? options.map((u) => u.uid) : [])\n\n useEffect(() => {\n if (mode !== 'pick' || loaded) return\n let cancelled = false\n listUserOptions({ keyword: '', page: 1, limit: FETCH_LIMIT })\n .then((data) => {\n if (cancelled) return\n setOptions(data?.list || [])\n setLoaded(true)\n })\n .catch((e) => {\n if (!cancelled) toastError(e)\n })\n return () => {\n cancelled = true\n }\n }, [mode, loaded])\n\n /** 候选手机号展示值:插件库 masked_mobile 优先,用户中心公开资料 mobile 兜底(均为脱敏值) */\n const mobileOf = (u) => u.masked_mobile || infoMap[String(u.uid)]?.mobile || ''\n\n /** 手机号片段匹配:所见即所搜(脱敏串 includes);输入完整 11 位明文号码时\n * 按脱敏串「前 3 位 + 后 4 位」比对(脱敏中间段无法匹配,属数据边界) */\n const mobileMatch = (masked, kw) => {\n if (!masked) return false\n if (masked.toLowerCase().includes(kw)) return true\n if (/^\\d{11}$/.test(kw)) return masked.slice(0, 3) === kw.slice(0, 3) && masked.slice(-4) === kw.slice(-4)\n return false\n }\n\n /** 过滤:uid / 昵称 / 脱敏手机号(昵称、兜底手机号来自用户中心公开资料) */\n const filtered = useMemo(() => {\n const kw = keyword.trim().toLowerCase()\n if (!kw) return options\n return options.filter((u) => {\n if (String(u.uid).includes(kw)) return true\n if (mobileMatch(mobileOf(u), kw)) return true\n const nickname = (infoMap[String(u.uid)]?.nickname || '').toLowerCase()\n return nickname.includes(kw)\n })\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [options, keyword, infoMap])\n\n const totalPages = Math.max(1, Math.ceil(filtered.length / PAGE_SIZE))\n const safePage = Math.min(page, totalPages)\n const pageItems = filtered.slice((safePage - 1) * PAGE_SIZE, safePage * PAGE_SIZE)\n\n const togglePick = (u) => {\n if (existing.has(Number(u.uid))) return\n setPickedUids((prev) => (prev.includes(u.uid) ? prev.filter((x) => x !== u.uid) : [...prev, u.uid]))\n }\n\n const submit = () => {\n if (mode === 'mobile') {\n const msg = validateMobile(mobile)\n if (msg) {\n setError(msg)\n return\n }\n onSubmit({ mobile: String(mobile).replace(/[\\s-]/g, ''), role })\n return\n }\n if (!pickedUids.length) {\n setError('请先从列表中选择用户(支持多选)')\n return\n }\n onSubmit({ uids: pickedUids, role })\n }\n\n return (\n <Modal\n title=\"添加成员\"\n onClose={onClose}\n footer={\n <>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={onClose} disabled={busy}>\n 取消\n </button>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-primary\" onClick={submit} disabled={busy}>\n {busy\n ? '添加中…'\n : mode === 'pick' && pickedUids.length\n ? `添加(已选 ${pickedUids.length} 人)`\n : '添加'}\n </button>\n </>\n }\n >\n {/* 添加方式切换 */}\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">添加方式</span>\n <div className=\"skai-kb-row-actions\">\n <button\n type=\"button\"\n className={`skai-kb-btn skai-kb-btn-sm ${mode === 'mobile' ? 'skai-kb-btn-primary' : ''}`}\n onClick={() => {\n setMode('mobile')\n setError('')\n }}\n >\n 按手机号\n </button>\n <button\n type=\"button\"\n className={`skai-kb-btn skai-kb-btn-sm ${mode === 'pick' ? 'skai-kb-btn-primary' : ''}`}\n onClick={() => {\n setMode('pick')\n setPickedUids([])\n setError('')\n }}\n >\n 从用户列表选择\n </button>\n </div>\n </div>\n\n {mode === 'mobile' ? (\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">成员手机号 *</span>\n <input\n className=\"skai-kb-input\"\n value={mobile}\n inputMode=\"tel\"\n maxLength={13}\n placeholder=\"11 位大陆手机号,如 13812345678\"\n onChange={(e) => setMobile(e.target.value)}\n />\n </div>\n ) : (\n <>\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">选择用户 *</span>\n <input\n className=\"skai-kb-input\"\n value={keyword}\n placeholder=\"搜索 uid、昵称或手机号片段\"\n onChange={(e) => {\n setKeyword(e.target.value)\n setPage(1)\n }}\n />\n </div>\n\n {/* 已选 chips(可移除) */}\n {pickedUids.length ? (\n <div className=\"skai-kb-picked-chips\">\n {pickedUids.map((uid) => {\n const info = infoMap[String(uid)]\n const nickname = (info?.nickname || '').trim()\n return (\n <span key={uid} className=\"skai-kb-picked-chip\">\n {info?.avatar ? <img className=\"skai-kb-picked-chip-avatar\" src={info.avatar} alt=\"\" /> : null}\n <span className=\"skai-kb-picked-chip-text\">{nickname || `uid ${uid}`}</span>\n <button\n type=\"button\"\n className=\"skai-kb-picked-chip-remove\"\n aria-label={`移除 ${nickname || uid}`}\n onClick={() => setPickedUids((prev) => prev.filter((x) => x !== uid))}\n >\n ×\n </button>\n </span>\n )\n })}\n </div>\n ) : null}\n\n <div className=\"skai-kb-user-pick-list\" role=\"listbox\" aria-label=\"用户候选列表\" aria-multiselectable=\"true\">\n {!loaded ? (\n <div className=\"skai-kb-sub\">加载中…</div>\n ) : pageItems.length === 0 ? (\n <div className=\"skai-kb-sub\">\n {options.length ? '无匹配用户' : '暂无候选用户(仅展示「正常」状态用户)'}\n </div>\n ) : (\n pageItems.map((u) => {\n const uidNum = Number(u.uid)\n const inKb = existing.has(uidNum)\n const checked = pickedUids.includes(u.uid)\n const info = infoMap[String(u.uid)]\n const nickname = (info?.nickname || '').trim()\n const initial = nickname ? nickname.slice(0, 1).toUpperCase() : '#'\n const mobileView = u.masked_mobile || info?.mobile || '手机号未知'\n return (\n <button\n key={u.uid}\n type=\"button\"\n role=\"option\"\n aria-selected={checked}\n disabled={inKb}\n className={`skai-kb-user-pick-item ${checked ? 'skai-kb-user-pick-item-active' : ''} ${inKb ? 'skai-kb-user-pick-item-disabled' : ''}`}\n onClick={() => togglePick(u)}\n >\n <span className={`skai-kb-pick-check ${checked ? 'skai-kb-pick-check-on' : ''}`} aria-hidden=\"true\">\n {checked ? '✓' : ''}\n </span>\n <span className=\"skai-kb-row\" style={{ minWidth: 0, flex: 1 }}>\n {info?.avatar ? (\n <img className=\"skai-kb-member-avatar\" src={info.avatar} alt=\"\" />\n ) : (\n <span className=\"skai-kb-member-avatar skai-kb-member-avatar-fallback\" aria-hidden=\"true\">\n {initial}\n </span>\n )}\n <span style={{ minWidth: 0 }}>\n <span className=\"skai-kb-user-pick-nickname\">\n {nickname || '用户'}(uid {u.uid})\n </span>\n <span className=\"skai-kb-sub\" style={{ display: 'block', padding: 0 }}>\n {mobileView}\n </span>\n </span>\n </span>\n {inKb ? <span className=\"skai-kb-badge skai-kb-badge-gray\">已在知识库</span> : null}\n </button>\n )\n })\n )}\n </div>\n {totalPages > 1 ? (\n <div className=\"skai-kb-row-actions\" style={{ marginTop: 6 }}>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm\"\n disabled={safePage <= 1}\n onClick={() => setPage((p) => Math.max(1, p - 1))}\n >\n 上一页\n </button>\n <span className=\"skai-kb-sub\">\n {safePage} / {totalPages} · 共 {filtered.length} 人\n </span>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm\"\n disabled={safePage >= totalPages}\n onClick={() => setPage((p) => p + 1)}\n >\n 下一页\n </button>\n </div>\n ) : null}\n </>\n )}\n\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">角色</span>\n <select className=\"skai-kb-select\" value={role} onChange={(e) => setRole(Number(e.target.value))}>\n <option value={2}>{ROLE_LABEL[2]}(上传、新增、修改文档)</option>\n <option value={3}>{ROLE_LABEL[3]}(查看文档、预览)</option>\n <option value={1}>{ROLE_LABEL[1]}(全部管理权限)</option>\n </select>\n </div>\n <div className=\"skai-kb-sub\">\n {mode === 'mobile'\n ? '通过手机号添加:已注册用户直接添加生效;尚未注册的用户会先创建待激活授权,其注册并登录知识库后自动成为成员'\n : '从列表选择:仅展示「正常」状态用户,可多选批量添加;已在知识库中的用户不可重复添加'}\n </div>\n {error ? <div className=\"skai-kb-field-error\">{error}</div> : null}\n </Modal>\n )\n}\n","/**\n * 知识库成员权限配置弹窗(知识库详情页内打开)\n * 成员列表、角色管理(所有者);权限变更实时写 PG,\n * 后端同步失效 Redis 权限缓存(cache:kb_perm:{uid})\n */\nimport { useCallback, useEffect, useState } from 'react'\nimport Modal from '../common/Modal.jsx'\nimport ConfirmDialog from '../common/ConfirmDialog.jsx'\nimport MemberList from './MemberList.jsx'\nimport MemberGrantModal from './MemberGrantModal.jsx'\nimport { listPermission, grantPermission, revokePermission, revokePendingPermission } from '../../api/kb.js'\nimport { findMemberByMobile } from '../../hooks/use-member-info.js'\nimport { toast, toastError } from '../../store/ui-store.js'\n\nexport default function PermissionModal({ kbId, kbName, isAdmin, onClose }) {\n const [members, setMembers] = useState([])\n const [granting, setGranting] = useState(false)\n const [removing, setRemoving] = useState(null)\n const [busy, setBusy] = useState(false)\n\n const reload = useCallback(() => {\n if (kbId == null) return\n listPermission(kbId)\n .then((data) => setMembers(data?.list || []))\n .catch(toastError)\n }, [kbId])\n\n useEffect(() => {\n reload()\n }, [reload])\n\n const submitGrant = (data) => {\n setBusy(true)\n // 从用户列表选择(多选):逐个按 uid 授权,allSettled 聚合成败\n if (data.uids?.length) {\n Promise.allSettled(data.uids.map((uid) => grantPermission(kbId, { uid: Number(uid), role: data.role })))\n .then((results) => {\n const ok = results.filter((r) => r.status === 'fulfilled').length\n const fail = results.length - ok\n if (ok) toast(`已添加 ${ok} 名成员${fail ? `,${fail} 名失败` : ''}`, fail ? 'info' : 'success')\n if (fail) toast(`${fail} 名用户添加失败,请重试`, 'error')\n if (!fail) setGranting(false)\n reload()\n })\n .finally(() => setBusy(false))\n return\n }\n // 从用户列表选择(单个,兼容):直接按 uid 授权\n if (data.uid) {\n grantPermission(kbId, { uid: Number(data.uid), role: data.role })\n .then(() => {\n toast('成员已添加', 'success')\n setGranting(false)\n reload()\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n return\n }\n // 按手机号添加:先经用户中心按手机号解析 uid:已注册 → 直接按 uid 授权;\n // 未注册(或用户中心接口不可用)→ 回退手机号 md5 待激活授权\n findMemberByMobile(data.mobile)\n .then((member) => {\n if (member) {\n const label = member.nickname ? `${member.nickname}(uid ${member.uid})` : `uid ${member.uid}`\n return grantPermission(kbId, { uid: Number(member.uid), role: data.role }).then(() => {\n toast(`已添加成员 ${label}`, 'success')\n setGranting(false)\n reload()\n })\n }\n return grantPermission(kbId, { mobile: data.mobile, role: data.role }).then((res) => {\n toast(\n res?.pending\n ? '该手机号尚未注册,已创建待激活授权,其注册登录后自动生效'\n : '成员已添加',\n 'success',\n )\n setGranting(false)\n reload()\n })\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const changeRole = (m, role) => {\n setBusy(true)\n grantPermission(kbId, { uid: m.uid, role })\n .then(() => {\n toast('角色已更新', 'success')\n reload()\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const submitRemove = () => {\n setBusy(true)\n // 待激活行:撤销预授权;正式成员:移除授权\n const req = removing.pending\n ? revokePendingPermission(kbId, removing.pending_id)\n : revokePermission(kbId, removing.uid)\n req\n .then(() => {\n toast(removing.pending ? '已撤销待激活授权' : '成员已移除', 'success')\n setRemoving(null)\n reload()\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n return (\n <>\n <Modal\n title={`成员权限 · ${kbName || `知识库 #${kbId}`}`}\n onClose={onClose}\n footer={\n isAdmin ? (\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-primary\"\n onClick={() => setGranting(true)}\n >\n 添加成员\n </button>\n ) : null\n }\n >\n {!isAdmin ? (\n <div className=\"skai-kb-sub\" style={{ marginBottom: 6 }}>\n 仅所有者可管理成员与角色\n </div>\n ) : null}\n <MemberList\n members={members}\n isAdmin={isAdmin}\n canManage={isAdmin}\n onRoleChange={changeRole}\n onRemove={setRemoving}\n busy={busy}\n />\n </Modal>\n {granting ? (\n <MemberGrantModal\n busy={busy}\n existingUids={members.map((m) => m.uid).filter((uid) => Number(uid) > 0)}\n onSubmit={submitGrant}\n onClose={() => setGranting(false)}\n />\n ) : null}\n {removing ? (\n <ConfirmDialog\n title={removing.pending ? '撤销待激活授权' : '移除成员'}\n message={\n removing.pending\n ? `确定撤销手机号 ${removing.masked_mobile || ''} 的待激活授权吗?撤销后该手机号登录将不再自动获得权限。`\n : `确定移除成员 #${removing.uid} 吗?移除后其将无法访问该知识库。`\n }\n confirmText={removing.pending ? '撤销' : '移除'}\n busy={busy}\n onConfirm={submitRemove}\n onClose={() => setRemoving(null)}\n />\n ) : null}\n </>\n )\n}\n","/**\n * 知识库详情页(独立标签页正文,params: { kbId })\n *\n * - 页头:知识库名称 / 角色 / MCP 状态;返回列表、权限配置、编辑、重建向量\n * - 文档列表:名称+文本关键词检索、标签过滤、分页;点击文档打开「文档详情」标签页\n * - 添加文档:拖拽/单文件上传(md/txt/pdf/docx),标签与分段覆盖配置\n * - 解析/向量化状态轮询(use-task-polling);失败重解析\n * - 知识库成员权限配置(弹窗,所有者)\n */\nimport { useCallback, useEffect, useState } from 'react'\nimport { useStore } from '../../store/create-store.js'\nimport {\n docStore,\n setDocList,\n setDocKeyword,\n setDocTagFilter,\n setDocPage,\n patchDocStatus,\n} from '../../store/doc-store.js'\nimport { folderStore, setFolderTree, setCurrentFolder, dragCtx, EMPTY_TREE } from '../../store/folder-store.js'\nimport { kbStore, upsertKb } from '../../store/kb-store.js'\nimport { setDocName, setKbName } from '../../store/title-store.js'\nimport { toast, toastError } from '../../store/ui-store.js'\nimport {\n listDocs,\n uploadDoc,\n deleteDoc,\n reparseDoc,\n listDocVersions,\n rollbackDoc,\n moveDoc,\n reorderDocs,\n} from '../../api/doc.js'\nimport { getFolderTree } from '../../api/folder.js'\nimport { listKb, updateKb } from '../../api/kb.js'\nimport { rebuildVector } from '../../api/task.js'\nimport { useKbPermission } from '../../hooks/use-kb-permission.js'\nimport { useTaskPolling } from '../../hooks/use-task-polling.js'\nimport { formatTime, EXT_LABEL, extOf } from '../../utils/file-type.js'\nimport { ROLE_LABEL } from '../../store/kb-store.js'\nimport DocSearchBar from '../../components/doc/DocSearchBar.jsx'\nimport DocStatusBadge from '../../components/doc/DocStatusBadge.jsx'\nimport FolderTree from '../../components/doc/FolderTree.jsx'\nimport MoveDocModal from '../../components/doc/MoveDocModal.jsx'\nimport { UploadDropzone, PickedFileMeta } from '../../components/doc/UploadDropzone.jsx'\nimport ChunkConfigForm from '../../components/doc/ChunkConfigForm.jsx'\nimport VersionTimeline from '../../components/doc/VersionTimeline.jsx'\nimport TagPicker from '../../components/kb/TagPicker.jsx'\nimport KbFormModal from '../../components/kb/KbFormModal.jsx'\nimport Modal from '../../components/common/Modal.jsx'\nimport ConfirmDialog from '../../components/common/ConfirmDialog.jsx'\nimport PermissionModal from '../../components/permission/PermissionModal.jsx'\nimport Toast from '../../components/common/Toast.jsx'\n\n/**\n * @param {object} props\n * @param {number} props.kbId 知识库 id(导航参数)\n * @param {string} [props.view] 导航视图提示('permission' 时自动打开权限配置)\n * @param {{ openDoc: (kbId: number, docId: number) => void, openHome: () => void }} props.nav\n */\nexport default function KbDetailPage({ kbId, view, nav }) {\n const kb = useStore(kbStore, (s) => s.list.find((k) => k.id === kbId))\n const list = useStore(docStore, (s) => s.list)\n const total = useStore(docStore, (s) => s.total)\n const page = useStore(docStore, (s) => s.page)\n const limit = useStore(docStore, (s) => s.limit)\n const keyword = useStore(docStore, (s) => s.keyword)\n const tagFilter = useStore(docStore, (s) => s.tagFilter)\n // 当前浏览目录(0=根目录);文档列表按目录过滤\n const folderTree = useStore(folderStore, (s) => (s.kbId === kbId ? s.tree : EMPTY_TREE))\n const currentFolderId = useStore(folderStore, (s) => (s.kbId === kbId ? s.currentId : 0))\n const { canEdit, canManage, isAdmin } = useKbPermission(kbId)\n const [uploading, setUploading] = useState(false)\n const [pickedFile, setPickedFile] = useState(null)\n const [uploadTags, setUploadTags] = useState([])\n const [uploadChunk, setUploadChunk] = useState({ chunk_size: null, chunk_overlap: null })\n const [uploadFolderId, setUploadFolderId] = useState(0)\n const [deleting, setDeleting] = useState(null)\n const [moving, setMoving] = useState(null)\n const [dragOverDocId, setDragOverDocId] = useState(null)\n const [menuDocId, setMenuDocId] = useState(null) // 卡片右上角「操作」下拉当前打开的文档 id\n const [versionsOf, setVersionsOf] = useState(null)\n const [versions, setVersions] = useState([])\n const [editing, setEditing] = useState(false)\n const [permissionOpen, setPermissionOpen] = useState(false)\n const [busy, setBusy] = useState(false)\n\n /** 文档列表加载(防串库:仅当返回仍属于当前 kbId 时回填;按当前目录递归列出其子树全部文档) */\n const reload = useCallback(\n (p = page) => {\n if (kbId == null) return\n listDocs(kbId, { keyword, tag: tagFilter, folderId: currentFolderId, recursive: true, page: p, limit })\n .then((data) => {\n const docList = data?.list || []\n setDocList(kbId, docList, data?.total || 0, p, limit)\n docList.forEach((d) => setDocName(kbId, d.id, d.name))\n })\n .catch(toastError)\n },\n [kbId, keyword, tagFilter, page, limit, currentFolderId],\n )\n\n /** 目录树加载(进入页面/结构变更后) */\n const reloadTree = useCallback(() => {\n if (kbId == null) return\n getFolderTree(kbId)\n .then((tree) => setFolderTree(kbId, tree || []))\n .catch(toastError)\n }, [kbId])\n\n // 切换知识库(新开/重新导航标签页)重置筛选并拉取列表 + 目录树\n useEffect(() => {\n setDocKeyword('')\n setDocTagFilter('')\n setDocPage(1)\n setCurrentFolder(0)\n reloadTree()\n reload(1)\n }, [kbId])\n\n useEffect(() => {\n reload(1)\n }, [keyword, tagFilter, currentFolderId])\n\n // 知识库元信息缺失时(直接打开详情标签页)拉一次列表补齐 + 标签页名称\n useEffect(() => {\n if (kb || kbId == null) return\n listKb({ page: 1, limit: 100 })\n .then((data) => {\n const kbList = data?.list || []\n const found = kbList.find((k) => k.id === kbId)\n if (found) {\n upsertKb(found)\n setKbName(found.id, found.name)\n }\n })\n .catch(() => {})\n }, [kb, kbId])\n\n // 解析中/向量化中的文档自动轮询刷新\n useTaskPolling(\n kbId != null && list.some((d) => d.status === 0 || d.status === 1 || d.status === 2),\n async () => {\n const data = await listDocs(kbId, { page, limit, keyword, tag: tagFilter })\n const docList = data?.list || []\n setDocList(kbId, docList, data?.total || 0, page, limit)\n docList.forEach((d) => setDocName(kbId, d.id, d.name))\n },\n )\n\n // 导航参数 view=permission:打开权限配置弹窗(每次重新导航都会步进 revision,\n // 以 revision 为依赖保证同参数再次导航也能弹出)\n useEffect(() => {\n if (view === 'permission' && isAdmin) setPermissionOpen(true)\n }, [view, kbId, isAdmin])\n\n const submitUpload = () => {\n if (!pickedFile) {\n toastError(new Error('请先选择文件'))\n return\n }\n setBusy(true)\n uploadDoc({\n kbId,\n file: pickedFile,\n tags: uploadTags,\n chunkSize: uploadChunk.chunk_size || '',\n chunkOverlap: uploadChunk.chunk_overlap || '',\n folderId: uploadFolderId,\n })\n .then((data) => {\n toast('文档已上传,开始解析', 'success')\n // 后端检测到模型未配置时返回 warning(向量化 / OCR,多行分隔),逐条警示\n if (data?.warning) {\n String(data.warning).split('\\n').forEach((m) => toast(m, 'warning', 6000))\n }\n setUploading(false)\n setPickedFile(null)\n setUploadTags([])\n setUploadChunk({ chunk_size: null, chunk_overlap: null })\n // 上传目标目录即当前浏览目录(默认),列表同步刷新\n reload(1)\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n /** 文档拖入目录树节点 → 移动到目标目录(0=根目录) */\n const submitDropMove = (docId, folderId) => {\n moveDoc(kbId, docId, folderId)\n .then(() => {\n toast(`已移动到「${folderId === 0 ? '根目录' : folderLabel(folderTree, folderId)}」`, 'success')\n reload(page)\n })\n .catch(toastError)\n }\n\n /** 文档拖拽排序(同目录内;drop 到目标文档前/后,整批提交该目录顺序;递归列表跨目录拖拽仅提示) */\n const submitDocReorder = (srcDoc, targetDoc, pos) => {\n if (srcDoc.id === targetDoc.id) return\n if ((srcDoc.folder_id || 0) !== (targetDoc.folder_id || 0)) {\n toast('跨目录调整请把文档拖到左侧目录树的目标目录', 'info')\n return\n }\n const ids = list\n .filter((d) => (d.folder_id || 0) === (srcDoc.folder_id || 0))\n .map((d) => d.id)\n .filter((id) => id !== srcDoc.id)\n let idx = ids.indexOf(targetDoc.id)\n if (idx < 0) return\n if (pos === 'after') idx += 1\n ids.splice(idx, 0, srcDoc.id)\n reorderDocs(kbId, srcDoc.folder_id || 0, ids)\n .then(() => reload(page))\n .catch(toastError)\n }\n\n const openVersions = (doc) => {\n setVersionsOf(doc)\n setVersions([])\n listDocVersions(kbId, doc.id)\n .then((data) => setVersions(data?.list || []))\n .catch(toastError)\n }\n\n const submitRollback = (v) => {\n setBusy(true)\n rollbackDoc(kbId, versionsOf.id, v.version_no)\n .then(() => {\n toast(`已回滚到 v${v.version_no},正在重新向量化`, 'success')\n setVersionsOf(null)\n reload(page)\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const submitDelete = () => {\n setBusy(true)\n deleteDoc(kbId, deleting.id)\n .then(() => {\n toast('文档已删除', 'success')\n setDeleting(null)\n reload(page)\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const submitReparse = (doc) => {\n reparseDoc(kbId, doc.id)\n .then(() => {\n patchDocStatus(doc.id, { status: 0 })\n toast('已提交重新解析', 'success')\n })\n .catch(toastError)\n }\n\n const submitRebuild = () => {\n setBusy(true)\n rebuildVector(kbId)\n .then((res) => {\n toast(`已提交向量重建任务${res?.task_id ? `(#${res.task_id})` : ''}`, 'success')\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n if (kbId == null) {\n return (\n <div className=\"skai-kb-page\">\n <div className=\"skai-kb-empty\">\n <p>缺少知识库参数</p>\n <p className=\"skai-kb-empty-sub\">请从首页的知识库列表进入</p>\n <div className=\"skai-kb-row\" style={{ justifyContent: 'center', marginTop: 10 }}>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-sm\" onClick={() => nav.openHome()}>\n 返回首页\n </button>\n </div>\n </div>\n <Toast />\n </div>\n )\n }\n\n const totalPages = Math.max(1, Math.ceil(total / limit))\n\n return (\n <div className=\"skai-kb-page\">\n {/* 页头(固定) */}\n <div className=\"skai-kb-detail-head\">\n <div className=\"skai-kb-row-between\">\n <div className=\"skai-kb-row\" style={{ minWidth: 0 }}>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm skai-kb-back\"\n onClick={() => nav.openHome()}\n title=\"返回知识库列表\"\n >\n ‹ 列表\n </button>\n <span className=\"skai-kb-detail-title\" title={kb ? kb.name : ''}>\n {kb ? kb.name : `知识库 #${kbId}`}\n </span>\n <span className={`skai-kb-badge ${kb?.my_role === 1 || kb?.my_role === 5 ? 'skai-kb-badge-blue' : 'skai-kb-badge-gray'}`}>\n {ROLE_LABEL[kb?.my_role] || '只读'}\n </span>\n {kb ? (\n <span className={`skai-kb-badge ${kb.enable_mcp ? 'skai-kb-badge-green' : 'skai-kb-badge-gray'}`}>\n {kb.enable_mcp ? 'MCP 开' : 'MCP 关'}\n </span>\n ) : null}\n </div>\n <div className=\"skai-kb-row\">\n {isAdmin ? (\n <>\n <button\n type=\"button\"\n className=\"skai-kb-btn\"\n onClick={() => setPermissionOpen(true)}\n >\n 权限配置\n </button>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={() => setEditing(true)}>\n 编辑\n </button>\n <button type=\"button\" className=\"skai-kb-btn\" disabled={busy} onClick={submitRebuild}>\n 重建向量\n </button>\n </>\n ) : null}\n </div>\n </div>\n </div>\n\n {/* 滚动区:目录树 + 文档工具栏 + 列表 + 分页 */}\n <div className=\"skai-kb-page-scroll\">\n <div className=\"skai-kb-doc-layout\">\n {/* 左栏:目录树 */}\n <FolderTree\n kbId={kbId}\n canEdit={canEdit}\n onTreeChange={reloadTree}\n onDropDoc={submitDropMove}\n />\n\n {/* 右栏:文档区 */}\n <div className=\"skai-kb-doc-main\">\n {/* 文档工具栏 */}\n <DocSearchBar keyword={keyword} tag={tagFilter} onKeyword={setDocKeyword} onTag={setDocTagFilter}>\n {canEdit ? (\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-primary\"\n onClick={() => {\n setUploadFolderId(currentFolderId)\n setUploading(true)\n }}\n >\n 添加文档\n </button>\n ) : null}\n </DocSearchBar>\n\n {/* 文档列表 */}\n {list.length === 0 ? (\n <div className=\"skai-kb-empty\">\n <p>暂无文档</p>\n <p className=\"skai-kb-empty-sub\">\n {canEdit ? '支持 md / txt / pdf / docx 上传,也可拖入左侧目录' : '支持 md / txt / pdf / docx'}\n </p>\n </div>\n ) : (\n <div className=\"skai-kb-card-list\">\n {list.map((doc, idx) => (\n <div\n key={doc.id}\n className={`skai-kb-card skai-kb-doc-item ${dragOverDocId === doc.id ? 'skai-kb-drop-in' : ''}`}\n onClick={() => nav.openDoc(kbId, doc.id)}\n role=\"button\"\n tabIndex={0}\n onKeyDown={(e) => e.key === 'Enter' && nav.openDoc(kbId, doc.id)}\n draggable={canEdit}\n onDragStart={(e) => {\n dragCtx.type = 'doc'\n dragCtx.id = doc.id\n e.dataTransfer.effectAllowed = 'move'\n e.dataTransfer.setData('text/plain', String(doc.id))\n }}\n onDragEnd={() => {\n dragCtx.type = null\n setDragOverDocId(null)\n }}\n onDragOver={(e) => {\n if (dragCtx.type !== 'doc' || dragCtx.id === doc.id || !canEdit) return\n e.preventDefault()\n e.dataTransfer.dropEffect = 'move'\n setDragOverDocId(doc.id)\n }}\n onDragLeave={() => setDragOverDocId((prev) => (prev === doc.id ? null : prev))}\n onDrop={(e) => {\n e.preventDefault()\n e.stopPropagation()\n const srcId = dragCtx.id\n dragCtx.type = null\n setDragOverDocId(null)\n const src = list.find((d) => d.id === srcId)\n if (src && src.id !== doc.id) {\n const rect = e.currentTarget.getBoundingClientRect()\n const pos = e.clientY - rect.top < rect.height / 2 ? 'before' : 'after'\n submitDocReorder(src, doc, pos)\n }\n }}\n data-idx={idx}\n >\n <div className=\"skai-kb-row-between\">\n <span className=\"skai-kb-title\" title={doc.name}>\n {doc.name}\n </span>\n <span className=\"skai-kb-doc-topbar\">\n <DocStatusBadge status={doc.status} />\n {canEdit ? (\n <span className=\"skai-kb-doc-menu-anchor\" onClick={(e) => e.stopPropagation()}>\n <button\n type=\"button\"\n className=\"skai-kb-doc-menu-trigger\"\n title=\"操作\"\n aria-expanded={menuDocId === doc.id}\n onClick={(e) => {\n e.stopPropagation()\n setMenuDocId(menuDocId === doc.id ? null : doc.id)\n }}\n >\n 操作\n <span className=\"skai-kb-caret\" aria-hidden=\"true\" />\n </button>\n {menuDocId === doc.id ? (\n <>\n <div className=\"skai-kb-menu-mask\" onClick={() => setMenuDocId(null)} />\n <div className=\"skai-kb-menu\" role=\"menu\">\n <button\n type=\"button\"\n className=\"skai-kb-menu-item\"\n role=\"menuitem\"\n onClick={() => {\n setMenuDocId(null)\n setMoving(doc)\n }}\n >\n 移动到…\n </button>\n {canManage ? (\n <button\n type=\"button\"\n className=\"skai-kb-menu-item is-danger\"\n role=\"menuitem\"\n onClick={() => {\n setMenuDocId(null)\n setDeleting(doc)\n }}\n >\n 删除\n </button>\n ) : null}\n </div>\n </>\n ) : null}\n </span>\n ) : null}\n </span>\n </div>\n <div className=\"skai-kb-kb-meta\">\n <span>{EXT_LABEL[extOf(doc.name)] || doc.file_type || '文件'}</span>\n <span>🕒 {formatTime(doc.update_time)}</span>\n {doc.chunk_count ? <span>🧩 {doc.chunk_count} 向量块</span> : null}\n {(doc.folder_id || 0) !== currentFolderId ? (\n <span title=\"来自下级目录\">📁 {folderLabel(folderTree, doc.folder_id)}</span>\n ) : null}\n </div>\n {doc.tags && doc.tags.length ? (\n <div style={{ marginTop: 4 }}>\n {doc.tags.map((t) => (\n <span key={t} className=\"skai-kb-tag\">\n {t}\n </span>\n ))}\n </div>\n ) : null}\n {doc.status === 4 && doc.error_msg ? (\n <div className=\"skai-kb-field-error\" style={{ marginTop: 4 }}>\n 失败原因:{doc.error_msg}\n </div>\n ) : null}\n {canEdit && doc.status === 4 ? (\n <div className=\"skai-kb-kb-actions\" onClick={(e) => e.stopPropagation()}>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm\"\n onClick={() => submitReparse(doc)}\n >\n 重新解析\n </button>\n </div>\n ) : null}\n </div>\n ))}\n </div>\n )}\n\n {/* 分页 */}\n {totalPages > 1 ? (\n <div className=\"skai-kb-pagination\">\n <span>\n 第 {page} / {totalPages} 页 · 共 {total} 篇\n </span>\n <div className=\"skai-kb-pagination-btns\">\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm\"\n disabled={page <= 1}\n onClick={() => {\n setDocPage(page - 1)\n reload(page - 1)\n }}\n >\n 上一页\n </button>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm\"\n disabled={page >= totalPages}\n onClick={() => {\n setDocPage(page + 1)\n reload(page + 1)\n }}\n >\n 下一页\n </button>\n </div>\n </div>\n ) : null}\n </div>\n </div>\n </div>\n\n {/* 上传文档弹窗 */}\n {uploading ? (\n <Modal\n title=\"添加文档\"\n onClose={() => setUploading(false)}\n footer={\n <>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={() => setUploading(false)} disabled={busy}>\n 取消\n </button>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-primary\"\n onClick={submitUpload}\n disabled={busy || !pickedFile}\n >\n {busy ? '上传中…' : '上传'}\n </button>\n </>\n }\n >\n <UploadDropzone onPick={setPickedFile} />\n <PickedFileMeta file={pickedFile} />\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">目标目录</span>\n <select\n className=\"skai-kb-input\"\n value={uploadFolderId}\n onChange={(e) => setUploadFolderId(Number(e.target.value))}\n >\n <option value={0}>根目录</option>\n {flattenFolderOptions(folderTree).map((o) => (\n <option key={o.id} value={o.id}>\n {' '.repeat(o.depth - 1)}\n {o.name}\n </option>\n ))}\n </select>\n <span className=\"skai-kb-field-hint\">默认为当前浏览的目录</span>\n </div>\n <div className=\"skai-kb-field\" style={{ marginTop: 8 }}>\n <span className=\"skai-kb-field-label\">标签</span>\n <TagPicker value={uploadTags} onChange={setUploadTags} />\n </div>\n <ChunkConfigForm advanced onChange={setUploadChunk} />\n </Modal>\n ) : null}\n\n {/* 历史版本弹窗 */}\n {versionsOf ? (\n <Modal title={`历史版本 · ${versionsOf.name}`} onClose={() => setVersionsOf(null)}>\n <VersionTimeline\n versions={versions}\n currentVersion={versionsOf.version_no}\n canEdit={canEdit}\n busy={busy}\n onPreview={() => toast('请在文档详情标签页查看内容', 'info')}\n onRollback={submitRollback}\n />\n </Modal>\n ) : null}\n\n {/* 移动文档弹窗 */}\n {moving ? (\n <MoveDocModal\n kbId={kbId}\n doc={moving}\n excludeFolderId={moving.folder_id || 0}\n onDone={() => reload(page)}\n onClose={() => setMoving(null)}\n />\n ) : null}\n\n {/* 删除文档确认 */}\n {deleting ? (\n <ConfirmDialog\n title=\"删除文档\"\n message={`确定删除「${deleting.name}」吗?删除后 MCP 检索将不再返回该文档。`}\n confirmText=\"删除\"\n busy={busy}\n onConfirm={submitDelete}\n onClose={() => setDeleting(null)}\n />\n ) : null}\n\n {/* 编辑知识库 */}\n {editing && kb ? (\n <KbFormModal\n initial={kb}\n busy={busy}\n onSubmit={(data) => {\n setBusy(true)\n updateKb(kbId, data)\n .then((updated) => {\n const merged = updated || { ...kb, ...data }\n upsertKb(merged)\n setKbName(merged.id, merged.name)\n toast('已保存', 'success')\n setEditing(false)\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }}\n onClose={() => setEditing(false)}\n />\n ) : null}\n\n {/* 权限配置弹窗 */}\n {permissionOpen ? (\n <PermissionModal kbId={kbId} kbName={kb?.name} isAdmin={isAdmin} onClose={() => setPermissionOpen(false)} />\n ) : null}\n <Toast />\n </div>\n )\n}\n\n/** 目录树平铺为下拉选项(depth 从 1 起,缩进用) */\nfunction flattenFolderOptions(tree) {\n const out = []\n const walk = (nodes, depth) => {\n for (const n of nodes || []) {\n out.push({ id: n.id, name: n.name, depth })\n walk(n.children, depth + 1)\n }\n }\n walk(tree, 1)\n return out\n}\n\n/** 按 id 查目录名称(toast 文案用) */\nfunction folderLabel(tree, folderId) {\n const found = flattenFolderOptions(tree).find((o) => o.id === folderId)\n return found ? found.name : `目录 #${folderId}`\n}\n","/**\n * 轻量 Markdown 渲染(无第三方依赖;文档详情页正文)\n *\n * - 文本一律作为 React 文本节点渲染(不经 dangerouslySetInnerHTML / innerHTML),\n * 文档内容中的 <script> 等片段只会原样展示,无注入面\n * - 块级:标题 #~######、围栏代码块 ```、引用 >、无序/有序列表、表格 |…|、\n * 分隔线 ---、段落\n * - 行内:`代码`、**粗体**、__粗体__、*斜体*、~~删除线~~、[链接](url)、\n * 、裸 http(s) 链接\n */\nimport { useMemo, Fragment } from 'react'\n\n/** 行内标记扫描:按优先级依次匹配,命中即递归处理内容 */\nconst INLINE_PATTERN =\n /(`[^`\\n]+`)|(\\*\\*[^*\\n]+\\*\\*)|(__[^_\\n]+__)|(\\*[^*\\n]+\\*)|(~~[^~\\n]+~~)|(!\\[[^\\]\\n]*\\]\\([^)\\s]+\\))|(\\[[^\\]\\n]+\\]\\([^)\\s]+\\))|(https?:\\/\\/[^\\s<>()[\\]]+)/g\n\n/** 递归渲染行内元素(key 前缀保证列表稳定;每次调用独立正则实例,避免递归串扰 lastIndex) */\nfunction renderInline(text, keyPrefix = 'i') {\n const re = new RegExp(INLINE_PATTERN.source, INLINE_PATTERN.flags)\n const nodes = []\n let last = 0\n let m\n let idx = 0\n while ((m = re.exec(text))) {\n if (m.index > last) nodes.push(text.slice(last, m.index))\n const tok = m[0]\n const key = `${keyPrefix}-${idx++}`\n if (tok.startsWith('`')) {\n nodes.push(\n <code key={key} className=\"skai-kb-md-code\">\n {tok.slice(1, -1)}\n </code>,\n )\n } else if (tok.startsWith('**') || tok.startsWith('__')) {\n nodes.push(<strong key={key}>{renderInline(tok.slice(2, -2), key)}</strong>)\n } else if (tok.startsWith('~~')) {\n nodes.push(<del key={key}>{renderInline(tok.slice(2, -2), key)}</del>)\n } else if (tok.startsWith('*')) {\n nodes.push(<em key={key}>{renderInline(tok.slice(1, -1), key)}</em>)\n } else if (tok.startsWith('![')) {\n const mm = /^!\\[([^\\]]*)\\]\\(([^)\\s]+)\\)$/.exec(tok)\n if (mm) {\n nodes.push(<img key={key} className=\"skai-kb-md-img\" src={mm[2]} alt={mm[1] || ''} loading=\"lazy\" />)\n } else {\n nodes.push(tok)\n }\n } else if (tok.startsWith('[')) {\n const mm = /^\\[([^\\]]+)\\]\\(([^)\\s]+)\\)$/.exec(tok)\n if (mm) {\n nodes.push(\n <a key={key} className=\"skai-kb-md-link\" href={mm[2]} target=\"_blank\" rel=\"noopener noreferrer\">\n {renderInline(mm[1], key)}\n </a>,\n )\n } else {\n nodes.push(tok)\n }\n } else {\n nodes.push(\n <a key={key} className=\"skai-kb-md-link\" href={tok} target=\"_blank\" rel=\"noopener noreferrer\">\n {tok}\n </a>,\n )\n }\n last = re.lastIndex\n }\n if (last < text.length) nodes.push(text.slice(last))\n return nodes\n}\n\n/** 表格行解析:| a | b | → ['a','b'](容忍首尾竖线缺失) */\nfunction splitTableRow(line) {\n return line\n .replace(/^\\s*\\|/, '')\n .replace(/\\|\\s*$/, '')\n .split('|')\n .map((c) => c.trim())\n}\n\nfunction isTableDivider(line) {\n return /^\\s*\\|?[\\s:-]*-[\\s:|-]*\\|?\\s*$/.test(line) && line.includes('-')\n}\n\n/** 块级解析:行数组 → React 元素数组 */\nfunction renderBlocks(lines, keyPrefix = 'b') {\n const blocks = []\n let i = 0\n let idx = 0\n const k = () => `${keyPrefix}-${idx++}`\n while (i < lines.length) {\n const line = lines[i]\n // 围栏代码块\n if (/^\\s*```/.test(line)) {\n const lang = line.replace(/^\\s*```/, '').trim()\n const buf = []\n i++\n while (i < lines.length && !/^\\s*```/.test(lines[i])) {\n buf.push(lines[i])\n i++\n }\n i++ // 跳过收尾 ```\n blocks.push(\n <pre key={k()} className=\"skai-kb-md-pre\" data-lang={lang || undefined}>\n <code>{buf.join('\\n')}</code>\n </pre>,\n )\n continue\n }\n // 标题\n const h = /^(#{1,6})\\s+(.*)$/.exec(line)\n if (h) {\n const level = h[1].length\n const content = renderInline(h[2].replace(/\\s+#+\\s*$/, ''), `${k()}-h`)\n const Tag = `h${Math.min(level + 1, 6)}` // 页内标题从 h2 起,避免抢标签页语义\n blocks.push(\n <Tag key={k()} className={`skai-kb-md-h skai-kb-md-h${level}`}>\n {content}\n </Tag>,\n )\n i++\n continue\n }\n // 分隔线\n if (/^\\s*(-{3,}|\\*{3,}|_{3,})\\s*$/.test(line)) {\n blocks.push(<hr key={k()} className=\"skai-kb-md-hr\" />)\n i++\n continue\n }\n // 引用(连续 > 行)\n if (/^\\s*>/.test(line)) {\n const buf = []\n while (i < lines.length && /^\\s*>/.test(lines[i])) {\n buf.push(lines[i].replace(/^\\s*>\\s?/, ''))\n i++\n }\n blocks.push(\n <blockquote key={k()} className=\"skai-kb-md-quote\">\n {renderBlocks(buf, `${k()}-q`)}\n </blockquote>,\n )\n continue\n }\n // 表格(表头行 + 分隔行)\n if (line.includes('|') && i + 1 < lines.length && isTableDivider(lines[i + 1]) && lines[i + 1].includes('|')) {\n const head = splitTableRow(line)\n i += 2\n const rows = []\n while (i < lines.length && lines[i].includes('|') && lines[i].trim() !== '') {\n rows.push(splitTableRow(lines[i]))\n i++\n }\n blocks.push(\n <div key={k()} className=\"skai-kb-md-table-wrap\">\n <table className=\"skai-kb-md-table\">\n <thead>\n <tr>\n {head.map((c, ci) => (\n <th key={ci}>{renderInline(c, `${k()}-th${ci}`)}</th>\n ))}\n </tr>\n </thead>\n <tbody>\n {rows.map((r, ri) => (\n <tr key={ri}>\n {r.map((c, ci) => (\n <td key={ci}>{renderInline(c, `${k()}-td${ri}-${ci}`)}</td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>,\n )\n continue\n }\n // 无序列表\n if (/^\\s*[-*+]\\s+/.test(line)) {\n const items = []\n while (i < lines.length && /^\\s*[-*+]\\s+/.test(lines[i])) {\n items.push(lines[i].replace(/^\\s*[-*+]\\s+/, ''))\n i++\n }\n blocks.push(\n <ul key={k()} className=\"skai-kb-md-ul\">\n {items.map((it, ii) => (\n <li key={ii}>{renderInline(it, `${k()}-li${ii}`)}</li>\n ))}\n </ul>,\n )\n continue\n }\n // 有序列表\n if (/^\\s*\\d+[.)]\\s+/.test(line)) {\n const items = []\n while (i < lines.length && /^\\s*\\d+[.)]\\s+/.test(lines[i])) {\n items.push(lines[i].replace(/^\\s*\\d+[.)]\\s+/, ''))\n i++\n }\n blocks.push(\n <ol key={k()} className=\"skai-kb-md-ol\">\n {items.map((it, ii) => (\n <li key={ii}>{renderInline(it, `${k()}-oli${ii}`)}</li>\n ))}\n </ol>,\n )\n continue\n }\n // 空行\n if (line.trim() === '') {\n i++\n continue\n }\n // 段落(连续非空、非特殊行合并;软换行以 <br/> 呈现)\n const buf = [line]\n i++\n while (\n i < lines.length &&\n lines[i].trim() !== '' &&\n !/^\\s*```/.test(lines[i]) &&\n !/^(#{1,6})\\s+/.test(lines[i]) &&\n !/^\\s*>/.test(lines[i]) &&\n !/^\\s*[-*+]\\s+/.test(lines[i]) &&\n !/^\\s*\\d+[.)]\\s+/.test(lines[i]) &&\n !/^\\s*(-{3,}|\\*{3,}|_{3,})\\s*$/.test(lines[i])\n ) {\n buf.push(lines[i])\n i++\n }\n blocks.push(\n <p key={k()} className=\"skai-kb-md-p\">\n {buf.map((ln, li) => (\n <Fragment key={li}>\n {li > 0 ? <br /> : null}\n {renderInline(ln, `${k()}-p${li}`)}\n </Fragment>\n ))}\n </p>,\n )\n }\n return blocks\n}\n\n/**\n * Markdown 渲染组件\n * @param {object} props\n * @param {string} props.text markdown 原文\n */\nexport default function Markdown({ text }) {\n const blocks = useMemo(() => renderBlocks(String(text || '').split(/\\r?\\n/)), [text])\n return <div className=\"skai-kb-md\">{blocks}</div>\n}\n","/**\n * Markdown 可视化编辑器(文档详情页正文区,组件内自管草稿状态)\n *\n * - 布局:工具栏 + 编辑区(默认「编辑」模式,占满父容器高度),可切换 仅编辑/分屏/仅预览;\n * - 工具栏:标题、加粗、斜体、删除线、行内代码、无序/有序列表、引用、代码块、\n * 表格、链接 —— 对选区包裹或行首插入前缀\n * - 保存:onSave(content, force);HTTP 409 冲突时由父级弹「放弃/覆盖」引导,\n * 覆盖重试时 force=true(本组件保持草稿不重置)\n * - 预览复用 Markdown 渲染组件(无 dangerouslySetInnerHTML,无注入面)\n */\nimport { useEffect, useRef, useState } from 'react'\nimport Markdown from '../markdown/Markdown.jsx'\nimport { SpinnerGlyph } from '../common/icons.jsx'\n\n/** 工具栏动作定义:wrap=选区包裹;line=行首前缀;block=整块插入 */\nconst TOOLBAR = [\n { label: 'H2', title: '标题', kind: 'line', arg: '## ' },\n { label: 'H3', title: '三级标题', kind: 'line', arg: '### ' },\n { label: 'B', title: '加粗', kind: 'wrap', arg: '**' },\n { label: 'I', title: '斜体', kind: 'wrap', arg: '*' },\n { label: 'S', title: '删除线', kind: 'wrap', arg: '~~' },\n { label: '‹›', title: '行内代码', kind: 'wrap', arg: '`' },\n { label: '• 列表', title: '无序列表', kind: 'line', arg: '- ' },\n { label: '1. 列表', title: '有序列表', kind: 'line', arg: '1. ' },\n { label: '❝ 引用', title: '引用', kind: 'line', arg: '> ' },\n {\n label: '{}. 代码块',\n title: '代码块',\n kind: 'block',\n arg: '\\n```\\n\\n```\\n',\n cursorOffset: -5, // 定位到首尾 ``` 之间的空行\n },\n {\n label: '▦ 表格',\n title: '表格',\n kind: 'block',\n arg: '\\n| 列1 | 列2 | 列3 |\\n| --- | --- | --- |\\n| | | |\\n',\n cursorOffset: -21,\n },\n { label: '🔗 链接', title: '链接', kind: 'wrap', arg: '[', suffix: '](https://)' },\n]\n\n/**\n * @param {object} props\n * @param {string} props.initial 进入编辑时的原文\n * @param {boolean} props.saving 保存中(禁用按钮)\n * @param {(content: string, force: boolean) => void} props.onSave\n * @param {() => void} props.onCancel\n * @param {((draft: string) => void) | undefined} props.onAIWrite AI 编写入口(传入时在视图切换行首渲染按钮,携带当前草稿)\n * @param {boolean} [props.aiRunning] AI 编写进行中(按钮禁用并显示进度文案)\n */\nexport default function MarkdownEditor({ initial, saving, onSave, onCancel, onAIWrite, aiRunning }) {\n const [draft, setDraft] = useState(initial)\n // 视图模式:split 分屏 / edit 仅编辑 / preview 仅预览\n const [viewMode, setViewMode] = useState('edit')\n const taRef = useRef(null)\n\n // 内容被外部重载(重新进入编辑)时重置草稿\n useEffect(() => setDraft(initial), [initial])\n\n /** 应用工具栏动作:wrap 包裹选区 / line 行首前缀 / block 插入整块 */\n const applyAction = (act) => {\n const ta = taRef.current\n if (!ta) return\n const { selectionStart: start, selectionEnd: end, value } = ta\n let next = value\n let cursor = end\n if (act.kind === 'wrap') {\n const sel = value.slice(start, end) || act.placeholder || ''\n const suffix = act.suffix || act.arg\n next = value.slice(0, start) + act.arg + sel + suffix + value.slice(end)\n cursor = start + act.arg.length + sel.length\n } else if (act.kind === 'line') {\n // 行首插入前缀(多行逐行加)\n const lineStart = value.lastIndexOf('\\n', start - 1) + 1\n const seg = value.slice(lineStart, end)\n const prefixed = seg\n .split('\\n')\n .map((ln) => (ln.trim() === '' && seg.includes('\\n') ? ln : act.arg + ln))\n .join('\\n')\n next = value.slice(0, lineStart) + prefixed + value.slice(end)\n cursor = lineStart + prefixed.length\n } else if (act.kind === 'block') {\n next = value.slice(0, end) + act.arg + value.slice(end)\n cursor = end + act.arg.length + (act.cursorOffset || 0)\n }\n setDraft(next)\n // 等状态回写后恢复焦点与选区\n requestAnimationFrame(() => {\n ta.focus()\n ta.setSelectionRange(cursor, cursor)\n })\n }\n\n const dirty = draft !== initial\n\n return (\n <div className={`skai-kb-editor ${viewMode}`}>\n <div className=\"skai-kb-editor-bar\">\n <div className=\"skai-kb-editor-tools\">\n {TOOLBAR.map((act) => (\n <button\n key={act.label}\n type=\"button\"\n className=\"skai-kb-editor-tool\"\n title={act.title}\n disabled={saving}\n onMouseDown={(e) => e.preventDefault()}\n onClick={() => applyAction(act)}\n >\n {act.label}\n </button>\n ))}\n </div>\n <div className=\"skai-kb-editor-modes\">\n {onAIWrite ? (\n <button\n type=\"button\"\n className=\"skai-kb-btn\"\n onClick={() => onAIWrite(draft)}\n disabled={aiRunning}\n title=\"AI 修改完善文档,结果回填编辑框\"\n >\n {aiRunning ? (\n <>\n <SpinnerGlyph />\n 编写中\n </>\n ) : (\n 'AI编写'\n )}\n </button>\n ) : null}\n <button\n type=\"button\"\n className={`skai-kb-editor-mode ${viewMode === 'edit' ? 'is-active' : ''}`}\n onClick={() => setViewMode('edit')}\n >\n 编辑\n </button>\n <button\n type=\"button\"\n className={`skai-kb-editor-mode ${viewMode === 'split' ? 'is-active' : ''}`}\n onClick={() => setViewMode('split')}\n >\n 分屏\n </button>\n <button\n type=\"button\"\n className={`skai-kb-editor-mode ${viewMode === 'preview' ? 'is-active' : ''}`}\n onClick={() => setViewMode('preview')}\n >\n 预览\n </button>\n {dirty ? <span className=\"skai-kb-editor-dirty\">未保存</span> : null}\n <button type=\"button\" className=\"skai-kb-btn\" onClick={onCancel} disabled={saving}>\n 取消\n </button>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-primary\"\n disabled={saving || !draft.trim()}\n onClick={() => onSave(draft, false)}\n >\n {saving ? '保存中…' : '保存'}\n </button>\n </div>\n </div>\n <div className={`skai-kb-editor-panes ${viewMode}`}>\n {viewMode !== 'preview' ? (\n <textarea\n ref={taRef}\n className=\"skai-kb-editor-input\"\n value={draft}\n spellCheck={false}\n placeholder=\"输入 Markdown 内容…\"\n onChange={(e) => setDraft(e.target.value)}\n onKeyDown={(e) => {\n // Cmd/Ctrl+B 加粗、Cmd/Ctrl+I 斜体、Cmd/Ctrl+S 保存\n if ((e.metaKey || e.ctrlKey) && !e.shiftKey) {\n const k = e.key.toLowerCase()\n if (k === 'b') {\n e.preventDefault()\n applyAction(TOOLBAR[2])\n } else if (k === 'i') {\n e.preventDefault()\n applyAction(TOOLBAR[3])\n } else if (k === 's') {\n e.preventDefault()\n if (!saving && draft.trim()) onSave(draft, false)\n }\n }\n // Tab 缩进两个空格\n if (e.key === 'Tab') {\n e.preventDefault()\n const ta = e.currentTarget\n const { selectionStart: s, selectionEnd: t, value } = ta\n setDraft(value.slice(0, s) + ' ' + value.slice(t))\n requestAnimationFrame(() => ta.setSelectionRange(s + 2, s + 2))\n }\n }}\n />\n ) : null}\n {viewMode !== 'edit' ? (\n <div className=\"skai-kb-editor-preview\">\n <Markdown text={draft} />\n </div>\n ) : null}\n </div>\n </div>\n )\n}\n","/**\n * 文档详情页(独立标签页正文,params: { kbId, docId },markdown 格式渲染)\n *\n * - 页头:文档名称 / 状态 / 类型 / 更新时间;返回知识库、引用文档到会话(输入框插入\n * 不可编辑引用 chip,降级纯文本/剪贴板)、历史版本、重新解析、删除(按角色展示)\n * - 正文:所有入库内容统一为 Markdown(上传时 pdf/docx 已由后端解析整理为 md),一律按 Markdown 渲染\n * (在线文本预览由后端解析后的文本承载)\n * - 版本:历史快照查看、回滚(回滚自动触发重新向量化)\n * - 编辑:重命名 / 标签 / 分段覆盖配置(编辑者与所有者)\n * - 在线编辑:「编辑内容」进入 Markdown 可视化编辑器(默认「编辑」模式 + 格式工具栏;所有文档\n * 上传时已由后端统一解析整理为 Markdown 存储),保存触发版本快照与重新解析/向量化,\n * updated_at 乐观校验冲突时引导放弃/覆盖\n */\nimport { useCallback, useEffect, useRef, useState } from 'react'\nimport { useStore } from '../../store/create-store.js'\nimport { docStore, patchDocStatus } from '../../store/doc-store.js'\nimport { setDocName } from '../../store/title-store.js'\nimport { toast, toastError } from '../../store/ui-store.js'\nimport { ROLE_LABEL } from '../../store/kb-store.js'\nimport { kbStore } from '../../store/kb-store.js'\nimport {\n getDoc,\n getDocContent,\n listDocVersions,\n rollbackDoc,\n updateDoc,\n updateDocContent,\n deleteDoc,\n reparseDoc,\n} from '../../api/doc.js'\nimport { runAIWriteSession, insertSessionReference } from '../../core/dsh-agent.js'\nimport { buildDocReferenceInsert, refSerializeText } from '../../core/kb-trigger.js'\nimport { useKbPermission } from '../../hooks/use-kb-permission.js'\nimport { useTaskPolling } from '../../hooks/use-task-polling.js'\nimport { formatTime, EXT_LABEL, extOf } from '../../utils/file-type.js'\nimport DocStatusBadge from '../../components/doc/DocStatusBadge.jsx'\nimport MarkdownEditor from '../../components/doc/MarkdownEditor.jsx'\nimport ChunkConfigForm from '../../components/doc/ChunkConfigForm.jsx'\nimport VersionTimeline from '../../components/doc/VersionTimeline.jsx'\nimport TagPicker from '../../components/kb/TagPicker.jsx'\nimport Markdown from '../../components/markdown/Markdown.jsx'\nimport Modal from '../../components/common/Modal.jsx'\nimport ConfirmDialog from '../../components/common/ConfirmDialog.jsx'\nimport Toast from '../../components/common/Toast.jsx'\nimport { FullscreenGlyph, FullscreenExitGlyph, SpinnerGlyph } from '../../components/common/icons.jsx'\n\n/** AI 编写默认提示词(弹窗内可修改) */\nconst AI_WRITE_PROMPT_DEFAULT = '修改和完善文档并排版,保持内容不变,不额外增加原有文档没有的内容。'\n\n/**\n * @param {object} props\n * @param {number} props.kbId 知识库 id\n * @param {number} props.docId 文档 id\n * @param {{ openKb: (kbId: number) => void }} props.nav\n */\nexport default function DocDetailPage({ kbId, docId, nav }) {\n const kb = useStore(kbStore, (s) => s.list.find((k) => k.id === kbId))\n const listDoc = useStore(docStore, (s) => s.list.find((d) => d.id === docId))\n const { canEdit, canManage, isAdmin } = useKbPermission(kbId)\n const [meta, setMeta] = useState(null)\n const [content, setContent] = useState('')\n const [loading, setLoading] = useState(true)\n const [contentError, setContentError] = useState('')\n const [versionsOpen, setVersionsOpen] = useState(false)\n const [versionsFull, setVersionsFull] = useState(false) // 历史版本弹窗全屏态\n const [versions, setVersions] = useState([])\n const [editing, setEditing] = useState(false)\n const [editName, setEditName] = useState('')\n const [editTags, setEditTags] = useState([])\n const [editChunk, setEditChunk] = useState({ chunk_size: null, chunk_overlap: null })\n const [previewVersion, setPreviewVersion] = useState(null)\n const [previewFull, setPreviewFull] = useState(false) // 版本内容预览弹窗全屏态\n const [deleting, setDeleting] = useState(false)\n const [busy, setBusy] = useState(false)\n // 在线编辑(Markdown 可视化编辑)\n const [editorOpen, setEditorOpen] = useState(false)\n const [savingContent, setSavingContent] = useState(false)\n const [conflict, setConflict] = useState(null) // { content } 乐观锁冲突待决(放弃/覆盖)\n // AI 编写(编辑器工具栏入口 → 提示词弹窗 → 独立子会话 → assistant 消息全文回填草稿)\n const [aiOpen, setAiOpen] = useState(false)\n const [aiPrompt, setAiPrompt] = useState(AI_WRITE_PROMPT_DEFAULT)\n const [aiRunning, setAiRunning] = useState(false)\n const [aiSource, setAiSource] = useState('') // 本次 AI 编写的输入底稿(编辑器当前草稿)\n const aiAbandonRef = useRef(false) // 「取消等待」置位:不再接收本次结果写回\n\n /** 文档元数据:详情接口优先,失败回退列表缓存 */\n const loadMeta = useCallback(() => {\n if (kbId == null || docId == null) return Promise.resolve(null)\n return getDoc(kbId, docId)\n .then((doc) => {\n setMeta(doc)\n setDocName(kbId, docId, doc.name)\n return doc\n })\n .catch(() => {\n if (listDoc) {\n setMeta(listDoc)\n setDocName(kbId, docId, listDoc.name)\n return listDoc\n }\n return null\n })\n }, [kbId, docId, listDoc])\n\n /** 正文内容 */\n const loadContent = useCallback(\n (versionNo) => {\n if (kbId == null || docId == null) return\n setLoading(true)\n setContentError('')\n getDocContent(kbId, docId, versionNo)\n .then((data) => setContent((data && data.content) || ''))\n .catch((e) => setContentError(e.msg || e.message || '内容加载失败'))\n .finally(() => setLoading(false))\n },\n [kbId, docId],\n )\n\n useEffect(() => {\n setMeta(null)\n setContent('')\n aiAbandonRef.current = true // 切换文档:放弃在途 AI 结果写回\n setAiRunning(false)\n setPreviewVersion(null)\n setPreviewFull(false)\n setVersionsOpen(false)\n setVersionsFull(false)\n loadMeta().finally(() => loadContent())\n }, [kbId, docId])\n\n // 组件卸载:放弃在途 AI 结果写回\n useEffect(() => () => {\n aiAbandonRef.current = true\n }, [])\n\n // 解析中/向量化中状态轮询(仅元数据,正文在「已就绪」后手动/重新进入查看)\n useTaskPolling(\n meta != null && (meta.status === 0 || meta.status === 1 || meta.status === 2),\n async () => {\n const doc = await loadMeta()\n if (doc && doc.status === 3 && (meta?.status || 0) < 3) loadContent()\n },\n )\n\n const openVersions = () => {\n setVersionsOpen(true)\n setVersions([])\n listDocVersions(kbId, docId)\n // 接口返回裸数组(data 即版本列表;?.list 为历史误读导致列表恒空)\n .then((data) => setVersions(Array.isArray(data) ? data : data?.list || []))\n .catch(toastError)\n }\n\n const submitRollback = (v) => {\n setBusy(true)\n rollbackDoc(kbId, docId, v.version_no)\n .then(() => {\n toast(`已回滚到 v${v.version_no},正在重新向量化`, 'success')\n setVersionsOpen(false)\n setPreviewVersion(null)\n loadMeta().then((doc) => {\n if (doc && doc.status === 3) loadContent()\n })\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const openEdit = () => {\n setEditName(meta?.name || '')\n setEditTags(meta?.tags || [])\n setEditChunk({ chunk_size: meta?.chunk_size || null, chunk_overlap: meta?.chunk_overlap || null })\n setEditing(true)\n }\n\n const submitEdit = () => {\n if (!editName.trim()) {\n toastError(new Error('请输入文档名称'))\n return\n }\n setBusy(true)\n updateDoc(kbId, docId, {\n name: editName.trim(),\n tags: editTags,\n chunk_size: editChunk.chunk_size,\n chunk_overlap: editChunk.chunk_overlap,\n })\n .then(() => {\n toast('已保存,文档重新向量化中', 'success')\n setEditing(false)\n loadMeta().then((doc) => {\n if (doc && doc.status === 3) loadContent()\n })\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const submitDelete = () => {\n setBusy(true)\n deleteDoc(kbId, docId)\n .then(() => {\n toast('文档已删除', 'success')\n nav.openKb(kbId)\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const submitReparse = () => {\n reparseDoc(kbId, docId)\n .then(() => {\n patchDocStatus(docId, { status: 0 })\n if (meta) setMeta({ ...meta, status: 0 })\n toast('已提交重新解析', 'success')\n })\n .catch(toastError)\n }\n\n /** 在线编辑保存:版本快照 + 重新解析/向量化;409 冲突时引导放弃/覆盖 */\n const submitContent = (draft, force) => {\n setSavingContent(true)\n updateDocContent(kbId, docId, { content: draft, baseUpdatedAt: meta?.update_time, force })\n .then((res) => {\n setConflict(null)\n setEditorOpen(false)\n toast(`已保存${res?.version_no ?? ''},重新解析/向量化中`, 'success')\n loadMeta().then((doc) => {\n if (doc && doc.status === 3) loadContent()\n })\n })\n .catch((e) => {\n if (e?.code === 409 || /冲突/.test(e?.msg || e?.message || '')) {\n setConflict({ content: draft })\n } else {\n toastError(e)\n }\n })\n .finally(() => setSavingContent(false))\n }\n\n /** AI 编写:提示词 + 编辑器当前草稿提交独立子会话,assistant 消息全文回填草稿 */\n const submitAIWrite = () => {\n const prompt = aiPrompt.trim()\n if (!prompt) {\n toastError(new Error('请输入提示词'))\n return\n }\n if (!aiSource.trim()) {\n toastError(new Error('文档内容为空,无法 AI 编写'))\n return\n }\n const text = [\n '【知识库 AI 编写】请根据提示词修改和完善下面的文档并排版。',\n `提示词:${prompt}`,\n '直接输出修改后的完整 Markdown 文档全文(不是片段、不是说明文字,不要附加任何解释或前后缀)。',\n `文档原文(kb_id=${kbId},doc_id=${docId},名称:${meta?.name || ''}):`,\n '<<<DOC_START>>>',\n aiSource,\n '<<<DOC_END>>>',\n ].join('\\n')\n aiAbandonRef.current = false\n setAiRunning(true)\n runAIWriteSession({\n text,\n onDelta: () => {}, // 过程帧预留:当前 UI 以弹窗文案呈现进度\n })\n .then((full) => {\n if (aiAbandonRef.current) return // 用户已取消等待或切换文档:不写回\n setAiRunning(false)\n setAiOpen(false)\n setConflict(null)\n setContent(full) // initial 变化触发 MarkdownEditor 草稿重置\n toast('AI 编写完成,已替换到编辑框,请确认后保存', 'success')\n })\n .catch((e) => {\n if (aiAbandonRef.current) return\n setAiRunning(false)\n toastError(e)\n })\n }\n\n /** 打开 AI 编写弹窗:记录底稿并重置提示词(编写中重开仅查看进度,不重置) */\n const openAIWrite = (draft) => {\n if (!aiRunning) {\n setAiSource(typeof draft === 'string' && draft.trim() ? draft : content)\n setAiPrompt(AI_WRITE_PROMPT_DEFAULT)\n }\n setAiOpen(true)\n }\n\n /** 编写中取消等待:AI 会话继续在 DSH 侧完成,仅前端不再接收结果写回 */\n const cancelAIWrite = () => {\n aiAbandonRef.current = true\n setAiRunning(false)\n setAiOpen(false)\n }\n\n if (kbId == null || docId == null) {\n return (\n <div className=\"skai-kb-page\">\n <div className=\"skai-kb-empty\">\n <p>缺少文档参数</p>\n <p className=\"skai-kb-empty-sub\">请从知识库详情页的文档列表进入</p>\n </div>\n <Toast />\n </div>\n )\n }\n\n const doc = meta\n const ext = extOf(doc?.name || '')\n const needsParse = doc && doc.status !== 3\n\n return (\n <div className=\"skai-kb-page skai-kb-doc-detail\">\n {/* 页头 */}\n <div className=\"skai-kb-detail-head\">\n <div className=\"skai-kb-row-between\">\n <div className=\"skai-kb-row\" style={{ minWidth: 0 }}>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm skai-kb-back\"\n onClick={() => nav.openKb(kbId)}\n title=\"返回知识库详情\"\n >\n ‹ {kb ? kb.name : '知识库'}\n </button>\n <span className=\"skai-kb-detail-title\" title={doc?.name || ''}>\n {doc?.name || (loading ? '加载中…' : `文档 #${docId}`)}\n </span>\n {doc ? <DocStatusBadge status={doc.status} /> : null}\n </div>\n <div className=\"skai-kb-row\">\n {canEdit ? (\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-primary\"\n onClick={() => {\n setConflict(null)\n setEditorOpen(true)\n }}\n disabled={editorOpen}\n >\n 编辑内容\n </button>\n ) : null}\n {canEdit ? (\n <button type=\"button\" className=\"skai-kb-btn\" onClick={openEdit}>\n 编辑\n </button>\n ) : null}\n <button type=\"button\" className=\"skai-kb-btn\" onClick={openVersions}>\n 历史版本\n </button>\n {canEdit && doc && doc.status === 4 ? (\n <button type=\"button\" className=\"skai-kb-btn\" onClick={submitReparse}>\n 重新解析\n </button>\n ) : null}\n {canManage ? (\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-ghost-danger\"\n onClick={() => setDeleting(true)}\n >\n 删除\n </button>\n ) : null}\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-primary\"\n disabled={!doc || doc.status !== 3}\n title={!doc ? '文档加载中' : doc.status !== 3 ? '文档解析就绪后才能引用' : '把文档引用以 chip 形式插入 DSH 当前会话的输入框'}\n onClick={async () => {\n const item = { kbId, docId, docName: doc?.name || '' }\n try {\n const r = await insertSessionReference(buildDocReferenceInsert(item), refSerializeText(item))\n if (r.chip) {\n toast('已将文档引用 chip 插入当前会话输入框,请补充问题后发送', 'success', 3600)\n } else {\n toast('宿主不支持插入引用 chip,已写入引用文本,请直接发送或补充问题', 'success', 4200)\n }\n } catch (e) {\n // 降级:直写失败(无打开会话/通道不可用)时退回复制到剪贴板\n const prompt = refSerializeText(item)\n try {\n await navigator.clipboard.writeText(prompt)\n toast(`引用已复制,请粘贴到 DSH 会话发送(${e?.message || '直写失败'})`, 'success', 4200)\n } catch (_) {\n toast('剪贴板不可用,请手动复制引用到会话', 'error', 3600)\n }\n }\n }}\n >\n 引用文档到会话\n </button>\n </div>\n </div>\n <div className=\"skai-kb-sub\" style={{ textAlign: 'right' }}>\n {EXT_LABEL[ext] || doc?.file_type || '文件'} · 更新于 {formatTime(doc?.update_time)} ·\n 当前版本 v{doc?.version_no ?? '-'}\n {doc?.chunk_count ? ` · ${doc.chunk_count} 向量块` : ''}\n <span className={`skai-kb-badge ${isAdmin ? 'skai-kb-badge-blue' : 'skai-kb-badge-gray'}`} style={{ marginLeft: 6 }}>\n {ROLE_LABEL[kb?.my_role] || ''}\n </span>\n </div>\n {doc?.status === 4 && doc?.error_msg ? (\n <div className=\"skai-kb-field-error\">解析失败:{doc.error_msg}</div>\n ) : null}\n </div>\n\n {/* 正文(编辑模式:Markdown 可视化编辑器;浏览模式:渲染预览) */}\n <div className=\"skai-kb-md-wrap\">\n {editorOpen ? (\n <MarkdownEditor\n initial={content}\n saving={savingContent}\n onSave={submitContent}\n onAIWrite={openAIWrite}\n aiRunning={aiRunning}\n onCancel={() => {\n setEditorOpen(false)\n setConflict(null)\n }}\n />\n ) : needsParse ? (\n <div className=\"skai-kb-empty\">\n <p>文档尚未完成解析({doc?.status === 4 ? '解析失败' : '解析中/向量化中'})</p>\n <p className=\"skai-kb-empty-sub\">解析完成后即可在线预览全文;当前可在列表中跟踪任务状态</p>\n </div>\n ) : loading ? (\n <div className=\"skai-kb-empty\">\n <p>内容加载中…</p>\n </div>\n ) : contentError ? (\n <div className=\"skai-kb-empty\">\n <p>{contentError}</p>\n </div>\n ) : (\n /* 所有入库内容统一为 Markdown(上传时 pdf/docx 已解析整理),一律按 Markdown 渲染 */\n <Markdown text={content} />\n )}\n </div>\n\n {/* 历史版本弹窗(版本列表) */}\n {versionsOpen ? (\n <Modal\n title={`历史版本 · ${doc?.name || ''}`}\n width=\"680px\"\n fullscreen={versionsFull}\n escClose={previewVersion === null}\n onClose={() => {\n setVersionsOpen(false)\n setVersionsFull(false)\n setPreviewVersion(null)\n setPreviewFull(false)\n }}\n extraHead={\n <button\n type=\"button\"\n className=\"skai-kb-icon-btn\"\n data-tip={versionsFull ? '退出全屏' : '全屏'}\n aria-label={versionsFull ? '退出全屏' : '全屏'}\n onClick={() => setVersionsFull(!versionsFull)}\n >\n {versionsFull ? <FullscreenExitGlyph /> : <FullscreenGlyph />}\n </button>\n }\n >\n <VersionTimeline\n versions={versions}\n currentVersion={doc?.version_no}\n canEdit={canEdit}\n busy={busy}\n onPreview={(v) => setPreviewVersion(v.version_no)}\n onRollback={submitRollback}\n />\n </Modal>\n ) : null}\n\n {/* 版本内容预览弹窗(独立弹窗,叠于版本列表之上;列表弹窗保持打开) */}\n {versionsOpen && previewVersion !== null ? (\n <Modal\n title={`版本内容 v${previewVersion} · ${doc?.name || ''}`}\n width=\"680px\"\n fullscreen={previewFull}\n onClose={() => {\n setPreviewVersion(null)\n setPreviewFull(false)\n }}\n extraHead={\n <button\n type=\"button\"\n className=\"skai-kb-icon-btn\"\n data-tip={previewFull ? '退出全屏' : '全屏'}\n aria-label={previewFull ? '退出全屏' : '全屏'}\n onClick={() => setPreviewFull(!previewFull)}\n >\n {previewFull ? <FullscreenExitGlyph /> : <FullscreenGlyph />}\n </button>\n }\n >\n <VersionPreview kbId={kbId} docId={docId} versionNo={previewVersion} />\n </Modal>\n ) : null}\n\n {/* 编辑文档弹窗 */}\n {editing ? (\n <Modal\n title=\"编辑文档\"\n onClose={() => setEditing(false)}\n footer={\n <>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={() => setEditing(false)} disabled={busy}>\n 取消\n </button>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-primary\" onClick={submitEdit} disabled={busy}>\n {busy ? '保存中…' : '保存'}\n </button>\n </>\n }\n >\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">名称 *</span>\n <input\n className=\"skai-kb-input\"\n value={editName}\n maxLength={128}\n onChange={(e) => setEditName(e.target.value)}\n />\n </div>\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">标签</span>\n <TagPicker value={editTags} onChange={setEditTags} />\n </div>\n <ChunkConfigForm advanced initial={{ chunk_size: editChunk.chunk_size || '', chunk_overlap: editChunk.chunk_overlap || '' }} onChange={setEditChunk} />\n <div className=\"skai-kb-sub\">修改名称/分段配置后,文档将自动重新向量化</div>\n </Modal>\n ) : null}\n\n {/* AI 编写弹窗(提示词确认 → 智能体编写 → 结果回填 → 手动保存;编写中锁定,仅「取消等待」可关) */}\n {aiOpen ? (\n <Modal\n title=\"AI 编写\"\n locked={aiRunning}\n escClose={!aiRunning}\n onClose={aiRunning ? cancelAIWrite : () => setAiOpen(false)}\n footer={\n <>\n <button\n type=\"button\"\n className=\"skai-kb-btn\"\n onClick={aiRunning ? cancelAIWrite : () => setAiOpen(false)}\n >\n {aiRunning ? '取消等待' : '取消'}\n </button>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-primary\"\n onClick={submitAIWrite}\n disabled={aiRunning}\n >\n {aiRunning ? (\n <>\n <SpinnerGlyph />\n 编写中\n </>\n ) : (\n '确认'\n )}\n </button>\n </>\n }\n >\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">提示词</span>\n <textarea\n className=\"skai-kb-textarea\"\n rows={4}\n value={aiPrompt}\n disabled={aiRunning}\n onChange={(e) => setAiPrompt(e.target.value)}\n />\n </div>\n {aiRunning ? (\n <div className=\"skai-kb-sub\">\n AI 正在编写(可在 DSH 会话列表查看进度),完成后将自动替换到编辑框;「取消等待」不再接收本次结果\n </div>\n ) : (\n <div className=\"skai-kb-sub\">\n 确认后提示词将携带文档原文提交 DSH 智能体独立会话编写,完成后自动替换编辑框内容,保存仍需手动确认\n </div>\n )}\n </Modal>\n ) : null}\n\n {/* 保存冲突(updated_at 乐观校验):放弃或覆盖 */}\n {conflict ? (\n <ConfirmDialog\n title=\"保存冲突\"\n message=\"文档内容已被他人更新。选择「覆盖保存」以当前内容强制保存;选择「取消」返回编辑器(可自行放弃修改)。\"\n confirmText=\"覆盖保存\"\n danger={false}\n busy={savingContent}\n onConfirm={() => submitContent(conflict.content, true)}\n onClose={() => setConflict(null)}\n />\n ) : null}\n\n {/* 删除确认 */}\n {deleting ? (\n <ConfirmDialog\n title=\"删除文档\"\n message={`确定删除「${doc?.name || ''}」吗?删除后 MCP 检索将不再返回该文档。`}\n confirmText=\"删除\"\n busy={busy}\n onConfirm={submitDelete}\n onClose={() => setDeleting(false)}\n />\n ) : null}\n <Toast />\n </div>\n )\n}\n\n/** 历史版本内容预览(md 渲染 / 纯文本) */\nfunction VersionPreview({ kbId, docId, versionNo }) {\n const [text, setText] = useState('')\n const [error, setError] = useState('')\n const [loading, setLoading] = useState(true)\n useEffect(() => {\n setLoading(true)\n setError('')\n getDocContent(kbId, docId, versionNo)\n .then((data) => setText((data && data.content) || ''))\n .catch((e) => setError(e.msg || e.message || '版本内容加载失败'))\n .finally(() => setLoading(false))\n }, [kbId, docId, versionNo])\n if (loading) return <div className=\"skai-kb-empty\"><p>版本内容加载中…</p></div>\n if (error) return <div className=\"skai-kb-empty\"><p>{error}</p></div>\n return <Markdown text={text} />\n}\n","/**\n * 模型服务配置 REST(对应后端 /kb/model-config*;仅管理员)\n *\n * 覆盖向量化(embedding)/ 重排(rerank)/ OCR 视觉识别(ocr)三类模型服务的\n * 设置页覆盖配置;api_key 语义(后端约定):传空串或原样传回掩码串(含 ****)\n * = 沿用当前生效密钥,传新值 = 更新密钥\n */\nimport request from '../core/request.js'\n\n/**\n * 读取三类模型服务当前生效配置(含来源 source: db=设置页覆盖 / env=环境变量 / unset=未配置)\n * @returns {Promise<{ embedding: { source: string, enabled: boolean, config: object }, rerank: { source: string, enabled: boolean, config: object }, ocr: { source: string, enabled: boolean, config: object } }>}\n */\nexport function getModelConfig() {\n return request.get('/model-config')\n}\n\n/**\n * 保存单项配置(config=null 表示恢复默认:清除设置页覆盖并回落部署环境变量配置)\n * @param {'embedding'|'rerank'|'ocr'} item\n * @param {object|null} config\n * @returns {Promise<object>} 保存成功返回同 GET 结构的全量配置\n */\nexport function saveModelConfig(item, config) {\n return request.put('/model-config', { item, config })\n}\n\n/**\n * 连通性测试(用传入 config 实际请求模型服务商)\n * @param {'embedding'|'rerank'|'ocr'} item\n * @param {object} config\n * @returns {Promise<{ message: string }>} 成功 message='连通性测试通过';失败抛 ApiError(msg 为中文错误原因)\n */\nexport function testModelConfig(item, config) {\n return request.post('/model-config/test', { item, config })\n}\n","/**\n * 服务器健康探测:GET <base>/kb/health(免鉴权)→ { status, app, version }\n *\n * 直连 fetch(不经 request.js:request 固定使用当前激活服务器基址并附带插件 Token),\n * 设置页用它逐个探测「已添加」的每台服务器,校验其部署的应用 id 与版本和插件是否匹配\n * (app / version 由后端 main.go 注入:版本经发布脚本 --build-arg VERSION → ldflags 写入)。\n */\nimport { APP_PATH } from '../core/server-config.js'\n\nexport function getHealthByBase(base) {\n const ctrl = new AbortController()\n const timer = setTimeout(() => ctrl.abort(), 5000)\n const url = `${String(base || '').replace(/\\/+$/, '')}${APP_PATH}/health`\n return fetch(url, { signal: ctrl.signal })\n .catch((error) => {\n if (error && error.name === 'AbortError') throw new Error('请求超时')\n throw new Error('网络请求失败')\n })\n .then((res) => res.json())\n .then((body) => {\n if (!body || body.code !== 0) throw new Error((body && body.msg) || '响应异常')\n return body.data || {}\n })\n .finally(() => clearTimeout(timer))\n}\n","","/**\n * 插件元信息(供桌面基座加载校验)\n */\nimport { version } from '../package.json'\n\nexport const manifest = {\n /** 插件标识(基座内唯一) */\n id: 'knowledge',\n /** 插件名称 */\n name: '知识库',\n /** npm 作用域包名 */\n packageName: '@shikeai/knowledge',\n /** 版本:单一来源 frontend/package.json,构建时(tsdown/vite)自动内联,禁止在此手写第二份 */\n version,\n /** 功能描述 */\n description: '时刻AI平台桌面端知识库插件:知识管理(右侧 Sidebar 标签页:首页/知识库详情/文档详情/设置)、成员权限、MCP RAG 检索服务',\n /** 作者 */\n author: 'shikeai',\n /** 平台内置预装插件,不可卸载 */\n builtin: true,\n uninstallable: false,\n /** 权限声明 */\n permissions: [\n 'tab:right-sidebar', // 注册右侧 Sidebar 标签页类型(首页 / 知识库详情 / 文档详情 / 设置)\n 'event:shikeai-usercenter', // 监听用户中心登录态事件(login / logout / expired / user-update)\n 'global:window', // 只读访问 window.SHIKEAI_USER_INFO / SHIKEAI_GET_SIGN_CREDENTIAL /\n // SHIKEAI_GET/SET_MEMBER_CONFIG(服务器配置云持久化)\n //(不接触用户中心 Token,登录态经按需验签换发)\n ],\n /**\n * UI 形态:DSH 右侧 Sidebar 标签页体系(每个主要功能各为一个新标签页,\n * 经 tab.actions.openTab(kind, { params }) 打开)\n * - 首页 shikeai-knowledge-home:知识库列表 / 添加知识库 / 设置入口(引导页胶囊直达)\n * - 知识库详情 shikeai-knowledge-kb:文档列表 / 权限配置 / 添加文档(params: { kbId })\n * - 文档详情 shikeai-knowledge-doc:markdown 渲染 / 版本 / 复制文档提示语(params: { kbId, docId })\n * - 设置 shikeai-knowledge-settings:后端服务器地址 / 管理员\n * 无内置对话面板,全部交互在标签页内完成,无页面跳转刷新\n */\n ui: {\n renderMode: 'drawer',\n drawerPosition: 'right',\n entries: ['sidebar-right-knowledge'],\n tabs: ['shikeai-knowledge-home', 'shikeai-knowledge-kb', 'shikeai-knowledge-doc', 'shikeai-knowledge-settings'],\n },\n}\n\nexport default manifest\n","/**\n * 新增/编辑后端服务器弹窗:名称 + 服务器URL(仅协议 + 域名/IP 及端口)\n * 应用路径固定 /kb 由前端统一拼装,无需用户配置\n * 校验与写入统一走 core/server-config,失败在表单内展示错误\n * 保存成功回调 onSaved({ added, activated }):activated=新增服务器被自动设为当前\n * (新增首个服务器),当前服务器即知识库 MCP 接入点,宿主登记随之同步至 DSH\n */\nimport { useState } from 'react'\nimport Modal from '../common/Modal.jsx'\nimport { addServer, updateServer, getActiveServer, validateServerName, validateServerUrl } from '../../core/server-config.js'\n\nexport default function ServerFormModal({ initial, onClose, onSaved }) {\n const isEdit = Boolean(initial && initial.id)\n const [name, setName] = useState(initial?.name || '')\n const [apiBase, setApiBase] = useState(initial?.api_base || '')\n const [error, setError] = useState('')\n\n const submit = () => {\n const msg = validateServerName(name) || validateServerUrl(apiBase)\n if (msg) {\n setError(msg)\n return\n }\n if (isEdit) {\n const err = updateServer(initial.id, name, apiBase)\n if (err) {\n setError(err)\n return\n }\n onSaved({ added: false, activated: false })\n return\n }\n const prevActiveId = getActiveServer()?.id || ''\n const err = addServer(name, apiBase)\n if (err) {\n setError(err)\n return\n }\n onSaved({ added: true, activated: (getActiveServer()?.id || '') !== prevActiveId })\n }\n\n return (\n <Modal\n title={isEdit ? '编辑服务器' : '添加服务器'}\n onClose={onClose}\n footer={\n <>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={onClose}>\n 取消\n </button>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-primary\" onClick={submit}>\n 保存\n </button>\n </>\n }\n >\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">名称 *</span>\n <input\n className=\"skai-kb-input\"\n value={name}\n maxLength={32}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"如:开发环境 / 内网服务器\"\n />\n </div>\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">服务器 URL *</span>\n <input\n className=\"skai-kb-input\"\n value={apiBase}\n onChange={(e) => setApiBase(e.target.value)}\n placeholder=\"http://127.0.0.1:8081\"\n />\n <span className=\"skai-kb-sub\">支持 http/https,仅填服务器 IP/域名及端口,如 http://127.0.0.1:8081;应用路径 /kb 固定,无需配置</span>\n </div>\n {error ? <div className=\"skai-kb-field-error\">{error}</div> : null}\n </Modal>\n )\n}\n","/**\n * 添加管理员弹窗:手机号(仅管理员操作)\n * 目标用户登录过 → 即时生效;未登录过 → 落待激活授权,其登录后自动补全 uid 生效\n */\nimport { useState } from 'react'\nimport Modal from '../common/Modal.jsx'\nimport { validateMobile } from '../../utils/validator.js'\n\nexport default function AdminFormModal({ busy, onSubmit, onClose }) {\n const [mobile, setMobile] = useState('')\n const [error, setError] = useState('')\n const submit = () => {\n const msg = validateMobile(mobile)\n if (msg) {\n setError(msg)\n return\n }\n onSubmit({ mobile: String(mobile).replace(/[\\s-]/g, '') })\n }\n return (\n <Modal\n title=\"添加管理员\"\n onClose={onClose}\n footer={\n <>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={onClose} disabled={busy}>\n 取消\n </button>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-primary\" onClick={submit} disabled={busy}>\n {busy ? '添加中…' : '添加'}\n </button>\n </>\n }\n >\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">用户手机号 *</span>\n <input\n className=\"skai-kb-input\"\n value={mobile}\n inputMode=\"tel\"\n maxLength={13}\n placeholder=\"11 位大陆手机号,如 13812345678\"\n onChange={(e) => setMobile(e.target.value)}\n />\n </div>\n <div className=\"skai-kb-sub\">\n 通过手机号添加:已注册用户直接添加生效;尚未注册的用户会先创建待激活授权,\n 其注册并登录知识库后自动成为管理员\n </div>\n {error ? <div className=\"skai-kb-field-error\">{error}</div> : null}\n </Modal>\n )\n}\n","/**\n * 模型服务编辑弹窗(设置页「模型服务」区块):向量化 / 重排 / OCR 单项配置表单\n *\n * - 服务商预设:常用国内服务商(按服务项收录可用者:向量化=硅基流动/阿里百炼/百度千帆,\n * 重排=硅基流动/智谱,OCR=DeepSeek/火山方舟/硅基流动/阿里百炼/智谱/Kimi/腾讯混元)+\n * 本地部署 Infinity(仅向量化与重排,对应 dev/docker-compose.yml 的 bge 容器)/\n * 本地部署(ollama · glm-ocr容器)(仅 OCR 项显示)/ 自定义;选预设回填地址与协议,\n * 模型为空或仍是预设默认值时回填推荐模型,ollama 预设另在提示词为空时回填官方触发\n * 前缀 Text Recognition:(GLM-OCR 为任务专用模型),不动已填密钥;本地部署预设的\n * 地址主机默认取当前 API 地址的\n * IP/主机名(API 为 http://127.0.0.1:8081 → http://127.0.0.1:7997),未配置回退 localhost。\n * 收录约束:向量化仅 1024 维模型(库列 vector(1024) 且\n * 后端不透传 dimensions 参数);重排仅 Cohere 兼容 {base}/rerank 端点(百炼/千帆\n * 端点格式不同暂不收录)\n * - api_key 语义(后端约定):留空或原样传回掩码串(含 ****)= 沿用当前生效密钥,\n * 传新值 = 更新密钥;表单回显后端掩码串\n * - 数字字段:留空不提交该字段(后端 0/缺省 = 沿用默认,OCR max_pages 0=不限制)\n * - 测试连接:以当前表单值调后端连通性测试,成功/失败经全局 Toast 透出后端返回信息\n * - footer:恢复默认(清除设置页覆盖,回落部署环境变量配置,经确认弹窗二次确认)/ 测试连接 / 保存;\n * 保存成功回调 onSaved(data),data 为保存后同 GET /kb/model-config 结构的全量配置\n */\nimport { useState } from 'react'\nimport Modal from '../common/Modal.jsx'\nimport ConfirmDialog from '../common/ConfirmDialog.jsx'\nimport { saveModelConfig, testModelConfig } from '../../api/modelconfig.js'\nimport { getApiBase } from '../../core/server-config.js'\nimport { toast, toastError } from '../../store/ui-store.js'\n\n/** 编辑项 → 展示名(与设置页「模型服务」面板行一致) */\nconst ITEM_NAMES = {\n embedding: '向量化(Embedding)',\n rerank: '重排(Rerank)',\n ocr: 'OCR(视觉识别)',\n}\n\n/**\n * 国内服务商预设(按服务项收录,选后回填地址与推荐模型)。选型约束见文件头注释:\n * - 向量化:库列固定 vector(1024) 且后端不透传 dimensions 参数,仅收录原生 1024 维模型\n * (豆包 embedding 2048 维、智谱 embedding-3 默认 2048 维暂不收录)\n * - 重排:后端拼接 {base}/rerank(Cohere 兼容),仅收录支持该端点的服务商\n * (百炼为原生 text-rerank、千帆为 /v2/rerankers,路径不兼容暂不收录)\n * - OCR:OpenAI 兼容 /chat/completions 视觉模型(DeepSeek 无向量化/重排,仅 OCR 项)\n */\nconst PROVIDER_PRESETS = {\n embedding: [\n {\n value: 'siliconflow',\n label: '硅基流动 SiliconFlow(推荐)',\n base: 'https://api.siliconflow.cn/v1',\n model: 'BAAI/bge-large-zh-v1.5',\n hint: '推荐模型:BAAI/bge-large-zh-v1.5(1024 维)',\n },\n {\n value: 'dashscope',\n label: '阿里云百炼(通义)',\n base: 'https://dashscope.aliyuncs.com/compatible-mode/v1',\n model: 'text-embedding-v4',\n hint: '推荐模型:text-embedding-v4(默认 1024 维,与库内向量列一致)',\n },\n {\n value: 'qianfan',\n label: '百度千帆',\n base: 'https://qianfan.baidubce.com/v2',\n model: 'bge-large-zh',\n hint: '推荐模型:bge-large-zh(1024 维)',\n },\n ],\n rerank: [\n {\n value: 'siliconflow',\n label: '硅基流动 SiliconFlow(推荐)',\n base: 'https://api.siliconflow.cn/v1',\n model: 'BAAI/bge-reranker-v2-m3',\n hint: '推荐模型:BAAI/bge-reranker-v2-m3',\n },\n {\n value: 'zhipu',\n label: '智谱 AI',\n base: 'https://open.bigmodel.cn/api/paas/v4',\n model: 'rerank',\n hint: '推荐模型:rerank(智谱 Cohere 兼容重排端点)',\n },\n ],\n ocr: [\n {\n value: 'deepseek',\n label: 'DeepSeek',\n base: 'https://api.deepseek.com',\n model: 'deepseek-flash',\n hint: '推荐模型:deepseek-flash(V4.1 Flash 原生多模态,支持 image_url 传图;DeepSeek 无向量化/重排服务)',\n },\n {\n value: 'ark',\n label: '火山方舟(字节跳动 · 豆包)',\n base: 'https://ark.cn-beijing.volces.com/api/v3',\n model: 'doubao-seed-2-1-pro-260915',\n hint: '推荐模型:doubao-seed-2-1-pro-260915(旗舰多模态,支持模型名直调;旧 doubao-seed-1.6 已于 2026-09 停服)',\n },\n {\n value: 'siliconflow',\n label: '硅基流动 SiliconFlow',\n base: 'https://api.siliconflow.cn/v1',\n model: 'Qwen/Qwen2.5-VL-32B-Instruct',\n hint: '推荐模型:Qwen/Qwen2.5-VL-32B-Instruct 等视觉模型',\n },\n {\n value: 'dashscope',\n label: '阿里云百炼(通义)',\n base: 'https://dashscope.aliyuncs.com/compatible-mode/v1',\n model: 'qwen-vl-max',\n hint: '推荐模型:qwen-vl-max(或 qwen3-vl 系列)',\n },\n {\n value: 'zhipu',\n label: '智谱 AI',\n base: 'https://open.bigmodel.cn/api/paas/v4',\n model: 'glm-4.6v-flash',\n hint: '推荐模型:glm-4.6v-flash(免费)/ glm-4.6v / GLM-OCR',\n },\n {\n value: 'moonshot',\n label: '月之暗面 Kimi',\n base: 'https://api.moonshot.cn/v1',\n model: 'kimi-k3.1-pro',\n hint: '推荐模型:kimi-k3.1-pro(原生视觉;kimi-latest 等旧视觉模型名已下线)',\n },\n {\n value: 'hunyuan',\n label: '腾讯混元',\n base: 'https://api.hunyuan.cloud.tencent.com/v1',\n model: 'hunyuan-vision',\n hint: '推荐模型:hunyuan-vision',\n },\n ],\n}\n\n/** 按值查找服务项的服务商预设 */\nconst findPreset = (item, value) => (PROVIDER_PRESETS[item] || []).find((p) => p.value === value)\n\n/**\n * 本地部署预设(dev/docker-compose.yml 的 bge 容器:Infinity 镜像,端口 7997,\n * 同时加载向量化与重排两个模型,无需 API 密钥)。Infinity 端点无 /v1 前缀,\n * 向量化与重排均用根路径(后端分别拼 {base}/embeddings、{base}/rerank,Cohere 兼容)。\n * 主机默认取当前 API 地址的 IP/主机名(本地模型与后端 API 同机部署,\n * 如 API 为 http://127.0.0.1:8081 则取 127.0.0.1),未配置或解析失败回退 localhost\n */\nfunction localModelHost() {\n try {\n const apiBase = getApiBase()\n if (!apiBase) return window.location.hostname || 'localhost'\n return new URL(apiBase, window.location.origin).hostname || 'localhost'\n } catch {\n return 'localhost'\n }\n}\n\n/** 本地部署 bge 容器地址(Infinity 端点无 /v1 前缀,向量化与重排均用根路径) */\nconst localBase = () => `http://${localModelHost()}:7997`\n\n/** 本地部署标准模型名(与 compose INFINITY_MODEL_ID 一致) */\nconst LOCAL_MODEL = {\n embedding: 'BAAI/bge-large-zh-v1.5',\n rerank: 'BAAI/bge-reranker-v2-m3',\n}\n/** 本地部署预设提示 */\nconst LOCAL_HINT = {\n embedding:\n '本地 Infinity(bge 容器,端口 7997,向量维度 1024):无需 API 密钥;默认主机与 API 地址一致;同 Docker 网络容器内可改用 http://bge:7997',\n rerank:\n '本地 Infinity(bge 容器,端口 7997):无需 API 密钥;默认主机与 API 地址一致;同 Docker 网络容器内可改用 http://bge:7997',\n}\n\n/**\n * 本地部署 Ollama 预设(dev/docker-compose.yml 的 ollama 容器:端口 11434,启动自动拉取\n * glm-ocr:q8_0,无需 API 密钥)。GLM-OCR 为任务专用模型,识别提示词需用官方触发前缀\n * (全文 Text Recognition: / 表格 Table Recognition: / 图 Figure Recognition:),\n * 自然语言提示词在无文字图上会输出退化内容;预设回填提示词仅在为空时写入(保留自定义)\n */\nconst OLLAMA_OCR = { model: 'glm-ocr:q8_0', prompt: 'Text Recognition:' }\n/** 本地部署 Ollama 预设提示 */\nconst OLLAMA_HINT =\n '本地部署 Ollama(glm-ocr 容器,端口 11434):无需 API 密钥;GLM-OCR 为任务专用模型,已回填官方识别前缀 Text Recognition:(表格用 Table Recognition:、图用 Figure Recognition:)'\n\n/** 地址域名特征 → 预设值(按已有配置自动识别服务商预设,仅识别当前服务项收录的预设) */\nconst BASE_MARKS = [\n ['siliconflow', 'siliconflow'],\n ['volces.com', 'ark'],\n ['dashscope.aliyuncs.com', 'dashscope'],\n ['qianfan.baidubce.com', 'qianfan'],\n ['bigmodel.cn', 'zhipu'],\n ['api.moonshot.cn', 'moonshot'],\n ['hunyuan.cloud.tencent.com', 'hunyuan'],\n ['deepseek.com', 'deepseek'],\n]\n\n/** 按已有配置自动识别服务商预设(OCR 协议 / 本地端口 / 地址域名),未命中返回 custom */\nfunction detectPreset(item, apiBase, protocol) {\n if (item === 'ocr' && (protocol || '') === 'ollama') return 'ollama'\n const base = String(apiBase || '')\n if ((item === 'embedding' || item === 'rerank') && base.includes(':7997')) return 'local'\n for (const [mark, value] of BASE_MARKS) {\n if (base.includes(mark) && findPreset(item, value)) return value\n }\n return 'custom'\n}\n\n/** 全部预设默认模型名:当前模型为空或仍是任一预设默认值时切换服务商才覆盖回填(保留自定义值) */\nconst PRESET_MODELS = [\n ...new Set([\n ...Object.values(PROVIDER_PRESETS).flat().map((p) => p.model),\n ...Object.values(LOCAL_MODEL),\n OLLAMA_OCR.model,\n ]),\n]\nconst isPresetModel = (m) => {\n const s = String(m ?? '').trim()\n return s === '' || PRESET_MODELS.includes(s)\n}\n\n/** 全部服务商预设默认地址:切换到本地部署等预设时,地址为空或仍是预设默认值才覆盖回填 */\nconst PRESET_BASES = [...new Set(Object.values(PROVIDER_PRESETS).flat().map((p) => p.base))]\n\n/** 数字输入 → number(空串/非法值返回 undefined,不提交该字段) */\nfunction toNumber(value) {\n const s = String(value ?? '').trim()\n if (s === '') return undefined\n const n = Number(s)\n return Number.isFinite(n) ? n : undefined\n}\n\nexport default function ModelServiceModal({ item, open, config, onClose, onSaved }) {\n const cfg = config || {}\n const [preset, setPreset] = useState(() => detectPreset(item, cfg.api_base, cfg.protocol))\n const [apiBase, setApiBase] = useState(cfg.api_base || '')\n const [apiKey, setApiKey] = useState(cfg.api_key || '')\n const [model, setModel] = useState(cfg.model || '')\n const [protocol, setProtocol] = useState(item === 'ocr' ? cfg.protocol || 'openai' : '')\n const [prompt, setPrompt] = useState(cfg.prompt || '')\n const [dimension, setDimension] = useState(cfg.dimension ?? '')\n const [batchSize, setBatchSize] = useState(cfg.batch_size ?? '')\n const [timeoutSec, setTimeoutSec] = useState(cfg.timeout_sec ?? '')\n const [topN, setTopN] = useState(cfg.top_n ?? '')\n const [maxPages, setMaxPages] = useState(cfg.max_pages ?? '')\n const [fieldErrors, setFieldErrors] = useState({})\n const [saving, setSaving] = useState(false)\n const [testing, setTesting] = useState(false)\n const [resetting, setResetting] = useState(false)\n const [confirmReset, setConfirmReset] = useState(false) // 恢复默认二次确认弹窗\n const busy = saving || testing || resetting\n\n /** 按编辑项差异组装提交体(公共 + 各项专属字段;数字留空不提交) */\n const buildPayload = () => {\n const payload = {\n api_base: apiBase.trim(),\n api_key: apiKey.trim(),\n model: model.trim(),\n }\n const put = (key, value) => {\n const n = toNumber(value)\n if (n !== undefined) payload[key] = n\n }\n if (item === 'embedding') {\n put('dimension', dimension)\n put('batch_size', batchSize)\n put('timeout_sec', timeoutSec)\n } else if (item === 'rerank') {\n put('top_n', topN)\n put('timeout_sec', timeoutSec)\n } else {\n payload.protocol = protocol || 'openai'\n payload.prompt = prompt.trim()\n put('timeout_sec', timeoutSec)\n put('max_pages', maxPages)\n }\n return payload\n }\n\n /** 必填校验:API 地址与模型名,行内错误提示 */\n const validate = () => {\n const errs = {}\n if (!apiBase.trim()) errs.api_base = '请填写 API 地址'\n if (!model.trim()) errs.model = '请填写模型名'\n setFieldErrors(errs)\n return Object.keys(errs).length === 0\n }\n\n const applyPreset = (next) => {\n setPreset(next)\n if (next === 'local' && (item === 'embedding' || item === 'rerank')) {\n // 本地部署预设:回填地址与标准模型名;密钥不动(无需密钥)\n setApiBase(localBase())\n if (isPresetModel(model)) setModel(LOCAL_MODEL[item])\n return\n }\n if (next === 'ollama' && item === 'ocr') {\n setProtocol('ollama')\n // 本地部署 Ollama:地址为空或仍是服务商预设默认值时,回填本机 11434(主机与 API 地址一致);\n // 模型名按预设默认值规则回填,识别提示词仅在为空时回填官方触发前缀(保留自定义提示词)\n const cur = apiBase.trim()\n if (cur === '' || PRESET_BASES.includes(cur)) setApiBase(`http://${localModelHost()}:11434`)\n if (isPresetModel(model)) setModel(OLLAMA_OCR.model)\n if (prompt.trim() === '') setPrompt(OLLAMA_OCR.prompt)\n return\n }\n const p = findPreset(item, next)\n if (!p) return // 自定义:不回填,保留当前表单值\n setApiBase(p.base)\n if (item === 'ocr') setProtocol('openai')\n if (isPresetModel(model)) setModel(p.model)\n }\n\n const handleTest = () => {\n if (busy || !validate()) return\n setTesting(true)\n testModelConfig(item, buildPayload())\n .then((data) => toast((data && data.message) || '连通性测试通过', 'success'))\n .catch(toastError)\n .finally(() => setTesting(false))\n }\n\n const handleSave = () => {\n if (busy || !validate()) return\n setSaving(true)\n saveModelConfig(item, buildPayload())\n .then((data) => {\n toast('已保存,配置立即生效', 'success')\n onSaved?.(data)\n })\n .catch(toastError)\n .finally(() => setSaving(false))\n }\n\n const handleReset = () => {\n if (busy) return\n setConfirmReset(true)\n }\n\n /** 确认弹窗确认后执行恢复默认:清除设置页覆盖,回落部署环境变量配置 */\n const doReset = () => {\n setResetting(true)\n saveModelConfig(item, null)\n .then((data) => {\n setConfirmReset(false)\n toast('已恢复默认配置', 'success')\n onSaved?.(data)\n })\n .catch(toastError)\n .finally(() => setResetting(false))\n }\n\n // 当前预设提示:服务商预设推荐模型 / 本地部署说明(Infinity 与 Ollama)\n const activeHint =\n findPreset(item, preset)?.hint ||\n (preset === 'local' ? LOCAL_HINT[item] : preset === 'ollama' ? OLLAMA_HINT : '')\n\n if (!open) return null\n\n return (\n <>\n <Modal\n title={`编辑模型服务 · ${ITEM_NAMES[item] || item}`}\n onClose={onClose}\n escClose={!confirmReset}\n footer={\n <>\n <button type=\"button\" className=\"skai-kb-btn\" disabled={busy} onClick={handleReset}>\n {resetting ? '恢复中…' : '恢复默认'}\n </button>\n <button type=\"button\" className=\"skai-kb-btn\" disabled={busy} onClick={handleTest}>\n {testing ? '测试中…' : '测试连接'}\n </button>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-primary\"\n disabled={busy}\n onClick={handleSave}\n >\n {saving ? '保存中…' : '保存'}\n </button>\n </>\n }\n >\n {/* 服务商预设 */}\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">服务商预设</span>\n <select className=\"skai-kb-select\" value={preset} onChange={(e) => applyPreset(e.target.value)}>\n {(PROVIDER_PRESETS[item] || []).map((p) => (\n <option key={p.value} value={p.value}>\n {p.label}\n </option>\n ))}\n {item === 'ocr' ? <option value=\"ollama\">本地部署(ollama · glm-ocr容器)</option> : null}\n {item === 'embedding' || item === 'rerank' ? (\n <option value=\"local\">本地部署(Infinity · bge 容器)</option>\n ) : null}\n <option value=\"custom\">自定义服务商</option>\n </select>\n {activeHint ? <span className=\"skai-kb-sub\">{activeHint}</span> : null}\n </div>\n\n {/* 公共字段 */}\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">API 地址 *</span>\n <input\n className=\"skai-kb-input\"\n value={apiBase}\n placeholder=\"https://api.siliconflow.cn/v1\"\n onChange={(e) => setApiBase(e.target.value)}\n />\n {fieldErrors.api_base ? <span className=\"skai-kb-field-error\">{fieldErrors.api_base}</span> : null}\n </div>\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">API 密钥</span>\n <input\n className=\"skai-kb-input\"\n value={apiKey}\n placeholder=\"留空沿用当前密钥\"\n onChange={(e) => setApiKey(e.target.value)}\n />\n <span className=\"skai-kb-sub\">\n 密钥经后端掩码展示(如 sk-a****abcd);留空或保持掩码串均表示沿用当前生效密钥,填写新值即更新\n </span>\n </div>\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">模型名 *</span>\n <input\n className=\"skai-kb-input\"\n value={model}\n placeholder={item === 'ocr' ? '如 Qwen/Qwen2.5-VL-32B-Instruct' : '如 BAAI/bge-large-zh-v1.5'}\n onChange={(e) => setModel(e.target.value)}\n />\n {fieldErrors.model ? <span className=\"skai-kb-field-error\">{fieldErrors.model}</span> : null}\n </div>\n\n {/* OCR 专属:调用协议 + 识别提示词 */}\n {item === 'ocr' ? (\n <>\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">调用协议</span>\n <select className=\"skai-kb-select\" value={protocol} onChange={(e) => setProtocol(e.target.value)}>\n <option value=\"openai\">OpenAI 兼容公网</option>\n <option value=\"ollama\">本地 Ollama</option>\n </select>\n </div>\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">识别提示词</span>\n <textarea\n className=\"skai-kb-textarea\"\n rows={3}\n value={prompt}\n placeholder=\"留空使用内置默认提示词\"\n onChange={(e) => setPrompt(e.target.value)}\n />\n </div>\n </>\n ) : null}\n\n {/* 各项专属数字字段(留空沿用默认) */}\n {item === 'embedding' ? (\n <>\n <div className=\"skai-kb-field-row\">\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">向量维度</span>\n <input\n className=\"skai-kb-input\"\n type=\"number\"\n min={0}\n value={dimension}\n placeholder=\"留空沿用默认 1024\"\n onChange={(e) => setDimension(e.target.value)}\n />\n </div>\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">批量大小</span>\n <input\n className=\"skai-kb-input\"\n type=\"number\"\n min={0}\n value={batchSize}\n placeholder=\"留空沿用默认\"\n onChange={(e) => setBatchSize(e.target.value)}\n />\n </div>\n </div>\n <div className=\"skai-kb-field-row\">\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">超时秒数</span>\n <input\n className=\"skai-kb-input\"\n type=\"number\"\n min={0}\n value={timeoutSec}\n placeholder=\"留空沿用默认\"\n onChange={(e) => setTimeoutSec(e.target.value)}\n />\n </div>\n </div>\n </>\n ) : null}\n {item === 'rerank' ? (\n <div className=\"skai-kb-field-row\">\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">重排后保留条数 top_n</span>\n <input\n className=\"skai-kb-input\"\n type=\"number\"\n min={0}\n value={topN}\n placeholder=\"留空沿用默认\"\n onChange={(e) => setTopN(e.target.value)}\n />\n </div>\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">超时秒数</span>\n <input\n className=\"skai-kb-input\"\n type=\"number\"\n min={0}\n value={timeoutSec}\n placeholder=\"留空沿用默认\"\n onChange={(e) => setTimeoutSec(e.target.value)}\n />\n </div>\n </div>\n ) : null}\n {item === 'ocr' ? (\n <div className=\"skai-kb-field-row\">\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">单文档识别页数上限</span>\n <input\n className=\"skai-kb-input\"\n type=\"number\"\n min={0}\n value={maxPages}\n placeholder=\"0=不限制\"\n onChange={(e) => setMaxPages(e.target.value)}\n />\n </div>\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">超时秒数</span>\n <input\n className=\"skai-kb-input\"\n type=\"number\"\n min={0}\n value={timeoutSec}\n placeholder=\"留空沿用默认\"\n onChange={(e) => setTimeoutSec(e.target.value)}\n />\n </div>\n </div>\n ) : null}\n </Modal>\n\n {/* 恢复默认二次确认(替代浏览器原生 confirm;Portal 同层后渲染自动盖在编辑弹窗上) */}\n {confirmReset ? (\n <ConfirmDialog\n title=\"恢复默认配置\"\n message={`确定恢复「${ITEM_NAMES[item] || item}」的默认配置吗?将清除设置页覆盖并回落到部署环境变量配置。`}\n confirmText=\"恢复默认\"\n danger={false}\n busy={resetting}\n onConfirm={doReset}\n onClose={() => setConfirmReset(false)}\n />\n ) : null}\n </>\n )\n}\n","/**\n * 模型服务「配置步骤帮助」弹窗(设置页「模型服务」区块各行「配置说明」按钮入口)\n *\n * 分节内容:使用说明(预设回填机制 + 各服务项已收录名单 + 1024 维约束)→\n * 各服务商配置方法(按服务商分节覆盖全部已收录预设:硅基流动 / 阿里云百炼 /\n * 百度千帆 / 智谱 / DeepSeek / 火山方舟 / Kimi / 腾讯混元,每节含控制台入口、\n * 密钥创建步骤、API 地址与各服务项推荐模型)→ 本地部署 Infinity(向量化 / 重排,\n * bge 容器)→ 本地部署(ollama · glm-ocr容器,自动拉取 glm-ocr:q8_0)→ 密钥与生效方式;\n * 服务商能力与推荐模型与 ModelServiceModal 的 PROVIDER_PRESETS 保持一致;\n * 样式用 knowledge.css 末尾的 skai-kb-help-* 局部类\n */\nimport Modal from '../common/Modal.jsx'\n\nexport default function ModelConfigHelpModal({ onClose }) {\n return (\n <Modal\n title=\"配置步骤帮助\"\n onClose={onClose}\n width={560}\n footer={\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-primary\" onClick={onClose}>\n 关闭\n </button>\n }\n >\n <div className=\"skai-kb-help-section\">\n <h4 className=\"skai-kb-help-title\">使用说明</h4>\n <p className=\"skai-kb-help-text\">\n 编辑弹窗「服务商预设」选择服务商后自动回填 API 地址与推荐模型,一般只需粘贴密钥 →\n 「测试连接」→ 保存;选择「自定义服务商」可手动填写任意 OpenAI 兼容地址。\n </p>\n <p className=\"skai-kb-help-text\">\n 各服务项已收录:向量化——硅基流动 / 阿里云百炼 / 百度千帆 / 本地部署;重排——硅基流动 /\n 智谱 / 本地部署;OCR——DeepSeek / 火山方舟 / 硅基流动 / 阿里云百炼 / 智谱 / Kimi /\n 腾讯混元 / 本地部署。向量化所选模型须为 1024 维(与库内向量列一致),各预设已按此筛选。\n </p>\n </div>\n <div className=\"skai-kb-help-section\">\n <h4 className=\"skai-kb-help-title\">硅基流动 SiliconFlow(向量化 / 重排 / OCR)</h4>\n <ol className=\"skai-kb-help-list\">\n <li>\n 注册并登录{' '}\n <a\n className=\"skai-kb-help-link\"\n href=\"https://cloud.siliconflow.cn/\"\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n https://cloud.siliconflow.cn/\n </a>\n </li>\n <li>控制台左侧「API 密钥」→「新建 API 密钥」并复制</li>\n <li>\n API 地址统一{' '}\n <code className=\"skai-kb-help-code\">https://api.siliconflow.cn/v1</code>\n :向量化模型 <code className=\"skai-kb-help-code\">BAAI/bge-large-zh-v1.5</code>(1024\n 维);重排模型 <code className=\"skai-kb-help-code\">BAAI/bge-reranker-v2-m3</code>\n ;OCR 视觉模型{' '}\n <code className=\"skai-kb-help-code\">Qwen/Qwen2.5-VL-32B-Instruct</code>\n (或其它支持视觉的模型)\n </li>\n <li>粘贴 API 密钥 → 点击「测试连接」→ 通过后保存</li>\n </ol>\n </div>\n <div className=\"skai-kb-help-section\">\n <h4 className=\"skai-kb-help-title\">阿里云百炼(向量化 / OCR)</h4>\n <ol className=\"skai-kb-help-list\">\n <li>\n 登录阿里云并开通模型服务{' '}\n <a\n className=\"skai-kb-help-link\"\n href=\"https://bailian.console.aliyun.com/\"\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n https://bailian.console.aliyun.com/\n </a>\n </li>\n <li>控制台右上「API-KEY」→ 创建并复制 API Key</li>\n <li>\n API 地址{' '}\n <code className=\"skai-kb-help-code\">https://dashscope.aliyuncs.com/compatible-mode/v1</code>\n :向量化模型 <code className=\"skai-kb-help-code\">text-embedding-v4</code>\n (默认 1024 维,与库内向量列一致);OCR 视觉模型{' '}\n <code className=\"skai-kb-help-code\">qwen-vl-max</code>(或 qwen3-vl 系列)\n </li>\n </ol>\n </div>\n <div className=\"skai-kb-help-section\">\n <h4 className=\"skai-kb-help-title\">百度千帆(向量化)</h4>\n <ol className=\"skai-kb-help-list\">\n <li>\n 登录百度智能云并开通千帆 ModelBuilder 服务{' '}\n <a\n className=\"skai-kb-help-link\"\n href=\"https://console.bce.baidu.com/qianfan/\"\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n https://console.bce.baidu.com/qianfan/\n </a>\n </li>\n <li>\n 在 IAM「API Key」页{' '}\n <a\n className=\"skai-kb-help-link\"\n href=\"https://console.bce.baidu.com/iam/#/iam/apikey/list\"\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n console.bce.baidu.com/iam/#/iam/apikey/list\n </a>{' '}\n 创建并复制(v2 接口按 Bearer 方式认证)\n </li>\n <li>\n API 地址 <code className=\"skai-kb-help-code\">https://qianfan.baidubce.com/v2</code>\n :向量化模型 <code className=\"skai-kb-help-code\">bge-large-zh</code>(1024 维)\n </li>\n </ol>\n </div>\n <div className=\"skai-kb-help-section\">\n <h4 className=\"skai-kb-help-title\">智谱 AI(重排 / OCR)</h4>\n <ol className=\"skai-kb-help-list\">\n <li>\n 注册并登录{' '}\n <a\n className=\"skai-kb-help-link\"\n href=\"https://open.bigmodel.cn/\"\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n https://open.bigmodel.cn/\n </a>\n </li>\n <li>控制台「API Keys」页 → 创建并复制</li>\n <li>\n API 地址{' '}\n <code className=\"skai-kb-help-code\">https://open.bigmodel.cn/api/paas/v4</code>\n :重排模型 <code className=\"skai-kb-help-code\">rerank</code>\n (Cohere 兼容 /rerank 端点);OCR 视觉模型{' '}\n <code className=\"skai-kb-help-code\">glm-4.6v-flash</code>(免费)/\n <code className=\"skai-kb-help-code\">glm-4.6v</code> /{' '}\n <code className=\"skai-kb-help-code\">GLM-OCR</code>\n </li>\n </ol>\n </div>\n <div className=\"skai-kb-help-section\">\n <h4 className=\"skai-kb-help-title\">DeepSeek(OCR)</h4>\n <ol className=\"skai-kb-help-list\">\n <li>\n 注册并登录{' '}\n <a\n className=\"skai-kb-help-link\"\n href=\"https://platform.deepseek.com/\"\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n https://platform.deepseek.com/\n </a>\n </li>\n <li>左侧「API Keys」→ 创建并复制(需先充值,按量计费)</li>\n <li>\n API 地址 <code className=\"skai-kb-help-code\">https://api.deepseek.com</code>\n :模型 <code className=\"skai-kb-help-code\">deepseek-flash</code>\n (原生多模态,支持 image_url 传图;DeepSeek 不提供向量化 / 重排服务)\n </li>\n </ol>\n </div>\n <div className=\"skai-kb-help-section\">\n <h4 className=\"skai-kb-help-title\">火山方舟(OCR)</h4>\n <ol className=\"skai-kb-help-list\">\n <li>\n 登录火山引擎(需实名认证)并进入方舟控制台{' '}\n <a\n className=\"skai-kb-help-link\"\n href=\"https://console.volcengine.com/ark/\"\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n https://console.volcengine.com/ark/\n </a>\n </li>\n <li>左侧「API Key 管理」→「创建 API Key」并复制</li>\n <li>\n 模型名直调(无需创建推理接入点):API 地址{' '}\n <code className=\"skai-kb-help-code\">https://ark.cn-beijing.volces.com/api/v3</code>\n ,OCR 模型 <code className=\"skai-kb-help-code\">doubao-seed-2-1-pro-260915</code>\n (旗舰多模态)\n </li>\n </ol>\n </div>\n <div className=\"skai-kb-help-section\">\n <h4 className=\"skai-kb-help-title\">月之暗面 Kimi(OCR)</h4>\n <ol className=\"skai-kb-help-list\">\n <li>\n 注册并登录{' '}\n <a\n className=\"skai-kb-help-link\"\n href=\"https://platform.moonshot.cn/\"\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n https://platform.moonshot.cn/\n </a>\n </li>\n <li>左侧「API Key 管理」→「新建」并复制</li>\n <li>\n API 地址 <code className=\"skai-kb-help-code\">https://api.moonshot.cn/v1</code>\n :OCR 模型 <code className=\"skai-kb-help-code\">kimi-k3.1-pro</code>(原生视觉)\n </li>\n </ol>\n </div>\n <div className=\"skai-kb-help-section\">\n <h4 className=\"skai-kb-help-title\">腾讯混元(OCR)</h4>\n <ol className=\"skai-kb-help-list\">\n <li>\n 登录腾讯云控制台{' '}\n <a\n className=\"skai-kb-help-link\"\n href=\"https://console.cloud.tencent.com/hunyuan\"\n target=\"_blank\"\n rel=\"noreferrer\"\n >\n https://console.cloud.tencent.com/hunyuan\n </a>{' '}\n 并开通混元模型服务\n </li>\n <li>左侧「API 密钥」→「创建 API Key」并复制</li>\n <li>\n API 地址{' '}\n <code className=\"skai-kb-help-code\">https://api.hunyuan.cloud.tencent.com/v1</code>\n :OCR 模型 <code className=\"skai-kb-help-code\">hunyuan-vision</code>\n </li>\n </ol>\n </div>\n <div className=\"skai-kb-help-section\">\n <h4 className=\"skai-kb-help-title\">本地部署(向量化 / 重排)</h4>\n <p className=\"skai-kb-help-text\">\n 部署栈自带 Infinity 服务(dev/docker-compose.yml 的{' '}\n <code className=\"skai-kb-help-code\">bge</code> 容器,端口{' '}\n <code className=\"skai-kb-help-code\">7997</code>\n ,同时加载向量化与重排两个模型),无需 API 密钥;编辑弹窗选择预设{' '}\n <code className=\"skai-kb-help-code\">本地部署(Infinity · bge 容器)</code>\n 即可自动回填,默认主机与当前 API 地址一致(未配置服务器时为 localhost)。\n </p>\n <p className=\"skai-kb-help-text\">\n 向量化:API 地址 <code className=\"skai-kb-help-code\">http://localhost:7997</code>,模型{' '}\n <code className=\"skai-kb-help-code\">BAAI/bge-large-zh-v1.5</code>(1024 维);重排:API 地址{' '}\n <code className=\"skai-kb-help-code\">http://localhost:7997</code>,模型{' '}\n <code className=\"skai-kb-help-code\">BAAI/bge-reranker-v2-m3</code>\n ;同 Docker 网络容器内调用时地址改用{' '}\n <code className=\"skai-kb-help-code\">http://bge:7997</code>。\n </p>\n </div>\n <div className=\"skai-kb-help-section\">\n <h4 className=\"skai-kb-help-title\">本地部署(ollama · glm-ocr容器,OCR)</h4>\n <p className=\"skai-kb-help-text\">\n 部署栈自带 <code className=\"skai-kb-help-code\">ollama</code> 容器(dev/docker-compose.yml,\n 端口 <code className=\"skai-kb-help-code\">11434</code>\n ,启动时自动拉取 <code className=\"skai-kb-help-code\">glm-ocr:q8_0</code>);编辑弹窗选择预设\n 「本地部署(ollama · glm-ocr容器)」自动回填地址(主机与当前 API 地址一致)与协议\n <code className=\"skai-kb-help-code\">ollama</code>\n ,OCR 模型填 <code className=\"skai-kb-help-code\">glm-ocr:q8_0</code>\n ;手动填写时 API 地址格式为 <code className=\"skai-kb-help-code\">http://主机:11434</code>。\n </p>\n <p className=\"skai-kb-help-text\">\n GLM-OCR 为任务专用模型,识别提示词需用官方触发前缀:全文{' '}\n <code className=\"skai-kb-help-code\">Text Recognition:</code>、表格{' '}\n <code className=\"skai-kb-help-code\">Table Recognition:</code>、图{' '}\n <code className=\"skai-kb-help-code\">Figure Recognition:</code>\n ;选择预设时已在提示词为空的情况下回填默认前缀{' '}\n <code className=\"skai-kb-help-code\">Text Recognition:</code>,自定义提示词不受影响。\n </p>\n </div>\n <div className=\"skai-kb-help-section\">\n <h4 className=\"skai-kb-help-title\">密钥与生效方式</h4>\n <p className=\"skai-kb-help-text\">\n 编辑时密钥留空或保留掩码串(含 <code className=\"skai-kb-help-code\">****</code>\n )表示沿用当前生效密钥,填入新值即更新;保存后立即生效,无需重启服务;「恢复默认」清除设置页覆盖并回落到部署环境变量配置。\n </p>\n </div>\n </Modal>\n )\n}\n","/**\n * 用户管理区块(设置页;仅管理员可见可操作,非管理员仅展示状态说明)\n *\n * - 用户列表:昵称(用户中心批量获取,仅展示)/ UID / 脱敏手机号 / 状态标签 /\n * 注册时间 / 最近审核信息;状态筛选(全部/待审核/正常/禁用)+ 关键词(UID 或\n * 手机号片段)+ 分页;管理员行标注「管理员」且不可被审核/禁用/删除\n * - 操作:审核通过(待审核→正常)、禁用(同步吊销其全部插件 Token)、启用\n * (禁用→正常)、删除(物理删除状态与授权,保留其知识库,悬空所有者由管理员\n * 经「修改所有者」接管);操作均写后端审计日志\n * - 新用户默认审核模式:需审核 / 无需审核(默认);切换仅影响之后首次验签的新用户\n */\nimport { useCallback, useEffect, useState } from 'react'\nimport {\n listUsers,\n getReviewConfig,\n setReviewConfig,\n reviewUser,\n disableUser,\n enableUser,\n deleteUser,\n} from '../../api/user.js'\nimport { toast, toastError } from '../../store/ui-store.js'\nimport { useMemberInfo } from '../../hooks/use-member-info.js'\nimport { formatTime } from '../../utils/file-type.js'\nimport ConfirmDialog from '../common/ConfirmDialog.jsx'\n\nconst PAGE_SIZE = 20\n\n/** 用户状态 → 展示文案与徽标色系(0 待审核 / 1 正常 / 2 禁用) */\nconst STATUS_VIEW = {\n 0: { text: '待审核', badge: 'skai-kb-badge-amber' },\n 1: { text: '正常', badge: 'skai-kb-badge-green' },\n 2: { text: '禁用', badge: 'skai-kb-badge-red' },\n}\n\nconst STATUS_FILTERS = [\n { value: -1, label: '全部' },\n { value: 0, label: '待审核' },\n { value: 1, label: '正常' },\n { value: 2, label: '禁用' },\n]\n\nexport default function UserManagePanel({ isAdmin }) {\n const [loading, setLoading] = useState(true)\n const [users, setUsers] = useState([])\n const [total, setTotal] = useState(0)\n const [pendingCount, setPendingCount] = useState(0)\n const [status, setStatus] = useState(-1)\n const [keyword, setKeyword] = useState('')\n const [page, setPage] = useState(1)\n const [mode, setMode] = useState(null) // null 加载中;0 无需审核;1 需审核\n const [modeBusy, setModeBusy] = useState(false)\n const [busy, setBusy] = useState(false)\n const [confirm, setConfirm] = useState(null) // { action, user }\n // 用户公开资料(昵称/头像/脱敏手机号,用户中心批量获取,仅展示不作为可信身份)\n const { infoMap } = useMemberInfo(users.map((u) => u.uid))\n\n const reload = useCallback(() => {\n if (!isAdmin) {\n setLoading(false)\n return\n }\n setLoading(true)\n listUsers({ status, keyword: keyword.trim() || undefined, page, limit: PAGE_SIZE })\n .then((res) => {\n setUsers(Array.isArray(res?.list) ? res.list : [])\n setTotal(Number(res?.total) || 0)\n setPendingCount(Number(res?.pending_count) || 0)\n })\n .catch(toastError)\n .finally(() => setLoading(false))\n }, [isAdmin, status, keyword, page])\n\n useEffect(reload, [reload])\n\n useEffect(() => {\n if (!isAdmin) return\n getReviewConfig()\n .then((res) => setMode(Number(res?.mode) === 1 ? 1 : 0))\n .catch(() => setMode(0))\n }, [isAdmin])\n\n const switchMode = (next) => {\n if (modeBusy || next === mode) return\n setModeBusy(true)\n setReviewConfig(next)\n .then(() => {\n setMode(next)\n toast(next === 1 ? '已开启需审核:新用户首次进入知识库将处于待审核状态' : '已关闭审核:新用户首次进入即为正常状态', 'success')\n })\n .catch(toastError)\n .finally(() => setModeBusy(false))\n }\n\n const runAction = () => {\n const { action, user } = confirm\n setBusy(true)\n action(user.uid)\n .then(() => {\n toast('操作成功', 'success')\n setConfirm(null)\n reload()\n })\n .catch(toastError)\n .finally(() => setBusy(false))\n }\n\n const totalPages = Math.max(1, Math.ceil(total / PAGE_SIZE))\n const canPrev = page > 1\n const canNext = page < totalPages\n\n if (!isAdmin) {\n return (\n <section className=\"skai-kb-panel\" aria-label=\"用户管理\">\n <div className=\"skai-kb-panel-head\">\n <h3>用户管理</h3>\n </div>\n <div className=\"skai-kb-sub\">用户管理仅管理员可用:审核新用户、禁用/启用账号、删除用户与配置新用户审核模式。</div>\n </section>\n )\n }\n\n return (\n <section className=\"skai-kb-panel\" aria-label=\"用户管理\">\n <div className=\"skai-kb-panel-head\">\n <h3>\n 用户管理\n {pendingCount > 0 ? <span className=\"skai-kb-badge skai-kb-badge-amber\">{pendingCount} 待审核</span> : null}\n </h3>\n </div>\n\n {/* 新用户默认审核模式 */}\n <div className=\"skai-kb-user-review-mode\">\n <span className=\"skai-kb-sub\" style={{ padding: 0 }}>\n 新用户默认审核模式(仅影响之后首次进入的新用户,不影响存量用户)\n </span>\n <div className=\"skai-kb-row-actions\">\n <button\n type=\"button\"\n className={`skai-kb-btn skai-kb-btn-sm ${mode === 1 ? 'skai-kb-btn-primary' : ''}`}\n disabled={mode === null || modeBusy}\n onClick={() => switchMode(1)}\n >\n 需审核\n </button>\n <button\n type=\"button\"\n className={`skai-kb-btn skai-kb-btn-sm ${mode === 0 ? 'skai-kb-btn-primary' : ''}`}\n disabled={mode === null || modeBusy}\n onClick={() => switchMode(0)}\n >\n 无需审核\n </button>\n </div>\n </div>\n\n {/* 筛选与关键词 */}\n <div className=\"skai-kb-user-toolbar\">\n <div className=\"skai-kb-row-actions\">\n {STATUS_FILTERS.map((f) => (\n <button\n key={f.value}\n type=\"button\"\n className={`skai-kb-btn skai-kb-btn-sm ${status === f.value ? 'skai-kb-btn-primary' : ''}`}\n onClick={() => {\n setStatus(f.value)\n setPage(1)\n }}\n >\n {f.label}\n </button>\n ))}\n </div>\n <input\n className=\"skai-kb-input skai-kb-user-search\"\n placeholder=\"搜索 UID 或手机号片段\"\n value={keyword}\n onChange={(e) => {\n setKeyword(e.target.value)\n setPage(1)\n }}\n />\n </div>\n\n {/* 用户列表 */}\n <ul className=\"skai-kb-server-list\">\n {loading ? (\n <li className=\"skai-kb-sub\">加载中…</li>\n ) : !users.length ? (\n <li className=\"skai-kb-empty skai-kb-empty-sub\">暂无符合条件的用户</li>\n ) : (\n users.map((u) => {\n const info = infoMap[String(u.uid)]\n const nickname = (info?.nickname || '').trim()\n const initial = nickname ? nickname.slice(0, 1).toUpperCase() : '#'\n const view = STATUS_VIEW[u.status] || { text: '未知', badge: 'skai-kb-badge-gray' }\n return (\n <li key={u.uid} className=\"skai-kb-server-item\">\n <span className=\"skai-kb-row\" style={{ minWidth: 0, flex: 1 }}>\n {info?.avatar ? (\n <img className=\"skai-kb-member-avatar\" src={info.avatar} alt=\"\" />\n ) : (\n <span className=\"skai-kb-member-avatar skai-kb-member-avatar-fallback\" aria-hidden=\"true\">\n {initial}\n </span>\n )}\n <span style={{ minWidth: 0 }}>\n <span className=\"skai-kb-server-name\">\n {nickname ? `${nickname} ` : ''}(UID:{u.uid})\n </span>\n <span className=\"skai-kb-sub\" style={{ display: 'block', padding: 0 }}>\n {u.masked_mobile || info?.mobile || '手机号未知'} · 进入于 {formatTime(u.create_time)}\n {u.review_time ? ` · 最近操作 ${formatTime(u.review_time)}` : ''}\n </span>\n </span>\n </span>\n {u.is_admin ? (\n <span className=\"skai-kb-badge skai-kb-badge-blue\">管理员</span>\n ) : (\n <>\n <span className={`skai-kb-badge ${view.badge}`}>{view.text}</span>\n <div className=\"skai-kb-row-actions\">\n {u.status === 0 ? (\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm\"\n disabled={busy}\n onClick={() => setConfirm({ action: reviewUser, user: u, title: '审核通过', message: `确定审核通过 uid ${u.uid} 吗?通过后该用户即可正常使用知识库全部功能。`, confirmText: '通过' })}\n >\n 审核\n </button>\n ) : null}\n {u.status === 2 ? (\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm\"\n disabled={busy}\n onClick={() => setConfirm({ action: enableUser, user: u, title: '启用用户', message: `确定启用 uid ${u.uid} 吗?启用后该用户恢复为正常状态。`, confirmText: '启用' })}\n >\n 启用\n </button>\n ) : null}\n {u.status !== 2 ? (\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm\"\n disabled={busy}\n onClick={() => setConfirm({ action: disableUser, user: u, title: '禁用用户', message: `确定禁用 uid ${u.uid} 吗?禁用后该用户全部业务功能立即不可用,其登录状态将被吊销。`, confirmText: '禁用' })}\n >\n 禁用\n </button>\n ) : null}\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm skai-kb-btn-ghost-danger\"\n disabled={busy}\n onClick={() => setConfirm({ action: deleteUser, user: u, title: '删除用户', message: `确定删除 uid ${u.uid} 吗?将移除其用户状态与全部成员授权(保留其创建的知识库,悬空所有者可经「修改所有者」接管);该用户再次登录将视为新用户。`, confirmText: '删除', danger: true })}\n >\n 删除\n </button>\n </div>\n </>\n )}\n </li>\n )\n })\n )}\n </ul>\n\n {/* 分页 */}\n {total > PAGE_SIZE ? (\n <div className=\"skai-kb-pagination\">\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-sm\" disabled={!canPrev || busy} onClick={() => setPage((p) => p - 1)}>\n 上一页\n </button>\n <span className=\"skai-kb-sub\" style={{ padding: 0 }}>\n 第 {page} / {totalPages} 页 · 共 {total} 人\n </span>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-sm\" disabled={!canNext || busy} onClick={() => setPage((p) => p + 1)}>\n 下一页\n </button>\n </div>\n ) : null}\n\n {confirm ? (\n <ConfirmDialog\n title={confirm.title}\n message={confirm.message}\n confirmText={confirm.confirmText}\n danger={confirm.danger}\n busy={busy}\n onConfirm={runAction}\n onClose={() => setConfirm(null)}\n />\n ) : null}\n </section>\n )\n}\n","/**\n * 设置页(独立标签页正文;布局对齐 CRM 设置页:页头 + panel 区块 + 行操作)\n *\n * - 页头:标题「设置」+ 右上角「添加服务器」主操作\n * - 服务器配置:多服务器增删改切(云持久化 knowledge.servers / knowledge.serverActive),\n * 当前服务器即 REST 基址与知识库 MCP 接入点,变更经 auth.subscribe 链路自动同步宿主\n * - 服务器探测:逐个探测已添加服务器(GET /kb/health 免鉴权),校验部署的应用id与版本\n * 和插件是否匹配,不匹配在该服务器条目下方红色提示(发布机制三处同号)\n * - 管理员:全局角色(昵称/uid/脱敏手机号/添加时间,资料经用户中心批量获取仅展示);\n * 管理员可添加、删除其他管理员(最后一个管理员不可删除);尚无任何管理员时可将\n * 当前登录用户初始化为管理员(首次部署「添加管理员」流程)\n * - 智能体(MCP)同步状态:宿主配置自检 + 手动重新自检 + 接入点展示\n * - 模型服务(仅管理员):向量化 / 重排 / OCR 的公网模型服务配置(优先推荐硅基流动),\n * 各行展示配置来源与模型名,支持编辑(含连通性测试、恢复默认)与配置步骤帮助\n * - 账号信息:当前用户角色与 UID(仅展示)\n */\nimport { useCallback, useEffect, useState } from 'react'\nimport {\n getServers,\n getActiveServer,\n setActiveServer,\n removeServer,\n isCloudPersistAvailable,\n subscribe,\n} from '../../core/server-config.js'\nimport { syncHostMcpAuth, checkHostMcpReady, getUserInfo } from '../../core/auth.js'\nimport { resetServerScopedStores } from '../../store/reset.js'\nimport { toast, toastError } from '../../store/ui-store.js'\nimport {\n adminExists,\n initAdmin,\n listAdmins,\n addAdminByUid,\n addAdminByMobile,\n removeAdminPending,\n removeAdmin,\n} from '../../api/auth.js'\nimport { formatTime } from '../../utils/file-type.js'\nimport { getMe } from '../../api/user.js'\nimport { getModelConfig } from '../../api/modelconfig.js'\nimport { getHealthByBase } from '../../api/health.js'\nimport { manifest } from '../../manifest.js'\nimport { useMemberInfo, findMemberByMobile } from '../../hooks/use-member-info.js'\nimport ServerFormModal from '../../components/settings/ServerFormModal.jsx'\nimport AdminFormModal from '../../components/settings/AdminFormModal.jsx'\nimport ModelServiceModal from '../../components/settings/ModelServiceModal.jsx'\nimport ModelConfigHelpModal from '../../components/settings/ModelConfigHelpModal.jsx'\nimport UserManagePanel from '../../components/settings/UserManagePanel.jsx'\nimport ConfirmDialog from '../../components/common/ConfirmDialog.jsx'\nimport Toast from '../../components/common/Toast.jsx'\nimport { Glyph, P } from '../../components/common/icons.jsx'\n\n/** MCP 自检状态 → 展示文案与色系 */\nconst MCP_STATUS_VIEW = {\n ok: { text: '已就绪:智能体会话中可使用 mcp__knowledge__* 检索工具', tone: 'success' },\n 'mismatch-fixed': { text: '配置曾不一致,已重新同步;若反复出现请查看控制台 [knowledge] 日志', tone: 'warning' },\n 'no-endpoint': { text: '尚未配置服务器,配置后自动同步 MCP', tone: 'warning' },\n 'no-token': { text: '插件 Token 未就绪(未登录或验签失败),登录后自动恢复', tone: 'warning' },\n 'no-settings': { text: '宿主 settings 服务不可用(插件版本过旧或宿主未注入)', tone: 'danger' },\n 'no-namespace': { text: '宿主未注册 knowledge 命名空间(Host 半区未加载,重启 DSH 后重试)', tone: 'danger' },\n 'no-host': { text: '非浏览器环境', tone: 'neutral' },\n error: { text: '自检失败', tone: 'danger' },\n}\n/** 自检色系 → 知识库徽标类 */\nconst TONE_BADGE = {\n success: 'skai-kb-badge-green',\n warning: 'skai-kb-badge-amber',\n danger: 'skai-kb-badge-red',\n neutral: 'skai-kb-badge-gray',\n}\n\n/** 模型服务三类配置项(面板行展示名与编辑 key,对应后端 /kb/model-config 的 item) */\nconst MODEL_ITEMS = [\n { key: 'embedding', name: '向量化(Embedding)' },\n { key: 'rerank', name: '重排(Rerank)' },\n { key: 'ocr', name: 'OCR(视觉识别)' },\n]\n/** 配置来源 → 展示文案与徽标色系(db=设置页覆盖 / env=环境变量 / unset=未配置) */\nconst MODEL_SOURCE_VIEW = {\n db: { text: '设置页配置', badge: 'skai-kb-badge-green' },\n env: { text: '环境变量配置', badge: 'skai-kb-badge-blue' },\n unset: { text: '未配置', badge: 'skai-kb-badge-gray' },\n}\n\nexport default function SettingsPage() {\n const [, forceUpdate] = useState(0)\n const [editing, setEditing] = useState(null)\n const [removing, setRemoving] = useState(null)\n const [adminInfo, setAdminInfo] = useState({\n loading: true,\n exists: false,\n isAdmin: false,\n list: [],\n pending: [],\n })\n const [addingAdmin, setAddingAdmin] = useState(false)\n const [removingAdmin, setRemovingAdmin] = useState(null)\n const [removingPending, setRemovingPending] = useState(null)\n const [adminBusy, setAdminBusy] = useState(false)\n const [busy, setBusy] = useState(false)\n const servers = getServers()\n const active = getActiveServer()\n const cloudOk = isCloudPersistAvailable()\n // 管理员公开资料(昵称/头像/脱敏手机号,用户中心批量获取,仅展示)\n const { infoMap } = useMemberInfo(adminInfo.list.map((m) => m.uid))\n\n useEffect(() => {\n const off = subscribe(() => forceUpdate((n) => n + 1))\n return off\n }, [])\n\n // 知识库 MCP 宿主配置自检:页面打开/配置变化即检查是否已在宿主就绪;\n // 值不一致自动重推修复;结构性问题给出可见原因(不再静默失败)\n const [mcpStatus, setMcpStatus] = useState({ checking: true, status: '', detail: '' })\n const runMcpCheck = useCallback(() => {\n setMcpStatus((s) => ({ ...s, checking: true }))\n return checkHostMcpReady()\n .then((res) => setMcpStatus({ checking: false, status: res.status, detail: res.detail || '' }))\n .catch((error) =>\n setMcpStatus({ checking: false, status: 'error', detail: (error && error.message) || '自检失败' }),\n )\n }, [])\n useEffect(() => {\n runMcpCheck()\n const off = subscribe(runMcpCheck)\n return () => {\n if (typeof off === 'function') off()\n }\n }, [runMcpCheck])\n\n // 服务器健康探测:逐个探测已添加服务器(GET /kb/health 免鉴权,直连各自基址),\n // 校验部署的应用id与版本和插件是否匹配;不匹配在该服务器条目下方红色提示。\n // 版本唯一来源 frontend/package.json(npm 包 / docker 镜像 / gitee tag 三处同号,scripts/release.sh)\n const [healthMap, setHealthMap] = useState({}) // 服务器id → { state: checking|ok|error, app, version, error }\n const serverSig = servers.map((s) => `${s.id}:${s.api_base}`).join('|')\n useEffect(() => {\n let cancelled = false\n for (const s of servers) {\n setHealthMap((m) =>\n m[s.id] && m[s.id].state === 'checking' ? m : { ...m, [s.id]: { state: 'checking' } },\n )\n getHealthByBase(s.api_base)\n .then((data) => {\n if (!cancelled)\n setHealthMap((m) => ({\n ...m,\n [s.id]: {\n state: 'ok',\n app: String(data?.app || ''),\n version: String(data?.version || ''),\n },\n }))\n })\n .catch((error) => {\n if (!cancelled)\n setHealthMap((m) => ({\n ...m,\n [s.id]: {\n state: 'error',\n error: (error && (error.msg || error.message)) || '请求失败',\n },\n }))\n })\n }\n return () => {\n cancelled = true\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [serverSig])\n\n // 探测结果 → 服务器条目下方的提示文案与色系(is-ok 绿 / is-danger 红 / is-muted 灰)\n const healthView = (h) => {\n if (!h || h.state === 'checking') return { cls: 'is-muted', text: '应用与版本检测中…' }\n if (h.state === 'error') return { cls: 'is-danger', text: `服务器不可达:${h.error}` }\n if (h.app && h.app !== manifest.id)\n return {\n cls: 'is-danger',\n text: `应用不匹配:该服务器部署的是「${h.app}」,本插件为 ${manifest.id}`,\n }\n if (!h.version)\n return {\n cls: 'is-danger',\n text: '后端未上报版本(版本过旧),请升级后端',\n tips: [`升级后端对应版本:在「时刻AI后台」将该应用升级到 v${manifest.version}`],\n }\n if (h.version === 'dev') return { cls: 'is-muted', text: '后端 dev(未注入版本,本地开发构建)' }\n if (h.version !== manifest.version)\n return {\n cls: 'is-danger',\n text: `前后端版本不一致:后端 v${h.version} / 插件 ${manifest.version}`,\n // 两个方向二选一:前端降到后端版本(DSH 安装命令),或后端升到前端版本(时刻AI后台)\n tips: [\n `部署前端对应版本:dsh plugin --profile web add ${manifest.packageName}@${h.version}`,\n `升级后端对应版本:在「时刻AI后台」将该应用升级到 v${manifest.version}`,\n ],\n }\n return { cls: 'is-ok', text: `应用与版本一致 v${h.version}` }\n }\n\n const reloadAdmin = () => {\n setAdminInfo((s) => ({ ...s, loading: true }))\n Promise.all([adminExists(), listAdmins()])\n .then(([status, res]) =>\n setAdminInfo({\n loading: false,\n exists: Boolean(status?.exists),\n isAdmin: Boolean(status?.is_admin),\n list: Array.isArray(res?.list) ? res.list : [],\n pending: Array.isArray(res?.pending) ? res.pending : [],\n }),\n )\n .catch(() =>\n setAdminInfo({ loading: false, exists: false, isAdmin: false, list: [], pending: [] }),\n )\n }\n useEffect(reloadAdmin, [])\n\n // 模型服务配置(仅管理员拉取展示与编辑;保存/恢复默认后重新拉取刷新)\n const [modelConfig, setModelConfig] = useState(null) // { embedding, rerank, ocr } 各 { source, enabled, config }\n const [modelLoading, setModelLoading] = useState(false)\n const [showModelHelp, setShowModelHelp] = useState(false)\n const [modelEditItem, setModelEditItem] = useState(null) // 'embedding' | 'rerank' | 'ocr' | null\n const reloadModelConfig = useCallback(() => {\n if (!adminInfo.isAdmin) return\n setModelLoading(true)\n getModelConfig()\n .then((res) => setModelConfig(res || null))\n .catch(toastError)\n .finally(() => setModelLoading(false))\n }, [adminInfo.isAdmin])\n useEffect(reloadModelConfig, [reloadModelConfig])\n\n // 自身平台状态(/user/me 豁免接口):待审核(0)/禁用(2)时隐藏「管理员」与「用户管理」区块——\n // 禁用用户换不到插件 Token,adminExists() 等请求被 40302 拦截会误判为「尚无管理员」,\n // 引导区块(添加我为管理员)对受限用户是误导性展示\n const [myStatus, setMyStatus] = useState(null) // null 未知;0 待审核;1 正常;2 禁用\n useEffect(() => {\n let cancelled = false\n getMe()\n .then((me) => !cancelled && setMyStatus(typeof me?.status === 'number' ? me.status : 1))\n .catch((error) => {\n // 被禁用户无有效 Token:getMe 经验签链路失败,40302/40301 错误码即自身状态\n if (!cancelled && error && error.code === 40302) setMyStatus(2)\n else if (!cancelled && error && error.code === 40301) setMyStatus(0)\n })\n return () => {\n cancelled = true\n }\n }, [])\n const statusRestricted = myStatus === 0 || myStatus === 2\n // 「管理员」区块仅两种情形展示:当前用户是平台管理员;或后端尚无任何管理员\n // (正常用户可见「认领首个管理员」引导,否则系统无法初始化)\n const showAdminSection = !statusRestricted && (!adminInfo.exists || adminInfo.isAdmin)\n\n const handleServerSaved = ({ added, activated }) => {\n setEditing(null)\n if (added && activated) {\n // 新增首个服务器自动激活:MCP 接入点变化,登记至宿主并清空上一服务器业务缓存\n resetServerScopedStores()\n syncHostMcpAuth()\n toast('服务器已添加并设为当前,知识库 MCP 接入点已同步至智能体', 'success')\n } else if (added) {\n toast('服务器已添加', 'success')\n } else {\n // 编辑当前服务器地址:宿主 MCP 配置随之更新\n syncHostMcpAuth()\n toast('已保存', 'success')\n }\n }\n\n const handleSwitch = (s) => {\n if (active && active.id === s.id) return\n setActiveServer(s.id)\n resetServerScopedStores()\n syncHostMcpAuth()\n toast(`已切换到「${s.name}」,业务数据将重新加载`, 'success')\n }\n\n const submitRemove = () => {\n const fallback = removing.id === (active && active.id)\n removeServer(removing.id)\n setRemoving(null)\n if (fallback) {\n resetServerScopedStores()\n syncHostMcpAuth()\n toast('已删除当前服务器,业务数据将重新加载', 'success')\n } else {\n toast('已删除', 'success')\n }\n }\n\n const handleInitAdmin = () => {\n setBusy(true)\n initAdmin()\n .then(() => {\n toast('已将当前用户设为管理员', 'success')\n })\n .catch(toastError)\n .finally(() => {\n setBusy(false)\n // 成功或「管理员已存在」等场景统一回查,及时纠正陈旧的界面状态\n reloadAdmin()\n })\n }\n\n const handleAddAdmin = ({ mobile }) => {\n setAdminBusy(true)\n // 先经用户中心按手机号解析 uid:已注册 → 直接按 uid 添加;\n // 未注册(或用户中心接口不可用)→ 回退手机号 md5 待激活授权\n findMemberByMobile(mobile)\n .then((member) => {\n if (member) {\n const label = member.nickname ? `${member.nickname}(uid ${member.uid})` : `uid ${member.uid}`\n return addAdminByUid(Number(member.uid)).then(() => {\n toast(`已添加管理员 ${label}`, 'success')\n setAddingAdmin(false)\n reloadAdmin()\n })\n }\n return addAdminByMobile(mobile).then((res) => {\n toast(\n res?.pending\n ? '该手机号尚未注册,已创建待激活授权,其注册登录后自动成为管理员'\n : '已添加管理员',\n 'success',\n )\n setAddingAdmin(false)\n reloadAdmin()\n })\n })\n .catch(toastError)\n .finally(() => setAdminBusy(false))\n }\n\n const handleRemovePending = () => {\n const target = removingPending\n setAdminBusy(true)\n removeAdminPending(target.id)\n .then(() => {\n toast(`已撤销手机号 ${target.masked_mobile || ''} 的待激活授权`, 'success')\n setRemovingPending(null)\n reloadAdmin()\n })\n .catch(toastError)\n .finally(() => setAdminBusy(false))\n }\n\n const handleRemoveAdmin = () => {\n const target = removingAdmin\n setAdminBusy(true)\n removeAdmin(target.uid)\n .then(() => {\n toast(`已删除管理员 uid ${target.uid}`, 'success')\n setRemovingAdmin(null)\n reloadAdmin()\n })\n .catch(toastError)\n .finally(() => setAdminBusy(false))\n }\n\n const mcpView =\n MCP_STATUS_VIEW[mcpStatus.status] ||\n (mcpStatus.checking ? { text: '自检中…', tone: 'neutral' } : { text: '未知状态', tone: 'neutral' })\n // 当前用户展示信息(公开资料只读,不作为可信身份)\n const meInfo = getUserInfo()\n const meUid = Number(meInfo?.uid ?? meInfo?.member_id ?? meInfo?.memberId) || 0\n\n return (\n <div className=\"skai-kb-page\">\n <header className=\"skai-kb-page-head\">\n <h2 className=\"skai-kb-page-title\">设置</h2>\n <div className=\"skai-kb-page-actions\">\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-primary\"\n onClick={() => setEditing({ id: '', name: '', api_base: '' })}\n >\n <Glyph size={12} d={P.plus} />\n 添加服务器\n </button>\n </div>\n </header>\n\n <div className=\"skai-kb-page-scroll\">\n {/* 服务器配置 */}\n <section className=\"skai-kb-panel\" aria-label=\"服务器配置\">\n <div className=\"skai-kb-panel-head\">\n <h3>服务器配置</h3>\n <span className=\"skai-kb-muted\">当前服务器即接口基址与知识库 MCP 接入点</span>\n </div>\n {servers.length ? (\n <ul className=\"skai-kb-server-list\">\n {servers.map((s) => {\n const isActive = Boolean(active && active.id === s.id)\n const health = healthView(healthMap[s.id])\n return (\n <li key={s.id} className={`skai-kb-server-item ${isActive ? 'is-active' : ''}`}>\n <div className=\"skai-kb-server-info\">\n <span className=\"skai-kb-server-name\">\n {s.name}\n {isActive ? <span className=\"skai-kb-badge skai-kb-badge-green\">当前</span> : null}\n </span>\n <span className=\"skai-kb-server-url\">{s.api_base}</span>\n <span className={`skai-kb-server-health ${health.cls}`}>{health.text}</span>\n {(health.tips || []).map((tip) => (\n <span key={tip} className=\"skai-kb-server-health is-muted\">\n · {tip}\n </span>\n ))}\n </div>\n <div className=\"skai-kb-row-actions\">\n {!isActive ? (\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-sm\" onClick={() => handleSwitch(s)}>\n 切换\n </button>\n ) : null}\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-sm\" onClick={() => setEditing(s)}>\n 编辑\n </button>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm skai-kb-btn-ghost-danger\"\n onClick={() => setRemoving(s)}\n >\n 删除\n </button>\n </div>\n </li>\n )\n })}\n </ul>\n ) : (\n <div className=\"skai-kb-empty skai-kb-empty-sub\">\n 尚未配置服务器。添加后即可使用知识库全部功能,并自动注册 mcp__knowledge__* 智能体工具。\n </div>\n )}\n {!cloudOk ? (\n <div className=\"skai-kb-sub skai-kb-cloud-hint\">\n 当前为游客态或用户中心配置接口未就绪:服务器配置仅本次会话内有效,登录后自动云同步。\n </div>\n ) : null}\n </section>\n\n {/* 模型服务(仅管理员可见):向量化 / 重排 / OCR 的公网模型服务配置 */}\n {adminInfo.isAdmin ? (\n <section className=\"skai-kb-panel\" aria-label=\"模型服务\">\n <div className=\"skai-kb-panel-head\">\n <h3>模型服务</h3>\n <span className=\"skai-kb-muted\">\n 向量化 / 重排 / OCR 支持调用互联网公网模型服务,优先推荐硅基流动\n </span>\n </div>\n <ul className=\"skai-kb-server-list\">\n {modelLoading && !modelConfig ? (\n <li className=\"skai-kb-sub\">配置加载中…</li>\n ) : (\n MODEL_ITEMS.map(({ key, name }) => {\n const entry = (modelConfig || {})[key] || {}\n const sourceView = MODEL_SOURCE_VIEW[entry.source] || MODEL_SOURCE_VIEW.unset\n return (\n <li key={key} className=\"skai-kb-server-item\">\n <div className=\"skai-kb-server-info\">\n <span className=\"skai-kb-server-name\">\n {name}\n <span className={`skai-kb-badge ${sourceView.badge}`}>{sourceView.text}</span>\n {entry.enabled === false ? (\n <span className=\"skai-kb-badge skai-kb-badge-red\">未启用</span>\n ) : null}\n </span>\n <span className=\"skai-kb-server-url\">模型:{entry.config?.model || '—'}</span>\n </div>\n <div className=\"skai-kb-row-actions\">\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm\"\n onClick={() => setShowModelHelp(true)}\n >\n 配置说明\n </button>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm\"\n onClick={() => setModelEditItem(key)}\n >\n 编辑\n </button>\n </div>\n </li>\n )\n })\n )}\n </ul>\n </section>\n ) : null}\n\n {/* 智能体(MCP)同步状态 */}\n <section className=\"skai-kb-panel\" aria-label=\"MCP 同步状态\">\n <div className=\"skai-kb-panel-head\">\n <h3>智能体(MCP)同步状态</h3>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm\"\n disabled={mcpStatus.checking}\n onClick={runMcpCheck}\n >\n <Glyph size={12} d={P.refresh} />\n 重新自检\n </button>\n </div>\n <div className=\"skai-kb-mcp-status\">\n <span className={`skai-kb-badge ${TONE_BADGE[mcpView.tone] || 'skai-kb-badge-gray'}`}>\n {mcpStatus.checking ? '检查中…' : mcpView.tone === 'success' ? '就绪' : '未就绪'}\n </span>\n <span className=\"skai-kb-mcp-text\">\n {mcpView.text}\n {mcpStatus.detail && mcpStatus.detail !== mcpView.text ? (\n <span className=\"skai-kb-muted\">({mcpStatus.detail})</span>\n ) : null}\n </span>\n </div>\n {active ? (\n <div className=\"skai-kb-sub\">\n 接入点:{active.api_base}/kb/mcp/v1 · 智能体经 mcp__knowledge__ 前缀工具检索知识库\n </div>\n ) : null}\n </section>\n\n {/* 管理员(仅平台管理员可见;后端尚无管理员时对正常用户展示认领引导;\n 待审核/禁用用户不展示:无管理能力,请求亦被门禁拦截) */}\n {showAdminSection ? (\n <section className=\"skai-kb-panel\" aria-label=\"管理员\">\n <div className=\"skai-kb-panel-head\">\n <h3>管理员</h3>\n {adminInfo.isAdmin ? (\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-primary\"\n onClick={() => setAddingAdmin(true)}\n >\n + 添加管理员\n </button>\n ) : null}\n </div>\n <div className=\"skai-kb-sub\" style={{ marginBottom: 8 }}>\n 管理员为全局角色:拥有全部知识库的最高权限,并可管理其他管理员(添加、删除);最后一个管理员不可删除\n </div>\n <ul className=\"skai-kb-server-list\">\n {adminInfo.loading ? (\n <li className=\"skai-kb-sub\">状态查询中…</li>\n ) : !adminInfo.exists ? (\n <li className=\"skai-kb-row\" style={{ justifyContent: 'space-between', gap: 8 }}>\n <span className=\"skai-kb-sub\">后端尚无管理员,可将当前登录用户初始化为管理员</span>\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-primary\"\n style={{ flex: 'none', width: 'auto' }}\n disabled={busy}\n onClick={handleInitAdmin}\n >\n {busy ? '提交中…' : '添加我为管理员'}\n </button>\n </li>\n ) : adminInfo.list.length ? (\n adminInfo.list.map((m) => {\n const info = infoMap[String(m.uid)]\n const nickname = (info?.nickname || '').trim()\n const initial = nickname ? nickname.slice(0, 1).toUpperCase() : '#'\n return (\n <li key={m.id} className=\"skai-kb-server-item\">\n <span className=\"skai-kb-row\" style={{ minWidth: 0, flex: 1 }}>\n {info?.avatar ? (\n <img className=\"skai-kb-member-avatar\" src={info.avatar} alt=\"\" />\n ) : (\n <span\n className=\"skai-kb-member-avatar skai-kb-member-avatar-fallback\"\n aria-hidden=\"true\"\n >\n {initial}\n </span>\n )}\n <span style={{ minWidth: 0 }}>\n <span className=\"skai-kb-server-name\">\n {nickname ? `${nickname} ` : ''}(UID:{m.uid})\n </span>\n <span className=\"skai-kb-sub\" style={{ display: 'block', padding: 0 }}>\n {info?.mobile ? `${info.mobile} · ` : ''}添加于 {formatTime(m.create_time)}\n </span>\n </span>\n </span>\n <span className=\"skai-kb-badge skai-kb-badge-blue\">管理员</span>\n {adminInfo.isAdmin ? (\n <div className=\"skai-kb-row-actions\">\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm skai-kb-btn-ghost-danger\"\n disabled={adminBusy}\n onClick={() => setRemovingAdmin(m)}\n >\n 删除\n </button>\n </div>\n ) : null}\n </li>\n )\n })\n ) : (\n <li className=\"skai-kb-sub\">后端已存在管理员(由部署时初始化产生)</li>\n )}\n {/* 待激活授权(手机号预添加管理员、对方尚未登录激活) */}\n {adminInfo.pending.map((p) => (\n <li key={`pending-${p.id}`} className=\"skai-kb-server-item\">\n <span className=\"skai-kb-row\" style={{ minWidth: 0, flex: 1 }}>\n <span\n className=\"skai-kb-member-avatar skai-kb-member-avatar-fallback\"\n aria-hidden=\"true\"\n >\n ?\n </span>\n <span style={{ minWidth: 0 }}>\n <span className=\"skai-kb-server-name\">{p.masked_mobile || '未激活手机号'}</span>\n <span className=\"skai-kb-sub\" style={{ display: 'block', padding: 0 }}>\n 发起于 {formatTime(p.create_time)} · 对方登录知识库后自动激活为管理员\n </span>\n </span>\n </span>\n <span className=\"skai-kb-badge\">待激活</span>\n {adminInfo.isAdmin ? (\n <div className=\"skai-kb-row-actions\">\n <button\n type=\"button\"\n className=\"skai-kb-btn skai-kb-btn-sm skai-kb-btn-ghost-danger\"\n disabled={adminBusy}\n onClick={() => setRemovingPending(p)}\n >\n 撤销\n </button>\n </div>\n ) : null}\n </li>\n ))}\n {!adminInfo.isAdmin && adminInfo.list.length ? (\n <li className=\"skai-kb-sub\">管理员由现有管理员管理;如需变更权限,请联系任一管理员</li>\n ) : null}\n </ul>\n </section>\n ) : null}\n\n {/* 用户管理(仅管理员可见可操作:状态审核/禁用/启用/删除 + 新用户审核模式) */}\n {!statusRestricted && adminInfo.isAdmin ? <UserManagePanel isAdmin /> : null}\n\n {/* 账号信息 */}\n <section className=\"skai-kb-panel\" aria-label=\"账号信息\">\n <div className=\"skai-kb-panel-head\">\n <h3>账号信息</h3>\n </div>\n <div className=\"skai-kb-detail-list\">\n <div className=\"skai-kb-detail-row\">\n <span className=\"skai-kb-field-label\">角色</span>\n <span className=\"skai-kb-detail-text\">\n {adminInfo.loading ? '识别中…' : adminInfo.isAdmin ? '管理员' : '用户'}\n </span>\n </div>\n <div className=\"skai-kb-detail-row\">\n <span className=\"skai-kb-field-label\">用户 UID</span>\n <span className=\"skai-kb-detail-text\">{meUid || '—'}</span>\n </div>\n </div>\n </section>\n </div>\n\n {/* 弹窗 */}\n {editing ? (\n <ServerFormModal\n initial={editing.id ? editing : null}\n onClose={() => setEditing(null)}\n onSaved={handleServerSaved}\n />\n ) : null}\n {removing ? (\n <ConfirmDialog\n title=\"删除服务器\"\n message={`确定删除服务器「${removing.name}」吗?仅移除云端保存的该条配置,不影响后端数据。`}\n confirmText=\"删除\"\n danger\n onConfirm={submitRemove}\n onClose={() => setRemoving(null)}\n />\n ) : null}\n {addingAdmin ? (\n <AdminFormModal busy={adminBusy} onSubmit={handleAddAdmin} onClose={() => setAddingAdmin(false)} />\n ) : null}\n {removingAdmin ? (\n <ConfirmDialog\n title=\"删除管理员\"\n message={`确定删除管理员 uid ${removingAdmin.uid} 吗?该用户将立即失去全部知识库的管理权限;如需恢复可重新添加。`}\n confirmText=\"删除\"\n danger\n busy={adminBusy}\n onConfirm={handleRemoveAdmin}\n onClose={() => setRemovingAdmin(null)}\n />\n ) : null}\n {removingPending ? (\n <ConfirmDialog\n title=\"撤销待激活授权\"\n message={`确定撤销手机号 ${removingPending.masked_mobile || ''} 的待激活授权吗?撤销后该手机号登录将不再自动成为管理员。`}\n confirmText=\"撤销\"\n danger\n busy={adminBusy}\n onConfirm={handleRemovePending}\n onClose={() => setRemovingPending(null)}\n />\n ) : null}\n {modelEditItem ? (\n <ModelServiceModal\n item={modelEditItem}\n open\n config={modelConfig?.[modelEditItem]?.config || null}\n onClose={() => setModelEditItem(null)}\n onSaved={() => {\n setModelEditItem(null)\n reloadModelConfig()\n }}\n />\n ) : null}\n {showModelHelp ? <ModelConfigHelpModal onClose={() => setShowModelHelp(false)} /> : null}\n <Toast />\n </div>\n )\n}\n","/**\n * Standalone 应用壳(非 DSH 宿主):以内部状态模拟 DSH 标签页语义\n *\n * 同一套页面组件(HomePage / KbDetailPage / DocDetailPage / SettingsPage),\n * 导航回调 openKb / openDoc / openHome / openSettings 行为与 DSH 标签页一致:\n * 打开即「新标签页」(此处渲染为顶部页签栏,可切换可关闭),页面无感宿主差异。\n * DSH 真实环境由 slots/sidebar-right.js 经 tab.actions.openTab 承载同一语义。\n */\nimport { useCallback, useMemo, useState } from 'react'\nimport HomePage from '../pages/home/HomePage.jsx'\nimport KbDetailPage from '../pages/kb/KbDetailPage.jsx'\nimport DocDetailPage from '../pages/doc/DocDetailPage.jsx'\nimport SettingsPage from '../pages/settings/SettingsPage.jsx'\nimport { KnowledgeGlyph } from '../components/common/icons.jsx'\n\nlet seq = 0\n\n/** 打开一个内部标签页(同 kind 已存在时复用并更新参数,对齐 DSH 同类标签页去重语义) */\nfunction openTabIn(tabs, setTabs, kind, params, extra) {\n const payload = { ...(params || {}), ...(extra || {}) }\n const keyOf = (t) =>\n `${t.kind}:${t.kind === 'doc' ? `${t.params.kbId}:${t.params.docId}` : t.kind === 'kb' ? t.params.kbId : ''}`\n const targetKey = `${kind}:${kind === 'doc' ? `${payload.kbId}:${payload.docId}` : kind === 'kb' ? payload.kbId : ''}`\n setTabs((prev) => {\n const idx = prev.findIndex((t) => keyOf(t) === targetKey)\n if (idx >= 0) {\n const next = prev.slice()\n next[idx] = { ...next[idx], params: payload }\n return next\n }\n return [...prev, { id: ++seq, kind, params: payload }]\n })\n}\n\nconst KIND_LABEL = {\n home: '知识库',\n kb: '知识库详情',\n doc: '文档详情',\n settings: '知识库设置',\n}\n\nexport default function StandaloneApp() {\n const [tabs, setTabs] = useState([{ id: 0, kind: 'home', params: {} }])\n const [activeId, setActiveId] = useState(0)\n const active = tabs.find((t) => t.id === activeId) || tabs[0]\n\n const nav = useMemo(\n () => ({\n openHome: () => openTabIn(tabs, setTabs, 'home', {}),\n openSettings: () => openTabIn(tabs, setTabs, 'settings', {}),\n openKb: (kbId, opts) => openTabIn(tabs, setTabs, 'kb', { kbId }, { view: opts?.view || '' }),\n openDoc: (kbId, docId) => openTabIn(tabs, setTabs, 'doc', { kbId, docId }),\n }),\n [tabs],\n )\n\n const close = useCallback(\n (id) => {\n if (tabs.length <= 1) return\n const idx = tabs.findIndex((t) => t.id === id)\n const next = tabs.filter((t) => t.id !== id)\n setTabs(next)\n if (id === activeId) setActiveId(next[Math.max(0, idx - 1)].id)\n },\n [tabs, activeId],\n )\n\n return (\n <div className=\"skai-kb-root skai-kb-app skai-kb-standalone-inner\" role=\"region\" aria-label=\"知识库\">\n <header className=\"skai-kb-header\">\n <div className=\"skai-kb-header-title\">\n <KnowledgeGlyph size={16} />\n <span>知识库</span>\n </div>\n <nav className=\"skai-kb-nav\" aria-label=\"知识库页面导航\">\n {tabs.map((t) => (\n <span key={t.id} style={{ display: 'inline-flex', flex: 'none' }}>\n <button\n type=\"button\"\n className={`skai-kb-nav-btn ${t.id === active.id ? 'is-active' : ''}`}\n onClick={() => setActiveId(t.id)}\n >\n {KIND_LABEL[t.kind] || t.kind}\n </button>\n {tabs.length > 1 ? (\n <button\n type=\"button\"\n className=\"skai-kb-tab-close\"\n aria-label={`关闭 ${KIND_LABEL[t.kind] || t.kind}`}\n onClick={(e) => {\n e.stopPropagation()\n close(t.id)\n }}\n >\n ✕\n </button>\n ) : null}\n </span>\n ))}\n </nav>\n </header>\n <main className=\"skai-kb-body\">\n {active.kind === 'home' ? <HomePage nav={nav} /> : null}\n {active.kind === 'kb' ? (\n <KbDetailPage kbId={active.params.kbId} view={active.params.view} nav={nav} />\n ) : null}\n {active.kind === 'doc' ? (\n <DocDetailPage kbId={active.params.kbId} docId={active.params.docId} nav={nav} />\n ) : null}\n {active.kind === 'settings' ? <SettingsPage /> : null}\n </main>\n </div>\n )\n}\n","export default \"/* ============================================================\\n 时刻AI知识库插件样式(前缀 skai-kb-,不覆盖宿主样式)\\n - 0.8.0 起渲染于 DSH 右侧 Sidebar 标签页正文(首页 / 知识库详情 /\\n 文档详情 / 设置 各为一个标签页)与 standalone 调试台:\\n .skai-kb-page 声明 inline-size 容器查询(与 .skai-kb-app 同名 skai-kb),\\n 布局按容器宽度自适应,不依赖视口宽度(面板开合、拖宽均正确响应)\\n - 颜色全部取 DSH 官方主题令牌(--dsw-alias-*),随宿主\\n 浅色/深色主题自动切换;var() 兜底值仅供 standalone 预览\\n (无宿主令牌)使用\\n - z-index 使用适中值(≤35),禁止覆盖宿主设置菜单\\n ============================================================ */\\n\\n/* ---------- 主题令牌别名层(统一映射到 DSH 官方令牌) ----------\\n DSH 强调色语义(与常见设计系统相反,务必注意):\\n - --dsw-alias-brand-primary:亮色主题为深色(bluish-1000)、暗色主题为浅色\\n (bluish-50),即「反色强调」——主按钮填充随主题黑白互换\\n - --dsw-alias-label-primary-foreground:强调填充上的前景文字,恒与填充反相\\n (亮色=白、暗色=黑),是主按钮等强调填充上文字的正确取值。\\n (DSH 无 --dsw-alias-brand-text;此前误用导致暗色模式白底白字)\\n - --dsw-alias-link:正文链接色(亮 deepseek-500 / 暗 deepseek-400,恒为蓝) */\\n.skai-kb-root,\\n.skai-kb-modal-mask,\\n.skai-kb-toast-layer {\\n --skai-kb-bg: var(--dsw-alias-bg-base, #ffffff);\\n --skai-kb-bg-card: var(--dsw-alias-bg-layer-1, #ffffff);\\n --skai-kb-bg-soft: var(--dsw-alias-bg-layer-2, #f6f7f9);\\n --skai-kb-bg-hover: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, 0.04));\\n --skai-kb-mask: var(--dsw-alias-bg-mask-1, rgba(17, 19, 23, 0.5));\\n --skai-kb-border: var(--dsw-alias-border-l1, #e4e6eb);\\n --skai-kb-border-strong: var(--dsw-alias-border-l2, #d0d3d9);\\n --skai-kb-text: var(--dsw-alias-label-primary, #1f2329);\\n --skai-kb-text-sub: var(--dsw-alias-label-secondary, #8a8f99);\\n --skai-kb-text-caption: var(--dsw-alias-label-caption, #9ca1ab);\\n /* 知识库品牌青色:与 DSH 侧边栏标签页/引导页图标同色(#06b6d4) */\\n --skai-kb-primary: #06b6d4;\\n /* 强调填充上的文字(官方前景令牌:亮=白 / 暗=黑;无 token 环境兜底白色) */\\n --skai-kb-on-primary: var(--dsw-alias-label-primary-foreground, #ffffff);\\n /* 主按钮:品牌青色实心 + 白字(青色为高亮度色相,不适用深底反色公式),hover 提亮一档(与 CRM 一致) */\\n --skai-kb-btn-primary: var(--skai-kb-primary);\\n --skai-kb-primary-weak: color-mix(in srgb, var(--skai-kb-primary) 12%, transparent);\\n --skai-kb-danger: var(--dsw-alias-state-error-primary, #d83931);\\n --skai-kb-danger-weak: color-mix(in srgb, var(--skai-kb-danger) 12%, transparent);\\n --skai-kb-ok: var(--dsw-alias-state-success-primary, #2ea44f);\\n --skai-kb-ok-weak: color-mix(in srgb, var(--skai-kb-ok) 14%, transparent);\\n --skai-kb-warn: var(--dsw-alias-state-warn-primary, #d97706);\\n --skai-kb-warn-weak: color-mix(in srgb, var(--skai-kb-warn) 14%, transparent);\\n --skai-kb-link: var(--skai-kb-primary);\\n --skai-kb-shadow: 0 8px 24px rgba(31, 35, 41, 0.12);\\n font: inherit;\\n font-size: 13px;\\n line-height: 1.5;\\n color: var(--skai-kb-text);\\n background: var(--skai-kb-bg);\\n scrollbar-width: thin;\\n}\\n\\n/* 盒模型统一(与 CRM 一致):root 作用域内全部 border-box */\\n.skai-kb-root *,\\n.skai-kb-root *::before,\\n.skai-kb-root *::after,\\n.skai-kb-modal-mask *,\\n.skai-kb-modal-mask *::before,\\n.skai-kb-modal-mask *::after {\\n box-sizing: border-box;\\n}\\n\\n/* 原生 button 不继承字体,与 CRM 一致显式继承宿主字体 */\\n.skai-kb-root button,\\n.skai-kb-modal-mask button {\\n font-family: inherit;\\n}\\n\\n/* 深色模式(跟随系统 prefers-color-scheme,与 CRM 插件策略一致):\\n 宿主令牌存在时仍优先取宿主值(var 包裹),此处仅提供 standalone 兜底 */\\n@media (prefers-color-scheme: dark) {\\n .skai-kb-root,\\n .skai-kb-modal-mask,\\n .skai-kb-toast-layer {\\n --skai-kb-bg: var(--dsw-alias-bg-base, #1e1f22);\\n --skai-kb-bg-card: var(--dsw-alias-bg-layer-1, #1e1f22);\\n --skai-kb-bg-soft: var(--dsw-alias-bg-layer-2, #2a2b2e);\\n --skai-kb-bg-hover: var(--dsw-alias-interactive-bg-hover, rgba(255, 255, 255, 0.08));\\n --skai-kb-mask: rgba(0, 0, 0, 0.55);\\n --skai-kb-border: var(--dsw-alias-border-l1, #2c2d2f);\\n --skai-kb-border-strong: var(--dsw-alias-border-l2, #3a3d42);\\n --skai-kb-text: var(--dsw-alias-label-primary, #e8eaed);\\n --skai-kb-text-sub: var(--dsw-alias-label-secondary, #8b8f96);\\n --skai-kb-text-caption: var(--dsw-alias-label-caption, #6f747d);\\n --skai-kb-primary: #22d3ee;\\n --skai-kb-on-primary: var(--dsw-alias-label-primary-foreground, #10131a);\\n --skai-kb-btn-primary: #06b6d4;\\n --skai-kb-danger: var(--dsw-alias-state-error-primary, #f5564e);\\n --skai-kb-ok: var(--dsw-alias-state-success-primary, #46c26a);\\n --skai-kb-warn: var(--dsw-alias-state-warn-primary, #e8a23c);\\n --skai-kb-link: var(--skai-kb-primary);\\n --skai-kb-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);\\n }\\n}\\n\\n/* ---------- 布局骨架(容器查询基准) ---------- */\\n.skai-kb-app {\\n display: flex;\\n flex-direction: column;\\n height: 100%;\\n min-height: 0;\\n position: relative;\\n container-type: inline-size;\\n container-name: skai-kb;\\n}\\n\\n/* standalone 调试台挂载容器(模拟抽屉内 100% 高度) */\\n.skai-kb-standalone-inner {\\n height: 100%;\\n min-height: 0;\\n}\\n\\n/* ---------- DSH 标签页正文骨架 ----------\\n sidebar.right.pane.tab 正文:不滚动定位容器(弹窗/Toast 绝对定位收敛于此),\\n 内容滚动由 .skai-kb-page-scroll 承担(文档详情为 .skai-kb-md-wrap) */\\n.skai-kb-tab-root {\\n height: 100%;\\n min-height: 0;\\n display: flex;\\n flex-direction: column;\\n}\\n.skai-kb-page {\\n position: relative;\\n display: flex;\\n flex-direction: column;\\n gap: 12px;\\n height: 100%;\\n min-height: 0;\\n padding: 14px 16px;\\n overflow: hidden;\\n container-type: inline-size;\\n container-name: skai-kb;\\n}\\n.skai-kb-tab-root > .skai-kb-page {\\n flex: 1;\\n}\\n.skai-kb-page-scroll {\\n flex: 1;\\n min-height: 0;\\n overflow-y: auto;\\n display: flex;\\n flex-direction: column;\\n gap: 12px;\\n}\\n\\n.skai-kb-header {\\n display: flex;\\n flex-direction: column;\\n gap: 8px;\\n padding: 14px 16px 0;\\n flex: none;\\n}\\n.skai-kb-header-title {\\n display: flex;\\n align-items: center;\\n gap: 6px;\\n font-size: 15px;\\n font-weight: 600;\\n color: var(--skai-kb-text);\\n}\\n\\n/* 分区导航:窄容器横向滑动(不换行挤压),宽容器自然展开 */\\n.skai-kb-nav {\\n display: flex;\\n gap: 4px;\\n overflow-x: auto;\\n scrollbar-width: none;\\n padding-bottom: 8px;\\n border-bottom: 1px solid var(--skai-kb-border);\\n align-items: center;\\n}\\n.skai-kb-nav::-webkit-scrollbar {\\n display: none;\\n}\\n.skai-kb-nav-btn {\\n flex: none;\\n border: none;\\n background: transparent;\\n color: var(--skai-kb-text-sub);\\n padding: 4px 10px;\\n border-radius: 999px;\\n cursor: pointer;\\n font-size: 12px;\\n transition: background 0.15s ease, color 0.15s ease;\\n}\\n.skai-kb-nav-btn:hover {\\n background: var(--skai-kb-bg-hover);\\n color: var(--skai-kb-text);\\n}\\n.skai-kb-nav-btn.is-active {\\n background: var(--skai-kb-primary-weak);\\n color: var(--skai-kb-primary);\\n font-weight: 500;\\n}\\n.skai-kb-nav-btn:focus-visible {\\n outline: 2px solid var(--skai-kb-primary);\\n outline-offset: 1px;\\n}\\n/* standalone 页签关闭钮 */\\n.skai-kb-tab-close {\\n flex: none;\\n border: none;\\n background: transparent;\\n color: var(--skai-kb-text-caption);\\n cursor: pointer;\\n font-size: 10px;\\n padding: 2px 4px;\\n border-radius: 6px;\\n}\\n.skai-kb-tab-close:hover {\\n background: var(--skai-kb-bg-hover);\\n color: var(--skai-kb-danger);\\n}\\n\\n.skai-kb-body {\\n flex: 1;\\n min-height: 0;\\n overflow-y: auto;\\n padding: 14px 16px;\\n}\\n\\n/* ---------- 详情页头(知识库详情 / 文档详情标签页) ---------- */\\n.skai-kb-detail-head {\\n flex: none;\\n display: flex;\\n flex-direction: column;\\n gap: 4px;\\n padding-bottom: 8px;\\n}\\n.skai-kb-detail-title {\\n font-weight: 600;\\n font-size: 15px;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n.skai-kb-back {\\n flex: none;\\n width: auto;\\n min-width: 0;\\n}\\n\\n/* ---------- 首页页头(左侧说明介绍 + 右上角设置入口) ---------- */\\n.skai-kb-home-head {\\n flex: none;\\n display: flex;\\n align-items: flex-start;\\n justify-content: space-between;\\n gap: 10px;\\n padding-bottom: 10px;\\n}\\n.skai-kb-home-head-main {\\n min-width: 0;\\n display: flex;\\n flex-direction: column;\\n gap: 3px;\\n}\\n.skai-kb-home-desc {\\n font-size: 12px;\\n line-height: 1.6;\\n color: var(--skai-kb-text-sub);\\n /* 介绍信息完整展示:不截断,自动换行铺满全量文字 */\\n overflow-wrap: anywhere;\\n}\\n.skai-kb-home-head > .skai-kb-btn {\\n flex: none;\\n width: auto;\\n margin-top: 1px;\\n}\\n\\n/* ---------- 通用元素 ---------- */\\n.skai-kb-btn {\\n display: inline-flex;\\n align-items: center;\\n justify-content: center;\\n gap: 5px;\\n width: auto;\\n height: 30px;\\n padding: 0 12px;\\n border: 1px solid var(--skai-kb-border);\\n border-radius: 8px;\\n background: var(--skai-kb-bg-card);\\n color: var(--skai-kb-text);\\n cursor: pointer;\\n font-size: 12.5px;\\n white-space: nowrap;\\n transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;\\n}\\n.skai-kb-btn:hover:not(:disabled) {\\n background: var(--skai-kb-bg-soft);\\n}\\n.skai-kb-btn:focus-visible {\\n outline: 2px solid var(--skai-kb-primary);\\n outline-offset: 1px;\\n}\\n.skai-kb-btn:disabled {\\n opacity: 0.55;\\n cursor: not-allowed;\\n}\\n/* 等待转圈动画(SpinnerGlyph 专用) */\\n@keyframes skai-kb-spin {\\n to {\\n transform: rotate(360deg);\\n }\\n}\\n.skai-kb-spin {\\n animation: skai-kb-spin 0.8s linear infinite;\\n flex: none;\\n}\\n.skai-kb-btn-primary {\\n background: var(--skai-kb-btn-primary);\\n border-color: transparent;\\n color: #fff;\\n}\\n.skai-kb-btn-primary:hover:not(:disabled) {\\n background: var(--skai-kb-btn-primary);\\n filter: brightness(1.08);\\n}\\n.skai-kb-btn-danger {\\n background: var(--skai-kb-danger);\\n border-color: var(--skai-kb-danger);\\n color: #fff;\\n}\\n.skai-kb-btn-danger:hover:not(:disabled) {\\n background: var(--skai-kb-danger);\\n filter: brightness(1.05);\\n}\\n.skai-kb-btn-ghost-danger {\\n border-color: transparent;\\n background: transparent;\\n color: var(--skai-kb-danger);\\n}\\n.skai-kb-btn-ghost-danger:hover:not(:disabled) {\\n background: var(--skai-kb-danger-weak);\\n}\\n.skai-kb-btn-sm {\\n width: auto;\\n height: 26px;\\n padding: 0 9px;\\n font-size: 12px;\\n border-radius: 8px;\\n}\\n\\n.skai-kb-icon-btn {\\n position: relative;\\n display: inline-flex;\\n align-items: center;\\n justify-content: center;\\n width: 26px;\\n height: 26px;\\n padding: 0;\\n border: none;\\n background: transparent;\\n color: var(--skai-kb-text-sub);\\n cursor: pointer;\\n border-radius: 8px;\\n font-size: 12px;\\n}\\n.skai-kb-icon-btn:hover {\\n background: var(--skai-kb-bg-hover);\\n color: var(--skai-kb-text);\\n}\\n/* 悬停文字提示(CSS 实现,即时显示;按钮右上角对齐避免溢出弹窗) */\\n.skai-kb-icon-btn[data-tip]:hover::after {\\n content: attr(data-tip);\\n position: absolute;\\n top: calc(100% + 4px);\\n right: 0;\\n z-index: 30;\\n padding: 4px 8px;\\n border-radius: 6px;\\n background: var(--skai-kb-bg);\\n color: var(--skai-kb-text);\\n font-size: 12px;\\n line-height: 1.4;\\n white-space: nowrap;\\n pointer-events: none;\\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\\n}\\n\\n.skai-kb-input,\\n.skai-kb-select,\\n.skai-kb-textarea {\\n width: 100%;\\n padding: 5px 10px;\\n border: 1px solid var(--skai-kb-border);\\n border-radius: 8px;\\n background: var(--skai-kb-bg);\\n color: var(--skai-kb-text);\\n /* 原生表单控件不继承字体,与 CRM 一致显式继承 */\\n font: inherit;\\n font-size: 12.5px;\\n box-sizing: border-box;\\n transition: border-color 0.15s ease, box-shadow 0.15s ease;\\n}\\n/* 下拉选择与 CRM 一致使用手型光标 */\\n.skai-kb-select {\\n cursor: pointer;\\n}\\n/* 单行输入控件与按钮(30px)同高 */\\n.skai-kb-input,\\n.skai-kb-select {\\n height: 30px;\\n}\\n.skai-kb-textarea {\\n min-height: 56px;\\n resize: vertical;\\n line-height: 1.6;\\n}\\n.skai-kb-input:focus,\\n.skai-kb-select:focus,\\n.skai-kb-textarea:focus {\\n outline: none;\\n border-color: var(--skai-kb-primary);\\n box-shadow: 0 0 0 2px var(--skai-kb-primary-weak);\\n}\\n.skai-kb-input::placeholder,\\n.skai-kb-textarea::placeholder {\\n color: var(--skai-kb-text-caption);\\n}\\n.skai-kb-field {\\n display: flex;\\n flex-direction: column;\\n gap: 4px;\\n margin-bottom: 10px;\\n}\\n.skai-kb-field-label {\\n font-size: 12px;\\n color: var(--skai-kb-text-sub);\\n}\\n.skai-kb-field-error {\\n font-size: 12px;\\n color: var(--skai-kb-danger);\\n}\\n.skai-kb-field-row {\\n display: flex;\\n gap: 8px;\\n}\\n.skai-kb-field-row > * {\\n flex: 1;\\n}\\n\\n.skai-kb-toolbar {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n margin-bottom: 10px;\\n flex-wrap: wrap;\\n flex: none;\\n}\\n.skai-kb-toolbar .skai-kb-search {\\n flex: 1;\\n min-width: 120px;\\n}\\n\\n.skai-kb-card {\\n border: 1px solid var(--skai-kb-border);\\n border-radius: 10px;\\n background: var(--skai-kb-bg-card);\\n padding: 10px 12px;\\n margin-bottom: 8px;\\n transition: border-color 0.15s ease, background 0.15s ease;\\n}\\n.skai-kb-card:hover {\\n border-color: var(--skai-kb-border-strong);\\n}\\n\\n/* 卡片列表:每行一个知识库卡片(纵向堆叠,占满整行宽度) */\\n.skai-kb-card-list {\\n display: flex;\\n flex-direction: column;\\n gap: 8px;\\n}\\n.skai-kb-card-list > .skai-kb-card {\\n margin-bottom: 0;\\n}\\n\\n.skai-kb-row {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n}\\n.skai-kb-row-between {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n gap: 8px;\\n}\\n.skai-kb-title {\\n font-weight: 600;\\n font-size: 13px;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n.skai-kb-sub {\\n padding: 7px 0 0 0;\\n font-size: 12px;\\n color: var(--skai-kb-text-sub);\\n /* 说明/介绍类文本完整展示:不截断省略,自动换行铺满全量文字 */\\n overflow-wrap: anywhere;\\n}\\n\\n.skai-kb-badge {\\n display: inline-flex;\\n align-items: center;\\n padding: 0 7px;\\n border-radius: 999px;\\n font-size: 11px;\\n line-height: 18px;\\n white-space: nowrap;\\n}\\n.skai-kb-badge-gray { background: var(--skai-kb-bg-soft); color: var(--skai-kb-text-sub); }\\n.skai-kb-badge-blue { background: var(--skai-kb-primary-weak); color: var(--skai-kb-primary); }\\n.skai-kb-badge-green { background: var(--skai-kb-ok-weak); color: var(--skai-kb-ok); }\\n.skai-kb-badge-amber { background: var(--skai-kb-warn-weak); color: var(--skai-kb-warn); }\\n.skai-kb-badge-red { background: var(--skai-kb-danger-weak); color: var(--skai-kb-danger); }\\n\\n.skai-kb-tag {\\n display: inline-block;\\n padding: 0 6px;\\n border-radius: 4px;\\n font-size: 11px;\\n line-height: 18px;\\n background: var(--skai-kb-bg-soft);\\n color: var(--skai-kb-text-sub);\\n margin-right: 4px;\\n}\\n\\n.skai-kb-empty {\\n display: flex;\\n flex-direction: column;\\n align-items: center;\\n justify-content: center;\\n gap: 6px;\\n text-align: center;\\n padding: 28px 16px;\\n color: var(--skai-kb-text-sub);\\n font-size: 13px;\\n}\\n.skai-kb-empty-sub {\\n font-size: 12px;\\n}\\n\\n.skai-kb-pagination {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n gap: 8px;\\n padding: 8px 0;\\n color: var(--skai-kb-text-sub);\\n font-size: 12px;\\n flex: none;\\n}\\n.skai-kb-pagination-btns {\\n display: flex;\\n gap: 8px;\\n}\\n\\n/* ---------- 设置页(对齐 CRM:页头 + panel 区块 + 行操作 + 详情列表) ---------- */\\n.skai-kb-page-head {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n gap: 10px;\\n flex-wrap: wrap;\\n flex: none;\\n}\\n.skai-kb-page-title {\\n display: inline-flex;\\n align-items: center;\\n gap: 6px;\\n margin: 0;\\n font-size: 15px;\\n font-weight: 600;\\n}\\n.skai-kb-page-title svg {\\n color: var(--skai-kb-primary);\\n}\\n.skai-kb-page-actions {\\n display: inline-flex;\\n align-items: center;\\n gap: 8px;\\n flex-wrap: wrap;\\n}\\n.skai-kb-panel {\\n display: flex;\\n flex-direction: column;\\n gap: 8px;\\n padding: 12px 14px;\\n border: 1px solid var(--skai-kb-border);\\n border-radius: 10px;\\n background: var(--skai-kb-bg-card);\\n}\\n.skai-kb-panel-head {\\n display: flex;\\n align-items: baseline;\\n justify-content: space-between;\\n gap: 8px;\\n flex-wrap: wrap;\\n}\\n.skai-kb-panel-head h3 {\\n margin: 0;\\n font-size: 13px;\\n font-weight: 600;\\n}\\n.skai-kb-panel-head .skai-kb-btn {\\n flex: none;\\n width: auto;\\n}\\n.skai-kb-muted {\\n color: var(--skai-kb-text-sub);\\n font-size: 12px;\\n}\\n.skai-kb-row-actions {\\n display: inline-flex;\\n align-items: center;\\n gap: 4px;\\n flex-wrap: wrap;\\n justify-content: flex-end;\\n}\\n.skai-kb-server-list {\\n display: flex;\\n flex-direction: column;\\n gap: 8px;\\n margin: 0;\\n padding: 0;\\n list-style: none;\\n}\\n.skai-kb-server-item {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n gap: 10px;\\n border: 1px solid var(--skai-kb-border);\\n border-radius: 8px;\\n background: var(--skai-kb-bg-card);\\n padding: 10px 12px;\\n transition: border-color 0.15s ease;\\n}\\n.skai-kb-server-item.is-active {\\n border-color: var(--skai-kb-primary);\\n background: var(--skai-kb-primary-weak);\\n}\\n.skai-kb-server-info {\\n display: flex;\\n flex-direction: column;\\n gap: 2px;\\n min-width: 0;\\n}\\n\\n/* 服务器条目下方健康提示(应用id / 版本匹配状态,探测 /kb/health) */\\n.skai-kb-server-health {\\n font-size: 12px;\\n line-height: 1.5;\\n}\\n\\n.skai-kb-server-health.is-ok {\\n color: var(--skai-kb-ok);\\n}\\n\\n.skai-kb-server-health.is-danger {\\n color: var(--skai-kb-danger);\\n}\\n\\n.skai-kb-server-health.is-muted {\\n color: var(--skai-kb-text-sub);\\n}\\n\\n.skai-kb-server-name {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n font-weight: 500;\\n font-size: 13px;\\n}\\n.skai-kb-server-url {\\n margin-top: 2px;\\n font-size: 12px;\\n color: var(--skai-kb-text-sub);\\n word-break: break-all;\\n}\\n.skai-kb-mcp-status {\\n display: flex;\\n align-items: flex-start;\\n gap: 8px;\\n}\\n.skai-kb-mcp-text {\\n font-size: 12.5px;\\n line-height: 1.6;\\n}\\n.skai-kb-cloud-hint {\\n padding: 8px 10px;\\n border: 1px dashed var(--skai-kb-border);\\n border-radius: 8px;\\n}\\n.skai-kb-detail-list {\\n display: flex;\\n flex-direction: column;\\n}\\n.skai-kb-detail-row {\\n display: flex;\\n gap: 12px;\\n padding: 7px 0;\\n border-bottom: 1px dashed var(--skai-kb-border);\\n font-size: 12.5px;\\n}\\n.skai-kb-detail-row:last-child {\\n border-bottom: none;\\n}\\n.skai-kb-detail-row .skai-kb-field-label {\\n width: 92px;\\n flex-shrink: 0;\\n padding-top: 1px;\\n}\\n.skai-kb-detail-text {\\n flex: 1;\\n min-width: 0;\\n word-break: break-all;\\n white-space: pre-wrap;\\n}\\n\\n/* ---------- 用户管理(设置页区块:审核模式开关 / 筛选工具条 / 状态横幅) ---------- */\\n.skai-kb-user-review-mode {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n gap: 8px;\\n flex-wrap: wrap;\\n padding: 8px 10px;\\n border: 1px dashed var(--skai-kb-border);\\n border-radius: 8px;\\n margin-bottom: 10px;\\n}\\n.skai-kb-user-toolbar {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n gap: 8px;\\n flex-wrap: wrap;\\n margin-bottom: 8px;\\n}\\n\\n/* 添加成员弹窗「从用户列表选择」候选列表(弹窗内滚动,选中高亮) */\\n.skai-kb-user-pick-list {\\n display: flex;\\n flex-direction: column;\\n gap: 4px;\\n max-height: 200px;\\n overflow-y: auto;\\n border: 1px solid var(--skai-kb-border, #e5e7eb);\\n border-radius: 8px;\\n padding: 4px;\\n margin-bottom: 8px;\\n}\\n.skai-kb-user-pick-item {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n gap: 8px;\\n width: 100%;\\n padding: 6px 8px;\\n border: none;\\n border-radius: 6px;\\n background: transparent;\\n color: inherit;\\n font-size: 12.5px;\\n text-align: left;\\n cursor: pointer;\\n}\\n.skai-kb-user-pick-item:hover {\\n background: var(--skai-kb-hover, rgba(0, 0, 0, 0.04));\\n}\\n.skai-kb-user-pick-item-active,\\n.skai-kb-user-pick-item-active:hover {\\n background: var(--skai-kb-primary-soft, rgba(49, 92, 255, 0.1));\\n}\\n.skai-kb-user-pick-nickname {\\n display: block;\\n font-weight: 500;\\n}\\n/* 多选复选标记(行首圆角方框,选中品牌色) */\\n.skai-kb-pick-check {\\n flex: none;\\n width: 16px;\\n height: 16px;\\n border: 1px solid var(--skai-kb-border, #d1d5db);\\n border-radius: 4px;\\n font-size: 11px;\\n line-height: 14px;\\n text-align: center;\\n color: #fff;\\n}\\n.skai-kb-pick-check-on {\\n background: var(--skai-kb-primary, #17b0c8);\\n border-color: var(--skai-kb-primary, #17b0c8);\\n}\\n.skai-kb-user-pick-item-disabled,\\n.skai-kb-user-pick-item-disabled:hover {\\n opacity: 0.55;\\n cursor: not-allowed;\\n background: transparent;\\n}\\n/* 已选用户 chips(头像 + 昵称 + 移除) */\\n.skai-kb-picked-chips {\\n display: flex;\\n flex-wrap: wrap;\\n gap: 6px;\\n margin-bottom: 8px;\\n}\\n.skai-kb-picked-chip {\\n display: inline-flex;\\n align-items: center;\\n gap: 6px;\\n max-width: 100%;\\n padding: 3px 6px 3px 4px;\\n border: 1px solid var(--skai-kb-border, #e5e7eb);\\n border-radius: 999px;\\n background: var(--skai-kb-primary-soft, rgba(23, 176, 200, 0.08));\\n font-size: 12px;\\n}\\n.skai-kb-picked-chip-avatar {\\n width: 18px;\\n height: 18px;\\n border-radius: 50%;\\n object-fit: cover;\\n}\\n.skai-kb-picked-chip-text {\\n min-width: 0;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n.skai-kb-picked-chip-remove {\\n flex: none;\\n width: 16px;\\n height: 16px;\\n padding: 0;\\n border: none;\\n border-radius: 50%;\\n background: rgba(0, 0, 0, 0.08);\\n color: inherit;\\n font-size: 12px;\\n line-height: 16px;\\n cursor: pointer;\\n}\\n.skai-kb-picked-chip-remove:hover {\\n background: rgba(0, 0, 0, 0.16);\\n}\\n.skai-kb-user-search {\\n width: 200px;\\n height: 26px;\\n flex: none;\\n}\\n\\n/* ---------- 弹窗(Portal 挂 body,遮罩 fixed 铺满整个窗口并居中,与 CRM 同款;\\n 弹层根已纳入文件头部主题令牌作用域;z-index ≤35 不覆盖宿主设置菜单) ---------- */\\n.skai-kb-modal-mask {\\n position: fixed;\\n inset: 0;\\n z-index: 30;\\n background: var(--skai-kb-mask);\\n display: flex;\\n align-items: center;\\n justify-content: center;\\n padding: 20px;\\n animation: skai-kb-fade-in 0.15s ease;\\n}\\n.skai-kb-modal {\\n width: 100%;\\n max-width: 520px;\\n max-height: 86%;\\n display: flex;\\n flex-direction: column;\\n background: var(--skai-kb-bg-card);\\n border-radius: 10px;\\n box-shadow: var(--skai-kb-shadow);\\n animation: skai-kb-pop-in 0.16s ease;\\n}\\n.skai-kb-modal.is-fullscreen {\\n max-width: none;\\n width: 100%;\\n max-height: 96%;\\n height: 96%;\\n}\\n.skai-kb-modal-head-actions {\\n display: inline-flex;\\n align-items: center;\\n gap: 2px;\\n flex: none;\\n}\\n.skai-kb-modal-head {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n gap: 8px;\\n padding: 12px 16px;\\n border-bottom: 1px solid var(--skai-kb-border);\\n flex: none;\\n}\\n.skai-kb-modal-title {\\n font-size: 14px;\\n font-weight: 600;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n.skai-kb-modal-body {\\n padding: 14px 16px;\\n overflow-y: auto;\\n}\\n.skai-kb-modal-foot {\\n display: flex;\\n align-items: center;\\n justify-content: flex-end;\\n gap: 8px;\\n padding: 10px 16px;\\n border-top: 1px solid var(--skai-kb-border);\\n flex: none;\\n}\\n.skai-kb-modal-foot .skai-kb-btn {\\n width: auto;\\n min-width: 72px;\\n}\\n.skai-kb-confirm-text {\\n margin: 0;\\n font-size: 13px;\\n line-height: 1.7;\\n}\\n\\n/* ---------- Toast(面板底 + 彩色描边样式,与 CRM 一致;z-index 34 宿主菜单避让约定内) ---------- */\\n.skai-kb-toast-layer {\\n /* createPortal 到 body + fixed:相对整个 DSH 窗口顶部居中(非插件标签页区域);\\n z-index 34 宿主菜单避让约定内 */\\n position: fixed;\\n left: 50%;\\n top: 18px;\\n transform: translateX(-50%);\\n z-index: 34;\\n display: flex;\\n flex-direction: column;\\n gap: 8px;\\n align-items: center;\\n pointer-events: none;\\n}\\n.skai-kb-toast {\\n pointer-events: auto;\\n max-width: 90%;\\n padding: 7px 14px;\\n border-radius: 999px;\\n font-size: 12.5px;\\n background: var(--skai-kb-bg-card);\\n border: 1px solid var(--skai-kb-border);\\n color: var(--skai-kb-text);\\n box-shadow: var(--skai-kb-shadow);\\n cursor: pointer;\\n word-break: break-all;\\n animation: skai-kb-toast-in 0.18s ease;\\n}\\n.skai-kb-toast-info { border-color: var(--skai-kb-primary); color: var(--skai-kb-primary); }\\n.skai-kb-toast-error { border-color: var(--skai-kb-danger); color: var(--skai-kb-danger); }\\n.skai-kb-toast-success { border-color: var(--skai-kb-ok); color: var(--skai-kb-ok); }\\n.skai-kb-toast-warning { border-color: var(--skai-kb-warn); color: var(--skai-kb-warn); white-space: pre-line; }\\n\\n/* ---------- 动画(与 CRM 同款节奏) ---------- */\\n@keyframes skai-kb-fade-in {\\n from { opacity: 0; }\\n to { opacity: 1; }\\n}\\n@keyframes skai-kb-pop-in {\\n from { opacity: 0; transform: translateY(8px) scale(0.98); }\\n to { opacity: 1; transform: translateY(0) scale(1); }\\n}\\n@keyframes skai-kb-toast-in {\\n from { opacity: 0; transform: translateY(-8px); }\\n to { opacity: 1; transform: translateY(0); }\\n}\\n\\n/* ---------- 概览统计(首页) ---------- */\\n.skai-kb-stat-grid {\\n display: grid;\\n grid-template-columns: repeat(2, minmax(0, 1fr));\\n gap: 10px;\\n margin-bottom: 4px;\\n}\\n.skai-kb-stat-card {\\n border: 1px solid var(--skai-kb-border);\\n border-radius: 10px;\\n background: var(--skai-kb-bg-card);\\n padding: 10px 12px;\\n}\\n.skai-kb-stat-num {\\n font-size: 18px;\\n font-weight: 600;\\n}\\n/* 统计卡内气泡(首页「用户数」待审核提示) */\\n.skai-kb-stat-badge {\\n margin-left: 8px;\\n vertical-align: 2px;\\n cursor: default;\\n}\\n.skai-kb-stat-label {\\n font-size: 12px;\\n color: var(--skai-kb-text-sub);\\n margin-top: 2px;\\n}\\n.skai-kb-quick-grid {\\n display: grid;\\n grid-template-columns: repeat(2, minmax(0, 1fr));\\n gap: 8px;\\n}\\n\\n/* ---------- 知识库卡片 ---------- */\\n.skai-kb-kb-meta {\\n display: flex;\\n gap: 12px;\\n margin-top: 6px;\\n font-size: 12px;\\n color: var(--skai-kb-text-sub);\\n flex-wrap: wrap;\\n}\\n.skai-kb-kb-actions {\\n display: flex;\\n gap: 6px;\\n margin-top: 8px;\\n flex-wrap: wrap;\\n}\\n.skai-kb-kb-actions .skai-kb-btn-sm {\\n flex: 1;\\n}\\n\\n/* ---------- 文档列表 ---------- */\\n.skai-kb-doc-item {\\n cursor: pointer;\\n}\\n\\n/* 文档卡片右上角「操作」下拉菜单(遮罩点击关闭;z-index ≤35 不覆盖宿主) */\\n.skai-kb-doc-topbar {\\n display: inline-flex;\\n align-items: center;\\n gap: 6px;\\n flex: none;\\n}\\n.skai-kb-doc-menu-anchor {\\n position: relative;\\n display: inline-flex;\\n}\\n.skai-kb-doc-menu-trigger {\\n display: inline-flex;\\n align-items: center;\\n gap: 4px;\\n line-height: 1;\\n border: none;\\n background: transparent;\\n color: var(--skai-kb-text-sub);\\n font-size: 12px;\\n padding: 2px 6px;\\n border-radius: 6px;\\n cursor: pointer;\\n}\\n/* CSS 三角下箭头:随 flex 垂直居中,字体字形对齐不可控故不用 ⌄ */\\n.skai-kb-caret {\\n width: 0;\\n height: 0;\\n border-left: 4px solid transparent;\\n border-right: 4px solid transparent;\\n border-top: 5px solid currentColor;\\n}\\n.skai-kb-doc-menu-trigger:hover {\\n background: var(--skai-kb-bg-hover);\\n color: var(--skai-kb-text);\\n}\\n.skai-kb-menu-mask {\\n position: fixed;\\n inset: 0;\\n z-index: 34;\\n}\\n.skai-kb-menu {\\n position: absolute;\\n top: 22px;\\n right: 0;\\n z-index: 35;\\n min-width: 104px;\\n padding: 4px;\\n background: var(--skai-kb-bg-card);\\n border: 1px solid var(--skai-kb-border-strong);\\n border-radius: 8px;\\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.14);\\n}\\n.skai-kb-menu-item {\\n display: block;\\n width: 100%;\\n text-align: left;\\n border: none;\\n background: transparent;\\n color: var(--skai-kb-text);\\n font-size: 12px;\\n padding: 6px 10px;\\n border-radius: 6px;\\n cursor: pointer;\\n white-space: nowrap;\\n}\\n.skai-kb-menu-item:hover {\\n background: var(--skai-kb-bg-hover);\\n}\\n.skai-kb-menu-item.is-danger {\\n color: var(--skai-kb-danger);\\n}\\n.skai-kb-menu-item.is-danger:hover {\\n background: var(--skai-kb-danger-weak);\\n}\\n\\n.skai-kb-pre {\\n white-space: pre-wrap;\\n word-break: break-word;\\n background: var(--skai-kb-bg-soft);\\n border: 1px solid var(--skai-kb-border);\\n border-radius: 8px;\\n padding: 8px 10px;\\n max-height: 260px;\\n overflow-y: auto;\\n font-size: 12px;\\n margin: 0;\\n}\\n\\n/* ---------- 文档详情正文 ---------- */\\n.skai-kb-doc-detail {\\n gap: 8px;\\n}\\n.skai-kb-md-wrap {\\n flex: 1;\\n min-height: 0;\\n overflow-y: auto;\\n border: 1px solid var(--skai-kb-border);\\n border-radius: 10px;\\n background: var(--skai-kb-bg-card);\\n padding: 14px 16px;\\n}\\n\\n/* ---------- Markdown 渲染(文档详情正文;.skai-kb-md 作用域,不外溢) ---------- */\\n.skai-kb-md {\\n font-size: 13px;\\n line-height: 1.7;\\n word-break: break-word;\\n}\\n.skai-kb-md .skai-kb-md-h {\\n font-weight: 600;\\n line-height: 1.4;\\n margin: 14px 0 6px;\\n}\\n.skai-kb-md .skai-kb-md-h:first-child {\\n margin-top: 0;\\n}\\n.skai-kb-md .skai-kb-md-h1 { font-size: 18px; }\\n.skai-kb-md .skai-kb-md-h2 { font-size: 16px; }\\n.skai-kb-md .skai-kb-md-h3 { font-size: 15px; }\\n.skai-kb-md .skai-kb-md-h4,\\n.skai-kb-md .skai-kb-md-h5,\\n.skai-kb-md .skai-kb-md-h6 { font-size: 14px; }\\n.skai-kb-md .skai-kb-md-p {\\n margin: 6px 0;\\n}\\n.skai-kb-md .skai-kb-md-code {\\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\\n font-size: 12px;\\n background: var(--skai-kb-bg-soft);\\n border: 1px solid var(--skai-kb-border);\\n border-radius: 4px;\\n padding: 0 4px;\\n}\\n.skai-kb-md .skai-kb-md-pre {\\n background: var(--skai-kb-bg-soft);\\n border: 1px solid var(--skai-kb-border);\\n border-radius: 8px;\\n padding: 10px 12px;\\n overflow-x: auto;\\n font-size: 12px;\\n line-height: 1.6;\\n margin: 8px 0;\\n white-space: pre;\\n}\\n.skai-kb-md .skai-kb-md-pre code {\\n font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\\n background: transparent;\\n border: none;\\n padding: 0;\\n}\\n.skai-kb-md .skai-kb-md-quote {\\n margin: 8px 0;\\n padding: 4px 12px;\\n border-left: 3px solid var(--skai-kb-border-strong);\\n color: var(--skai-kb-text-sub);\\n background: var(--skai-kb-bg-soft);\\n border-radius: 0 8px 8px 0;\\n}\\n.skai-kb-md .skai-kb-md-ul,\\n.skai-kb-md .skai-kb-md-ol {\\n margin: 6px 0;\\n padding-left: 22px;\\n}\\n.skai-kb-md .skai-kb-md-li {\\n margin: 2px 0;\\n}\\n.skai-kb-md .skai-kb-md-link {\\n color: var(--skai-kb-link);\\n text-decoration: none;\\n}\\n.skai-kb-md .skai-kb-md-link:hover {\\n text-decoration: underline;\\n}\\n.skai-kb-md .skai-kb-md-img {\\n max-width: 100%;\\n border-radius: 8px;\\n border: 1px solid var(--skai-kb-border);\\n}\\n.skai-kb-md .skai-kb-md-hr {\\n border: none;\\n border-top: 1px solid var(--skai-kb-border);\\n margin: 12px 0;\\n}\\n.skai-kb-md .skai-kb-md-table-wrap {\\n overflow-x: auto;\\n margin: 8px 0;\\n}\\n.skai-kb-md .skai-kb-md-table {\\n border-collapse: collapse;\\n font-size: 12px;\\n min-width: 60%;\\n}\\n.skai-kb-md .skai-kb-md-table th,\\n.skai-kb-md .skai-kb-md-table td {\\n border: 1px solid var(--skai-kb-border);\\n padding: 4px 10px;\\n text-align: left;\\n}\\n.skai-kb-md .skai-kb-md-table th {\\n background: var(--skai-kb-bg-soft);\\n font-weight: 600;\\n}\\n\\n/* ---------- 时间线(文档版本) ---------- */\\n.skai-kb-timeline {\\n list-style: none;\\n margin: 0;\\n padding: 0 0 0 14px;\\n border-left: 2px solid var(--skai-kb-border);\\n}\\n.skai-kb-timeline li {\\n position: relative;\\n padding: 0 0 12px 10px;\\n}\\n.skai-kb-timeline li::before {\\n content: '';\\n position: absolute;\\n left: -20px;\\n top: 4px;\\n width: 8px;\\n height: 8px;\\n border-radius: 50%;\\n background: var(--skai-kb-primary);\\n}\\n\\n/* ---------- 文档上传 ---------- */\\n.skai-kb-dropzone {\\n border: 1px dashed var(--skai-kb-border-strong);\\n border-radius: 8px;\\n padding: 12px;\\n}\\n\\n/* ---------- 成员权限 ---------- */\\n.skai-kb-member-row {\\n display: flex;\\n align-items: center;\\n gap: 8px;\\n padding: 6px 0;\\n border-bottom: 1px solid var(--skai-kb-border);\\n}\\n.skai-kb-member-row:last-child {\\n border-bottom: none;\\n}\\n.skai-kb-member-avatar {\\n width: 30px;\\n height: 30px;\\n border-radius: 50%;\\n flex: none;\\n object-fit: cover;\\n background: var(--skai-kb-bg-soft);\\n}\\n.skai-kb-member-avatar-fallback {\\n display: inline-flex;\\n align-items: center;\\n justify-content: center;\\n font-size: 13px;\\n font-weight: 500;\\n color: var(--skai-kb-primary);\\n background: var(--skai-kb-primary-weak);\\n}\\n.skai-kb-member-main {\\n flex: 1;\\n min-width: 0;\\n display: flex;\\n flex-direction: column;\\n gap: 1px;\\n}\\n.skai-kb-member-name {\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n.skai-kb-member-mobile {\\n font-size: 12px;\\n color: var(--skai-kb-text-sub);\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n\\n/* ============================================================\\n 宽容器布局(DSH 标签页 / standalone 宽屏):按容器宽度自适应,\\n 与视口无关(面板开合、拖宽均正确响应)\\n ============================================================ */\\n@container skai-kb (min-width: 620px) {\\n /* 概览:统计四列 */\\n .skai-kb-stat-grid {\\n grid-template-columns: repeat(4, minmax(0, 1fr));\\n }\\n .skai-kb-quick-grid {\\n grid-template-columns: repeat(3, minmax(0, 1fr));\\n }\\n}\\n\\n@container skai-kb (min-width: 980px) {\\n /* 超宽容器:正文限宽保持可读性(卡片分列由基础网格自适应) */\\n .skai-kb-page-scroll,\\n .skai-kb-md-wrap {\\n max-width: 1080px;\\n }\\n}\\n\\n/* =======================================================================\\n 目录(文件夹)管理:目录树 + 文档列表布局 + 拖拽指示\\n ======================================================================= */\\n\\n/* 详情页两栏布局:左目录树 + 右文档区(窄容器降级为上下布局) */\\n.skai-kb-doc-layout {\\n display: flex;\\n gap: 10px;\\n align-items: stretch;\\n min-height: 0;\\n}\\n\\n.skai-kb-doc-main {\\n flex: 1;\\n min-width: 0;\\n display: flex;\\n flex-direction: column;\\n gap: 10px;\\n}\\n\\n/* 目录树面板 */\\n.skai-kb-folder-tree {\\n flex: none;\\n width: 168px;\\n display: flex;\\n flex-direction: column;\\n background: var(--skai-kb-bg-card, #fff);\\n border: 1px solid var(--skai-kb-border, #e5e7eb);\\n border-radius: 10px;\\n padding: 6px;\\n align-self: flex-start;\\n position: sticky;\\n top: 0;\\n}\\n\\n.skai-kb-folder-head {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n padding: 2px 6px 6px;\\n border-bottom: 1px solid var(--skai-kb-bg-soft, #f0f1f3);\\n margin-bottom: 4px;\\n}\\n\\n.skai-kb-folder-head-title {\\n font-size: 12px;\\n font-weight: 600;\\n color: var(--skai-kb-text-sub, #6b7280);\\n}\\n\\n.skai-kb-folder-body {\\n display: flex;\\n flex-direction: column;\\n gap: 1px;\\n overflow-y: auto;\\n max-height: 320px;\\n}\\n\\n.skai-kb-folder-item {\\n display: flex;\\n align-items: center;\\n gap: 4px;\\n padding: 4px 6px;\\n border-radius: 7px;\\n cursor: pointer;\\n font-size: 12.5px;\\n color: var(--skai-kb-text, #374151);\\n border: 1px dashed transparent;\\n user-select: none;\\n min-width: 0;\\n}\\n\\n.skai-kb-folder-item:hover {\\n background: var(--skai-kb-bg-hover, #f5f6f8);\\n}\\n\\n.skai-kb-folder-item.is-active {\\n background: var(--skai-kb-primary-weak, #eef4ff);\\n color: var(--skai-kb-primary, #2f6bff);\\n font-weight: 500;\\n}\\n\\n.skai-kb-folder-arrow {\\n flex: none;\\n width: 12px;\\n font-size: 10px;\\n color: var(--skai-kb-text-caption, #9ca3af);\\n text-align: center;\\n}\\n\\n.skai-kb-folder-arrow.is-leaf {\\n visibility: hidden;\\n}\\n\\n.skai-kb-folder-icon {\\n flex: none;\\n font-size: 12px;\\n}\\n\\n.skai-kb-folder-name {\\n flex: 1;\\n min-width: 0;\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n\\n.skai-kb-folder-actions {\\n flex: none;\\n display: none;\\n gap: 2px;\\n}\\n\\n.skai-kb-folder-item:hover .skai-kb-folder-actions {\\n display: inline-flex;\\n}\\n\\n.skai-kb-folder-act {\\n border: 0;\\n background: transparent;\\n padding: 0 3px;\\n font-size: 11px;\\n line-height: 16px;\\n color: var(--skai-kb-text-caption, #9ca3af);\\n border-radius: 4px;\\n cursor: pointer;\\n}\\n\\n.skai-kb-folder-act:hover {\\n background: var(--skai-kb-bg-soft, #f0f1f3);\\n color: var(--skai-kb-primary, #2f6bff);\\n}\\n\\n.skai-kb-folder-act.is-danger:hover {\\n color: var(--skai-kb-danger, #e5484d);\\n}\\n\\n/* 目录树节点:文档拖入高亮(in)与同级排序插入线(before/after) */\\n.skai-kb-folder-item.skai-kb-drop-in {\\n border: 1px solid var(--skai-kb-primary, #2f6bff);\\n background: var(--skai-kb-primary-weak, #eef4ff);\\n}\\n\\n.skai-kb-folder-item.skai-kb-drop-before {\\n box-shadow: inset 0 2px 0 0 var(--skai-kb-primary, #2f6bff);\\n}\\n\\n.skai-kb-folder-item.skai-kb-drop-after {\\n box-shadow: inset 0 -2px 0 0 var(--skai-kb-primary, #2f6bff);\\n}\\n\\n/* 文档列表项:作为同目录排序 drop 目标时高亮 */\\n.skai-kb-doc-item.skai-kb-drop-in {\\n outline: 1.5px dashed var(--skai-kb-primary, #2f6bff);\\n outline-offset: -2px;\\n}\\n\\n/* 移动文档弹窗:目录选择列表 */\\n.skai-kb-move-list {\\n display: flex;\\n flex-direction: column;\\n gap: 2px;\\n max-height: 240px;\\n overflow-y: auto;\\n border: 1px solid var(--skai-kb-border, #e5e7eb);\\n border-radius: 8px;\\n padding: 4px;\\n}\\n\\n.skai-kb-move-item {\\n border: 0;\\n background: transparent;\\n text-align: left;\\n padding: 6px 8px;\\n font-size: 12.5px;\\n border-radius: 6px;\\n cursor: pointer;\\n color: var(--skai-kb-text, #374151);\\n overflow: hidden;\\n text-overflow: ellipsis;\\n white-space: nowrap;\\n}\\n\\n.skai-kb-move-item:hover {\\n background: var(--skai-kb-bg-hover, #f5f6f8);\\n}\\n\\n.skai-kb-move-item.is-active {\\n background: var(--skai-kb-primary-weak, #eef4ff);\\n color: var(--skai-kb-primary, #2f6bff);\\n font-weight: 500;\\n}\\n\\n/* =======================================================================\\n 文档在线编辑:Markdown 可视化编辑器(工具栏 + 双栏分屏)\\n ======================================================================= */\\n\\n.skai-kb-editor {\\n display: flex;\\n flex-direction: column;\\n gap: 8px;\\n height: 100%;\\n min-height: 320px;\\n}\\n\\n.skai-kb-editor-bar {\\n display: flex;\\n align-items: center;\\n justify-content: space-between;\\n gap: 8px;\\n flex-wrap: wrap;\\n}\\n\\n.skai-kb-editor-tools {\\n display: flex;\\n align-items: center;\\n gap: 2px;\\n flex-wrap: wrap;\\n}\\n\\n.skai-kb-editor-tool {\\n border: 1px solid var(--skai-kb-border, #e5e7eb);\\n background: var(--skai-kb-bg-card, #fff);\\n border-radius: 6px;\\n padding: 3px 7px;\\n font-size: 11.5px;\\n line-height: 16px;\\n color: var(--skai-kb-text, #374151);\\n cursor: pointer;\\n}\\n\\n.skai-kb-editor-tool:hover:not(:disabled) {\\n border-color: var(--skai-kb-primary, #2f6bff);\\n color: var(--skai-kb-primary, #2f6bff);\\n}\\n\\n.skai-kb-editor-tool:disabled {\\n opacity: 0.5;\\n cursor: not-allowed;\\n}\\n\\n.skai-kb-editor-modes {\\n display: flex;\\n align-items: center;\\n gap: 6px;\\n}\\n\\n.skai-kb-editor-mode {\\n border: 1px solid transparent;\\n background: transparent;\\n padding: 3px 8px;\\n font-size: 12px;\\n border-radius: 6px;\\n cursor: pointer;\\n color: var(--skai-kb-text-sub, #6b7280);\\n}\\n\\n.skai-kb-editor-mode.is-active {\\n background: var(--skai-kb-primary-weak, #eef4ff);\\n color: var(--skai-kb-primary, #2f6bff);\\n font-weight: 500;\\n}\\n\\n.skai-kb-editor-dirty {\\n font-size: 11px;\\n color: var(--skai-kb-warn, #d97706);\\n}\\n\\n/* 双栏分屏:编辑区 | 预览区(仅预览/仅编辑时单栏占满) */\\n.skai-kb-editor-panes {\\n display: flex;\\n gap: 8px;\\n flex: 1;\\n min-height: 0;\\n}\\n\\n.skai-kb-editor-input {\\n flex: 1;\\n min-width: 0;\\n min-height: 300px;\\n resize: vertical;\\n border: 1px solid var(--skai-kb-border, #e5e7eb);\\n border-radius: 10px;\\n padding: 10px 12px;\\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\\n font-size: 12.5px;\\n line-height: 1.6;\\n color: var(--skai-kb-text, #374151);\\n background: var(--skai-kb-bg-card, #fff);\\n}\\n\\n.skai-kb-editor-input:focus {\\n outline: none;\\n border-color: var(--skai-kb-primary, #2f6bff);\\n}\\n\\n/* 仅编辑模式:编辑框撑满父容器高度(取消最小高度下限与手动拉伸) */\\n.skai-kb-editor.edit .skai-kb-editor-input {\\n min-height: 0;\\n resize: none;\\n}\\n\\n.skai-kb-editor-preview {\\n flex: 1;\\n min-width: 0;\\n min-height: 300px;\\n border: 1px solid var(--skai-kb-border, #e5e7eb);\\n border-radius: 10px;\\n padding: 10px 12px;\\n overflow-y: auto;\\n background: var(--skai-kb-bg-soft, #fafafa);\\n}\\n\\n/* 窄容器:编辑器分屏改为上下堆叠 */\\n@container skai-kb (max-width: 560px) {\\n .skai-kb-doc-layout {\\n flex-direction: column;\\n }\\n\\n .skai-kb-folder-tree {\\n width: auto;\\n position: static;\\n }\\n\\n .skai-kb-folder-body {\\n flex-direction: row;\\n flex-wrap: wrap;\\n max-height: none;\\n }\\n\\n .skai-kb-editor-panes.split {\\n flex-direction: column;\\n }\\n\\n .skai-kb-editor-panes.split .skai-kb-editor-input,\\n .skai-kb-editor-panes.split .skai-kb-editor-preview {\\n min-height: 180px;\\n }\\n}\\n\\n/* ---------- 对话消息操作区「存入知识库」(conversation.chat.assistant-actions) ----------\\n 按钮渲染于宿主 AI 消息操作行(官方复制/点赞同款 28px 图标钮),颜色直接取\\n DSH 官方令牌(--dsw-alias-*,全局可达,随宿主浅/深色主题切换);\\n --skai-kb-* 别名仅作 standalone 兜底 */\\n.skai-kb-chat-save-btn {\\n width: 28px;\\n height: 28px;\\n display: inline-flex;\\n align-items: center;\\n justify-content: center;\\n padding: 6px;\\n color: var(--dsw-alias-label-tertiary, var(--skai-kb-text-caption, #9ca1ab));\\n background: none;\\n border: none;\\n border-radius: 28px;\\n cursor: pointer;\\n transition: color 0.15s, background 0.15s;\\n}\\n\\n.skai-kb-chat-save-btn:hover {\\n color: var(--dsw-alias-label-secondary, var(--skai-kb-text-sub, #8a8f99));\\n background: var(--dsw-alias-interactive-bg-hover, var(--skai-kb-bg-hover, rgba(0, 0, 0, 0.04)));\\n}\\n\\n.skai-kb-chat-save-preview {\\n display: flex;\\n flex-direction: column;\\n gap: 4px;\\n}\\n\\n.skai-kb-chat-save-preview-label {\\n font-size: 12px;\\n color: var(--skai-kb-text-caption);\\n}\\n\\n/* 保存方式切换(新建文档 / 覆盖已有文档):与弹窗按钮风格一致 */\\n.skai-kb-chat-save-modes {\\n display: flex;\\n gap: 8px;\\n}\\n.skai-kb-chat-save-hint {\\n display: block;\\n margin-top: 4px;\\n font-size: 12px;\\n color: var(--skai-kb-text-caption);\\n}\\n\\n.skai-kb-chat-save-preview pre {\\n max-height: 140px;\\n overflow: auto;\\n margin: 0;\\n padding: 8px 10px;\\n font-size: 12px;\\n line-height: 1.6;\\n white-space: pre-wrap;\\n word-break: break-word;\\n background: var(--skai-kb-bg-soft);\\n border-radius: 6px;\\n}\\n\\n/* ---------- 模型服务帮助弹窗(设置页「模型服务」区块「配置说明」入口) ---------- */\\n.skai-kb-help-section {\\n margin-bottom: 14px;\\n}\\n.skai-kb-help-section:last-child {\\n margin-bottom: 0;\\n}\\n.skai-kb-help-title {\\n margin: 0 0 6px;\\n font-size: 13px;\\n font-weight: 600;\\n}\\n.skai-kb-help-list {\\n margin: 0;\\n padding-left: 18px;\\n display: flex;\\n flex-direction: column;\\n gap: 4px;\\n}\\n.skai-kb-help-list li {\\n font-size: 12.5px;\\n line-height: 1.7;\\n}\\n.skai-kb-help-text {\\n margin: 0;\\n font-size: 12.5px;\\n line-height: 1.7;\\n}\\n.skai-kb-help-link {\\n color: var(--skai-kb-primary);\\n text-decoration: none;\\n word-break: break-all;\\n}\\n.skai-kb-help-link:hover {\\n text-decoration: underline;\\n}\\n.skai-kb-help-code {\\n padding: 1px 5px;\\n border-radius: 4px;\\n background: var(--skai-kb-bg-soft);\\n font-size: 12px;\\n word-break: break-all;\\n}\\n\\n\"","/**\n * 知识库插件 standalone 入口(非 DSH 宿主:静态托管 / vite 调试台)\n *\n * - install():样式注入 + 登录态事件 + 服务器配置加载(DSH client 半区共用)\n * - activate({ container }):挂载 StandaloneApp(内部导航壳:以内部状态模拟\n * DSH 标签页语义,同一套页面组件,openKb / openDoc / openSettings 行为一致)\n * - deactivate():卸载\n */\nimport { createRoot } from 'react-dom/client'\nimport { createElement } from 'react'\nimport StandaloneApp from './app/StandaloneApp.jsx'\nimport { initAuth, disposeAuth } from './core/auth.js'\nimport { initServerConfig } from './core/server-config.js'\nimport styles from './styles/knowledge.css?raw'\n\nlet styleEl = null\nlet root = null\nlet container = null\n\n/** 注入样式 + 初始化登录态/服务器配置(幂等) */\nexport function install() {\n if (typeof document === 'undefined') return\n if (!styleEl) {\n styleEl = document.createElement('style')\n styleEl.textContent = styles\n document.head.appendChild(styleEl)\n }\n initAuth()\n initServerConfig()\n}\n\n/** 挂载 standalone 应用 */\nexport function activate({ container: mountEl } = {}) {\n if (!mountEl) throw new Error('[knowledge] activate({ container }) 需要挂载容器')\n install()\n container = mountEl\n root = createRoot(mountEl)\n root.render(createElement(StandaloneApp))\n}\n\n/** 卸载 standalone 应用 */\nexport function deactivate() {\n if (root) {\n root.unmount()\n root = null\n }\n container = null\n}\n\n/** 移除样式与登录态监听(整插件停用时) */\nexport function uninstall() {\n deactivate()\n if (styleEl) {\n styleEl.remove()\n styleEl = null\n }\n disposeAuth()\n}\n\n/** DSH Client 半区入口(宿主加载 lib/client.js,不经本文件) */\nexport { apply, inject } from './client-entry.js'\n\nexport default { install, activate, deactivate, uninstall }\n","/**\n * 标签页正文与活标题(对齐 @deepseek-ai/dsh-client-ui-sidebar-right 插槽契约)\n *\n * 正文注册进 keyed 插槽 sidebar.right.pane.tab(key = 标签页类型 id),\n * 组件自动获得框架注入的 props.useTabInfo():读取 tab.navigation.params(打开时\n * 传入的 { kbId, docId } 等导航参数)、tab.actions.openTab(打开其他功能标签页)。\n * 每个「主要功能」各为一个标签页类型,经 kind 打开即新开标签页:\n * home 首页(知识库列表 / 添加知识库 / 设置入口,引导页胶囊直达)\n * kb 知识库详情(文档列表 / 权限配置 / 添加文档)\n * doc 文档详情(markdown 渲染 / 版本 / 复制文档提示语)\n * settings 设置(后端服务器地址 / 管理员)\n */\nimport { Component } from 'react'\nimport { KnowledgeGlyph } from '../components/common/icons.jsx'\nimport HomePage from '../pages/home/HomePage.jsx'\nimport KbDetailPage from '../pages/kb/KbDetailPage.jsx'\nimport DocDetailPage from '../pages/doc/DocDetailPage.jsx'\nimport SettingsPage from '../pages/settings/SettingsPage.jsx'\nimport { useStore } from '../store/create-store.js'\nimport { titleStore } from '../store/title-store.js'\n\n/** 标签页类型 id(keyed 插槽 key 域,跨插件唯一) */\nexport const TAB_TYPE = {\n home: '@shikeai/knowledge/home',\n kb: '@shikeai/knowledge/kb',\n doc: '@shikeai/knowledge/doc',\n settings: '@shikeai/knowledge/settings',\n}\n\n/** 打开类型(openTab 的 kind;kind 与类型 id 一一对应) */\nexport const TAB_KIND = {\n home: 'shikeai-knowledge-home',\n kb: 'shikeai-knowledge-kb',\n doc: 'shikeai-knowledge-doc',\n settings: 'shikeai-knowledge-settings',\n}\n\n/** 标签页类型定义表(sidebarRightTabs.register 输入;title 为打开时 chip 兜底文案) */\nexport function tabTypeDefinitions() {\n return [\n {\n id: TAB_TYPE.home,\n kind: TAB_KIND.home,\n priority: 'extension',\n title: () => '知识库',\n guide: [\n {\n id: 'knowledge-home',\n order: 20,\n title: () => '知识库',\n description: () => '知识库管理与 RAG 智能检索',\n icon: () => (\n <span style={{ color: '#06b6d4', display: 'inline-flex' }}>\n {KnowledgeGlyph({ size: 28 })}\n </span>\n ),\n },\n ],\n },\n { id: TAB_TYPE.kb, kind: TAB_KIND.kb, priority: 'extension', title: () => '知识库详情' },\n { id: TAB_TYPE.doc, kind: TAB_KIND.doc, priority: 'extension', title: () => '文档详情' },\n { id: TAB_TYPE.settings, kind: TAB_KIND.settings, priority: 'extension', title: () => '知识库设置' },\n ]\n}\n\n/** 统一导航实现:把 openTab 语义传给页面组件 */\nfunction makeNav(actions) {\n return {\n openHome: () => actions.openTab(TAB_KIND.home),\n openSettings: () => actions.openTab(TAB_KIND.settings),\n openKb: (kbId, opts) => actions.openTab(TAB_KIND.kb, { params: { kbId, view: opts?.view || '' } }),\n openDoc: (kbId, docId) => actions.openTab(TAB_KIND.doc, { params: { kbId, docId } }),\n }\n}\n\n/** 标签页根(主题令牌层 + 标签页正文骨架;页面组件与 standalone 完全共用) */\nfunction TabRoot({ children }) {\n return <div className=\"skai-kb-root skai-kb-tab-root\">{children}</div>\n}\n\n/**\n * 标签页正文自诊断边界:渲染期异常直接显示在正文区(含错误消息与组件栈),\n * 避免宿主错误边界把条目 abdicate 后只剩空白 pane 无从排查。\n * 注意:无法捕获 useTabInfo 工厂本身在 ContextualEntry 内的抛错(边界在框架层之外)。\n */\nclass TabBodyErrorBoundary extends Component {\n state = { error: null }\n\n static getDerivedStateFromError(error) {\n return { error }\n }\n\n componentDidCatch(error, info) {\n console.error('[shikeai-knowledge] 标签页正文渲染异常:', error, info?.componentStack)\n }\n\n render() {\n const { error } = this.state\n if (error) {\n return (\n <div className=\"skai-kb-root skai-kb-page\">\n <div className=\"skai-kb-empty\">\n <p>知识库标签页渲染出错</p>\n <p className=\"skai-kb-empty-sub\">{String(error && error.message ? error.message : error)}</p>\n {info_stack(error)}\n </div>\n </div>\n )\n }\n return this.props.children\n }\n}\n\n// getDerivedStateFromError 阶段拿不到 componentStack,改为在 componentDidCatch 记录;\n// 这里仅渲染错误消息主体(componentStack 经 console.error 输出)。\nfunction info_stack(error) {\n return error && error.stack ? (\n <pre className=\"skai-kb-pre\" style={{ marginTop: 8, textAlign: 'left' }}>{String(error.stack).slice(0, 800)}</pre>\n ) : null\n}\n\n/** 读取 tabInfo 并做防御:框架未注入 hook 时给出可读诊断而不是 TypeError 崩溃 */\nfunction useTabInfoSafe(props) {\n const readTabInfo = props && props.useTabInfo\n if (typeof readTabInfo !== 'function') {\n const keys = props ? Object.keys(props).join(', ') : '(无 props)'\n throw new Error(`知识库插件未收到框架注入的 useTabInfo hook(收到 props: ${keys})——检查 sidebar.right.pane.tab 座位声明`)\n }\n return readTabInfo()\n}\n\n/* ---------- 首页 ---------- */\n\n/** 首页活标题 chip:图标 + 「知识库」(对齐引导页胶囊图标) */\nexport function HomeTabTitle() {\n return (\n <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4 }}>\n <span style={{ color: '#06b6d4', display: 'inline-flex' }}>{KnowledgeGlyph({ size: 16 })}</span>\n 知识库\n </span>\n )\n}\n\nexport function HomeTabBody(props) {\n const { tab } = useTabInfoSafe(props)\n const nav = makeNav(tab.actions)\n return (\n <TabBodyErrorBoundary>\n <TabRoot>\n <HomePage nav={nav} />\n </TabRoot>\n </TabBodyErrorBoundary>\n )\n}\n\n/* ---------- 知识库详情 ---------- */\n\nexport function KbTabBody(props) {\n const { tab } = useTabInfoSafe(props)\n const nav = makeNav(tab.actions)\n const params = (tab && tab.navigation && tab.navigation.params) || {}\n return (\n <TabBodyErrorBoundary>\n <TabRoot>\n <KbDetailPage kbId={params.kbId} view={params.view || ''} nav={nav} />\n </TabRoot>\n </TabBodyErrorBoundary>\n )\n}\n\nexport function KbTabTitle(props) {\n const { tab } = props.useTabInfo()\n const kbNames = useStore(titleStore, (s) => s.kbNames)\n const params = tab.navigation.params || {}\n return kbNames[String(params.kbId)] || '知识库详情'\n}\n\n/* ---------- 文档详情 ---------- */\n\nexport function DocTabBody(props) {\n const { tab } = useTabInfoSafe(props)\n const nav = makeNav(tab.actions)\n const params = (tab && tab.navigation && tab.navigation.params) || {}\n return (\n <TabBodyErrorBoundary>\n <TabRoot>\n <DocDetailPage kbId={params.kbId} docId={params.docId} nav={nav} />\n </TabRoot>\n </TabBodyErrorBoundary>\n )\n}\n\nexport function DocTabTitle(props) {\n const { tab } = useTabInfoSafe(props)\n const docNames = useStore(titleStore, (s) => s.docNames)\n const params = (tab && tab.navigation && tab.navigation.params) || {}\n return docNames[`${params.kbId}:${params.docId}`] || '文档详情'\n}\n\n/* ---------- 设置 ---------- */\n\nexport function SettingsTabBody() {\n return (\n <TabBodyErrorBoundary>\n <TabRoot>\n <SettingsPage />\n </TabRoot>\n </TabBodyErrorBoundary>\n )\n}\n\nexport function SettingsTabTitle() {\n return '知识库设置'\n}\n\n/** 标签页正文名册(slots/sidebar-right.js 注册用) */\nexport function tabBodyRegistry() {\n return [\n { typeId: TAB_TYPE.home, Body: HomeTabBody, Title: HomeTabTitle },\n { typeId: TAB_TYPE.kb, Body: KbTabBody, Title: KbTabTitle },\n { typeId: TAB_TYPE.doc, Body: DocTabBody, Title: DocTabTitle },\n { typeId: TAB_TYPE.settings, Body: SettingsTabBody, Title: SettingsTabTitle },\n ]\n}\n","/**\n * 右侧 Sidebar 标签页注册(@deepseek-ai/dsh-client-ui-sidebar-right)\n *\n * - ctx.sidebarRightTabs.register({ id, kind, title, guide? }):声明标签页类型;\n * 仅首页类型声明 guide 条目(引导页胶囊直达),kb/doc/settings 由页面动作\n * openTab(kind, { params }) 打开(每个主要功能各一个新标签页)\n * - keyed 插槽 sidebar.right.pane.tab(key = 类型 id):标签页正文;\n * 组件自动获得 props.useTabInfo()(导航参数 / openTab 动作)\n * - keyed 插槽 sidebar.right.pane.tab.title:活标题 chip(知识库/文档加载后实时命名)\n * - ctx.slots.inject 内部等待插槽声明出现并管理注册 disposer,无需 effect 包裹注册本身\n */\nimport { tabTypeDefinitions, tabBodyRegistry } from '../app/tab-bodies.jsx'\n\n/**\n * 注册全部标签页类型、正文与活标题(client-entry apply 内调用,幂等)\n * @param {object} ctx client 半区 cordis ctx(含 sidebarRightTabs / slots)\n */\nexport function registerSidebarRightTabs(ctx) {\n // 标签页类型注册(每个类型一条注册,独立 effect 便于单点失败不影响其他类型)\n tabTypeDefinitions().forEach((def) => {\n ctx.effect(() => ctx.sidebarRightTabs.register(def), `shikeai-knowledge: tab type ${def.id}`)\n })\n\n // 正文与活标题(keyed 插槽按类型 id 分发;重复注册会抛错,effect 保证 dispose 清理)\n tabBodyRegistry().forEach(({ typeId, Body, Title }) => {\n ctx.effect(\n () =>\n ctx.slots.inject('sidebar.right.pane.tab', () =>\n ctx.slots.register({ name: 'sidebar.right.pane.tab', key: typeId }, Body),\n ),\n `shikeai-knowledge: tab body ${typeId}`,\n )\n if (Title) {\n ctx.effect(\n () =>\n ctx.slots.inject('sidebar.right.pane.tab.title', () =>\n ctx.slots.register({ name: 'sidebar.right.pane.tab.title', key: typeId }, Title),\n ),\n `shikeai-knowledge: tab title ${typeId}`,\n )\n }\n })\n}\n\nexport default registerSidebarRightTabs\n","/**\n * 知识库 MCP HTTP 客户端(client 半区直连,无状态 tools/call)\n *\n * - 与 REST(core/request.js)同源同鉴权:Authorization: Bearer <插件 Token>,\n * ensurePluginToken() 按需验签换发;后端 MCP Server(internal/mcp/server.go)的\n * tools/call 仅校验 Token、不要求 initialize 握手,客户端直发即可\n * - 401 兜底与 request.js 一致:静默清 Token → 重新验签 → 重放一次(仅一次)\n * - 未配置服务器(getMcpEndpoint() 为空串)直接抛错,不发请求\n * - 响应自适应 application/json 与 text/event-stream(后端当前返回 JSON,SSE 留兼容)\n * - 独立于 core/request.js:MCP 为 JSON-RPC 2.0 通道,响应非 {code,msg,data} 结构\n */\nimport { getMcpEndpoint } from '../core/server-config.js'\nimport { ensurePluginToken, invalidatePluginToken } from '../core/auth.js'\n\n/** 单次 RPC 超时(文档内容入库可能较大,取 30s) */\nconst MCP_TIMEOUT_MS = 30000\n\n/** MCP 调用错误(message 透出服务端 msg / JSON-RPC error.message,调用方统一读 .msg) */\nexport class McpError extends Error {\n constructor(message, code = 0) {\n super(message)\n this.name = 'McpError'\n this.code = code\n this.msg = message\n }\n}\n\nlet rpcSeq = 0\n\n/** 从 SSE 流解析出 id 匹配的 JSON-RPC 响应(读完即取消,不挂住连接) */\nasync function readSseMessage(res, wantId) {\n const reader = res.body.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n buffer += decoder.decode(value, { stream: true })\n let index\n while ((index = buffer.indexOf('\\n\\n')) >= 0) {\n const block = buffer.slice(0, index)\n buffer = buffer.slice(index + 2)\n for (const line of block.split('\\n')) {\n if (!line.startsWith('data:')) continue\n const data = line.slice(5).trim()\n if (!data) continue\n try {\n const message = JSON.parse(data)\n if (message.id === wantId) return message\n } catch {}\n }\n }\n }\n } finally {\n try {\n await reader.cancel()\n } catch {}\n }\n return null\n}\n\n/** 单次 tools/call RPC(不处理重试/重放;错误语义见 McpError.code:401=Token 失效) */\nasync function rpcOnce(url, token, name, args) {\n const id = ++rpcSeq\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), MCP_TIMEOUT_MS)\n let res\n try {\n res = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Accept: 'application/json, text/event-stream',\n Authorization: `Bearer ${token}`,\n },\n body: JSON.stringify({\n jsonrpc: '2.0',\n id,\n method: 'tools/call',\n params: { name, arguments: args || {} },\n }),\n signal: controller.signal,\n })\n } catch (error) {\n if (error && error.name === 'AbortError') throw new McpError('MCP 请求超时,请检查网络后重试')\n throw new McpError('网络连接失败,请检查内网后重试')\n } finally {\n clearTimeout(timer)\n }\n if (res.status === 401) throw new McpError('未登录或登录已失效', 401)\n if (!res.ok) {\n const text = await res.text().catch(() => '')\n throw new McpError(`MCP 请求异常(HTTP ${res.status})${text ? `:${text.slice(0, 200)}` : ''}`)\n }\n const contentType = res.headers.get('content-type') || ''\n const message = contentType.includes('text/event-stream')\n ? await readSseMessage(res, id)\n : await res.json().catch(() => null)\n if (!message) throw new McpError('MCP 响应解析失败')\n if (message.error) {\n throw new McpError(message.error.message || JSON.stringify(message.error), message.error.code || 0)\n }\n return message.result\n}\n\n/** content 数组转纯文本(text 项拼接;无 text 项时 JSON 兜底) */\nfunction textOfContent(content) {\n if (!Array.isArray(content)) return ''\n const texts = content.filter((item) => item && item.type === 'text').map((item) => item.text ?? '')\n if (texts.length) return texts.join('\\n')\n return content.length ? JSON.stringify(content) : ''\n}\n\n/**\n * 调用知识库 MCP 工具(tools/call,无状态;401 静默重验签重放一次)\n * @param {string} name 工具名(如 kb_doc_add)\n * @param {object} args 工具参数\n * @returns {Promise<object>} MCP result(isError 语义已在内部转为异常)\n */\nexport async function mcpCallTool(name, args, retried = false) {\n const url = getMcpEndpoint()\n if (!url) throw new McpError('请先在设置页配置服务器信息')\n let token\n try {\n token = await ensurePluginToken()\n } catch (error) {\n throw new McpError((error && error.message) || '请先在用户中心登录', 401)\n }\n let result\n try {\n result = await rpcOnce(url, token, name, args)\n } catch (error) {\n if (error instanceof McpError && error.code === 401 && !retried) {\n invalidatePluginToken()\n try {\n await ensurePluginToken()\n return await mcpCallTool(name, args, true)\n } catch {\n throw new McpError('请先在用户中心登录', 401)\n }\n }\n throw error\n }\n if (result && result.isError) throw new McpError(textOfContent(result.content) || '知识库工具执行失败')\n return result\n}\n\n/** 解包 MCP 工具结果为业务数据(structuredContent 优先,content[0].text JSON 兜底) */\nfunction unwrapToolData(result) {\n if (result?.structuredContent && typeof result.structuredContent === 'object') return result.structuredContent\n const text = textOfContent(result?.content)\n if (text) {\n try {\n return JSON.parse(text)\n } catch {}\n }\n return null\n}\n\n/**\n * 向知识库添加文档(MCP kb_doc_add;服务端解析/分块/向量化异步执行)\n * @param {object} p { kbId, docName, content, fileType?, tags?, folderId? }\n * @returns {Promise<{doc_id:number, task_id:number, hint?:string}>}\n */\nexport async function mcpAddDoc({ kbId, docName, content, fileType = 'md', tags, folderId }) {\n const result = await mcpCallTool('kb_doc_add', {\n kb_id: Number(kbId),\n doc_name: String(docName || ''),\n content: String(content || ''),\n file_type: fileType,\n ...(tags && tags.length ? { tags } : {}),\n ...(folderId ? { folder_id: Number(folderId) } : {}),\n })\n return unwrapToolData(result) || {}\n}\n","/**\n * 「存入知识库」图标按钮(DSH AI 消息操作区插槽组件 conversation.chat.assistant-actions)\n *\n * - props 契约(官方 dsh-client-ui-chat):owner 传 { messageId },session 作用域\n * 标准 props 注入 useChat(ChatSnapshot 选择器 hook);消息正文经 useChat 快照\n * 在 ChatNodeStore 中按 finalNode.messageId 匹配 assistant 节点取 text blocks\n * (LLM 回复本身就是 markdown,拼接原文即可;reasoning/工具块不入库)\n * - useStore 稳定快照约定:selector 返回快照本体(identity 稳定),文本派生走\n * useMemo,避免 getSnapshot 不稳定引发 React #185\n * - useChat 缺失或未命中时回退 DOM 纯文本抽取(保真度下降,仅兜底)\n * - 弹窗不挂 slot DOM(会话列 overflow 裁剪,模态不能挂进 slot——usercenter 先例):\n * Modal 自身 Portal 挂 body 固定层(z-index 30 ≤ 35,不覆盖宿主设置菜单),直接复用通用 Modal\n * - 按钮视觉对齐官方操作行(28px 图标钮,feedback 同款令牌)\n * - 提交走 MCP kb_doc_add(api/mcp.js),服务端解析/分块/向量化异步执行\n */\nimport { useEffect, useMemo, useRef, useState } from 'react'\nimport Modal from '../common/Modal.jsx'\nimport ConfirmDialog from '../common/ConfirmDialog.jsx'\nimport { BookPlusGlyph } from '../common/icons.jsx'\nimport { listKb } from '../../api/kb.js'\nimport { listDocs, updateDocContent } from '../../api/doc.js'\nimport { mcpAddDoc } from '../../api/mcp.js'\nimport { toast, toastError } from '../../store/ui-store.js'\n\n/** 按钮文案(DOM 兜底抽取时据此从克隆树中剔除按钮自身区域) */\nconst BTN_LABEL = '存入知识库'\n\n/**\n * 从 ChatSnapshot 提取指定 messageId 的 AI 回复 markdown 原文:\n * ChatNodeStore.values() 中 kind 'assistant-step' 且 data.finalNode.messageId\n * 匹配的节点,取其 blocks 的 text 项(跳过 reasoning/工具调用)以空行拼接\n */\nfunction extractTextFromChat(chat, messageId) {\n if (!chat || !messageId) return ''\n try {\n for (const node of chat.nodes.values()) {\n if (!node || node.kind !== 'assistant-step') continue\n const data = node.data\n if (!data || data.finalNode?.messageId !== messageId) continue\n return (data.blocks || [])\n .filter((b) => b && b.kind === 'text' && typeof b.text === 'string' && b.text.trim())\n .map((b) => b.text)\n .join('\\n\\n')\n .trim()\n }\n } catch {}\n return ''\n}\n\n/**\n * DOM 兜底:从操作区按钮向上找所在 turn 的 AI 回复正文(克隆后剔除\n * 按钮/图标等非正文节点)。宿主节点包裹层带 data-chat-turn=<turn>,\n * 取同 turn 的 assistant-step 节点文本\n */\nfunction extractFromDom(buttonEl) {\n if (!buttonEl || typeof document === 'undefined') return ''\n const tail = buttonEl.closest('[data-turn-tail]')\n const turnEl = tail?.closest('[data-chat-turn]') || buttonEl.closest('[data-chat-turn]')\n if (!turnEl) return ''\n const turn = turnEl.getAttribute('data-chat-turn')\n const scope = turn\n ? Array.from(document.querySelectorAll(`[data-chat-turn=\"${turn}\"]`)).find((el) =>\n (el.getAttribute('data-chat-flow-kind') || '').includes('assistant'),\n ) || turnEl.parentElement\n : turnEl.parentElement\n if (!scope) return ''\n const clone = scope.cloneNode(true)\n clone.querySelectorAll('button, svg, [aria-hidden=\"true\"]').forEach((el) => el.remove())\n if (clone.textContent.includes(BTN_LABEL)) {\n clone.querySelectorAll('span,div').forEach((el) => {\n if (!el.children.length && el.textContent.trim() === BTN_LABEL) el.remove()\n })\n }\n return (clone.innerText || clone.textContent || '').trim()\n}\n\n/** 默认文档名:首行语义摘要(≤24 字)+ 日期时间,避免重名 */\nfunction defaultDocName(text) {\n const firstLine = String(text).split('\\n').map((l) => l.trim()).find(Boolean) || ''\n const head = firstLine.replace(/[#*`>~[\\]]/g, '').slice(0, 24).trim() || '对话回复'\n const d = new Date()\n const pad = (n) => String(n).padStart(2, '0')\n return `${head}-${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}.md`\n}\n\n/**\n * 从 ChatSnapshot 提取会话最近指定的知识库文档:扫 user 消息文本中\n * 「kb_id[:=]N / doc_id[:=]N」标记(AI 编写与文档问答 prompt 均携带),\n * 取最后一条带 doc_id 的用户消息(最近上下文优先)。返回 { kbId, docId },未命中为 0\n */\nfunction extractKbDocRef(chat) {\n if (!chat || typeof chat.nodes?.values !== 'function') return { kbId: 0, docId: 0 }\n let ref = { kbId: 0, docId: 0 }\n try {\n for (const node of chat.nodes.values()) {\n if (!node || node.kind !== 'user' || !node.data) continue\n const text = (node.data.content || [])\n .map((b) => (b && typeof b.text === 'string' ? b.text : ''))\n .join('\\n')\n if (!text) continue\n const docM = text.match(/doc_id\\s*[:=:]\\s*(\\d+)/)\n if (docM) {\n const kbM = text.match(/kb_id\\s*[:=:]\\s*(\\d+)/)\n ref = { kbId: kbM ? Number(kbM[1]) : 0, docId: Number(docM[1]) }\n } else {\n const kbM = text.match(/kb_id\\s*[:=:]\\s*(\\d+)/)\n if (kbM && !ref.kbId) ref = { kbId: Number(kbM[1]), docId: 0 }\n }\n }\n } catch {}\n return ref\n}\n\nexport default function SaveToKbButton(props) {\n const { messageId, useChat } = props || {}\n const btnRef = useRef(null)\n const [open, setOpen] = useState(false)\n const [content, setContent] = useState('')\n const [kbs, setKbs] = useState([])\n const [kbLoaded, setKbLoaded] = useState(false)\n const [kbId, setKbId] = useState(0)\n const [docName, setDocName] = useState('')\n const [tags, setTags] = useState('')\n const [error, setError] = useState('')\n const [busy, setBusy] = useState(false)\n // 保存方式:create=新建文档(原有流程);overwrite=选择已有文档覆盖内容\n const [mode, setMode] = useState('create')\n const [docs, setDocs] = useState([])\n const [docsLoaded, setDocsLoaded] = useState(false)\n const [docId, setDocId] = useState(0)\n // 覆盖冲突(409 乐观锁):确认弹窗状态(替代浏览器原生 confirm)与强制覆盖执行中标记\n const [confirmForce, setConfirmForce] = useState(false)\n const [forcing, setForcing] = useState(false)\n\n // 快照本体为 selector 结果(identity 稳定);文本派生在 useMemo 内完成\n const chat = typeof useChat === 'function' ? useChat((s) => s) : null\n const chatText = useMemo(() => extractTextFromChat(chat, messageId), [chat, messageId])\n // 会话最近指定的知识库文档(AI 编写/文档问答 prompt 的 kb_id/doc_id 标记)\n const kbDocRef = useMemo(() => extractKbDocRef(chat), [chat])\n // 数值化依赖:chat 快照流式更新会换本体,依赖原始 number 避免 effect 反复重拉\n const refKbId = kbDocRef.kbId\n const refDocId = kbDocRef.docId\n\n // 弹窗首次打开拉知识库列表(复用 REST listKb;失败 toast,不阻塞弹窗)。\n // 默认知识库优先选会话指定的(ref.kbId 在列表内),否则取列表首位\n useEffect(() => {\n if (!open || kbLoaded) return undefined\n let cancelled = false\n listKb({ page: 1, limit: 100 })\n .then((res) => {\n if (cancelled) return\n const list = (res && res.list) || []\n setKbs(list)\n const first = Number(list[0]?.id) || 0\n const refKb = kbDocRef.kbId && list.some((kb) => Number(kb.id) === kbDocRef.kbId) ? kbDocRef.kbId : 0\n setKbId((cur) => cur || refKb || first)\n setKbLoaded(true)\n })\n .catch((e) => {\n if (!cancelled) toastError(e)\n })\n return () => {\n cancelled = true\n }\n }, [open, kbLoaded, refKbId])\n\n // 覆盖模式:按所选知识库拉文档列表(切库重拉)。\n // 加载完成后若会话指定文档在该库中,则默认选中它\n useEffect(() => {\n if (!open || mode !== 'overwrite' || !kbId) return undefined\n let cancelled = false\n setDocsLoaded(false)\n setDocs([])\n setDocId(0)\n listDocs(kbId, { page: 1, limit: 200 })\n .then((res) => {\n if (cancelled) return\n const list = (res && res.list) || []\n setDocs(list)\n if (refDocId && list.some((d) => Number(d.id) === refDocId)) {\n setDocId(refDocId)\n }\n })\n .catch((e) => {\n if (!cancelled) toastError(e)\n })\n .finally(() => {\n if (!cancelled) setDocsLoaded(true)\n })\n return () => {\n cancelled = true\n }\n }, [open, mode, kbId, refDocId])\n\n function openModal() {\n const text = chatText || extractFromDom(btnRef.current)\n if (!text) {\n toast('未获取到消息内容,无法保存', 'error')\n return\n }\n setContent(text)\n setDocName(defaultDocName(text))\n setTags('')\n setError('')\n setMode('create')\n setOpen(true)\n }\n\n async function submit() {\n if (!kbId) {\n setError('请选择目标知识库')\n return\n }\n setBusy(true)\n setError('')\n try {\n if (mode === 'overwrite') {\n await submitOverwrite()\n } else {\n await submitCreate()\n }\n } finally {\n setBusy(false)\n }\n }\n\n /** 新建文档:MCP kb_doc_add(服务端解析/分块/向量化异步执行) */\n async function submitCreate() {\n if (!docName.trim()) {\n setError('请输入文档名称')\n return\n }\n try {\n const tagArr = tags.split(/[,,、\\s]+/).map((t) => t.trim()).filter(Boolean)\n const data = await mcpAddDoc({ kbId, docName: docName.trim(), content, tags: tagArr })\n toast(`已存入知识库(文档 ID ${data.doc_id ?? '?'}),解析与向量化异步执行中`, 'success', 4000)\n setOpen(false)\n } catch (e) {\n setError((e && (e.msg || e.message)) || '保存失败,请稍后重试')\n }\n }\n\n /**\n * 覆盖已有文档:REST updateDocContent(走编辑权限校验 + base_updated_at 乐观锁,\n * 原内容自动保留为历史版本快照);409 冲突时确认后强制覆盖\n */\n async function submitOverwrite() {\n if (!docId) {\n setError('请选择要覆盖的文档')\n return\n }\n const target = docs.find((d) => Number(d.id) === Number(docId))\n try {\n await updateDocContent(kbId, docId, { content, baseUpdatedAt: target?.update_time || 0 })\n toast(`已覆盖文档「${target?.name || docId}」,重新解析与向量化中`, 'success', 4000)\n setOpen(false)\n } catch (e) {\n const conflict = e?.code === 409 || /冲突/.test(e?.msg || e?.message || '')\n if (conflict) {\n // 冲突转确认弹窗(替代浏览器原生 confirm),用户确认后强制覆盖\n setConfirmForce(true)\n return\n }\n setError((e && (e.msg || e.message)) || '覆盖失败,请稍后重试')\n }\n }\n\n /** 冲突确认弹窗确认后强制覆盖(force=true 跳过乐观锁) */\n async function doForceOverwrite() {\n const target = docs.find((d) => Number(d.id) === Number(docId))\n setForcing(true)\n try {\n await updateDocContent(kbId, docId, { content, baseUpdatedAt: target?.update_time || 0, force: true })\n toast(`已强制覆盖文档「${target?.name || docId}」,重新解析与向量化中`, 'success', 4000)\n setConfirmForce(false)\n setOpen(false)\n } catch (e2) {\n setConfirmForce(false)\n setError((e2 && (e2.msg || e2.message)) || '覆盖失败,请稍后重试')\n } finally {\n setForcing(false)\n }\n }\n\n return (\n <>\n <button\n ref={btnRef}\n type=\"button\"\n className=\"skai-kb-chat-save-btn\"\n title={BTN_LABEL}\n aria-label={BTN_LABEL}\n onClick={openModal}\n >\n <BookPlusGlyph size={15} />\n </button>\n\n {open ? (\n <Modal\n title=\"存入知识库\"\n width={480}\n escClose={!confirmForce}\n onClose={() => {\n if (!busy && !confirmForce) setOpen(false)\n }}\n footer={\n <>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={() => setOpen(false)} disabled={busy}>\n 取消\n </button>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-primary\" onClick={submit} disabled={busy}>\n {busy ? '提交中…' : mode === 'overwrite' ? '覆盖' : '保存'}\n </button>\n </>\n }\n >\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">保存方式</span>\n <div className=\"skai-kb-chat-save-modes\">\n <button\n type=\"button\"\n className={`skai-kb-btn${mode === 'create' ? ' skai-kb-btn-primary' : ''}`}\n onClick={() => setMode('create')}\n disabled={busy}\n >\n 新建文档\n </button>\n <button\n type=\"button\"\n className={`skai-kb-btn${mode === 'overwrite' ? ' skai-kb-btn-primary' : ''}`}\n onClick={() => {\n setMode('overwrite')\n setError('')\n }}\n disabled={busy}\n >\n 覆盖已有文档\n </button>\n </div>\n </div>\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">目标知识库 *</span>\n <select className=\"skai-kb-select\" value={kbId} onChange={(e) => setKbId(Number(e.target.value) || 0)} disabled={busy}>\n {!kbLoaded ? <option value={0}>加载中…</option> : null}\n {kbLoaded && kbs.length === 0 ? <option value={0}>(无可用知识库,请先创建)</option> : null}\n {kbs.map((kb) => (\n <option key={kb.id} value={kb.id}>\n {kb.name}\n </option>\n ))}\n </select>\n </div>\n {mode === 'overwrite' ? (\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">选择要覆盖的文档 *</span>\n <select\n className=\"skai-kb-select\"\n value={docId}\n onChange={(e) => setDocId(Number(e.target.value) || 0)}\n disabled={busy || !docsLoaded || docs.length === 0}\n >\n {!docsLoaded ? <option value={0}>加载中…</option> : null}\n {docsLoaded && docs.length === 0 ? <option value={0}>(该知识库暂无文档)</option> : null}\n {docs.map((d) => (\n <option key={d.id} value={d.id}>\n {d.name}\n </option>\n ))}\n </select>\n <span className=\"skai-kb-chat-save-hint\">覆盖将替换文档全部内容,原内容自动保留为历史版本</span>\n </div>\n ) : (\n <>\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">文档名称 *</span>\n <input\n className=\"skai-kb-input\"\n value={docName}\n maxLength={120}\n onChange={(e) => setDocName(e.target.value)}\n placeholder=\"如:接口设计要点-20260101-1530.md\"\n disabled={busy}\n />\n </div>\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">业务标签(逗号分隔,可选)</span>\n <input\n className=\"skai-kb-input\"\n value={tags}\n onChange={(e) => setTags(e.target.value)}\n placeholder=\"如:对话纪要, 方案\"\n disabled={busy}\n />\n </div>\n </>\n )}\n <div className=\"skai-kb-chat-save-preview\">\n <span className=\"skai-kb-chat-save-preview-label\">内容预览(前 200 字)</span>\n <pre>\n {content.slice(0, 200)}\n {content.length > 200 ? '…' : ''}\n </pre>\n </div>\n {error ? <div className=\"skai-kb-field-error\">{error}</div> : null}\n </Modal>\n ) : null}\n\n {/* 覆盖冲突二次确认(替代浏览器原生 confirm;Portal 同层后渲染自动盖在存入弹窗上) */}\n {confirmForce ? (\n <ConfirmDialog\n title=\"文档已被修改\"\n message=\"该文档在此期间已被其他人修改,是否强制覆盖?覆盖将替换文档全部内容,原内容自动保留为历史版本。\"\n confirmText=\"强制覆盖\"\n busy={forcing}\n onConfirm={doForceOverwrite}\n onClose={() => setConfirmForce(false)}\n />\n ) : null}\n </>\n )\n}\n","/**\n * 「引用知识库」图标按钮(DSH 输入区左侧工具行插槽 conversation.input.left)\n *\n * - props 契约(官方 dsh-client-ui-conversation,list/session 型插槽标准 props):\n * inputActions(官方输入动作面,唯一写入通道 setDraft(text))+ useInput\n * (InputState 快照选择器 hook,用于读取当前草稿)\n * - 交互链路:点击按钮 → 弹窗选择知识库 → 经 inputActions.setDraft 将\n * 引用提示语(含 kb_id 与名称)写入输入框 → 用户发送后由智能体据此\n * 调用 MCP kb_rag_query 检索该知识库(后端 mcp tools.go 已暴露该工具)\n * - 草稿保留:以「提示语 + 原问题」拼接,避免覆盖用户已输入内容\n * - 弹窗不挂 slot DOM(输入区 DOM 会被会话布局裁剪):Modal 自身 Portal 挂 body\n * 固定层(z-index 30 ≤ 35,不覆盖宿主设置菜单),直接复用通用 Modal\n * - 复用「存入知识库」按钮既有范式:同款 .skai-kb-chat-save-btn 图标钮样式、\n * 全局 toast;无新增 CSS/依赖\n */\nimport { useEffect, useState } from 'react'\nimport Modal from '../common/Modal.jsx'\nimport { BookSearchGlyph } from '../common/icons.jsx'\nimport { listKb } from '../../api/kb.js'\nimport { toast, toastError } from '../../store/ui-store.js'\n\nconst BTN_LABEL = '引用知识库'\n\n/**\n * 生成引用提示语:显式携带 kb_id 与名称,使智能体可稳定识别并调用\n * kb_rag_query(入参 kb_id/query 必填)。已有草稿时追加于提示语之后\n */\nfunction buildReference(kbId, kbName, draft) {\n const head = `请结合知识库(kb_id: ${kbId},名称:${kbName})回答我的问题`\n const q = String(draft || '').trim()\n return q ? `${head}:${q}` : `${head}:`\n}\n\nexport default function ReferenceKbButton(props) {\n const { useInput, inputActions } = props || {}\n const [open, setOpen] = useState(false)\n const [kbs, setKbs] = useState([])\n const [kbLoaded, setKbLoaded] = useState(false)\n const [kbId, setKbId] = useState(0)\n\n // 快照选择器返回字符串(identity 稳定,规避 React #185);草稿随输入实时更新\n const draft = typeof useInput === 'function' ? useInput((s) => s.draft) : ''\n\n // 弹窗首次打开拉知识库列表(复用 REST listKb;失败 toast,不阻塞弹窗)\n useEffect(() => {\n if (!open || kbLoaded) return undefined\n let cancelled = false\n listKb({ page: 1, limit: 100 })\n .then((res) => {\n if (cancelled) return\n const list = (res && res.list) || []\n setKbs(list)\n if (list.length) setKbId((cur) => cur || Number(list[0].id) || 0)\n setKbLoaded(true)\n })\n .catch((e) => {\n if (!cancelled) toastError(e)\n })\n return () => {\n cancelled = true\n }\n }, [open, kbLoaded])\n\n function openModal() {\n if (!inputActions || typeof inputActions.setDraft !== 'function') {\n toast('当前环境不支持写入输入框', 'error')\n return\n }\n setOpen(true)\n }\n\n function apply() {\n const kb = kbs.find((k) => Number(k.id) === Number(kbId))\n if (!kb) {\n toast('请选择知识库', 'error')\n return\n }\n inputActions.setDraft(buildReference(Number(kb.id), kb.name, draft))\n setOpen(false)\n }\n\n const selected = kbs.find((k) => Number(k.id) === Number(kbId)) || null\n\n return (\n <>\n <button\n type=\"button\"\n className=\"skai-kb-chat-save-btn\"\n title={BTN_LABEL}\n aria-label={BTN_LABEL}\n onClick={openModal}\n >\n <BookSearchGlyph size={15} />\n </button>\n\n {open ? (\n <Modal\n title=\"引用知识库\"\n width={480}\n onClose={() => setOpen(false)}\n footer={\n <>\n <button type=\"button\" className=\"skai-kb-btn\" onClick={() => setOpen(false)}>\n 取消\n </button>\n <button type=\"button\" className=\"skai-kb-btn skai-kb-btn-primary\" onClick={apply}>\n 引用\n </button>\n </>\n }\n >\n <div className=\"skai-kb-field\">\n <span className=\"skai-kb-field-label\">目标知识库 *</span>\n <select\n className=\"skai-kb-select\"\n value={kbId}\n onChange={(e) => setKbId(Number(e.target.value) || 0)}\n >\n {!kbLoaded ? <option value={0}>加载中…</option> : null}\n {kbLoaded && kbs.length === 0 ? <option value={0}>(无可用知识库,请先创建)</option> : null}\n {kbs.map((kb) => (\n <option key={kb.id} value={kb.id}>\n {kb.name}\n </option>\n ))}\n </select>\n </div>\n <div className=\"skai-kb-chat-save-preview\">\n <span className=\"skai-kb-chat-save-preview-label\">引用提示语预览</span>\n <pre>{buildReference(kbId || 0, selected ? selected.name : '', draft)}</pre>\n </div>\n </Modal>\n ) : null}\n </>\n )\n}\n","/**\n * DSH 对话 AI 消息操作区插槽注入(「存入知识库」图标按钮)\n *\n * - 插槽名 conversation.chat.assistant-actions(DSH 官方契约,dsh-client-ui-chat\n * 声明:kind 'list' / scope 'session',owner 传 { messageId };官方点赞点踩\n * (dsh-client-ui-message-feedback,order 10)走同一插槽,本入口 order 20 排其后\n * - list 型插槽注册:register 必选自有 id(独立 cell,fresh id 新增、复用 id 替换)\n * - 组件标准 props:sessionId 作用域插槽自动注入 useChat(ChatSnapshot 选择器\n * hook),消息正文由组件经 messageId 查 ChatNodeStore 得到(见 SaveToKbButton)\n * - ctx.slots.inject 内部等待插槽声明出现并管理注册 disposer\n */\nimport SaveToKbButton from '../components/chat/SaveToKbButton.jsx'\nimport ReferenceKbButton from '../components/chat/ReferenceKbButton.jsx'\n\n/** DSH AI 消息操作区插槽(官方 dsh-client-ui-chat 声明) */\nconst CHAT_ASSISTANT_ACTIONS_SLOT = 'conversation.chat.assistant-actions'\n\n/**\n * 注册 AI 消息操作区「存入知识库」入口(client-entry apply 内调用,幂等)\n * @param {object} ctx client 半区 cordis ctx(含 slots)\n */\nexport function registerChatMessageSlots(ctx) {\n ctx.effect(\n () =>\n ctx.slots.inject(CHAT_ASSISTANT_ACTIONS_SLOT, () =>\n ctx.slots.register(\n { name: CHAT_ASSISTANT_ACTIONS_SLOT, id: 'shikeai-knowledge-save-kb', order: 20 },\n SaveToKbButton,\n ),\n ),\n 'shikeai-knowledge: chat assistant-actions save-to-kb',\n )\n}\n\n/** DSH 输入区左侧工具行插槽(官方 dsh-client-ui-conversation 声明;list/session,无现有占用) */\nconst CONVERSATION_INPUT_LEFT_SLOT = 'conversation.input.left'\n\n/**\n * 注册输入区「引用知识库」入口(client-entry apply 内调用,幂等)\n * 选中知识库后经 inputActions.setDraft 将引用提示语写入输入框,\n * 由智能体据此调用 MCP kb_rag_query 检索对应知识库\n * @param {object} ctx client 半区 cordis ctx(含 slots)\n */\nexport function registerChatInputSlots(ctx) {\n ctx.effect(\n () =>\n ctx.slots.inject(CONVERSATION_INPUT_LEFT_SLOT, () =>\n ctx.slots.register(\n { name: CONVERSATION_INPUT_LEFT_SLOT, id: 'shikeai-knowledge-reference-kb', order: 30 },\n ReferenceKbButton,\n ),\n ),\n 'shikeai-knowledge: conversation input-left reference-kb',\n )\n}\n\nexport default registerChatMessageSlots\n","/**\n * DSH Web Client 半区入口(构建为 lib/client.js 的 ModuleLoader bundle)\n *\n * 挂载方式(DSH 右侧 Sidebar 标签页体系,每个主要功能各一个标签页):\n * - ctx.sidebarRightTabs.register:注册 4 个标签页类型\n * 首页 shikeai-knowledge-home(引导页胶囊直达;知识库列表/添加知识库/设置入口)\n * 知识库详情 shikeai-knowledge-kb(params: { kbId };文档列表/权限配置/添加文档)\n * 文档详情 shikeai-knowledge-doc(params: { kbId, docId };markdown 渲染)\n * 设置 shikeai-knowledge-settings(后端服务器地址/管理员)\n * - keyed 插槽 sidebar.right.pane.tab / sidebar.right.pane.tab.title:\n * 标签页正文与活标题(正文自动获得 props.useTabInfo())\n * - ctx.remote.settings:MCP 服务器配置经 knowledge namespace 同步宿主\n *\n * 登录态只读复用用户中心插件(按需验签换发插件自有 Token);无内置对话面板,\n * RAG 检索由 DSH 智能体经 MCP kb_rag_query 完成。非 DSH 宿主(standalone)\n * 不走本入口,走 index.js 的 activate()。\n */\nimport { setHostMcpContext } from './core/host-mcp-sync.js'\nimport { setHostContext, setSessionsContext } from './core/dsh-agent.js'\nimport { registerKbTriggerSource } from './core/kb-trigger.js'\nimport { install } from './index.js'\nimport { registerSidebarRightTabs } from './slots/sidebar-right.js'\nimport { registerChatInputSlots, registerChatMessageSlots } from './slots/chat-message.js'\n\n/** Client 服务依赖:slots(插槽注册)、sidebarRightTabs(标签页类型注册表)、remote.settings(MCP 配置同步宿主)、remote.session(AI 编写会话通道)、sessions(list 快照 current = 当前打开的会话 + scope(id) 取 session 域 ctx 写输入框)、inputTriggers(@知识库 触发源注册) */\nexport const inject = ['slots', 'sidebarRightTabs', 'remote', 'remote.settings', 'remote.session', 'sessions', 'inputTriggers']\n\nexport function apply(ctx) {\n setHostMcpContext(ctx)\n setHostContext(ctx)\n setSessionsContext(ctx.sessions)\n\n // 样式注入 + 登录态事件绑定 + 服务器配置加载(与 standalone 路径共用)\n install()\n\n // 右侧 Sidebar 标签页类型 + 正文 + 活标题\n registerSidebarRightTabs(ctx)\n\n // 对话消息操作区「存入知识库」入口(MCP kb_doc_add 入库)\n registerChatMessageSlots(ctx)\n\n // 输入区「引用知识库」入口(写入引用提示语,触发 MCP kb_rag_query 检索)\n registerChatInputSlots(ctx)\n\n // `@知识库` 输入触发源:候选列文档,选中插入不可编辑 reference chip\n // (发送时经 serialize 序列化为 kb_id/doc_id 结构化标记)\n const disposeKbTrigger = registerKbTriggerSource(ctx)\n\n // fiber dispose(generation 切换 / 插件停用):撤销宿主 MCP / 会话通道 ctx 引用\n if (typeof ctx.effect === 'function') {\n ctx.effect(\n () => () => {\n setHostMcpContext(null)\n setHostContext(null)\n setSessionsContext(null)\n disposeKbTrigger()\n },\n 'shikeai-knowledge: client dispose',\n )\n }\n}\n"],"mappings":"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"}
|