@leterhong/multichat 1.7.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/backend/package.json +1 -1
  2. package/frontend/dist/assets/{agentPicker-DIOlVr1C.js → agentPicker-Jan8fWb3.js} +9 -9
  3. package/frontend/dist/assets/{assets-D2_TVEqD.js → assets-ChkvQqhp.js} +1 -1
  4. package/frontend/dist/assets/{compare-BYqbOF36.js → compare-CkyqXEbN.js} +1 -1
  5. package/frontend/dist/assets/conversations-DoyXfY4T.js +1 -0
  6. package/frontend/dist/assets/data-BN7t_AoO.js +1 -0
  7. package/frontend/dist/assets/{extensionImport-C2cHyfeC.js → extensionImport-DPZhdnxE.js} +10 -10
  8. package/frontend/dist/assets/{importExport-BWpKt1dW.js → importExport-Bb6-L-4y.js} +18 -18
  9. package/frontend/dist/assets/index-CeU_ksnE.js +49 -0
  10. package/frontend/dist/assets/index-DDdMiim6.css +1 -0
  11. package/frontend/dist/assets/init-yIIG9GSH.js +1 -0
  12. package/frontend/dist/assets/{modal-CO4he94s.js → modal-BYrNUOVj.js} +1 -1
  13. package/frontend/dist/assets/modelPicker-B612Gojw.js +14 -0
  14. package/frontend/dist/assets/pluginsUI-KCpFagXv.js +16 -0
  15. package/frontend/dist/assets/react-sySUN5R7.js +1 -0
  16. package/frontend/dist/assets/{render-BVmIwN3C.js → render-BBfAbC8M.js} +1 -1
  17. package/frontend/dist/assets/send-BAyqvnlM.js +14 -0
  18. package/frontend/dist/assets/settings-DkUaMAOG.js +2 -0
  19. package/frontend/dist/assets/{shell-BLqMMR-L.js → shell-Cny595HR.js} +1 -1
  20. package/frontend/dist/assets/{workbench-ChZGUESv.js → workbench-cTwE7423.js} +12 -12
  21. package/frontend/dist/boot-fallback.js +2 -0
  22. package/frontend/dist/icon-maskable.svg +18 -6
  23. package/frontend/dist/icon.svg +13 -6
  24. package/frontend/dist/index.html +6 -6
  25. package/frontend/dist/manifest.webmanifest +2 -2
  26. package/frontend/dist/theme-seed.js +10 -0
  27. package/package.json +1 -1
  28. package/frontend/dist/assets/conversations-DSJtvviE.js +0 -1
  29. package/frontend/dist/assets/data-D6TAf2h9.js +0 -1
  30. package/frontend/dist/assets/index-BaUGyQ3C.js +0 -46
  31. package/frontend/dist/assets/index-DXwClNo-.css +0 -1
  32. package/frontend/dist/assets/init-DUZJcBWS.js +0 -1
  33. package/frontend/dist/assets/modelPicker-Ddloc_nz.js +0 -14
  34. package/frontend/dist/assets/pluginsUI-28Rxtlgo.js +0 -16
  35. package/frontend/dist/assets/react-CDEwA66Z.js +0 -1
  36. package/frontend/dist/assets/send-yu3ud0kM.js +0 -14
  37. package/frontend/dist/assets/settings-IUzleKUb.js +0 -2
@@ -1,4 +1,4 @@
1
- import{C as e,S as t,g as n,o as r,r as i,s as a,t as o,w as s}from"./index-BaUGyQ3C.js";var c=null;function l(){let e=n.selectedProvider;return!e||!n.selectedModel?!1:!!e.baseUrl&&([`ollama`,`lmstudio`,`mock`].includes(String(e.apiType||``).toLowerCase())||e.apiKeyMasked||e.apiKey)}function u(e){let t=e?.usage||{};return t.totalTokens??t.total_tokens??t.total??0}function d(e,t,n){let r=e?.[t]||e?.[n]||[];return Array.isArray(r)?r.length:0}function f(){let e=n.selectedAgent,t=!!(n.selectedProvider&&n.selectedModel),r=l(),i=!!(n.selectedProject&&n.selectedProject.id!==`pr_inbox`&&n.selectedProject.name!==`收件箱`);return[{label:`模型选择`,ok:t,detail:t?`${n.selectedProvider.name||n.selectedProvider.id} · ${n.selectedModel}`:`尚未选择模型`,tab:`providers`},{label:`连接配置`,ok:r,detail:r?`凭据与地址已配置`:`需要补充 API 地址或凭据`,tab:`providers`},{label:`项目上下文`,ok:i,detail:i?n.selectedProject.name:`尚未打开项目文件夹`,tab:`workspace`},{label:`运行配置`,ok:!0,detail:e?e.name:`直接对话(无工具注入)`,tab:`agents`}]}function p(e){return{running:`运行中`,completed:`已完成`,error:`失败`,cancelled:`已取消`,rejected:`已拒绝`}[e]||e||`暂无记录`}function m(){let r=t(`#inspectorBody`);if(!r)return;let i=n.selectedAgent,a=n.runs?.[0],o=f(),c=o.every(e=>e.ok),l=n.selectedAssetIds?.size||0,m=(n.assets||[]).filter(e=>n.selectedAssetIds?.has(e.id)).reduce((e,t)=>e+Number(t.size||t.bytes||0),0),h=Math.ceil(m/4),_=(n.memories||[]).filter(e=>e.enabled!==!1).length,v=d(i,`skillRefs`,`skillIds`),y=d(i,`toolIds`,`toolIds`),b=d(i,`mcpServerIds`,`mcpServerIds`),x=Math.round(o.filter(e=>e.ok).length/o.length*100);r.innerHTML=`
1
+ import{D as e,E as t,O as n,b as r,c as i,d as a,r as o,t as s}from"./index-CeU_ksnE.js";var c=null;function l(){let e=r.selectedProvider;return!e||!r.selectedModel?!1:!!e.baseUrl&&([`ollama`,`lmstudio`,`mock`].includes(String(e.apiType||``).toLowerCase())||e.apiKeyMasked||e.apiKey)}function u(e){let t=e?.usage||{};return t.totalTokens??t.total_tokens??t.total??0}function d(e,t,n){let r=e?.[t]||e?.[n]||[];return Array.isArray(r)?r.length:0}function f(){let e=r.selectedAgent,t=!!(r.selectedProvider&&r.selectedModel),n=l(),i=!!(r.selectedProject&&r.selectedProject.id!==`pr_inbox`&&r.selectedProject.name!==`收件箱`);return[{label:`模型选择`,ok:t,detail:t?`${r.selectedProvider.name||r.selectedProvider.id} · ${r.selectedModel}`:`尚未选择模型`,tab:`providers`},{label:`连接配置`,ok:n,detail:n?`凭据与地址已配置`:`需要补充 API 地址或凭据`,tab:`providers`},{label:`项目上下文`,ok:i,detail:i?r.selectedProject.name:`尚未打开项目文件夹`,tab:`workspace`},{label:`运行配置`,ok:!0,detail:e?e.name:`直接对话(无工具注入)`,tab:`agents`}]}function p(e){return{running:`运行中`,completed:`已完成`,error:`失败`,cancelled:`已取消`,rejected:`已拒绝`}[e]||e||`暂无记录`}function m(){let i=t(`#inspectorBody`);if(!i)return;let a=r.selectedAgent,o=r.runs?.[0],s=f(),c=s.every(e=>e.ok),l=r.selectedAssetIds?.size||0,m=(r.assets||[]).filter(e=>r.selectedAssetIds?.has(e.id)).reduce((e,t)=>e+Number(t.size||t.bytes||0),0),h=Math.ceil(m/4),_=(r.memories||[]).filter(e=>e.enabled!==!1).length,v=d(a,`skillRefs`,`skillIds`),y=d(a,`toolIds`,`toolIds`),b=d(a,`mcpServerIds`,`mcpServerIds`),x=Math.round(s.filter(e=>e.ok).length/s.length*100);i.innerHTML=`
2
2
  <section class="inspector-status ${c?`ready`:`needs-attention`}">
3
3
  <div class="inspector-score"><strong>${x}</strong><span>%</span></div>
4
4
  <div><strong>${c?`可以开始运行`:`需要完成配置`}</strong><span>${c?`必要条件已经就绪`:`补齐下面的配置项后再运行`}</span></div>
@@ -6,9 +6,9 @@ import{C as e,S as t,g as n,o as r,r as i,s as a,t as o,w as s}from"./index-BaUG
6
6
  <section class="inspector-section">
7
7
  <div class="inspector-section-head"><strong>会话配置</strong><button type="button" data-inspector-settings="agents">编辑</button></div>
8
8
  <dl class="inspector-facts">
9
- <div><dt>模型</dt><dd>${s(n.selectedModel||`未选择`)}</dd></div>
10
- <div><dt>运行配置</dt><dd>${s(i?.name||`直接对话`)}</dd></div>
11
- <div><dt>项目</dt><dd>${s(n.selectedProject?.id===`pr_inbox`?`临时对话`:n.selectedProject?.name||`未选择`)}</dd></div>
9
+ <div><dt>模型</dt><dd>${n(r.selectedModel||`未选择`)}</dd></div>
10
+ <div><dt>运行配置</dt><dd>${n(a?.name||`直接对话`)}</dd></div>
11
+ <div><dt>项目</dt><dd>${n(r.selectedProject?.id===`pr_inbox`?`临时对话`:r.selectedProject?.name||`未选择`)}</dd></div>
12
12
  </dl>
13
13
  </section>
14
14
  <section class="inspector-section">
@@ -20,21 +20,21 @@ import{C as e,S as t,g as n,o as r,r as i,s as a,t as o,w as s}from"./index-BaUG
20
20
  <div><strong>${y+b}</strong><span>工具</span></div>
21
21
  </div>
22
22
  <div class="context-budget"><div><span>文件上下文估算</span><strong>${h.toLocaleString(`zh-CN`)} Token</strong></div><div class="context-budget-track"><span style="width:${Math.min(100,h/320)}%"></span></div><small>仅估算已选文件;模型系统提示和对话历史未计入。</small></div>
23
- ${i?`<p class="inspector-note">${v} Skills · ${y} 内置工具 · ${b} MCP 服务</p>`:`<p class="inspector-note">直接对话不会注入工具或运行配置提示词。</p>`}
23
+ ${a?`<p class="inspector-note">${v} Skills · ${y} 内置工具 · ${b} MCP 服务</p>`:`<p class="inspector-note">直接对话不会注入工具或运行配置提示词。</p>`}
24
24
  </section>
25
25
  <section class="inspector-section">
26
26
  <div class="inspector-section-head"><strong>运行前检查</strong><button type="button" data-inspector-settings="capabilities">能力清单</button></div>
27
27
  <div class="inspector-checks">
28
- ${o.map(e=>`<button type="button" data-inspector-settings="${e.tab}" class="inspector-check ${e.ok?`ok`:`warn`}"><span aria-hidden="true">${e.ok?`✓`:`!`}</span><div><strong>${s(e.label)}</strong><small>${s(e.detail)}</small></div></button>`).join(``)}
28
+ ${s.map(e=>`<button type="button" data-inspector-settings="${e.tab}" class="inspector-check ${e.ok?`ok`:`warn`}"><span aria-hidden="true">${e.ok?`✓`:`!`}</span><div><strong>${n(e.label)}</strong><small>${n(e.detail)}</small></div></button>`).join(``)}
29
29
  </div>
30
30
  </section>
31
31
  <section class="inspector-section">
32
32
  <div class="inspector-section-head"><strong>最近运行</strong><button type="button" data-inspector-settings="runs">查看日志</button></div>
33
- ${a?`<div class="inspector-run"><div><span class="run-state ${s(a.status)}">${s(p(a.status))}</span><strong>${s(a.agentName||a.agentId||`直接对话`)}</strong></div><dl><div><dt>步骤</dt><dd>${s(a.steps||0)}</dd></div><div><dt>工具调用</dt><dd>${s(a.toolCalls||0)}</dd></div><div><dt>Token</dt><dd>${s(u(a).toLocaleString(`zh-CN`))}</dd></div></dl></div>`:`<div class="inspector-empty">完成一次运行后,这里会显示步骤、工具调用和 Token。</div>`}
33
+ ${o?`<div class="inspector-run"><div><span class="run-state ${n(o.status)}">${n(p(o.status))}</span><strong>${n(o.agentName||o.agentId||`直接对话`)}</strong></div><dl><div><dt>步骤</dt><dd>${n(o.steps||0)}</dd></div><div><dt>工具调用</dt><dd>${n(o.toolCalls||0)}</dd></div><div><dt>Token</dt><dd>${n(u(o).toLocaleString(`zh-CN`))}</dd></div></dl></div>`:`<div class="inspector-empty">完成一次运行后,这里会显示步骤、工具调用和 Token。</div>`}
34
34
  </section>
35
- `,e(`[data-inspector-settings]`,r).forEach(e=>{e.onclick=()=>{g(),openSettings(e.dataset.inspectorSettings||`general`)}})}function h(){o(`context`)}function g(){let e=t(`#sessionInspector`),n=t(`#mainWorkspace`),r=t(`#inspectorBtn`);e&&n&&(e.contains(document.activeElement)&&(r||document.body).focus(),n.classList.remove(`inspector-open`),e.setAttribute(`aria-hidden`,`true`),e.inert=!0,r?.setAttribute(`aria-expanded`,`false`))}function _(){o(`activity`)}function v(){let e=(n.conversations||[]).slice(0,8).map(e=>({id:`conversation:${e.id}`,label:e.title||`未命名对话`,description:`打开最近对话`,group:`对话`,run:()=>openConversation(e.id)})),o=(n.providers||[]).flatMap(e=>(e.models||[]).slice(0,5).map(t=>({id:`model:${e.id}:${t}`,label:t,description:`切换到 ${e.name||e.id}`,group:`模型`,run:()=>selectModel(e.id,t)}))).slice(0,10),s=(n.agents||[]).slice(0,6).map(e=>({id:`agent:${e.id}`,label:e.name||e.id,description:`在智能体页面查看和编辑运行配置`,group:`智能体`,run:()=>openSettings(`agents`)}));return[{id:`new`,label:`新任务`,description:`使用当前模型开始一个任务`,group:`任务`,shortcut:`Ctrl N`,run:()=>{i(`chat`),newConversation()}},{id:`run-agent`,label:`运行智能体`,description:`选择智能体并开始一个可使用工具的任务`,group:`任务`,run:()=>{i(`agent`),newConversation().then(()=>t(`#agentPicker`)?.click())}},{id:`inspect`,label:`打开 AI 活动中心`,description:`检查模型活动、上下文和真实运行指标`,group:`对话`,shortcut:`Ctrl I`,run:_},...e,...o,...s,{id:`compare`,label:`模型对比`,description:`使用相同任务和上下文并行比较 2–4 个模型`,group:`任务`,shortcut:`Ctrl M`,run:()=>{i(`compare`),openSettings(`experiment`)}},{id:`switch-project`,label:`切换项目`,description:`选择项目或打开本地项目文件夹`,group:`工作区`,run:()=>t(`#workspacePicker`)?.click()},{id:`settings`,label:`打开设置`,description:`配置外观、模型、能力与运行记录`,group:`工作区`,run:()=>openSettings(`general`)},{id:`providers`,label:`模型连接`,description:`添加模型提供方、地址和凭据`,group:`设置`,run:()=>openSettings(`providers`)},{id:`agents`,label:`运行配置`,description:`组合提示词、Skills、工具与 MCP`,group:`设置`,run:()=>openSettings(`agents`)},{id:`workspace`,label:`项目与文件`,description:`管理代码文件、记忆、快照和项目默认值`,group:`设置`,run:()=>openSettings(`workspace`)},{id:`skills`,label:`Skills`,description:`浏览、导入和管理工作流能力`,group:`能力`,run:()=>openSettings(`skills`)},{id:`mcp`,label:`MCP 服务`,description:`管理外部工具连接与信任状态`,group:`能力`,run:()=>openSettings(`mcp`)},{id:`plugins`,label:`插件`,description:`导入、审查和启用扩展包`,group:`能力`,run:()=>openSettings(`plugins`)},{id:`runs`,label:`运行日志`,description:`查看 Turn、Step、工具调用和审批记录`,group:`观察`,run:()=>openSettings(`runs`)},{id:`usage`,label:`Token 用量`,description:`查看每日消耗、模型分布和缓存命中`,group:`观察`,run:()=>openSettings(`usage`)},{id:`theme`,label:r()===`dark`?`切换为浅色界面`:`切换为深色界面`,description:`更改当前设备上的显示主题`,group:`界面`,run:()=>a(r()===`dark`?`light`:`dark`)}]}function y(n=``){let r=t(`#commandList`);if(!r)return;let i=n.trim().toLowerCase(),a=v().filter(e=>`${e.label} ${e.description} ${e.group}`.toLowerCase().includes(i));r.innerHTML=a.length?a.map(e=>`
35
+ `,e(`[data-inspector-settings]`,i).forEach(e=>{e.onclick=()=>{g(),openSettings(e.dataset.inspectorSettings||`general`)}})}function h(){s(`context`)}function g(){let e=t(`#sessionInspector`),n=t(`#mainWorkspace`),r=t(`#inspectorBtn`);e&&n&&(e.contains(document.activeElement)&&(r||document.body).focus(),n.classList.remove(`inspector-open`),e.setAttribute(`aria-hidden`,`true`),e.inert=!0,r?.setAttribute(`aria-expanded`,`false`))}function _(){s(`activity`)}function v(){let e=(r.conversations||[]).slice(0,8).map(e=>({id:`conversation:${e.id}`,label:e.title||`未命名对话`,description:`打开最近对话`,group:`对话`,run:()=>openConversation(e.id)})),n=(r.providers||[]).flatMap(e=>(e.models||[]).slice(0,5).map(t=>({id:`model:${e.id}:${t}`,label:t,description:`切换到 ${e.name||e.id}`,group:`模型`,run:()=>selectModel(e.id,t)}))).slice(0,10),s=(r.agents||[]).slice(0,6).map(e=>({id:`agent:${e.id}`,label:e.name||e.id,description:`在智能体页面查看和编辑运行配置`,group:`智能体`,run:()=>openSettings(`agents`)}));return[{id:`new`,label:`新任务`,description:`使用当前模型开始一个任务`,group:`任务`,shortcut:`Ctrl N`,run:()=>{o(`chat`),newConversation()}},{id:`run-agent`,label:`运行智能体`,description:`选择智能体并开始一个可使用工具的任务`,group:`任务`,run:()=>{o(`agent`),newConversation().then(()=>t(`#agentPicker`)?.click())}},{id:`inspect`,label:`打开 AI 活动中心`,description:`检查模型活动、上下文和真实运行指标`,group:`对话`,shortcut:`Ctrl I`,run:_},...e,...n,...s,{id:`compare`,label:`模型对比`,description:`使用相同任务和上下文并行比较 2–4 个模型`,group:`任务`,shortcut:`Ctrl M`,run:()=>{o(`compare`),openSettings(`experiment`)}},{id:`switch-project`,label:`切换项目`,description:`选择项目或打开本地项目文件夹`,group:`工作区`,run:()=>t(`#workspacePicker`)?.click()},{id:`settings`,label:`打开设置`,description:`配置外观、模型、能力与运行记录`,group:`工作区`,run:()=>openSettings(`general`)},{id:`providers`,label:`模型连接`,description:`添加模型提供方、地址和凭据`,group:`设置`,run:()=>openSettings(`providers`)},{id:`agents`,label:`运行配置`,description:`组合提示词、Skills、工具与 MCP`,group:`设置`,run:()=>openSettings(`agents`)},{id:`workspace`,label:`项目与文件`,description:`管理代码文件、记忆、快照和项目默认值`,group:`设置`,run:()=>openSettings(`workspace`)},{id:`skills`,label:`Skills`,description:`浏览、导入和管理工作流能力`,group:`能力`,run:()=>openSettings(`skills`)},{id:`mcp`,label:`MCP 服务`,description:`管理外部工具连接与信任状态`,group:`能力`,run:()=>openSettings(`mcp`)},{id:`plugins`,label:`插件`,description:`导入、审查和启用扩展包`,group:`能力`,run:()=>openSettings(`plugins`)},{id:`runs`,label:`运行日志`,description:`查看 Turn、Step、工具调用和审批记录`,group:`观察`,run:()=>openSettings(`runs`)},{id:`usage`,label:`Token 用量`,description:`查看每日消耗、模型分布和缓存命中`,group:`观察`,run:()=>openSettings(`usage`)},{id:`theme`,label:i()===`dark`?`切换为浅色界面`:`切换为深色界面`,description:`更改当前设备上的显示主题`,group:`界面`,run:()=>a(i()===`dark`?`light`:`dark`)}]}function y(r=``){let i=t(`#commandList`);if(!i)return;let a=r.trim().toLowerCase(),o=v().filter(e=>`${e.label} ${e.description} ${e.group}`.toLowerCase().includes(a));i.innerHTML=o.length?o.map(e=>`
36
36
  <button class="command-item" type="button" data-command="${e.id}">
37
- <span class="command-item-group">${s(e.group)}</span>
38
- <span class="command-item-copy"><strong>${s(e.label)}</strong><small>${s(e.description)}</small></span>
39
- ${e.shortcut?`<kbd>${s(e.shortcut)}</kbd>`:`<span class="command-arrow" aria-hidden="true">›</span>`}
40
- </button>`).join(``):`<div class="command-empty">没有匹配的操作</div>`,e(`[data-command]`,r).forEach(e=>{e.onclick=()=>{let t=v().find(t=>t.id===e.dataset.command);x(!1),t?.run()}})}function b(){let e=t(`#commandPalette`),n=t(`#commandSearch`);e&&n&&(c=document.activeElement,n.value=``,y(),e.inert=!1,e.setAttribute(`aria-hidden`,`false`),e.classList.add(`open`),t(`#app`).inert=!0,window.setTimeout(()=>n.focus(),0))}function x(e=!0){let n=t(`#commandPalette`);n&&(t(`#app`).inert=!1,n.contains(document.activeElement)&&(c||t(`#commandBtn`)||document.body).focus(),n.classList.remove(`open`),n.setAttribute(`aria-hidden`,`true`),n.inert=!0,e&&c&&document.contains(c)&&c.focus())}function S(){let n={general:`通用与外观`,workspace:`项目、文件与记忆`,providers:`模型`,experiment:`模型对比`,agents:`智能体`,capabilities:`能力审计`,usage:`Token 用量`,runs:`运行记录`};e(`.settings-tab[data-tab]`).forEach(e=>{let t=e.querySelector(`span:last-child`);t&&n[e.dataset.tab||``]&&(t.textContent=n[e.dataset.tab||``])}),t(`#commandBtn`).onclick=b;let r=t(`#commandSearch`);r.oninput=()=>y(r.value),r.onkeydown=t=>{let n=Array.from(e(`.command-item`));t.key===`ArrowDown`&&n.length&&(t.preventDefault(),n[0].focus()),t.key===`Enter`&&n.length&&(t.preventDefault(),n[0].click())},t(`#commandList`).addEventListener(`keydown`,t=>{let n=Array.from(e(`.command-item`)),i=n.indexOf(document.activeElement);t.key===`ArrowDown`&&i>=0&&(t.preventDefault(),n[(i+1)%n.length]?.focus()),t.key===`ArrowUp`&&i>=0&&(t.preventDefault(),(i===0?r:n[i-1])?.focus())}),e(`[data-open-settings]`).forEach(e=>{e.onclick=()=>openSettings(e.dataset.openSettings||`general`)}),t(`#commandPalette`).addEventListener(`mousedown`,e=>{e.target===t(`#commandPalette`)&&x()}),document.addEventListener(`keydown`,e=>{(t(`#settings`)?.classList.contains(`open`)||t(`#modal`)?.classList.contains(`open`))&&(e.ctrlKey||e.metaKey)&&[`k`,`i`,`m`,`n`].includes(e.key.toLowerCase())||((e.ctrlKey||e.metaKey)&&e.key.toLowerCase()===`k`?(e.preventDefault(),t(`#commandPalette`)?.classList.contains(`open`)?x():b()):(e.ctrlKey||e.metaKey)&&e.key.toLowerCase()===`i`?(e.preventDefault(),t(`#commandPalette`)?.classList.contains(`open`)&&x(!1),_()):(e.ctrlKey||e.metaKey)&&e.key.toLowerCase()===`m`?(e.preventDefault(),t(`#commandPalette`)?.classList.contains(`open`)&&x(!1),openSettings(`experiment`)):(e.ctrlKey||e.metaKey)&&e.key.toLowerCase()===`n`?(e.preventDefault(),t(`#commandPalette`)?.classList.contains(`open`)&&x(!1),newConversation()):e.key===`Escape`&&(t(`#commandPalette`)?.classList.contains(`open`)?x():t(`#mainWorkspace`)?.classList.contains(`inspector-open`)&&g()))}),m()}export{x as closeCommandPalette,g as closeInspector,b as openCommandPalette,h as openInspector,m as renderInspector,S as setupWorkbench,_ as toggleInspector};
37
+ <span class="command-item-group">${n(e.group)}</span>
38
+ <span class="command-item-copy"><strong>${n(e.label)}</strong><small>${n(e.description)}</small></span>
39
+ ${e.shortcut?`<kbd>${n(e.shortcut)}</kbd>`:`<span class="command-arrow" aria-hidden="true">›</span>`}
40
+ </button>`).join(``):`<div class="command-empty">没有匹配的操作</div>`,e(`[data-command]`,i).forEach(e=>{e.onclick=()=>{let t=v().find(t=>t.id===e.dataset.command);x(!1),t?.run()}})}function b(){let e=t(`#commandPalette`),n=t(`#commandSearch`);e&&n&&(c=document.activeElement,n.value=``,y(),e.inert=!1,e.setAttribute(`aria-hidden`,`false`),e.classList.add(`open`),t(`#app`).inert=!0,window.setTimeout(()=>n.focus(),0))}function x(e=!0){let n=t(`#commandPalette`);n&&(t(`#app`).inert=!1,n.contains(document.activeElement)&&(c||t(`#commandBtn`)||document.body).focus(),n.classList.remove(`open`),n.setAttribute(`aria-hidden`,`true`),n.inert=!0,e&&c&&document.contains(c)&&c.focus())}function S(){let n={general:`通用与外观`,workspace:`项目、文件与记忆`,providers:`模型`,experiment:`模型对比`,agents:`智能体`,capabilities:`能力审计`,usage:`Token 用量`,runs:`运行记录`};e(`.settings-tab[data-tab]`).forEach(e=>{let t=e.querySelector(`span:last-child`);t&&n[e.dataset.tab||``]&&(t.textContent=n[e.dataset.tab||``])}),t(`#commandBtn`).onclick=b;let r=t(`#commandSearch`);r.oninput=()=>y(r.value),r.onkeydown=t=>{let n=Array.from(e(`.command-item`));t.key===`ArrowDown`&&n.length&&(t.preventDefault(),n[0].focus()),t.key===`Enter`&&n.length&&(t.preventDefault(),n[0].click())},t(`#commandList`).addEventListener(`keydown`,t=>{let n=Array.from(e(`.command-item`)),i=n.indexOf(document.activeElement);t.key===`ArrowDown`&&i>=0&&(t.preventDefault(),n[(i+1)%n.length]?.focus()),t.key===`ArrowUp`&&i>=0&&(t.preventDefault(),(i===0?r:n[i-1])?.focus())}),e(`[data-open-settings]`).forEach(e=>{e.onclick=()=>openSettings(e.dataset.openSettings||`general`)}),t(`#commandPalette`).addEventListener(`mousedown`,e=>{e.target===t(`#commandPalette`)&&x()}),document.addEventListener(`keydown`,e=>{(t(`#settings`)?.classList.contains(`open`)||t(`#modal`)?.classList.contains(`open`))&&(e.ctrlKey||e.metaKey)&&[`k`,`i`,`m`,`n`].includes(e.key.toLowerCase())||((e.ctrlKey||e.metaKey)&&e.key.toLowerCase()===`k`?(e.preventDefault(),t(`#commandPalette`)?.classList.contains(`open`)?x():b()):(e.ctrlKey||e.metaKey)&&e.key.toLowerCase()===`i`?(e.preventDefault(),t(`#commandPalette`)?.classList.contains(`open`)&&x(!1),_()):(e.ctrlKey||e.metaKey)&&e.key.toLowerCase()===`m`?(e.preventDefault(),t(`#commandPalette`)?.classList.contains(`open`)&&x(!1),openSettings(`experiment`)):(e.ctrlKey||e.metaKey)&&e.key.toLowerCase()===`n`?(e.preventDefault(),t(`#commandPalette`)?.classList.contains(`open`)&&x(!1),newConversation()):e.key===`Escape`&&(t(`#commandPalette`)?.classList.contains(`open`)?x():t(`#mainWorkspace`)?.classList.contains(`inspector-open`)&&g()))}),m()}export{x as closeCommandPalette,g as closeInspector,b as openCommandPalette,h as openInspector,m as renderInspector,S as setupWorkbench,_ as toggleInspector};
@@ -12,5 +12,7 @@
12
12
  fb.style.display = 'flex';
13
13
  }, 4000);
14
14
  });
15
+ var retry = document.getElementById('bootReloadBtn');
16
+ if (retry) retry.addEventListener('click', function () { location.reload(); });
15
17
  new MutationObserver(hide).observe(document.documentElement, { childList: true, subtree: true });
16
18
  })();
@@ -1,7 +1,19 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
2
- <defs><linearGradient id="mc" x1="72" y1="54" x2="444" y2="462" gradientUnits="userSpaceOnUse"><stop stop-color="#2563EB"/><stop offset=".62" stop-color="#3B5BD7"/><stop offset="1" stop-color="#1C91B8"/></linearGradient></defs>
3
- <rect width="512" height="512" fill="url(#mc)"/>
4
- <path d="M140 130h143c32 0 58 26 58 58v57c0 32-26 58-58 58h-69l-57 44v-46c-42-4-75-39-75-81v-32c0-32 26-58 58-58Z" fill="#102757" fill-opacity=".25" stroke="#fff" stroke-width="23" stroke-linejoin="round"/>
5
- <path d="M231 205h136c32 0 58 26 58 58v57c0 43-33 78-74 81v45l-59-43h-61c-32 0-58-26-58-58v-82c0-32 26-58 58-58Z" fill="#fff" fill-opacity=".1" stroke="#fff" stroke-width="23" stroke-linejoin="round"/>
6
- <circle cx="254" cy="292" r="17" fill="#fff"/><circle cx="315" cy="292" r="17" fill="#fff"/>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36">
2
+ <title>MultiChat</title>
3
+ <style>
4
+ .bg { fill: #f7f8fa; }
5
+ .arc { fill: none; stroke: #3b6cf6; stroke-width: 3.1; stroke-linecap: round; }
6
+ .core { fill: #3b6cf6; }
7
+ @media (prefers-color-scheme: dark) {
8
+ .bg { fill: #1e1e2e; }
9
+ .arc { stroke: #89b4fa; }
10
+ .core { fill: #89b4fa; }
11
+ }
12
+ </style>
13
+ <rect class="bg" width="36" height="36"/>
14
+ <g transform="translate(5.04 5.04) scale(0.72)">
15
+ <path class="arc" d="M7.5 15.5a11 11 0 0 1 21 0"/>
16
+ <path class="arc" d="M28.5 20.5a11 11 0 0 1-21 0"/>
17
+ <circle class="core" cx="18" cy="18" r="4.3"/>
18
+ </g>
7
19
  </svg>
@@ -1,7 +1,14 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
2
- <defs><linearGradient id="mc" x1="84" y1="66" x2="440" y2="456" gradientUnits="userSpaceOnUse"><stop stop-color="#2563EB"/><stop offset=".62" stop-color="#3B5BD7"/><stop offset="1" stop-color="#1C91B8"/></linearGradient></defs>
3
- <rect width="512" height="512" rx="112" fill="url(#mc)"/>
4
- <path d="M120 105h172c38 0 69 31 69 69v68c0 38-31 69-69 69h-83l-68 52v-55c-51-4-90-46-90-97v-37c0-38 31-69 69-69Z" fill="#102757" fill-opacity=".25" stroke="#fff" stroke-width="27" stroke-linejoin="round"/>
5
- <path d="M229 196h163c38 0 69 31 69 69v68c0 51-39 93-88 97v53l-70-51h-74c-38 0-69-31-69-69v-98c0-38 31-69 69-69Z" fill="#fff" fill-opacity=".1" stroke="#fff" stroke-width="27" stroke-linejoin="round"/>
6
- <circle cx="257" cy="300" r="21" fill="#fff"/><circle cx="330" cy="300" r="21" fill="#fff"/>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36">
2
+ <title>MultiChat</title>
3
+ <style>
4
+ .arc { fill: none; stroke: #3b6cf6; stroke-width: 3.1; stroke-linecap: round; }
5
+ .core { fill: #3b6cf6; }
6
+ @media (prefers-color-scheme: dark) {
7
+ .arc { stroke: #89b4fa; }
8
+ .core { fill: #89b4fa; }
9
+ }
10
+ </style>
11
+ <path class="arc" d="M7.5 15.5a11 11 0 0 1 21 0"/>
12
+ <path class="arc" d="M28.5 20.5a11 11 0 0 1-21 0"/>
13
+ <circle class="core" cx="18" cy="18" r="4.3"/>
7
14
  </svg>
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
6
- <meta name="theme-color" content="#0b1526" />
6
+ <meta name="theme-color" content="#f7f8fa" id="mcThemeColor" />
7
7
  <meta name="color-scheme" content="light dark" />
8
8
  <title>MultiChat · 本地模型工作台</title>
9
9
  <link rel="manifest" href="/manifest.webmanifest" />
@@ -12,16 +12,16 @@
12
12
  <meta name="apple-mobile-web-app-title" content="MultiChat" />
13
13
  <meta name="mobile-web-app-capable" content="yes" />
14
14
  <script src="/theme-seed.js"></script>
15
- <script type="module" crossorigin src="/assets/index-BaUGyQ3C.js"></script>
16
- <link rel="modulepreload" crossorigin href="/assets/react-CDEwA66Z.js">
17
- <link rel="stylesheet" crossorigin href="/assets/index-DXwClNo-.css">
15
+ <script type="module" crossorigin src="/assets/index-CeU_ksnE.js"></script>
16
+ <link rel="modulepreload" crossorigin href="/assets/react-sySUN5R7.js">
17
+ <link rel="stylesheet" crossorigin href="/assets/index-DDdMiim6.css">
18
18
  </head>
19
19
  <body>
20
20
  <div id="root"></div>
21
- <div id="bootFallback" role="alert" style="display:none;position:fixed;inset:0;z-index:999;flex-direction:column;align-items:center;justify-content:center;gap:14px;background:var(--bg-base,#f6f7f9);color:var(--label-primary,#172033);font-family:system-ui,sans-serif;">
21
+ <div id="bootFallback" role="alert" style="display:none;position:fixed;inset:0;z-index:999;flex-direction:column;align-items:center;justify-content:center;gap:14px;background:var(--mc-surface,#ffffff);color:var(--mc-text,#1f2329);font-family:system-ui,sans-serif;">
22
22
  <strong style="font-size:16px;">MultiChat 加载失败</strong>
23
23
  <span style="font-size:13px;opacity:.7;">页面资源未能在 4 秒内就绪,可能是服务刚重启或网络缓存过期。</span>
24
- <button type="button" onclick="location.reload()" style="padding:9px 18px;border:0;border-radius:9px;background:#315fce;color:#fff;font-size:13px;cursor:pointer;">重新加载</button>
24
+ <button type="button" id="bootReloadBtn" style="padding:9px 18px;border:0;border-radius:8px;background:var(--mc-accent,#3b6cf6);color:#fff;font-size:13px;cursor:pointer;">重新加载</button>
25
25
  </div>
26
26
  <script src="/boot-fallback.js"></script>
27
27
  </body>
@@ -6,8 +6,8 @@
6
6
  "scope": "/",
7
7
  "display": "standalone",
8
8
  "orientation": "any",
9
- "background_color": "#070b13",
10
- "theme_color": "#0b1526",
9
+ "background_color": "#f7f8fa",
10
+ "theme_color": "#f7f8fa",
11
11
  "lang": "zh-CN",
12
12
  "icons": [
13
13
  {
@@ -1,4 +1,6 @@
1
1
  // Deep-link theme override: /?theme=light or #/?theme=dark.
2
+ // Also seeds the primitive-layer switches (accent skin, spacing density)
3
+ // before first paint so the saved appearance never flashes.
2
4
  // Loaded synchronously from <head> (CSP allows 'self'), applied pre-paint and
3
5
  // persisted so the hash-router's history rewrites cannot lose it.
4
6
  (function () {
@@ -8,4 +10,12 @@
8
10
  location.hash.match(/[?&]theme=(light|dark|system)\b/);
9
11
  if (m) localStorage.setItem('multichat_theme', m[1]);
10
12
  } catch (e) {}
13
+
14
+ try {
15
+ var root = document.documentElement;
16
+ var skin = localStorage.getItem('multichat_skin');
17
+ var density = localStorage.getItem('multichat_density');
18
+ root.dataset.skin = skin === 'graphite' || skin === 'teal' ? skin : 'blue';
19
+ root.dataset.density = density === 'compact' ? density : 'comfortable';
20
+ } catch (e) {}
11
21
  })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leterhong/multichat",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "Local-first multi-model agent workspace with Skills, MCP servers, and plugins",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1 +0,0 @@
1
- import{S as e,b as t,c as n,g as r,h as i,i as a,x as o,y as s}from"./index-BaUGyQ3C.js";function c(e=r.currentConvId,n=r.selectedProject?.id){let i=t(e,n);r.workflowScope=i,r.workflow=s(i)}async function l(){try{r.conversations=await n(`/api/conversations`),r.conversationsLoadFailed=!1}catch{r.conversations=[],r.conversationsLoadFailed=!0}}function u(){}async function d(t){let i=r.conversations.find(e=>e.id===t);if(i&&await showConfirm({title:`删除对话`,message:`删除「${i.title||`新对话`}」?`,confirmLabel:`删除`,danger:!0}))try{await n(`/api/conversations/`+encodeURIComponent(t),{method:`DELETE`}),r.conversations=r.conversations.filter(e=>e.id!==t),r.currentConvId===t&&(r.currentConvId=null,r.messages=[],c(null,r.selectedProject?.id),e(`#topbarTitle`).textContent=`新对话`,a(`chat`),location.hash!==`#/new`&&history.replaceState(null,``,`#/new`)),o(`对话已删除`)}catch(e){o(`删除对话失败:`+e.message,`error`)}}async function f(t){let i=r.conversations.find(e=>e.id===t);if(!i)return;let a=await showPrompt({title:`重命名任务`,label:`任务名称`,value:i.title||`新任务`,placeholder:`输入新的任务名称`,maxLength:120});if(a?.trim())try{let i=await n(`/api/conversations/`+encodeURIComponent(t),{method:`PUT`,body:JSON.stringify({title:a.trim()})});r.conversations=r.conversations.map(e=>e.id===t?{...e,...i}:e),r.currentConvId===t&&(e(`#topbarTitle`).textContent=i.title||a.trim()),o(`任务已重命名`)}catch(e){o(`重命名失败:`+e.message,`error`)}}async function p(){a(`home`),r.currentConvId=null,r.messages=[],c(null,r.selectedProject?.id),e(`#topbarTitle`).textContent=`新对话`,renderContent(),renderInspector(),requestAnimationFrame(()=>e(`#heroInput`)?.focus()),location.hash!==`#/home`&&history.pushState(null,``,`#/home`)}async function m(t){try{a(`chat`);let i=await n(`/api/conversations/`+encodeURIComponent(t));(i.workspaceId&&(!r.selectedWorkspace||r.selectedWorkspace.id!==i.workspaceId)||i.projectId&&(!r.selectedProject||r.selectedProject.id!==i.projectId))&&(r.selectedWorkspace=r.workspaces.find(e=>e.id===i.workspaceId)||r.selectedWorkspace,r.selectedWorkspace&&await loadProjects(),i.projectId&&(r.selectedProject=r.projects.find(e=>e.id===i.projectId)||r.selectedProject,r.selectedProject&&(localStorage.setItem(`multichat_project`,r.selectedProject.id),r.assets=await n(`/api/assets?projectId=`+encodeURIComponent(r.selectedProject.id)),r.selectedAssetIds=new Set(r.assets.map(e=>e.id))))),r.currentConvId=i.id,r.messages=(i.messages||[]).map(e=>({role:e.role,content:e.content,model:e.model})),c(i.id,i.projectId||r.selectedProject?.id),e(`#topbarTitle`).textContent=i.title||`对话`,renderTopbar(),renderContent(),g();let o=`#/chat/${encodeURIComponent(i.id)}`;location.hash!==o&&history.pushState(null,``,o)}catch(e){if(e?.status===404){r.conversations=r.conversations.filter(e=>e.id!==t),r.currentConvId===t&&(r.currentConvId=null,r.messages=[],c(null,r.selectedProject?.id)),a(`home`),history.replaceState(null,``,`#/home`),renderTopbar(),renderContent(),o(`该任务不存在或已被删除,已返回新任务页`,`error`);return}o(`打开对话失败:`+e.message,`error`)}}function h(e){try{return e<1024?e+` B`:e<1048576?(e/1024).toFixed(1)+` KB`:(e/1024/1024).toFixed(1)+` MB`}catch{return``}}function g(){renderContent(),renderInspector()}function _(){let e=r.selectedProject;if(e){if(e.defaultAgentId){let t=r.agents.find(t=>t.id===e.defaultAgentId);t&&(r.selectedAgent=t,i())}if(e.defaultProviderId&&e.defaultModel){let t=r.providers.find(t=>t.id===e.defaultProviderId);t&&(r.selectedProvider=t,r.selectedModel=e.defaultModel,localStorage.setItem(`multichat_lastModel`,t.id+`:`+e.defaultModel))}renderTopbar()}}export{c as activateWorkflow,_ as applyProjectDefaults,d as deleteConversation,h as fmtSize,l as loadConversations,p as newConversation,m as openConversation,f as renameConversation,u as renderConvList,g as renderFileContext};
@@ -1 +0,0 @@
1
- import{c as e,g as t}from"./index-BaUGyQ3C.js";async function n(){try{t.providers=await e(`/api/providers`)}catch{t.providers=[]}}async function r(){try{t.runtime=await e(`/api/runtime`)}catch{t.runtime=null}}async function i(){try{t.runs=await e(`/api/runs?limit=40`)}catch{t.runs=[]}}async function a(n=t.usageRange){t.usageRange=String(n||`30`),t.usageLoading=!0;try{let n=new Date().getTimezoneOffset();t.usage=await e(`/api/usage?range=${encodeURIComponent(t.usageRange)}&offset=${n}`)}catch{t.usage=null}finally{t.usageLoading=!1}}async function o(){try{t.capabilities=await e(`/api/capabilities`)}catch{t.capabilities=null}}async function s(){if(!t.selectedProject)t.memories=[],t.snapshots=[];else try{[t.memories,t.snapshots]=await Promise.all([e(`/api/memories?projectId=`+encodeURIComponent(t.selectedProject.id)),e(`/api/snapshots?projectId=`+encodeURIComponent(t.selectedProject.id))])}catch{t.memories=[],t.snapshots=[]}}async function c(){try{t.workspaces=await e(`/api/workspaces`);let n=localStorage.getItem(`multichat_workspace`);t.selectedWorkspace=t.workspaces.find(e=>e.id===n)||t.workspaces[0]||null,await l()}catch{t.workspaces=[],t.projects=[]}}async function l(){if(!t.selectedWorkspace)t.projects=[],t.selectedProject=null;else try{t.projects=await e(`/api/projects?workspaceId=`+encodeURIComponent(t.selectedWorkspace.id));let n=localStorage.getItem(`multichat_project`);t.selectedProject=t.projects.find(e=>e.id===n)||t.projects.find(e=>e.id===t.selectedWorkspace.defaultProjectId)||t.projects[0]||null,localStorage.setItem(`multichat_workspace`,t.selectedWorkspace.id),t.selectedProject&&localStorage.setItem(`multichat_project`,t.selectedProject.id),t.selectedProject&&(t.assets=await e(`/api/assets?projectId=`+encodeURIComponent(t.selectedProject.id)),t.selectedAssetIds=new Set(t.assets.map(e=>e.id)),applyProjectDefaults(),await s())}catch{t.projects=[],t.selectedProject=null,t.assets=[],t.selectedAssetIds=new Set}}async function u(){try{t.skills=await e(`/api/skills`)}catch{t.skills=[]}}async function d(){try{t.tools=await e(`/api/tools`)}catch{t.tools=[]}}async function f(){try{t.mcpServers=await e(`/api/mcp-servers`)}catch{t.mcpServers=[]}}async function p(){let n=t.selectedAgent?.id;try{t.agents=await e(`/api/agents`),n&&(t.selectedAgent=t.agents.find(e=>e.id===n)||null)}catch{t.agents=[],n&&(t.selectedAgent=null)}}async function m(){try{t.plugins=await e(`/api/plugins`)}catch{t.plugins=[]}}export{p as loadAgents,o as loadCapabilities,f as loadMcpServers,m as loadPlugins,s as loadProjectControlData,l as loadProjects,n as loadProviders,i as loadRuns,r as loadRuntime,u as loadSkills,d as loadTools,a as loadUsage,c as loadWorkspaces};