zen-gitsync 2.19.3 → 2.19.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/package.json +1 -1
  2. package/src/config.js +14 -0
  3. package/src/ui/public/assets/{AgentView-DzYcmZ80.css → AgentView-DAad0_qd.css} +1 -1
  4. package/src/ui/public/assets/{AgentView-DdZB5M3K.js → AgentView-DfARpZyC.js} +2 -2
  5. package/src/ui/public/assets/{AppVersionBadge-Clw0AO_V.js → AppVersionBadge-NdUFOUvY.js} +1 -1
  6. package/src/ui/public/assets/{BranchSelector-WG_dzJ1z.js → BranchSelector-C9OwntcN.js} +1 -1
  7. package/src/ui/public/assets/{CommitForm-Bai-xBwV.js → CommitForm-BrVzZBex.js} +1 -1
  8. package/src/ui/public/assets/{EditorView-DYznT1et.js → EditorView-BYyNWD9L.js} +1 -1
  9. package/src/ui/public/assets/{FlowOrchestrationWorkspace-B982yExF.js → FlowOrchestrationWorkspace-CR6SGCav.js} +1 -1
  10. package/src/ui/public/assets/{LogList-BG9RlR5V.js → LogList-9CoA8BE9.js} +1 -1
  11. package/src/ui/public/assets/{MindmapView-CfF3dnO9.js → MindmapView-BhliaJwt.js} +1 -1
  12. package/src/ui/public/assets/{MonitorView-C6NkhaTu.js → MonitorView-DcNrEb7I.js} +1 -1
  13. package/src/ui/public/assets/{ProjectManagerView-DfFtI8I9.js → ProjectManagerView-D6jyqFJI.js} +1 -1
  14. package/src/ui/public/assets/{ProjectStartupButton-PZDHhzaY.js → ProjectStartupButton-Bj99Poi0.js} +1 -1
  15. package/src/ui/public/assets/{RemoteManagerDialog-CGbTl8Nf.js → RemoteManagerDialog-kxRl8-yT.js} +1 -1
  16. package/src/ui/public/assets/{RemoteRepoCard-DIbrkSSq.js → RemoteRepoCard-ByN8bINN.js} +1 -1
  17. package/src/ui/public/assets/{SourceMapView-dmFzB7XF.js → SourceMapView-6gUYKwKF.js} +1 -1
  18. package/src/ui/public/assets/{WorkbenchView-oGjBJIT6.js → WorkbenchView-BwBnMnIK.js} +1 -1
  19. package/src/ui/public/assets/{index-Bz3MwUuu.js → index-D6QfSjkU.js} +3 -3
  20. package/src/ui/public/assets/{taskExecutionExport-0qwbiZRh.js → taskExecutionExport-BmT0ExK3.js} +1 -1
  21. package/src/ui/public/assets/{useWorkbenchProjects-flU0ll2K.js → useWorkbenchProjects-CezbGd4B.js} +1 -1
  22. package/src/ui/public/index.html +1 -1
  23. package/src/ui/server/routes/codeAnalysis.js +4 -2
  24. package/src/ui/server/routes/config.js +3 -1
  25. package/src/ui/server/routes/git/aiDiffSummary.js +3 -1
  26. package/src/ui/server/routes/projectStartupAi.js +3 -1
  27. package/src/ui/server/routes/projectStartupAi.test.js +7 -4
  28. package/src/ui/server/routes/recentDirectoriesAiSummary.js +3 -1
  29. package/src/ui/server/routes/recentDirectoriesAiSummary.test.js +4 -2
  30. package/src/ui/server/routes/workbench/agentRoutes.js +6 -1
  31. package/src/ui/server/routes/workbench/agentRoutes.test.js +57 -0
  32. package/src/ui/server/routes/workbench/dispatchInstruction.js +4 -2
  33. package/src/ui/server/routes/workbench/imageDescribe.js +4 -2
  34. package/src/ui/server/routes/workbench/index.js +3 -1
  35. package/src/ui/server/routes/workbench/scheduler.js +3 -1
@@ -1,4 +1,4 @@
1
- import"./rolldown-runtime-C0FnF6B9.js";import{An as e,Ar as t,C as n,Cn as r,Gn as i,In as a,J as o,Jr as s,Mn as c,S as l,Sn as u,Sr as d,Tn as f,Y as p,Yn as m,_n as h,et as g,gr as _,i as v,ir as y,lr as b,qn as x,w as ee,wn as S,xn as C}from"./element-plus-CkMnLwcU.js";import{n as w,t as T}from"./_plugin-vue_export-helper-DlU9e1mk.js";import{d as E,f as D,m as O,p as k,t as A}from"./configStore-BNFH8Gjg.js";import{A as j,E as M,L as N,T as P,xt as F}from"./index-Bz3MwUuu.js";var te=[`png`,`jpg`,`jpeg`,`gif`,`webp`,`bmp`,`svg`],ne=/!\[([^\]]*)\]\(\s*(?:<([^<>\n]+)>|([^()\s]+))(\s+["'][^"']*["'])?\s*\)/g,re=/^\s*(`{3,}|~{3,})/,ie=/\.([a-z0-9]+)$/;function I(e){let t=e.trim().toLowerCase().match(ie);return!!t&&te.includes(t[1])}function ae(e){let t=String(e||``).trim();if(!t)return!1;if(/^[a-zA-Z]:[\\/]/.test(t))return I(t);let n=t.match(/^([a-z][a-z0-9+.-]+):/i);return n&&n[1].toLowerCase()!==`file`||t.startsWith(`//`)||t.startsWith(`/`)?!1:I(t)}function oe(e,t){return`/api/workbench/jobs/${encodeURIComponent(e)}/image?path=${encodeURIComponent(t)}`}function se(e,t){return`/api/agent/sessions/${encodeURIComponent(e)}/image?path=${encodeURIComponent(t)}`}function L(e,t){return e.includes(`![`)?e.replace(ne,(e,n,r,i,a)=>{let o=(r??i??``).trim();return ae(o)?`![${n}](${t(o)}${a||``})`:e}):e}function R(e,t){let n=typeof e==`string`?e:``;if(!n||!t||!n.includes(`![`))return n;let r=n.split(`
1
+ import"./rolldown-runtime-C0FnF6B9.js";import{An as e,Ar as t,C as n,Cn as r,Gn as i,In as a,J as o,Jr as s,Mn as c,S as l,Sn as u,Sr as d,Tn as f,Y as p,Yn as m,_n as h,et as g,gr as _,i as v,ir as y,lr as b,qn as x,w as ee,wn as S,xn as C}from"./element-plus-CkMnLwcU.js";import{n as w,t as T}from"./_plugin-vue_export-helper-DlU9e1mk.js";import{d as E,f as D,m as O,p as k,t as A}from"./configStore-BNFH8Gjg.js";import{A as j,E as M,L as N,T as P,xt as F}from"./index-D6QfSjkU.js";var te=[`png`,`jpg`,`jpeg`,`gif`,`webp`,`bmp`,`svg`],ne=/!\[([^\]]*)\]\(\s*(?:<([^<>\n]+)>|([^()\s]+))(\s+["'][^"']*["'])?\s*\)/g,re=/^\s*(`{3,}|~{3,})/,ie=/\.([a-z0-9]+)$/;function I(e){let t=e.trim().toLowerCase().match(ie);return!!t&&te.includes(t[1])}function ae(e){let t=String(e||``).trim();if(!t)return!1;if(/^[a-zA-Z]:[\\/]/.test(t))return I(t);let n=t.match(/^([a-z][a-z0-9+.-]+):/i);return n&&n[1].toLowerCase()!==`file`||t.startsWith(`//`)||t.startsWith(`/`)?!1:I(t)}function oe(e,t){return`/api/workbench/jobs/${encodeURIComponent(e)}/image?path=${encodeURIComponent(t)}`}function se(e,t){return`/api/agent/sessions/${encodeURIComponent(e)}/image?path=${encodeURIComponent(t)}`}function L(e,t){return e.includes(`![`)?e.replace(ne,(e,n,r,i,a)=>{let o=(r??i??``).trim();return ae(o)?`![${n}](${t(o)}${a||``})`:e}):e}function R(e,t){let n=typeof e==`string`?e:``;if(!n||!t||!n.includes(`![`))return n;let r=n.split(`
2
2
  `),i=null,a=[];for(let e of r){let n=e.match(re);if(n){let t=n[1][0];i===null?i=t:i===t&&(i=null),a.push(e);continue}a.push(i===null?L(e,t):e)}return a.join(`
3
3
  `)}function z(e,t){return R(e,t?e=>oe(t,e):null)}function B(e,t){return R(e,t?e=>se(t,e):null)}b();var V=1e5;function H(){let e=_([]),t=_([]),n=_(V),r=_([]),i=_(null),a=_(!1),o=_(!1),s=_(``),c=_({}),l=_([]),u=_(!1),d=_(!1),f=_(M);async function p(o=!1){try{let l=await fetch(`/api/workbench/orchestrator`,{cache:`no-store`}).then(e=>e.json());return l?.success?(Number.isInteger(l.maxInstructionChars)&&l.maxInstructionChars>0&&(n.value=l.maxInstructionChars),e.value=Array.isArray(l.instructions)?l.instructions:[],t.value=Array.isArray(l.activity)?l.activity:[],r.value=Array.isArray(l.running)?l.running:[],P().setRunning(r.value.length),i.value=l.updatedAt||null,s.value=typeof l.defaultPrompt==`string`?l.defaultPrompt:``,c.value=l.projectPrompts&&typeof l.projectPrompts==`object`?l.projectPrompts:{},f.value=j(l.reportIntervalMs),a.value=!0,!0):(o||v.error(l?.error||w(`@WORKBENCH:读取编排状态失败`)),!1)}catch(e){return o||v.error(w(`@WORKBENCH:网络错误: `)+(e?.message||e)),!1}}async function m(e=!1){if(u.value)return!1;u.value=!0;try{let t=await fetch(`/api/workbench/orchestrator/reports`,{cache:`no-store`}).then(e=>e.json());return t?.success?(l.value=Array.isArray(t.reports)?t.reports:[],!0):(e||v.error(t?.error||w(`@WORKBENCH:读取进度报告失败`)),!1)}catch(t){return e||v.error(w(`@WORKBENCH:网络错误: `)+(t?.message||t)),!1}finally{u.value=!1}}async function h(){if(d.value)return null;d.value=!0;try{let e=String(A().locale||``).startsWith(`en`)?`en`:`zh`,t=await fetch(`/api/workbench/orchestrator/report`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({locale:e})}).then(e=>e.json());return t?.success?t.report?(l.value=[t.report,...l.value].slice(0,20),t.report):(v.info(w(`@WORKBENCH:当前没有正在执行的任务,没有可汇报的进度`)),null):(v.error(t?.error||w(`@WORKBENCH:生成进度报告失败`)),null)}catch(e){return v.error(w(`@WORKBENCH:网络错误: `)+(e?.message||e)),null}finally{d.value=!1}}async function g(e){try{let t=await fetch(`/api/workbench/orchestrator/report-interval`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({intervalMs:e})}).then(e=>e.json());return t?.success?(f.value=j(t.reportIntervalMs),!0):(v.error(t?.error||w(`@WORKBENCH:保存失败`)),!1)}catch(e){return v.error(w(`@WORKBENCH:网络错误: `)+(e?.message||e)),!1}}async function y(e){try{let t=await fetch(`/api/workbench/orchestrator/default-prompt`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({prompt:e})}).then(e=>e.json());return t?.success?(s.value=typeof t.defaultPrompt==`string`?t.defaultPrompt:``,v.success(w(`@WORKBENCH:已保存全局预设提示词`)),!0):(v.error(t?.error||w(`@WORKBENCH:保存失败`)),!1)}catch(e){return v.error(w(`@WORKBENCH:网络错误: `)+(e?.message||e)),!1}}async function b(e,t){try{let n=await fetch(`/api/workbench/orchestrator/project-prompt`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({projectPath:e,prompt:t})}).then(e=>e.json());return n?.success?(c.value=n.projectPrompts&&typeof n.projectPrompts==`object`?n.projectPrompts:{},v.success(w(`@WORKBENCH:已保存项目预设提示词`)),!0):(v.error(n?.error||w(`@WORKBENCH:保存失败`)),!1)}catch(e){return v.error(w(`@WORKBENCH:网络错误: `)+(e?.message||e)),!1}}async function x(e){if(o.value)return null;o.value=!0;try{let t=await fetch(`/api/workbench/orchestrator/dispatch`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({text:e.text,projectPath:e.projectPath||``,autoRun:e.autoRun!==!1,useDefaultPrompt:e.useDefaultPrompt!==!1,executor:e.executor,imageText:e.imageText,attachments:(e.attachments||[]).map(e=>({id:e.id,ext:e.ext,originalName:e.originalName}))})}).then(e=>e.json());return t?.success?(await p(!0),{task:t.task||null,ran:!!t.ran}):(v.error(t?.error||w(`@WORKBENCH:派发失败`)),null)}catch(e){return v.error(w(`@WORKBENCH:网络错误: `)+(e?.message||e)),null}finally{o.value=!1}}return{instructions:e,activity:t,running:r,updatedAt:i,loaded:a,dispatching:o,maxInstructionChars:n,defaultPrompt:s,projectPrompts:c,reports:l,loadingReports:u,generatingReport:d,reportIntervalMs:f,loadOrchestrator:p,dispatch:x,saveDefaultPrompt:y,saveProjectPrompt:b,loadReports:m,generateReport:h,setReportInterval:g}}a();function U(){let e=A(),t=F(),n=C({get:()=>e.resolvedTaskExecutor,set:t=>{D(t)&&e.setLastTaskExecutor(t)}}),r=C(()=>({claude:t.claudeAvailable,opencode:t.opencodeAvailable,codex:t.codexAvailable,codebuddy:t.codebuddyAvailable,pi:t.piAvailable,codearts:t.codeartsAvailable})),i=C(()=>E.some(e=>r.value[e.id])),a=C(()=>r.value[n.value]?n.value:Object.keys(r.value).find(e=>r.value[e])??n.value);function o(e){r.value[e]&&(n.value=e)}let s=C(()=>e.ui.dispatchExecutorPriority??[]),c=C(()=>s.value.length>0),l=C(()=>c.value?k(s.value,r.value,a.value):a.value);function u(e){return t.executorModelText(e)}function d(e){return[u(e),t.executorModelDetail(e)].filter(Boolean).join(` · `)}return{selected:n,active:a,priority:s,hasPriority:c,dispatchTarget:l,availability:r,hasAnyExecutor:i,choose:o,executorModelText:u,executorModelTitle:d}}a(),b(),t();var W={key:0,class:`tep tep--static`},G=[`title`,`aria-label`],K={class:`tep__btn-name`},ce={class:`tep__btn-tag`},le=[`title`,`aria-label`],ue={class:`tep__btn-name`},de={class:`tep__item`},fe={class:`tep__item-name`},pe=[`title`],me={key:2,class:`tep__item-missing`},he=T(c({__name:`TaskExecutorPicker`,props:{title:{},readonly:{type:Boolean},value:{}},setup(t){let a=t,{active:c,availability:_,choose:v,executorModelText:b,executorModelTitle:T}=U(),D=C(()=>a.readonly&&a.value?a.value:c.value),k=F();i(()=>{k.fetchExecutorModels()});function A(){return[a.title,T(D.value)].filter(Boolean).join(` · `)}return(i,a)=>{let c=o,C=n,k=ee,j=l;return t.readonly?(x(),f(`span`,W,[u(`span`,{class:`tep__btn`,title:A(),"aria-label":d(w)(`@WORKBENCH:任务执行器`)},[e(N,{executor:D.value,class:`tep__btn-icon`},null,8,[`executor`]),u(`span`,K,s(d(O)(D.value)),1),u(`span`,ce,s(d(w)(`@AGENT:按优先级`)),1)],8,G)])):(x(),r(j,{key:1,trigger:`click`,class:`tep`,onCommand:d(v)},{dropdown:y(()=>[e(k,null,{default:y(()=>[(x(!0),f(h,null,m(d(E),t=>(x(),r(C,{key:t.id,command:t.id,disabled:!d(_)[t.id]},{default:y(()=>[u(`span`,de,[e(N,{executor:t.id,class:`tep__item-icon`},null,8,[`executor`]),u(`span`,fe,s(t.name),1),d(b)(t.id)?(x(),f(`span`,{key:0,class:`tep__item-model`,title:d(T)(t.id)},s(d(b)(t.id)),9,pe)):S(``,!0),D.value===t.id?(x(),r(c,{key:1,class:`tep__item-check`},{default:y(()=>[e(d(g))]),_:1})):d(_)[t.id]?S(``,!0):(x(),f(`span`,me,s(d(w)(`@42BB9:未安装`)),1))])]),_:2},1032,[`command`,`disabled`]))),128))]),_:1})]),default:y(()=>[u(`button`,{type:`button`,class:`tep__btn`,title:A(),"aria-label":d(w)(`@WORKBENCH:任务执行器`)},[e(N,{executor:D.value,class:`tep__btn-icon`},null,8,[`executor`]),u(`span`,ue,s(d(O)(D.value)),1),e(c,{class:`tep__btn-caret`},{default:y(()=>[e(d(p))]),_:1})],8,le)]),_:1},8,[`onCommand`]))}}}),[[`__scopeId`,`data-v-52969d85`]]),ge=8192;function _e(e,t){return e.length>t?`…(前文已截断)\n${e.slice(-t)}`:e}function ve(e,t){let n=e||`done`;return n!==`pending`&&n!==`running`||t===`running`||t===`pending`?n:t===`cancelled`||t===`error`?`error`:`done`}function q(e){let t=e?.toolCalls;if(!Array.isArray(t)||t.length===0)return[];let n=e?.status||`done`,r=[];for(let e=0;e<t.length;e++){let i=t[e];if(!i||typeof i!=`object`)continue;let a=ve(i.status,n),o=typeof i.result==`string`?i.result:``;r.push({id:typeof i.id==`string`&&i.id?i.id:`tool-${e}`,name:typeof i.name==`string`?i.name:``,argsPreview:typeof i.argsPreview==`string`?i.argsPreview:``,arguments:typeof i.arguments==`string`?i.arguments:``,result:o?_e(o,ge):``,status:a,error:typeof i.error==`string`&&i.error?i.error:void 0})}return r}var ye=`
4
4
 
@@ -1 +1 @@
1
- import"./rolldown-runtime-C0FnF6B9.js";import{An as e,Ar as t,Cn as n,In as r,J as i,Jr as a,Lt as o,Mn as s,Nt as ee,Sn as c,Sr as l,Tn as u,Ur as d,Yn as f,_n as p,gn as m,gr as h,hn as g,i as _,ir as v,lr as y,on as b,qn as x,st as S,wn as C,xn as te,xt as ne}from"./element-plus-CkMnLwcU.js";import{n as w,t as T}from"./_plugin-vue_export-helper-DlU9e1mk.js";import{t as E}from"./SvgIcon-DqzYKNo_.js";import{$ as re,G as D,J as ie,K as O,Q as ae,U as k,W as oe,X as se,Y as A,Z as ce,et as j,nt as le,q as ue,tt as M,xt as N}from"./index-Bz3MwUuu.js";function P(){let e=N();function t(t){return e.lastCheckedAt!==null&&!e.isToolAvailable(t)}async function n(t,n,r){if(!n)return`no-dir`;if(!await A())return _.warning(w(`@67CE7:工具检测失败,请稍后重试`)),`failed`;if(!e.isToolAvailable(t))return`install`;let i=await j(t,n,r);return i.success?(_.success(i.message||w(`@67CE7:已用 {tool} 打开目录`,{tool:O[t]})),`opened`):(_.error(`${w(`@67CE7:打开失败: `)}${i.error??``}`),`failed`)}return{toolMissing:t,tryOpenWithTool:n}}r(),y(),t(),b();var F=[`aria-label`],I=[`onKeydown`],L={class:`proj-menu__icon`},R={class:`proj-menu__label`},z=[`onKeydown`],B={class:`proj-menu__icon`},V={class:`proj-menu__label`},H=[`onKeydown`],U={class:`proj-menu__icon`},de={class:`proj-menu__label`},fe=[`onKeydown`],pe={class:`proj-menu__icon`},me={class:`proj-menu__label`},he=[`onKeydown`],ge={class:`proj-menu__icon`},_e={class:`proj-menu__label`},ve={class:`proj-menu__title`,role:`presentation`},ye=[`onClick`,`onKeydown`],be={class:`proj-menu__icon`},xe={class:`proj-menu__label`},Se={key:0,class:`proj-menu__hint`},Ce={class:`proj-menu__icon`},we=[`src`],Te={class:`proj-menu__label`},Ee={class:`proj-menu__hint`},De={class:`proj-menu__icon`},Oe=[`src`],ke={class:`proj-menu__label`},Ae={class:`proj-menu__icon`},je={class:`proj-menu__label`},Me={class:`proj-menu__icon`},Ne={class:`proj-menu__label`},Pe={key:0,class:`proj-menu__hint`},Fe={key:1,class:`proj-menu__hint`},Ie={class:`proj-menu__icon`},Le={class:`proj-menu__label`},Re={class:`proj-menu__icon`},ze={class:`proj-menu__label`},Be={class:`proj-menu__icon`},Ve={class:`proj-menu__label`},He={class:`proj-menu__title`,role:`presentation`},Ue=[`onClick`,`onKeydown`],W={class:`proj-menu__icon`},We=[`src`],Ge={class:`proj-menu__label`},Ke={class:`proj-menu__hint`},G=T(s({__name:`ProjectOpenMenuList`,props:{path:{},name:{}},emits:[`done`],setup(t,{emit:r}){let s=t,y=r,{toolMissing:b,tryOpenWithTool:T}=P(),A=N(),j=h(!1),G=h(null),K=te(()=>oe.filter(e=>A.desktopAppOf(e)).map(e=>({id:e,name:O[e],icon:D.find(t=>t.id===e)?.icon??``})));async function q(e){let t=A.desktopAppOf(e);if(!t)return;if(y(`done`),!t.installed){window.open(t.downloadUrl,`_blank`,`noopener,noreferrer`);return}let n=await ce(e);n.success?_.success(n.message||w(`@67CE7:已打开 {app}`,{app:t.name})):_.error(n.error||w(`@WORKBENCH:打开桌面端失败`))}async function J(){y(`done`);let e=await ae(s.path);e.success?_.success(e.message||w(`@WORKBENCH:已在文件管理器中打开文件夹`)):_.error(e.error||w(`@WORKBENCH:打开文件夹失败`))}async function Y(){y(`done`);let e=await re(s.path);e.success?_.success(e.message||w(`@67CE7:已在终端中打开目录`)):_.error(e.error||w(`@WORKBENCH:打开终端失败`))}async function X(){y(`done`);let e=await se(s.path);e.success?_.success(w(`@WORKBENCH:已在新标签页启动 g ui`)):_.error(e.error||w(`@WORKBENCH:启动 g ui 失败`))}async function Z(){if(y(`done`),s.name)try{await navigator.clipboard.writeText(s.name),_.success(w(`@67CE7:已复制文件夹名称`))}catch{_.error(w(`@67CE7:复制失败`))}}async function Q(){if(y(`done`),s.path)try{await navigator.clipboard.writeText(s.path),_.success(w(`@67CE7:已复制文件夹路径`))}catch{_.error(w(`@67CE7:复制失败`))}}async function $(e,t){if(await T(e,s.path,t)===`install`){G.value=e,j.value=!0;return}y(`done`)}return(t,r)=>{let s=i;return x(),u(p,null,[c(`ul`,{class:`proj-menu`,role:`menu`,"aria-label":l(w)(`@WORKBENCH:打开方式`)},[c(`li`,{class:`proj-menu__item`,role:`menuitem`,tabindex:`-1`,onClick:J,onKeydown:[g(m(J,[`prevent`]),[`enter`]),g(m(J,[`prevent`]),[`space`])]},[c(`span`,L,[e(s,{"aria-hidden":`true`},{default:v(()=>[e(l(ne))]),_:1})]),c(`span`,R,a(l(w)(`@WORKBENCH:在文件管理器中打开`)),1)],40,I),c(`li`,{class:`proj-menu__item`,role:`menuitem`,tabindex:`-1`,onClick:Y,onKeydown:[g(m(Y,[`prevent`]),[`enter`]),g(m(Y,[`prevent`]),[`space`])]},[c(`span`,B,[e(s,{"aria-hidden":`true`},{default:v(()=>[e(l(ee))]),_:1})]),c(`span`,V,a(l(w)(`@WORKBENCH:在终端中打开`)),1)],40,z),c(`li`,{class:`proj-menu__item`,role:`menuitem`,tabindex:`-1`,onClick:X,onKeydown:[g(m(X,[`prevent`]),[`enter`]),g(m(X,[`prevent`]),[`space`])]},[c(`span`,U,[e(s,{"aria-hidden":`true`},{default:v(()=>[e(l(o))]),_:1})]),c(`span`,de,a(l(w)(`@WORKBENCH:在新标签页启动 g ui`)),1)],40,H),c(`li`,{class:`proj-menu__item`,role:`menuitem`,tabindex:`-1`,onClick:Z,onKeydown:[g(m(Z,[`prevent`]),[`enter`]),g(m(Z,[`prevent`]),[`space`])]},[c(`span`,pe,[e(s,{"aria-hidden":`true`},{default:v(()=>[e(l(S))]),_:1})]),c(`span`,me,a(l(w)(`@67CE7:复制文件夹名称`)),1)],40,fe),c(`li`,{class:`proj-menu__item`,role:`menuitem`,tabindex:`-1`,onClick:Q,onKeydown:[g(m(Q,[`prevent`]),[`enter`]),g(m(Q,[`prevent`]),[`space`])]},[c(`span`,ge,[e(s,{"aria-hidden":`true`},{default:v(()=>[e(l(S))]),_:1})]),c(`span`,_e,a(l(w)(`@67CE7:复制文件夹路径`)),1)],40,he),r[23]||=c(`li`,{class:`proj-menu__sep`,role:`separator`},null,-1),c(`li`,ve,a(l(w)(`@WORKBENCH:用工具打开`)),1),(x(!0),u(p,null,f(l(D),t=>(x(),u(`li`,{key:t.id,class:d([`proj-menu__item`,{"is-missing":l(b)(t.id)}]),role:`menuitem`,tabindex:`-1`,onClick:e=>$(t.id),onKeydown:[g(m(e=>$(t.id),[`prevent`]),[`enter`]),g(m(e=>$(t.id),[`prevent`]),[`space`])]},[c(`span`,be,[e(E,{"icon-class":t.icon,class:d({"icon-invert-dark":t.id===`codex`,"icon-outline-dark":l(k).has(t.id)})},null,8,[`icon-class`,`class`])]),c(`span`,xe,a(l(w)(t.labelKey)),1),l(b)(t.id)?(x(),u(`span`,Se,a(l(w)(`@67CE7:未安装`)),1)):C(``,!0)],42,ye))),128)),c(`li`,{class:d([`proj-menu__item`,{"is-missing":l(b)(`claude`)}]),role:`menuitem`,tabindex:`-1`,onClick:r[0]||=e=>$(`claude`),onKeydown:[r[1]||=g(m(e=>$(`claude`),[`prevent`]),[`enter`]),r[2]||=g(m(e=>$(`claude`),[`prevent`]),[`space`])]},[c(`span`,Ce,[c(`img`,{src:l(M),alt:``,class:`proj-menu__img`},null,8,we)]),c(`span`,Te,a(l(w)(`@67CE7:用 Claude Code 打开`)),1),c(`span`,Ee,a(l(b)(`claude`)?l(w)(`@67CE7:未安装`):l(w)(`@67CE7:默认权限`)),1)],34),c(`li`,{class:d([`proj-menu__item proj-menu__item--danger`,{"is-missing":l(b)(`claude`)}]),role:`menuitem`,tabindex:`-1`,onClick:r[3]||=e=>$(`claude`,`bypassPermissions`),onKeydown:[r[4]||=g(m(e=>$(`claude`,`bypassPermissions`),[`prevent`]),[`enter`]),r[5]||=g(m(e=>$(`claude`,`bypassPermissions`),[`prevent`]),[`space`])]},[c(`span`,De,[c(`img`,{src:l(M),alt:``,class:`proj-menu__img`},null,8,Oe)]),c(`span`,ke,a(l(w)(`@67CE7:用 Claude Code 打开(完全批准)`)),1)],34),c(`li`,{class:d([`proj-menu__item proj-menu__item--danger`,{"is-missing":l(b)(`opencode`)}]),role:`menuitem`,tabindex:`-1`,onClick:r[6]||=e=>$(`opencode`,`auto`),onKeydown:[r[7]||=g(m(e=>$(`opencode`,`auto`),[`prevent`]),[`enter`]),r[8]||=g(m(e=>$(`opencode`,`auto`),[`prevent`]),[`space`])]},[c(`span`,Ae,[e(E,{"icon-class":`opencode`})]),c(`span`,je,a(l(w)(`@67CE7:用 OpenCode 打开(完全批准)`)),1)],34),c(`li`,{class:d([`proj-menu__item`,{"is-missing":l(b)(`codex`)}]),role:`menuitem`,tabindex:`-1`,onClick:r[9]||=e=>$(`codex`,`sandboxed`),onKeydown:[r[10]||=g(m(e=>$(`codex`,`sandboxed`),[`prevent`]),[`enter`]),r[11]||=g(m(e=>$(`codex`,`sandboxed`),[`prevent`]),[`space`])]},[c(`span`,Me,[e(E,{"icon-class":`codex`,class:`icon-invert-dark`})]),c(`span`,Ne,a(l(w)(`@67CE7:用 Codex 打开(自动批准)`)),1),l(b)(`codex`)?(x(),u(`span`,Fe,a(l(w)(`@67CE7:未安装`)),1)):(x(),u(`span`,Pe,a(l(w)(`@67CE7:沙箱内`)),1))],34),c(`li`,{class:d([`proj-menu__item proj-menu__item--danger`,{"is-missing":l(b)(`codex`)}]),role:`menuitem`,tabindex:`-1`,onClick:r[12]||=e=>$(`codex`,`bypass`),onKeydown:[r[13]||=g(m(e=>$(`codex`,`bypass`),[`prevent`]),[`enter`]),r[14]||=g(m(e=>$(`codex`,`bypass`),[`prevent`]),[`space`])]},[c(`span`,Ie,[e(E,{"icon-class":`codex`,class:`icon-invert-dark`})]),c(`span`,Le,a(l(w)(`@67CE7:用 Codex 打开(完全批准)`)),1)],34),c(`li`,{class:d([`proj-menu__item proj-menu__item--danger`,{"is-missing":l(b)(`codebuddy`)}]),role:`menuitem`,tabindex:`-1`,onClick:r[15]||=e=>$(`codebuddy`,`bypassPermissions`),onKeydown:[r[16]||=g(m(e=>$(`codebuddy`,`bypassPermissions`),[`prevent`]),[`enter`]),r[17]||=g(m(e=>$(`codebuddy`,`bypassPermissions`),[`prevent`]),[`space`])]},[c(`span`,Re,[e(E,{"icon-class":`codebuddy`})]),c(`span`,ze,a(l(w)(`@67CE7:用 CodeBuddy Code 打开(完全批准)`)),1)],34),c(`li`,{class:d([`proj-menu__item proj-menu__item--danger`,{"is-missing":l(b)(`kimi`)}]),role:`menuitem`,tabindex:`-1`,onClick:r[18]||=e=>$(`kimi`,`auto`),onKeydown:[r[19]||=g(m(e=>$(`kimi`,`auto`),[`prevent`]),[`enter`]),r[20]||=g(m(e=>$(`kimi`,`auto`),[`prevent`]),[`space`])]},[c(`span`,Be,[e(E,{"icon-class":`kimi`})]),c(`span`,Ve,a(l(w)(`@67CE7:用 Kimi Code 打开(完全批准)`)),1)],34),K.value.length?(x(),u(p,{key:0},[r[22]||=c(`li`,{class:`proj-menu__sep`,role:`separator`},null,-1),c(`li`,He,a(l(w)(`@WORKBENCH:桌面端`)),1),(x(!0),u(p,null,f(K.value,e=>(x(),u(`li`,{key:`desktop-${e.id}`,class:`proj-menu__item`,role:`menuitem`,tabindex:`-1`,onClick:t=>q(e.id),onKeydown:[g(m(t=>q(e.id),[`prevent`]),[`enter`]),g(m(t=>q(e.id),[`prevent`]),[`space`])]},[c(`span`,W,[e.id===`claude`?(x(),u(`img`,{key:0,src:l(M),alt:``,class:`proj-menu__img`},null,8,We)):(x(),n(E,{key:1,"icon-class":e.icon,class:d({"icon-invert-dark":e.id===`codex`,"icon-outline-dark":l(k).has(e.id)})},null,8,[`icon-class`,`class`]))]),c(`span`,Ge,a(l(ie)(l(A).desktopAppOf(e.id))),1),c(`span`,Ke,a(l(ue)(l(A).desktopAppOf(e.id))),1)],40,Ue))),128))],64)):C(``,!0)],8,F),e(le,{modelValue:j.value,"onUpdate:modelValue":r[21]||=e=>j.value=e,tool:G.value},null,8,[`modelValue`,`tool`])],64)}}}),[[`__scopeId`,`data-v-80fde3fe`]]);y();function K(){let e=h([]),t=h([]),n=h(``),r=h(!1),i=h(!1);async function a(a=!1){a||(r.value=!0);try{let r=await fetch(`/api/workbench/projects`,{cache:`no-store`}).then(e=>e.json());return r?.success?(e.value=Array.isArray(r.projects)?r.projects:[],t.value=Array.isArray(r.tasks)?r.tasks:[],n.value=r.currentProjectPath||``,i.value=!0,!0):(a||_.error(r?.error||w(`@WORKBENCH:读取项目列表失败`)),!1)}catch(e){return a||_.error(w(`@WORKBENCH:网络错误: `)+(e?.message||e)),!1}finally{r.value=!1}}async function o(e){if(!e)return{ok:!1,keptTasks:0};try{let t=await fetch(`/api/workbench/projects/remove`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({path:e})}).then(e=>e.json()).catch(()=>null);return t?.success?{ok:!0,keptTasks:Number.isFinite(t.keptTasks)?t.keptTasks:0}:(_.error(t?.error||w(`@WORKBENCH:移除项目失败`)),{ok:!1,keptTasks:0})}catch(e){return _.error(w(`@WORKBENCH:网络错误: `)+(e?.message||e)),{ok:!1,keptTasks:0}}}async function s(e){if(!e)return{ok:!1,alreadyKnown:!1};try{let t=await fetch(`/api/workbench/projects/add`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({path:e})}).then(e=>e.json()).catch(()=>null);return t?.success?{ok:!0,alreadyKnown:!!t.alreadyKnown}:(_.error(t?.error||w(`@PROJM:添加项目失败`)),{ok:!1,alreadyKnown:!1})}catch(e){return _.error(w(`@WORKBENCH:网络错误: `)+(e?.message||e)),{ok:!1,alreadyKnown:!1}}}return{projects:e,boardTasks:t,currentProjectPath:n,loading:r,loaded:i,loadProjects:a,removeProject:o,addProject:s}}export{G as n,K as t};
1
+ import"./rolldown-runtime-C0FnF6B9.js";import{An as e,Ar as t,Cn as n,In as r,J as i,Jr as a,Lt as o,Mn as s,Nt as ee,Sn as c,Sr as l,Tn as u,Ur as d,Yn as f,_n as p,gn as m,gr as h,hn as g,i as _,ir as v,lr as y,on as b,qn as x,st as S,wn as C,xn as te,xt as ne}from"./element-plus-CkMnLwcU.js";import{n as w,t as T}from"./_plugin-vue_export-helper-DlU9e1mk.js";import{t as E}from"./SvgIcon-DqzYKNo_.js";import{$ as re,G as D,J as ie,K as O,Q as ae,U as k,W as oe,X as se,Y as A,Z as ce,et as j,nt as le,q as ue,tt as M,xt as N}from"./index-D6QfSjkU.js";function P(){let e=N();function t(t){return e.lastCheckedAt!==null&&!e.isToolAvailable(t)}async function n(t,n,r){if(!n)return`no-dir`;if(!await A())return _.warning(w(`@67CE7:工具检测失败,请稍后重试`)),`failed`;if(!e.isToolAvailable(t))return`install`;let i=await j(t,n,r);return i.success?(_.success(i.message||w(`@67CE7:已用 {tool} 打开目录`,{tool:O[t]})),`opened`):(_.error(`${w(`@67CE7:打开失败: `)}${i.error??``}`),`failed`)}return{toolMissing:t,tryOpenWithTool:n}}r(),y(),t(),b();var F=[`aria-label`],I=[`onKeydown`],L={class:`proj-menu__icon`},R={class:`proj-menu__label`},z=[`onKeydown`],B={class:`proj-menu__icon`},V={class:`proj-menu__label`},H=[`onKeydown`],U={class:`proj-menu__icon`},de={class:`proj-menu__label`},fe=[`onKeydown`],pe={class:`proj-menu__icon`},me={class:`proj-menu__label`},he=[`onKeydown`],ge={class:`proj-menu__icon`},_e={class:`proj-menu__label`},ve={class:`proj-menu__title`,role:`presentation`},ye=[`onClick`,`onKeydown`],be={class:`proj-menu__icon`},xe={class:`proj-menu__label`},Se={key:0,class:`proj-menu__hint`},Ce={class:`proj-menu__icon`},we=[`src`],Te={class:`proj-menu__label`},Ee={class:`proj-menu__hint`},De={class:`proj-menu__icon`},Oe=[`src`],ke={class:`proj-menu__label`},Ae={class:`proj-menu__icon`},je={class:`proj-menu__label`},Me={class:`proj-menu__icon`},Ne={class:`proj-menu__label`},Pe={key:0,class:`proj-menu__hint`},Fe={key:1,class:`proj-menu__hint`},Ie={class:`proj-menu__icon`},Le={class:`proj-menu__label`},Re={class:`proj-menu__icon`},ze={class:`proj-menu__label`},Be={class:`proj-menu__icon`},Ve={class:`proj-menu__label`},He={class:`proj-menu__title`,role:`presentation`},Ue=[`onClick`,`onKeydown`],W={class:`proj-menu__icon`},We=[`src`],Ge={class:`proj-menu__label`},Ke={class:`proj-menu__hint`},G=T(s({__name:`ProjectOpenMenuList`,props:{path:{},name:{}},emits:[`done`],setup(t,{emit:r}){let s=t,y=r,{toolMissing:b,tryOpenWithTool:T}=P(),A=N(),j=h(!1),G=h(null),K=te(()=>oe.filter(e=>A.desktopAppOf(e)).map(e=>({id:e,name:O[e],icon:D.find(t=>t.id===e)?.icon??``})));async function q(e){let t=A.desktopAppOf(e);if(!t)return;if(y(`done`),!t.installed){window.open(t.downloadUrl,`_blank`,`noopener,noreferrer`);return}let n=await ce(e);n.success?_.success(n.message||w(`@67CE7:已打开 {app}`,{app:t.name})):_.error(n.error||w(`@WORKBENCH:打开桌面端失败`))}async function J(){y(`done`);let e=await ae(s.path);e.success?_.success(e.message||w(`@WORKBENCH:已在文件管理器中打开文件夹`)):_.error(e.error||w(`@WORKBENCH:打开文件夹失败`))}async function Y(){y(`done`);let e=await re(s.path);e.success?_.success(e.message||w(`@67CE7:已在终端中打开目录`)):_.error(e.error||w(`@WORKBENCH:打开终端失败`))}async function X(){y(`done`);let e=await se(s.path);e.success?_.success(w(`@WORKBENCH:已在新标签页启动 g ui`)):_.error(e.error||w(`@WORKBENCH:启动 g ui 失败`))}async function Z(){if(y(`done`),s.name)try{await navigator.clipboard.writeText(s.name),_.success(w(`@67CE7:已复制文件夹名称`))}catch{_.error(w(`@67CE7:复制失败`))}}async function Q(){if(y(`done`),s.path)try{await navigator.clipboard.writeText(s.path),_.success(w(`@67CE7:已复制文件夹路径`))}catch{_.error(w(`@67CE7:复制失败`))}}async function $(e,t){if(await T(e,s.path,t)===`install`){G.value=e,j.value=!0;return}y(`done`)}return(t,r)=>{let s=i;return x(),u(p,null,[c(`ul`,{class:`proj-menu`,role:`menu`,"aria-label":l(w)(`@WORKBENCH:打开方式`)},[c(`li`,{class:`proj-menu__item`,role:`menuitem`,tabindex:`-1`,onClick:J,onKeydown:[g(m(J,[`prevent`]),[`enter`]),g(m(J,[`prevent`]),[`space`])]},[c(`span`,L,[e(s,{"aria-hidden":`true`},{default:v(()=>[e(l(ne))]),_:1})]),c(`span`,R,a(l(w)(`@WORKBENCH:在文件管理器中打开`)),1)],40,I),c(`li`,{class:`proj-menu__item`,role:`menuitem`,tabindex:`-1`,onClick:Y,onKeydown:[g(m(Y,[`prevent`]),[`enter`]),g(m(Y,[`prevent`]),[`space`])]},[c(`span`,B,[e(s,{"aria-hidden":`true`},{default:v(()=>[e(l(ee))]),_:1})]),c(`span`,V,a(l(w)(`@WORKBENCH:在终端中打开`)),1)],40,z),c(`li`,{class:`proj-menu__item`,role:`menuitem`,tabindex:`-1`,onClick:X,onKeydown:[g(m(X,[`prevent`]),[`enter`]),g(m(X,[`prevent`]),[`space`])]},[c(`span`,U,[e(s,{"aria-hidden":`true`},{default:v(()=>[e(l(o))]),_:1})]),c(`span`,de,a(l(w)(`@WORKBENCH:在新标签页启动 g ui`)),1)],40,H),c(`li`,{class:`proj-menu__item`,role:`menuitem`,tabindex:`-1`,onClick:Z,onKeydown:[g(m(Z,[`prevent`]),[`enter`]),g(m(Z,[`prevent`]),[`space`])]},[c(`span`,pe,[e(s,{"aria-hidden":`true`},{default:v(()=>[e(l(S))]),_:1})]),c(`span`,me,a(l(w)(`@67CE7:复制文件夹名称`)),1)],40,fe),c(`li`,{class:`proj-menu__item`,role:`menuitem`,tabindex:`-1`,onClick:Q,onKeydown:[g(m(Q,[`prevent`]),[`enter`]),g(m(Q,[`prevent`]),[`space`])]},[c(`span`,ge,[e(s,{"aria-hidden":`true`},{default:v(()=>[e(l(S))]),_:1})]),c(`span`,_e,a(l(w)(`@67CE7:复制文件夹路径`)),1)],40,he),r[23]||=c(`li`,{class:`proj-menu__sep`,role:`separator`},null,-1),c(`li`,ve,a(l(w)(`@WORKBENCH:用工具打开`)),1),(x(!0),u(p,null,f(l(D),t=>(x(),u(`li`,{key:t.id,class:d([`proj-menu__item`,{"is-missing":l(b)(t.id)}]),role:`menuitem`,tabindex:`-1`,onClick:e=>$(t.id),onKeydown:[g(m(e=>$(t.id),[`prevent`]),[`enter`]),g(m(e=>$(t.id),[`prevent`]),[`space`])]},[c(`span`,be,[e(E,{"icon-class":t.icon,class:d({"icon-invert-dark":t.id===`codex`,"icon-outline-dark":l(k).has(t.id)})},null,8,[`icon-class`,`class`])]),c(`span`,xe,a(l(w)(t.labelKey)),1),l(b)(t.id)?(x(),u(`span`,Se,a(l(w)(`@67CE7:未安装`)),1)):C(``,!0)],42,ye))),128)),c(`li`,{class:d([`proj-menu__item`,{"is-missing":l(b)(`claude`)}]),role:`menuitem`,tabindex:`-1`,onClick:r[0]||=e=>$(`claude`),onKeydown:[r[1]||=g(m(e=>$(`claude`),[`prevent`]),[`enter`]),r[2]||=g(m(e=>$(`claude`),[`prevent`]),[`space`])]},[c(`span`,Ce,[c(`img`,{src:l(M),alt:``,class:`proj-menu__img`},null,8,we)]),c(`span`,Te,a(l(w)(`@67CE7:用 Claude Code 打开`)),1),c(`span`,Ee,a(l(b)(`claude`)?l(w)(`@67CE7:未安装`):l(w)(`@67CE7:默认权限`)),1)],34),c(`li`,{class:d([`proj-menu__item proj-menu__item--danger`,{"is-missing":l(b)(`claude`)}]),role:`menuitem`,tabindex:`-1`,onClick:r[3]||=e=>$(`claude`,`bypassPermissions`),onKeydown:[r[4]||=g(m(e=>$(`claude`,`bypassPermissions`),[`prevent`]),[`enter`]),r[5]||=g(m(e=>$(`claude`,`bypassPermissions`),[`prevent`]),[`space`])]},[c(`span`,De,[c(`img`,{src:l(M),alt:``,class:`proj-menu__img`},null,8,Oe)]),c(`span`,ke,a(l(w)(`@67CE7:用 Claude Code 打开(完全批准)`)),1)],34),c(`li`,{class:d([`proj-menu__item proj-menu__item--danger`,{"is-missing":l(b)(`opencode`)}]),role:`menuitem`,tabindex:`-1`,onClick:r[6]||=e=>$(`opencode`,`auto`),onKeydown:[r[7]||=g(m(e=>$(`opencode`,`auto`),[`prevent`]),[`enter`]),r[8]||=g(m(e=>$(`opencode`,`auto`),[`prevent`]),[`space`])]},[c(`span`,Ae,[e(E,{"icon-class":`opencode`})]),c(`span`,je,a(l(w)(`@67CE7:用 OpenCode 打开(完全批准)`)),1)],34),c(`li`,{class:d([`proj-menu__item`,{"is-missing":l(b)(`codex`)}]),role:`menuitem`,tabindex:`-1`,onClick:r[9]||=e=>$(`codex`,`sandboxed`),onKeydown:[r[10]||=g(m(e=>$(`codex`,`sandboxed`),[`prevent`]),[`enter`]),r[11]||=g(m(e=>$(`codex`,`sandboxed`),[`prevent`]),[`space`])]},[c(`span`,Me,[e(E,{"icon-class":`codex`,class:`icon-invert-dark`})]),c(`span`,Ne,a(l(w)(`@67CE7:用 Codex 打开(自动批准)`)),1),l(b)(`codex`)?(x(),u(`span`,Fe,a(l(w)(`@67CE7:未安装`)),1)):(x(),u(`span`,Pe,a(l(w)(`@67CE7:沙箱内`)),1))],34),c(`li`,{class:d([`proj-menu__item proj-menu__item--danger`,{"is-missing":l(b)(`codex`)}]),role:`menuitem`,tabindex:`-1`,onClick:r[12]||=e=>$(`codex`,`bypass`),onKeydown:[r[13]||=g(m(e=>$(`codex`,`bypass`),[`prevent`]),[`enter`]),r[14]||=g(m(e=>$(`codex`,`bypass`),[`prevent`]),[`space`])]},[c(`span`,Ie,[e(E,{"icon-class":`codex`,class:`icon-invert-dark`})]),c(`span`,Le,a(l(w)(`@67CE7:用 Codex 打开(完全批准)`)),1)],34),c(`li`,{class:d([`proj-menu__item proj-menu__item--danger`,{"is-missing":l(b)(`codebuddy`)}]),role:`menuitem`,tabindex:`-1`,onClick:r[15]||=e=>$(`codebuddy`,`bypassPermissions`),onKeydown:[r[16]||=g(m(e=>$(`codebuddy`,`bypassPermissions`),[`prevent`]),[`enter`]),r[17]||=g(m(e=>$(`codebuddy`,`bypassPermissions`),[`prevent`]),[`space`])]},[c(`span`,Re,[e(E,{"icon-class":`codebuddy`})]),c(`span`,ze,a(l(w)(`@67CE7:用 CodeBuddy Code 打开(完全批准)`)),1)],34),c(`li`,{class:d([`proj-menu__item proj-menu__item--danger`,{"is-missing":l(b)(`kimi`)}]),role:`menuitem`,tabindex:`-1`,onClick:r[18]||=e=>$(`kimi`,`auto`),onKeydown:[r[19]||=g(m(e=>$(`kimi`,`auto`),[`prevent`]),[`enter`]),r[20]||=g(m(e=>$(`kimi`,`auto`),[`prevent`]),[`space`])]},[c(`span`,Be,[e(E,{"icon-class":`kimi`})]),c(`span`,Ve,a(l(w)(`@67CE7:用 Kimi Code 打开(完全批准)`)),1)],34),K.value.length?(x(),u(p,{key:0},[r[22]||=c(`li`,{class:`proj-menu__sep`,role:`separator`},null,-1),c(`li`,He,a(l(w)(`@WORKBENCH:桌面端`)),1),(x(!0),u(p,null,f(K.value,e=>(x(),u(`li`,{key:`desktop-${e.id}`,class:`proj-menu__item`,role:`menuitem`,tabindex:`-1`,onClick:t=>q(e.id),onKeydown:[g(m(t=>q(e.id),[`prevent`]),[`enter`]),g(m(t=>q(e.id),[`prevent`]),[`space`])]},[c(`span`,W,[e.id===`claude`?(x(),u(`img`,{key:0,src:l(M),alt:``,class:`proj-menu__img`},null,8,We)):(x(),n(E,{key:1,"icon-class":e.icon,class:d({"icon-invert-dark":e.id===`codex`,"icon-outline-dark":l(k).has(e.id)})},null,8,[`icon-class`,`class`]))]),c(`span`,Ge,a(l(ie)(l(A).desktopAppOf(e.id))),1),c(`span`,Ke,a(l(ue)(l(A).desktopAppOf(e.id))),1)],40,Ue))),128))],64)):C(``,!0)],8,F),e(le,{modelValue:j.value,"onUpdate:modelValue":r[21]||=e=>j.value=e,tool:G.value},null,8,[`modelValue`,`tool`])],64)}}}),[[`__scopeId`,`data-v-80fde3fe`]]);y();function K(){let e=h([]),t=h([]),n=h(``),r=h(!1),i=h(!1);async function a(a=!1){a||(r.value=!0);try{let r=await fetch(`/api/workbench/projects`,{cache:`no-store`}).then(e=>e.json());return r?.success?(e.value=Array.isArray(r.projects)?r.projects:[],t.value=Array.isArray(r.tasks)?r.tasks:[],n.value=r.currentProjectPath||``,i.value=!0,!0):(a||_.error(r?.error||w(`@WORKBENCH:读取项目列表失败`)),!1)}catch(e){return a||_.error(w(`@WORKBENCH:网络错误: `)+(e?.message||e)),!1}finally{r.value=!1}}async function o(e){if(!e)return{ok:!1,keptTasks:0};try{let t=await fetch(`/api/workbench/projects/remove`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({path:e})}).then(e=>e.json()).catch(()=>null);return t?.success?{ok:!0,keptTasks:Number.isFinite(t.keptTasks)?t.keptTasks:0}:(_.error(t?.error||w(`@WORKBENCH:移除项目失败`)),{ok:!1,keptTasks:0})}catch(e){return _.error(w(`@WORKBENCH:网络错误: `)+(e?.message||e)),{ok:!1,keptTasks:0}}}async function s(e){if(!e)return{ok:!1,alreadyKnown:!1};try{let t=await fetch(`/api/workbench/projects/add`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({path:e})}).then(e=>e.json()).catch(()=>null);return t?.success?{ok:!0,alreadyKnown:!!t.alreadyKnown}:(_.error(t?.error||w(`@PROJM:添加项目失败`)),{ok:!1,alreadyKnown:!1})}catch(e){return _.error(w(`@WORKBENCH:网络错误: `)+(e?.message||e)),{ok:!1,alreadyKnown:!1}}}return{projects:e,boardTasks:t,currentProjectPath:n,loading:r,loaded:i,loadProjects:a,removeProject:o,addProject:s}}export{G as n,K as t};
@@ -10,7 +10,7 @@
10
10
  <meta name="theme-color" content="#141820" media="(prefers-color-scheme: dark)" />
11
11
  <title>Zen GitSync</title>
12
12
  <!-- 字体改为自托管(@font-face 见 src/main.css),不再依赖 Google Fonts 外链 -->
13
- <script type="module" crossorigin src="/assets/index-Bz3MwUuu.js"></script>
13
+ <script type="module" crossorigin src="/assets/index-D6QfSjkU.js"></script>
14
14
  <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-C0FnF6B9.js">
15
15
  <link rel="modulepreload" crossorigin href="/assets/dagre-DYyfV0Dg.js">
16
16
  <link rel="modulepreload" crossorigin href="/assets/element-plus-CkMnLwcU.js">
@@ -17,6 +17,8 @@ import fs from 'fs/promises';
17
17
  import path from 'path';
18
18
  import { buildAiChatRequest } from '../../../utils/aiEndpoint.js';
19
19
  import { buildModelFallbackChain, modelLabel, runWithModelFallback } from '../../../utils/aiModelFallback.js';
20
+ // 运行期取模型的唯一入口(内置默认模型不落盘,直读 raw.models 会判成"未配置模型")
21
+ import { resolveModels } from '../../../config.js';
20
22
 
21
23
  // 代码文件扩展名
22
24
  const CODE_EXTENSIONS = [
@@ -531,7 +533,7 @@ export function registerCodeAnalysisRoutes({ app, configManager, getCurrentProje
531
533
  let chain;
532
534
  try {
533
535
  const rawConfig = await configManager.readRawConfigFile();
534
- const models = Array.isArray(rawConfig.models) ? rawConfig.models : [];
536
+ const models = resolveModels(rawConfig);
535
537
  const picked = modelId ? models.find(m => m.id === modelId) : null;
536
538
  chain = buildModelFallbackChain(
537
539
  picked ? [picked, ...models.filter(m => m !== picked)] : models,
@@ -997,7 +999,7 @@ ${hubContentText || '(无)'}
997
999
  let chain;
998
1000
  try {
999
1001
  const rawConfig = await configManager.readRawConfigFile();
1000
- const models = Array.isArray(rawConfig.models) ? rawConfig.models : [];
1002
+ const models = resolveModels(rawConfig);
1001
1003
  const picked = modelId ? models.find(m => m.id === modelId) : null;
1002
1004
  chain = buildModelFallbackChain(
1003
1005
  picked ? [picked, ...models.filter(m => m !== picked)] : models,
@@ -18,6 +18,8 @@ import path from 'path';
18
18
  import fs from 'fs/promises';
19
19
  import open from 'open';
20
20
  import logger from '../utils/logger.js';
21
+ // 运行期取模型的唯一入口(内置默认模型不落盘,直读 raw.models 会判成"未配置模型")
22
+ import { resolveModels } from '../../../config.js';
21
23
  import { CONFIG_FILE } from '../../../paths.js';
22
24
  // AI 请求的地址/请求头统一走这里:OpenCode 网关要求自报 User-Agent 并带
23
25
  // x-opencode-session,否则直接 4xx(见 src/utils/aiEndpoint.js 顶部说明)
@@ -1260,7 +1262,7 @@ export function registerConfigRoutes({
1260
1262
  try {
1261
1263
  const rawConfig = await configManager.readRawConfigFile()
1262
1264
  const userLocale = reqLocale || rawConfig.locale || 'zh-CN'
1263
- const models = Array.isArray(rawConfig.models) ? rawConfig.models : []
1265
+ const models = resolveModels(rawConfig)
1264
1266
  // 候选链 = 默认模型打头 + 其余已配置模型:默认模型额度用完 / 限流时自动换下一个,
1265
1267
  // 而不是让「AI 生成提交信息」直接报错(这几个功能是最常按的按钮)
1266
1268
  const chain = buildModelFallbackChain(models)
@@ -39,6 +39,8 @@ import path from 'node:path';
39
39
  import express from 'express';
40
40
  import { callLlmStream } from '../workbench/llmClient.js';
41
41
  import { buildModelFallbackChain, modelLabel, runWithModelFallback } from '../../../../utils/aiModelFallback.js';
42
+ // 运行期取模型的唯一入口(内置默认模型不落盘,直读 raw.models 会判成"未配置模型")
43
+ import { resolveModels } from '../../../../config.js';
42
44
  import { ensureWithinCwd } from '../../utils/pathGuard.js';
43
45
  import logger from '../../utils/logger.js';
44
46
  import { createThinkFilter } from '../../../../cli/ai/streamFilter.js';
@@ -371,7 +373,7 @@ export function registerAiDiffSummaryRoutes({
371
373
  let chain;
372
374
  try {
373
375
  const rawConfig = await configManager.readRawConfigFile();
374
- const models = Array.isArray(rawConfig.models) ? rawConfig.models : [];
376
+ const models = resolveModels(rawConfig);
375
377
  chain = buildModelFallbackChain(models);
376
378
  } catch (err) {
377
379
  send({ type: 'error', error: '读取 AI 配置失败: ' + err.message, code: 'CONFIG_ERR' });
@@ -42,6 +42,8 @@ import path from 'path';
42
42
  import { callLlmJson } from './workbench/llmClient.js';
43
43
  import { stripThinkingBlocks } from './workbench/jsonParse.js';
44
44
  import { buildProjectEntries, canonicalProjectPath } from './workbench/projectRegistry.js';
45
+ // 运行期取模型的唯一入口(内置默认模型不落盘,直读 raw.models 会判成"未配置模型")
46
+ import { resolveModels } from '../../../config.js';
45
47
  import { TASKS_FILE, readJson } from './workbench/shared.js';
46
48
  import { buildModelFallbackChain, modelLabel, runWithModelFallback } from '../../../utils/aiModelFallback.js';
47
49
  import logger from '../utils/logger.js';
@@ -550,7 +552,7 @@ export function registerProjectStartupAiRoutes({ app, configManager, getCurrentP
550
552
  let chain;
551
553
  try {
552
554
  const rawConfig = await configManager.readRawConfigFile();
553
- const models = Array.isArray(rawConfig.models) ? rawConfig.models : [];
555
+ const models = resolveModels(rawConfig);
554
556
  chain = buildModelFallbackChain(models);
555
557
  } catch (err) {
556
558
  return res.status(500).json({ success: false, code: 'CONFIG_ERR', error: '读取 AI 配置失败: ' + err.message });
@@ -358,11 +358,11 @@ function stubLlm(content) {
358
358
 
359
359
  const MODEL = { model: 'fixture-model', baseURL: 'https://api.example.com/v1', apiKey: 'k', isDefault: true }
360
360
 
361
- async function runRoute({ models, root, locale = 'zh', body = {}, isKnownProject }) {
361
+ async function runRoute({ models, modelsSeeded = false, root, locale = 'zh', body = {}, isKnownProject }) {
362
362
  const app = createFakeApp()
363
363
  registerProjectStartupAiRoutes({
364
364
  app,
365
- configManager: { readRawConfigFile: async () => ({ models }) },
365
+ configManager: { readRawConfigFile: async () => ({ models, ...(modelsSeeded ? { modelsSeeded: true } : {}) }) },
366
366
  getCurrentProjectPath: () => root,
367
367
  // 不传就交给实现自己的默认判据(读真实 tasks.json / config)——测试里一律注入
368
368
  ...(isKnownProject ? { isKnownProject } : {}),
@@ -372,11 +372,14 @@ async function runRoute({ models, root, locale = 'zh', body = {}, isKnownProject
372
372
  return res
373
373
  }
374
374
 
375
- test('路由: 没配模型直接 NO_MODEL,一次网络请求都不发', async () => {
375
+ // 注意 modelsSeeded:空数组 **不再等于** "没模型" —— 它是"新装 / 没写过这个键",
376
+ // 会回落内置的免费默认模型(见 config.js 的 resolveModels)。只有用户主动把模型
377
+ // 删光(写入口打上 modelsSeeded)才是真的没模型可发请求。
378
+ test('路由: 用户把模型全删了(modelsSeeded)直接 NO_MODEL,一次网络请求都不发', async () => {
376
379
  const root = makeFixture()
377
380
  const [restore, calls] = stubLlm('{"suggestions":[]}')
378
381
  try {
379
- const res = await runRoute({ models: [], root })
382
+ const res = await runRoute({ models: [], modelsSeeded: true, root })
380
383
  assert.equal(res.statusCode, 200)
381
384
  assert.equal(res.body.success, false)
382
385
  assert.equal(res.body.code, 'NO_MODEL')
@@ -38,6 +38,8 @@ import { callLlmStream } from './workbench/llmClient.js';
38
38
  import { createThinkFilter } from '../../../cli/ai/streamFilter.js';
39
39
  import { normalizeDirKey } from '../utils/directoryGitState.js';
40
40
  import { buildModelFallbackChain, modelLabel, runWithModelFallback } from '../../../utils/aiModelFallback.js';
41
+ // 运行期取模型的唯一入口(内置默认模型不落盘,直读 raw.models 会判成"未配置模型")
42
+ import { resolveModels } from '../../../config.js';
41
43
  import logger from '../utils/logger.js';
42
44
 
43
45
  /** 一次最多解读多少个目录,与 /api/recent_directories/git-state 的上限保持一致 */
@@ -281,7 +283,7 @@ export function registerRecentDirectoriesSummaryRoutes({ app, configManager }) {
281
283
  let chain;
282
284
  try {
283
285
  const rawConfig = await configManager.readRawConfigFile();
284
- const models = Array.isArray(rawConfig.models) ? rawConfig.models : [];
286
+ const models = resolveModels(rawConfig);
285
287
  chain = buildModelFallbackChain(models);
286
288
  } catch (err) {
287
289
  send({ type: 'error', error: '读取 AI 配置失败: ' + err.message, code: 'CONFIG_ERR' });
@@ -243,14 +243,16 @@ test('路由: 白名单外的路径一律不解读(NO_ITEMS)', async () => {
243
243
  assert.equal(events[0].code, 'NO_ITEMS') // 任意路径解读 = 不能开的口子
244
244
  })
245
245
 
246
- test('路由: 没有配置模型时直接 NO_MODEL,不读最近目录也不联网', async () => {
246
+ // modelsSeeded:空数组本身不是"没模型"(会回落内置免费模型,见 config.js 的
247
+ // resolveModels),只有用户主动删光才真的没有候选链。
248
+ test('路由: 用户把模型全删了(modelsSeeded)直接 NO_MODEL,不读最近目录也不联网', async () => {
247
249
  let listed = false
248
250
  const app = createFakeApp()
249
251
  registerRecentDirectoriesSummaryRoutes({
250
252
  app,
251
253
  configManager: {
252
254
  getRecentDirectories: async () => { listed = true; return ['C:\\ws\\a'] },
253
- readRawConfigFile: async () => ({ models: [] }),
255
+ readRawConfigFile: async () => ({ models: [], modelsSeeded: true }),
254
256
  },
255
257
  })
256
258
  const res = createFakeRes()
@@ -52,6 +52,10 @@ import { resolveJobImagePath, IMAGE_PATH_STATUS, IMAGE_PATH_ERRORS, isInsideRoot
52
52
  import { resolveRequestBudget } from '../../../../cli/ai/context.js';
53
53
  // 每轮用时记录的写入口径(与 CLI 侧共用一份,见函数上的注释)
54
54
  import { recordTurnTiming } from '../../../../cli/ai/sessionStore.js';
55
+ // 运行期取模型的唯一入口:内置默认模型只在 defaultConfig 里,磁盘上的 config.json
56
+ // 没有 models 这个键 —— 直读 rawConfig.models 会在全新安装上判成"未配置 AI 模型",
57
+ // 而设置页(走 loadConfig)明明显示着 agnes-3.0-flash。见 config.js 的 resolveModels。
58
+ import { resolveModels } from '../../../../config.js';
55
59
 
56
60
  const { genSessionId, autoTitle, read: readSession, write: writeSession, delete: deleteSession, listMeta: listSessionsMeta, enforceRetention, rename: renameSession } = agentSessionStore;
57
61
 
@@ -637,7 +641,8 @@ export function registerAgentRoutes({ app, getCurrentProjectPath, configManager,
637
641
  try {
638
642
  if (!configManager) throw new Error('configManager 不可用');
639
643
  const rawConfig = await configManager.readRawConfigFile();
640
- const models = Array.isArray(rawConfig.models) ? rawConfig.models : [];
644
+ // 不能直读 rawConfig.models:内置免费模型不落盘(见 resolveModels 的注释)
645
+ const models = resolveModels(rawConfig);
641
646
  model = models.find(m => m.isDefault) || models[0];
642
647
  // 请求预算:全局配置 aiMaxRequestTokens(缺省/越界由 resolveRequestBudget
643
648
  // 兜底夹取),与 CLI `g ai`、设置页保存回执共用同一份解析 —— 别在这里另算。
@@ -366,6 +366,63 @@ test('每轮用时:turn_done 推给前端,并与落盘的 turnTimings 是同
366
366
  }
367
367
  });
368
368
 
369
+ // 回归(2026-11-02 用户报"发完消息什么都没了"):磁盘上的 config.json 里**没有
370
+ // models 这个键** —— 内置的免费默认模型只在 defaultConfig 里,从不落盘(见 config.js
371
+ // 的 resolveModels)。这条路以前直读 rawConfig.models → 候选链为空 → 秒回一条
372
+ // "未配置 AI 模型"。而设置页读的是 loadConfig(已过 resolveModels),界面上明明
373
+ // 显示着 agnes-3.0-flash,发出去却被拒。这里钉住"没有这个键 = 用内置默认"。
374
+ test('配置里没有 models 键(全新安装)时走内置默认模型,不报未配置模型', async () => {
375
+ const activeCwd = path.resolve('active-project');
376
+ let chatHandler;
377
+ const app = {
378
+ get() {},
379
+ delete() {},
380
+ put() {},
381
+ post(route, handler) {
382
+ if (route === '/api/agent/chat') chatHandler = handler;
383
+ }
384
+ };
385
+ registerAgentRoutes({
386
+ app,
387
+ getCurrentProjectPath: () => activeCwd,
388
+ // 与真实磁盘上的形状一致:新装的 config.json 只有 recentDirectories / ui,没有 models
389
+ configManager: { readRawConfigFile: async () => ({ recentDirectories: [], ui: {} }) },
390
+ snapshotter: STUB_SNAPSHOTTER
391
+ });
392
+
393
+ let requestedUrl = '';
394
+ const originalFetch = globalThis.fetch;
395
+ globalThis.fetch = async (url) => {
396
+ requestedUrl = String(url);
397
+ return new Response(new ReadableStream({
398
+ start(stream) {
399
+ const bytes = new TextEncoder();
400
+ stream.enqueue(bytes.encode(event({ choices: [{ delta: { content: '内置模型的回答' } }] })));
401
+ stream.enqueue(bytes.encode('data: [DONE]\n\n'));
402
+ stream.close();
403
+ }
404
+ }), { status: 200, headers: { 'content-type': 'text/event-stream' } });
405
+ };
406
+
407
+ let output = '';
408
+ try {
409
+ const req = { body: { userMessage: '你好', cwd: activeCwd }, headers: {}, socket: { once() {} } };
410
+ const res = { set() {}, flushHeaders() {}, write(c) { output += c; }, end() {} };
411
+ await chatHandler(req, res);
412
+ } finally {
413
+ globalThis.fetch = originalFetch;
414
+ }
415
+
416
+ assert.doesNotMatch(output, /未配置 AI 模型/, '内置默认模型不该被当成"没配模型"');
417
+ assert.doesNotMatch(output, /"type":"error"/);
418
+ assert.match(output, /内置模型的回答/);
419
+ assert.match(requestedUrl, /agnes-ai\.com/, '发的就是内置那条通道');
420
+ // 跑成功 → 会话落盘,前端刷新列表才找得到它(否则那一轮会从界面上消失)
421
+ const dir = path.join(SANDBOX, '.zen-gitsync', 'agent-sessions');
422
+ const files = readdirSync(dir).filter(f => f.endsWith('.json'));
423
+ assert.ok(files.length >= 1, '成功的一轮必须落盘');
424
+ });
425
+
369
426
  // ── dispatch_task 的注入闸门(2026-09-28)────────────────────────────────
370
427
  // 改由右下角悬浮面板里的 g ai 派活之后,这一条守两件事:
371
428
  // ① allowDispatch 的对话里,dispatch_task 真的能建出任务,且工具结果说清了
@@ -43,7 +43,9 @@ import { readOrchestrator, resolveDispatchPrompt, appendInstruction } from './or
43
43
  import { buildProjectEntries } from './projectRegistry.js';
44
44
  import { resolveInstructionTarget } from './targetResolver.js';
45
45
  import { runSingleSubtask } from './taskRunner.js';
46
- import { normalizeTaskExecutor as normalizeExecutorId } from '../../../../config.js';
46
+ // resolveModels 是运行期取模型的唯一入口(内置默认模型不落盘,直读 raw.models
47
+ // 会判成"未配置模型"),见 config.js 的同名函数
48
+ import { normalizeTaskExecutor as normalizeExecutorId, resolveModels } from '../../../../config.js';
47
49
  import { publish } from './jobStore.js';
48
50
 
49
51
  /**
@@ -143,7 +145,7 @@ export function createDispatcher({ configManager, getCurrentProjectPath, runTask
143
145
  getModel: async () => {
144
146
  if (!configManager) return null;
145
147
  const rawConfig = await configManager.readRawConfigFile();
146
- const models = Array.isArray(rawConfig.models) ? rawConfig.models : [];
148
+ const models = resolveModels(rawConfig);
147
149
  return models.find(m => m.isDefault) || models[0] || null;
148
150
  },
149
151
  onAgentError: (err) => {
@@ -43,6 +43,8 @@ import fs from 'node:fs';
43
43
  import path from 'node:path';
44
44
  import { logger, readJson, CONFIG_FILE } from './shared.js';
45
45
  import { isImageExt } from './attachmentUtils.js';
46
+ // 运行期取模型的唯一入口(内置默认模型不落盘,直读 raw.models 会判成"未配置模型")
47
+ import { resolveModels } from '../../../../config.js';
46
48
  import { callLlmStream } from './llmClient.js';
47
49
  import { buildModelFallbackChain, modelLabel, runWithModelFallback } from '../../../../utils/aiModelFallback.js';
48
50
 
@@ -77,7 +79,7 @@ const SYSTEM_PROMPT = [
77
79
  export async function resolveDescribeModel() {
78
80
  try {
79
81
  const raw = await readJson(CONFIG_FILE, {});
80
- const models = Array.isArray(raw?.models) ? raw.models : [];
82
+ const models = resolveModels(raw);
81
83
  return models.find(m => m && m.isDefault) || models[0] || null;
82
84
  } catch (err) {
83
85
  logger.warn('[imageDescribe] 读取 AI 配置失败,跳过图片转文字:', err?.message || err);
@@ -94,7 +96,7 @@ export async function resolveDescribeModel() {
94
96
  export async function resolveDescribeModelChain() {
95
97
  try {
96
98
  const raw = await readJson(CONFIG_FILE, {});
97
- return buildModelFallbackChain(Array.isArray(raw?.models) ? raw.models : []);
99
+ return buildModelFallbackChain(resolveModels(raw));
98
100
  } catch (err) {
99
101
  logger.warn('[imageDescribe] 读取 AI 配置失败,跳过图片转文字:', err?.message || err);
100
102
  return [];
@@ -35,6 +35,8 @@ import path from 'path';
35
35
  import { execFile } from 'child_process';
36
36
  import express from 'express';
37
37
  import { asyncRoute, HttpError } from '../../utils/asyncRoute.js';
38
+ // 运行期取模型的唯一入口(内置默认模型不落盘,直读 raw.models 会判成"未配置模型")
39
+ import { resolveModels } from '../../../../config.js';
38
40
 
39
41
  import {
40
42
  logger,
@@ -1554,7 +1556,7 @@ export function registerWorkbenchRoutes({
1554
1556
  if (!configManager || typeof configManager.readRawConfigFile !== 'function') return out;
1555
1557
  try {
1556
1558
  const raw = await configManager.readRawConfigFile();
1557
- const models = Array.isArray(raw && raw.models) ? raw.models : [];
1559
+ const models = resolveModels(raw);
1558
1560
  out.model = models.find(m => m && m.isDefault) || models[0] || null;
1559
1561
  out.locale = typeof (raw && raw.locale) === 'string' ? raw.locale : '';
1560
1562
  } catch (err) {
@@ -45,6 +45,8 @@ import { isSessionBusy, acquireSession, releaseSession } from './sessionGate.js'
45
45
  import { logger as defaultLogger, nowIso } from './shared.js';
46
46
  import { recordTurnTiming } from '../../../../cli/ai/sessionStore.js';
47
47
  import { resolveRequestBudget } from '../../../../cli/ai/context.js';
48
+ // 运行期取模型的唯一入口(内置默认模型不落盘,直读 raw.models 会判成"未配置模型")
49
+ import { resolveModels } from '../../../../config.js';
48
50
  import {
49
51
  loadTasks, getTask, claimFire, cleanClaims, setTaskFire, setTaskRun,
50
52
  } from '../../../../utils/scheduleStore.js';
@@ -192,7 +194,7 @@ export function createScheduler({
192
194
  try {
193
195
  if (!configManager) throw new Error('configManager 不可用');
194
196
  const rawConfig = await configManager.readRawConfigFile();
195
- const models = Array.isArray(rawConfig.models) ? rawConfig.models : [];
197
+ const models = resolveModels(rawConfig);
196
198
  // 任务可指定模型(按 name 或 model 匹配);匹配不到回落全局默认
197
199
  let model = task.model
198
200
  ? models.find(m => m.name === task.model || m.model === task.model) || null