zen-gitsync 2.17.34 → 2.17.36
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/README.md +17 -3
- package/package.json +4 -1
- package/src/cli/ai/agent.js +34 -2
- package/src/cli/ai/cli.integration.test.js +30 -0
- package/src/cli/ai/paste.js +372 -0
- package/src/cli/ai/paste.test.js +276 -0
- package/src/cli/ai/termui.js +44 -6
- package/src/cli/ai/termui.test.js +39 -3
- package/src/ui/public/assets/{AgentEngineSelector-DVuUEDHz.js → AgentEngineSelector-DVs4LGHZ.js} +1 -1
- package/src/ui/public/assets/{AgentView-xdFrDybl.js → AgentView-Blp40VRr.js} +1 -1
- package/src/ui/public/assets/{AppVersionBadge-CCqQiZPO.js → AppVersionBadge-BEnoFzwh.js} +2 -2
- package/src/ui/public/assets/{BranchSelector-GD8NqzJj.js → BranchSelector-C7eXeFif.js} +1 -1
- package/src/ui/public/assets/{CommitForm-DNuJSePt.js → CommitForm-CK9jLJOC.js} +1 -1
- package/src/ui/public/assets/{CommonDialog-Cg3qSsFG.js → CommonDialog-BTeIpgGT.js} +1 -1
- package/src/ui/public/assets/{EditorView-ivXCi959.js → EditorView-D00zvntf.js} +1 -1
- package/src/ui/public/assets/{FileDiffViewer-DS1-m59W.js → FileDiffViewer-zqgG9ok3.js} +1 -1
- package/src/ui/public/assets/{FlowExecutionViewer-DXhO7HwA.js → FlowExecutionViewer-VFnxkbIs.js} +1 -1
- package/src/ui/public/assets/{FlowOrchestrationWorkspace-DIJboi94.js → FlowOrchestrationWorkspace-CIIdKK3v.js} +1 -1
- package/src/ui/public/assets/{IconButton-BVgngz_Y.js → IconButton-Cgc5v9vb.js} +1 -1
- package/src/ui/public/assets/{LogList-DGRGqcb_.js → LogList-DyQv-Yec.js} +1 -1
- package/src/ui/public/assets/{MindmapView-CRtCsbfO.js → MindmapView-EC2Wk_Qi.js} +1 -1
- package/src/ui/public/assets/{MonitorView-Ml1e4m41.js → MonitorView-Z5ZbGtaU.js} +1 -1
- package/src/ui/public/assets/{ProjectStartupButton-BDoX_Equ.js → ProjectStartupButton-Ci19q1bL.js} +1 -1
- package/src/ui/public/assets/{RecentDirectoriesChat-CwPIeHuv.js → RecentDirectoriesChat-DT0sguEG.js} +1 -1
- package/src/ui/public/assets/{RemoteManagerDialog-B9JvGgsK.js → RemoteManagerDialog-BRQpjMSK.js} +1 -1
- package/src/ui/public/assets/{RemoteRepoCard-BvZJtHNN.js → RemoteRepoCard-yK90_VfS.js} +1 -1
- package/src/ui/public/assets/{SourceMapView-CxTHZDOP.js → SourceMapView-C55ixUwz.js} +1 -1
- package/src/ui/public/assets/{SvgIcon-dJcILWS2.js → SvgIcon-ub85vovN.js} +1 -1
- package/src/ui/public/assets/{TemplateManager-BqrwTyxG.js → TemplateManager-uDno_64z.js} +1 -1
- package/src/ui/public/assets/{UserInputNode-D28zKp0v.js → UserInputNode-Ce55MMEZ.js} +1 -1
- package/src/ui/public/assets/WorkbenchView-CtJD3pz-.js +228 -0
- package/src/ui/public/assets/WorkbenchView-D1Pf6Etd.css +1 -0
- package/src/ui/public/assets/{_plugin-vue_export-helper-Be8qXN0e.js → _plugin-vue_export-helper-VuE2vqnn.js} +2 -2
- package/src/ui/public/assets/{agentConversations-BAvoMaCc.js → agentConversations-DcW54Tlt.js} +1 -1
- package/src/ui/public/assets/{configStore-Bj7SEMRL.js → configStore-De_8eQuS.js} +1 -1
- package/src/ui/public/assets/{gitStore-BaBKqLlD.js → gitStore-BP6TATf7.js} +1 -1
- package/src/ui/public/assets/{index-B0MdMohu.js → index-Bq_-TrTP.js} +5 -5
- package/src/ui/public/assets/{previewSandbox-DKUIjkxY.js → previewSandbox-DcVlFmag.js} +1 -1
- package/src/ui/public/assets/{toolsStore-MahCZx-D.js → toolsStore-CQclze0T.js} +1 -1
- package/src/ui/public/index.html +11 -11
- package/src/ui/server/routes/workbench/hiddenProjects.js +87 -0
- package/src/ui/server/routes/workbench/hiddenProjects.test.js +60 -0
- package/src/ui/server/routes/workbench/index.js +69 -1
- package/src/ui/server/routes/workbench/shared.js +8 -0
- package/src/ui/public/assets/WorkbenchView-BhWKWSFS.js +0 -220
- package/src/ui/public/assets/WorkbenchView-Bx5r6sZ5.css +0 -1
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import"./rolldown-runtime-C0FnF6B9.js";import{$n as e,Bn as t,C as n,Cn as r,Ct as i,Dn as a,En as o,Et as s,F as c,Fr as l,Ft as u,G as d,Gt as f,Ht as p,I as m,In as h,J as g,Jr as _,Jt as v,K as y,Lt as b,Mn as x,Mt as S,N as C,Nn as w,On as T,Pn as E,Rt as D,S as O,St as ee,Tn as k,U as A,Vt as j,Wn as M,X as te,Xr as N,Y as ne,Yn as re,Z as ie,Zn as P,_n as F,_t as ae,a as I,an as oe,b as se,bn as L,br as R,cr as z,ct as B,dn as V,dt as H,ei as U,gn as ce,i as le,kn as W,lr as G,lt as ue,mn as de,nr as K,o as fe,or as q,ot as pe,pr as J,pt as me,qn as he,r as ge,tt as _e,v as ve,vn as Y,vr as ye,w as be,xn as X,y as xe,yn as Z,yt as Se,z as Ce,zt as we}from"./element-plus-Buzx8xRf.js";import{a as Te,i as Ee,n as De,r as Oe,t as ke}from"./vendor-wERX2bc3.js";import{n as Q,t as Ae}from"./_plugin-vue_export-helper-VuE2vqnn.js";import{t as je}from"./SvgIcon-ub85vovN.js";import{a as Me,i as Ne,o as Pe,t as Fe}from"./configStore-De_8eQuS.js";import{t as Ie}from"./toolsStore-CQclze0T.js";import{t as Le}from"./useThemeObserver-CWioG2jb.js";import{t as Re}from"./CommonDialog-BTeIpgGT.js";import{E as $,_ as ze,d as Be,f as Ve,g as He,h as Ue,m as We,o as Ge,p as Ke,s as qe,u as Je,v as Ye}from"./index-Bq_-TrTP.js";import{a as Xe,i as Ze,n as Qe,o as $e,r as et,s as tt,t as nt,u as rt}from"./agentConversations-DcW54Tlt.js";import{n as it,t as at}from"./AgentEngineSelector-DVs4LGHZ.js";t(),J();var ot=h({__name:`AttachmentZone`,props:{attachments:{type:Array,required:!0},isImage:{type:Function,required:!0},humanSize:{type:Function,required:!0},isUploading:{type:Boolean,required:!0},isPasteHover:{type:Boolean,required:!0},onPick:{type:Function,required:!0},onRemove:{type:Function,required:!0},rawBase:{type:String,required:!1}},emits:[`paste`,`drop`,`dragover`,`dragenter`,`dragleave`],setup(e,{expose:t,emit:n}){t();let r=e;function i(e){return`${r.rawBase||`/api/workbench/attachments`}/${e.id}/raw`}let a=n,o=k(()=>r.attachments.filter(e=>r.isImage(e))),s=k(()=>o.value.map(e=>i(e))),c=R(0),l=R(!1);function u(e){if(r.isImage(e)){let t=o.value.findIndex(t=>t.id===e.id);c.value=t>=0?t:0,l.value=!0}else window.open(i(e),`_blank`,`noopener`)}function d(){l.value=!1}let f=R({visible:!1,x:0,y:0,att:null}),p=R(!1);function m(e,t){if(!r.isImage(e))return;t.preventDefault();let n=window.innerWidth-180,i=window.innerHeight-120;f.value={visible:!0,x:Math.min(t.clientX,n),y:Math.min(t.clientY,i),att:e}}function h(){f.value.visible&&(f.value.visible=!1)}async function g(){let e=f.value.att;if(e&&!p.value){if(h(),!navigator.clipboard||typeof ClipboardItem>`u`){I({type:`warning`,message:Q(`@WORKBENCH:当前浏览器不支持复制图片`)});return}p.value=!0;try{let t=await fetch(i(e),{credentials:`same-origin`});if(!t.ok)throw Error(`HTTP ${t.status}`);let n=await t.blob(),r=[`image/png`,`image/jpeg`,`image/webp`,`image/gif`].includes(n.type)?n.type:`image/png`,a=new ClipboardItem({[r]:n});await navigator.clipboard.write([a]),I({type:`success`,message:Q(`@WORKBENCH:图片已复制到剪贴板`),duration:1800})}catch(e){I({type:`error`,message:Q(`@WORKBENCH:复制失败 {error}`,{error:e?.message||``})})}finally{p.value=!1}}}typeof window<`u`&&(window.addEventListener(`click`,h),window.addEventListener(`scroll`,h,!0),window.addEventListener(`blur`,h)),he(()=>{typeof window<`u`&&(window.removeEventListener(`click`,h),window.removeEventListener(`scroll`,h,!0),window.removeEventListener(`blur`,h))});let _={props:r,rawOf:i,emit:a,imageList:o,previewUrls:s,previewIndex:c,previewVisible:l,previewAttachment:u,closePreview:d,contextMenu:f,copyBusy:p,openContextMenu:m,closeContextMenu:h,copyImageToClipboard:g,get ElImageViewer(){return se},get $t(){return Q}};return Object.defineProperty(_,"__isScriptSetup",{enumerable:!1,value:!0}),_}});l(),t(),V();var st={class:`wb-attachments__head`},ct={class:`wb-attachments__label`},lt={class:`wb-attachments__count`},ut=[`disabled`],dt={key:0,class:`wb-attachments__paste-hint`},ft={key:1,class:`wb-attachments__list`},pt=[`title`,`onClick`,`onContextmenu`],mt=[`src`,`alt`],ht={key:1},gt={class:`wb-attachment__meta`},_t=[`title`],vt=[`onClick`,`title`];function yt(t,n,i,s,c,l){return P(),W(X,null,[o(`div`,{class:_([`wb-attachments`,{"is-paste-hover":i.isPasteHover}]),onPaste:n[1]||=e=>s.emit(`paste`,e),onDrop:n[2]||=L(e=>s.emit(`drop`,e),[`prevent`]),onDragover:n[3]||=L(e=>s.emit(`dragover`,e),[`prevent`]),onDragenter:n[4]||=L(e=>s.emit(`dragenter`,e),[`prevent`]),onDragleave:n[5]||=e=>s.emit(`dragleave`,e)},[o(`div`,st,[o(`span`,ct,[w(U(s.$t(`@WORKBENCH:附件`))+` `,1),T(` 只报个数:数量不设上限,写成 "N / 9" 会让人以为还剩几个能加 `),o(`span`,lt,U(i.attachments.length),1)]),o(`button`,{class:`wb-attachments__add wb-soft-btn`,disabled:i.isUploading,onClick:n[0]||=(...e)=>i.onPick&&i.onPick(...e)},U(i.isUploading?s.$t(`@WORKBENCH:上传中…`):s.$t(`@WORKBENCH:添加附件`)),9,ut)]),i.isPasteHover?(P(),W(`div`,dt,U(s.$t(`@WORKBENCH:粘贴图片以快速添加`)),1)):T(`v-if`,!0),i.attachments.length>0?(P(),W(`ul`,ft,[(P(!0),W(X,null,e(i.attachments,e=>(P(),W(`li`,{key:e.id,class:`wb-attachment`},[o(`button`,{type:`button`,class:`wb-attachment__preview`,title:s.$t(`@WORKBENCH:点击预览`),onClick:t=>s.previewAttachment(e),onContextmenu:t=>s.openContextMenu(e,t)},[o(`div`,{class:_([`wb-attachment__icon`,{"wb-attachment__icon--img":i.isImage(e)}])},[i.isImage(e)?(P(),W(`img`,{key:0,src:s.rawOf(e),alt:e.originalName,loading:`lazy`},null,8,mt)):(P(),W(`span`,ht,U(e.ext.toUpperCase()),1))],2),o(`div`,gt,[o(`div`,{class:`wb-attachment__name`,title:`${e.originalName} (${i.humanSize(e.size)})`},U(e.originalName),9,_t)])],40,pt),o(`button`,{class:`wb-attachment__del`,onClick:L(t=>i.onRemove(e),[`stop`]),title:s.$t(`@WORKBENCH:删除`)},`×`,8,vt)]))),128))])):T(`v-if`,!0)],34),T(`
|
|
2
|
+
el-image-viewer 自己通过内部 <Teleport to="body" :disabled="!teleported"> 把遮罩渲染到 body。
|
|
3
|
+
不要在外面再包一层 <teleport to="body"> —— 嵌套 Teleport 在 element-plus 2.11.x 下会让组件
|
|
4
|
+
的 v-if 容器内残留占位、且内部 Teleport 因找不到正确锚点而不挂载,导致点击图片无反应。
|
|
5
|
+
显式传 :teleported="true" 是为了保证内部 Teleport 启用(默认是 undefined 关闭)。
|
|
6
|
+
`),s.previewVisible&&s.previewUrls.length>0?(P(),a(s.ElImageViewer,{key:0,"url-list":s.previewUrls,"initial-index":s.previewIndex,"hide-on-click-modal":!0,teleported:!0,onClose:s.closePreview},null,8,[`url-list`,`initial-index`])):T(`v-if`,!0),T(` 右键菜单:仅图片附件可用 `),(P(),a(r,{to:`body`},[s.contextMenu.visible&&s.contextMenu.att&&i.isImage(s.contextMenu.att)?(P(),W(`ul`,{key:0,class:`wb-ctx-menu`,style:N({top:s.contextMenu.y+`px`,left:s.contextMenu.x+`px`}),onContextmenu:n[6]||=L(()=>{},[`prevent`])},[o(`li`,{class:_([`wb-ctx-menu__item`,{"is-disabled":s.copyBusy}]),onClick:s.copyImageToClipboard},[n[7]||=o(`span`,{class:`wb-ctx-menu__icon`,"aria-hidden":`true`},[o(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`1.8`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[o(`rect`,{x:`9`,y:`9`,width:`11`,height:`11`,rx:`2`}),o(`path`,{d:`M5 15V5a2 2 0 0 1 2-2h10`})])],-1),o(`span`,null,U(s.$t(`@WORKBENCH:复制图片`)),1)],2)],36)):T(`v-if`,!0)]))],64)}var bt=Ae(ot,[[`render`,yt],[`__scopeId`,`data-v-d2df2361`],[`__file`,`C:/workspace/github_workspace/xz333221/zen-gitsync/src/ui/client/src/components/AttachmentZone.vue`]]),xt=De(`claude`),St=De(`opencode`),Ct=De(`codex`);function wt(e){return e===`opencode`?St:e===`codex`?Ct:xt}function Tt(e){switch(e){case`todo`:return Q(`@WORKBENCH:待执行`);case`running`:return Q(`@WORKBENCH:执行中`);case`done`:return Q(`@WORKBENCH:已完成`);case`error`:return Q(`@WORKBENCH:出错`);case`cancelled`:return Q(`@WORKBENCH:已取消`);case`pending`:return Q(`@WORKBENCH:排队中`);default:return e}}function Et(e){switch(e){case`running`:return`var(--color-primary)`;case`done`:return`#22c55e`;case`error`:return`#ef4444`;case`cancelled`:return`#9ca3af`;case`pending`:return`#f59e0b`;default:return`var(--text-tertiary)`}}var Dt=8192;function Ot(e,t){return e.length>t?`…(前文已截断)\n${e.slice(-t)}`:e}function kt(e,t){let n=e||`done`;return n!==`pending`&&n!==`running`||t===`running`||t===`pending`?n:t===`cancelled`||t===`error`?`error`:`done`}function At(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=kt(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?Ot(o,Dt):``,status:a,error:typeof i.error==`string`&&i.error?i.error:void 0})}return r}var jt=`
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
`,Mt=`[运行环境 ·`,Nt=`## 跨会话记忆库`,Pt=/\n\n---\n本任务包含 \d+ 个附件(请按文件路径读取[\s\S]*$/,Ft=/\n\n续接 #\d+\s*$/;function It(e){let t=e.indexOf(jt);return t===-1?0:t+7}function Lt(e){let t=typeof e==`string`?e:``;return t?(t.startsWith(Mt)&&(t=t.slice(It(t))),t.startsWith(Nt)&&(t=t.slice(It(t))),t=t.replace(Pt,``).replace(Ft,``),t.trim()):``}var Rt=[`png`,`jpg`,`jpeg`,`gif`,`webp`,`bmp`,`svg`],zt=/!\[([^\]]*)\]\(\s*(?:<([^<>\n]+)>|([^()\s]+))(\s+["'][^"']*["'])?\s*\)/g,Bt=/^\s*(`{3,}|~{3,})/,Vt=/\.([a-z0-9]+)$/;function Ht(e){let t=e.trim().toLowerCase().match(Vt);return!!t&&Rt.includes(t[1])}function Ut(e){let t=String(e||``).trim();if(!t)return!1;if(/^[a-zA-Z]:[\\/]/.test(t))return Ht(t);let n=t.match(/^([a-z][a-z0-9+.-]+):/i);return n&&n[1].toLowerCase()!==`file`||t.startsWith(`//`)||t.startsWith(`/`)?!1:Ht(t)}function Wt(e,t){return`/api/workbench/jobs/${encodeURIComponent(e)}/image?path=${encodeURIComponent(t)}`}function Gt(e,t){return e.includes(`}${a||``})`:e}):e}function Kt(e,t){let n=typeof e==`string`?e:``;if(!n||!t||!n.includes(`![`))return n;let r=n.split(`
|
|
11
|
+
`),i=null,a=[];for(let e of r){let n=e.match(Bt);if(n){let t=n[1][0];i===null?i=t:i===t&&(i=null),a.push(e);continue}a.push(i===null?Gt(e,t):e)}return a.join(`
|
|
12
|
+
`)}t(),J();var qt=65536,Jt=h({__name:`JobLogDetails`,props:{job:{type:Object,required:!0}},emits:[`re-execute`],setup(e,{expose:t,emit:n}){t();let r=Fe(),i=e,a=n,o=R(!1);function s(){o.value=!o.value}let c=k(()=>i.job.status===`running`||i.job.status===`pending`);q(()=>i.job.status,(e,t)=>{t!==`running`&&t!==`pending`&&(e===`running`||e===`pending`)&&(o.value=!1)});function l(){let e=i.job.output||``;return e?Kt(e.length<=qt?e:`${Q(`@WORKBENCH:…(前文已截断)`)}\n${e.slice(-65536)}`,i.job.id):``}function u(){let e=i.job.thinking||``;return e?e.length<=qt?e:`${Q(`@WORKBENCH:…(前文已截断)`)}\n${e.slice(-65536)}`:``}async function d(e){try{if(navigator?.clipboard?.writeText)return await navigator.clipboard.writeText(e),!0}catch{}try{let t=document.createElement(`textarea`);t.value=e,t.style.position=`fixed`,t.style.opacity=`0`,t.style.left=`-9999px`,document.body.appendChild(t),t.select();let n=document.execCommand(`copy`);return document.body.removeChild(t),n}catch{return!1}}async function f(){let e=[];if(i.job.prompt&&e.push(`## ${Q(`@WORKBENCH:用户提示词`)}\n\n${i.job.prompt}`),i.job.thinking&&e.push(`## ${Q(`@WORKBENCH:Claude 思考`)}\n\n${i.job.thinking}`),i.job.output&&e.push(`## ${Q(`@WORKBENCH:模型返回`)}\n\n${i.job.output}`),!e.length){I.warning(Q(`@WORKBENCH:暂无内容可复制`));return}await d(e.join(`
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
`))?I.success(Q(`@WORKBENCH:已复制到剪贴板`)):I.error(Q(`@WORKBENCH:复制失败`))}let p=k(()=>{let e=i.job.status;return e===`done`||e===`error`||e===`cancelled`}),m=k(()=>i.job.status===`cancelled`?`wb-log-summary__status--cancelled`:i.job.status===`error`?`wb-log-summary__status--error`:`wb-log-summary__status--done`),h=k(()=>i.job.status===`cancelled`?`⏹`:i.job.status===`error`?`✗`:`✓`),g=k(()=>i.job.status===`cancelled`?Q(`@WORKBENCH:已停止`):i.job.status===`error`?Q(`@WORKBENCH:执行出错`):Q(`@WORKBENCH:执行完成`)),_=k(()=>Pe(i.job?.agent)),v=k(()=>wt(i.job?.agent));function y(e,t){return e===`running`||e===`pending`?t?`streaming`:`pending`:e===`error`?`error`:`done`}let b=k(()=>{let e=i.job,t=[],n=e.startedAt?new Date(e.startedAt).getTime():Date.now();if(e.prompt){let r=Lt(e.prompt);r&&t.push({id:`${e.id}-u`,role:`user`,content:r,status:`done`,createdAt:n})}let r=l(),a=u(),o=!!r,s=!!a,c=At(e),d=c.length>0,f=o||s||d,p=y(e.status,f);return t.push({id:`${e.id}-a`,role:`assistant`,content:r,reasoning:s?a:void 0,reasoningStatus:s?o?`done`:p===`streaming`?`streaming`:`done`:void 0,toolCalls:d?c:void 0,status:p,error:p===`error`&&e.error||void 0,createdAt:n}),t}),x=R(null);q(()=>i.job.status,(e,t)=>{e===`running`&&t!==`running`&&(x.value=x.value??Date.now())});let S=k(()=>{if(!x.value)return``;let e=x.value,t=i.job.endedAt?new Date(i.job.endedAt).getTime():Date.now(),n=Math.max(0,Math.floor((t-e)/1e3));return n<60?`${n}s`:`${Math.floor(n/60)}分${(n%60).toString().padStart(2,`0`)}秒`}),C=R(!1),w=k(()=>!!(i.job.output&&i.job.output.length)),T=k(()=>Kt(i.job.output||``,i.job.id)),E=R(null);q(C,async e=>{e&&(await M(),E.value&&(E.value.scrollTop=E.value.scrollHeight))}),q(()=>(i.job.output||``).length,async()=>{C.value&&(await M(),E.value&&(E.value.scrollTop=E.value.scrollHeight))});function D(){}let O=k(()=>p.value&&!!i.job.prompt);function ee(){a(`re-execute`,i.job)}let A={configStore:r,props:i,emit:a,isCollapsed:o,toggleOpen:s,isActive:c,MAX_LOG_DISPLAY:qt,displayOutput:l,displayThinking:u,copyToClipboard:d,copyAll:f,isFinished:p,finishedStatusClass:m,finishedStatusIcon:h,finishedStatusLabel:g,assistantLabel:_,assistantAvatar:v,mapStatus:y,chatMessages:b,startedAt:x,elapsedLabel:S,fullscreenOpen:C,hasOutput:w,fullscreenSource:T,fullscreenContainerRef:E,onFullscreenClosed:D,canReExecute:O,onReExecute:ee,get ChatContainer(){return Te},get MarkdownRenderer(){return Ee},get $t(){return Q},CommonDialog:Re};return Object.defineProperty(A,"__isScriptSetup",{enumerable:!1,value:!0}),A}});l(),t(),V();var Yt=[`aria-expanded`],Xt={class:`wb-log-summary__left`},Zt={key:0,class:`wb-log-summary__status wb-log-summary__status--running`},Qt={class:`wb-log-summary__label`},$t={key:0,class:`wb-log-summary__elapsed`},en={key:1,class:`wb-log-summary__status wb-log-summary__status--pending`},tn={class:`wb-log-summary__label`},nn={class:`wb-log-summary__icon`},rn={class:`wb-log-summary__label`},an={key:0,class:`wb-log-summary__elapsed`},on={key:3},sn={class:`wb-log-summary__right`},cn={class:`wb-log-summary__meta`},ln=[`title`,`aria-label`],un={class:`wb-log-details__body`},dn={class:`wb-job-chat`},fn={key:0,class:`wb-chat__foot`},pn=[`title`,`aria-label`],mn={ref:`fullscreenContainerRef`,class:`wb-log-fullscreen`},hn={key:1,class:`wb-log-fullscreen__empty`};function gn(e,t,n,r,i,s){return P(),W(`div`,{class:_([`wb-log-details`,{"is-running":r.isActive,"is-pending":n.job.status===`pending`,"is-finished":r.isFinished}])},[o(`div`,{class:`wb-log-summary`,onClick:r.toggleOpen,role:`button`,"aria-expanded":!r.isCollapsed},[o(`span`,Xt,[n.job.status===`running`?(P(),W(`span`,Zt,[o(`span`,Qt,U(r.$t(`@WORKBENCH:正在执行…`)),1),t[1]||=o(`span`,{class:`wb-log-dots`,"aria-hidden":`true`},[o(`span`,{class:`wb-log-dots__dot`}),o(`span`,{class:`wb-log-dots__dot`}),o(`span`,{class:`wb-log-dots__dot`})],-1),r.elapsedLabel?(P(),W(`span`,$t,U(r.elapsedLabel),1)):T(`v-if`,!0)])):n.job.status===`pending`?(P(),W(`span`,en,[o(`span`,tn,U(r.$t(`@WORKBENCH:排队中…`)),1),t[2]||=o(`span`,{class:`wb-log-dots`,"aria-hidden":`true`},[o(`span`,{class:`wb-log-dots__dot`}),o(`span`,{class:`wb-log-dots__dot`}),o(`span`,{class:`wb-log-dots__dot`})],-1)])):r.isFinished?(P(),W(`span`,{key:2,class:_([`wb-log-summary__status`,r.finishedStatusClass])},[o(`span`,nn,U(r.finishedStatusIcon),1),o(`span`,rn,U(r.finishedStatusLabel),1),r.elapsedLabel?(P(),W(`span`,an,U(r.elapsedLabel),1)):T(`v-if`,!0)],2)):(P(),W(`span`,on,U(r.$t(`@WORKBENCH:查看执行日志`)),1))]),o(`span`,sn,[o(`span`,cn,U((n.job.output||``).length)+` `+U(r.$t(`@WORKBENCH:字符`)),1),o(`button`,{type:`button`,class:`wb-log-copy`,title:r.$t(`@WORKBENCH:复制全部(含提示词与输出)`),"aria-label":r.$t(`@WORKBENCH:复制全部`),onClick:L(r.copyAll,[`stop`])},` ⧉ `,8,ln)])],8,Yt),T(`
|
|
17
|
+
body 容器:用 zen-ai-chat-ui 的 ChatContainer 渲染单轮对话。
|
|
18
|
+
关掉 ChatContainer 自带的输入框(show-input=false —— 续聊输入由父组件统一承载),
|
|
19
|
+
下方保留"重新执行"footer。
|
|
20
|
+
|
|
21
|
+
⚠️ 别改回「class 挂到 ChatContainer 上 + CSS 隐藏」:传给 zen-ai-chat-ui 组件的 class
|
|
22
|
+
在**生产构建**里不会落到组件根节点上(dev 会落、prod 静默丢),\`.wb-job-chat :deep(.acu-*)\`
|
|
23
|
+
就全成了死代码 —— 自带的输入框藏不住,背景/气泡密度也全是库默认值。
|
|
24
|
+
2026-09-29 在 WorkbenchView 上就是这个坑(「已完成任务点开有 2 个输入框」)。
|
|
25
|
+
所以外层套一个自己的 div 承载 class。
|
|
26
|
+
`),G(o(`div`,un,[o(`div`,dn,[E(r.ChatContainer,{messages:r.chatMessages,"assistant-name":r.assistantLabel,"assistant-avatar":r.assistantAvatar,"show-avatar":!0,theme:r.configStore.theme,"tool-calls-config":{group:!0,collapseThreshold:2},"plan-config":{labels:{title:r.$t(`@AGENT:计划`),raw:r.$t(`@AGENT:原始参数`)}},"show-input":!1},null,8,[`messages`,`assistant-name`,`assistant-avatar`,`theme`,`plan-config`])]),T(` footer:任务结束后显示"重新执行",运行中不显示 `),r.canReExecute?(P(),W(`footer`,fn,[o(`button`,{type:`button`,class:`wb-chat__action`,title:r.$t(`@WORKBENCH:用相同的提示词重新执行此任务`),"aria-label":r.$t(`@WORKBENCH:重新执行`),onClick:r.onReExecute},` ↻ `,8,pn)])):T(`v-if`,!0),T(` 全屏查看 dialog `),E(r.CommonDialog,{modelValue:r.fullscreenOpen,"onUpdate:modelValue":t[0]||=e=>r.fullscreenOpen=e,title:r.$t(`@WORKBENCH:模型返回 - 全屏查看`),size:`fullscreen`,type:`flex`,"close-on-click-modal":!1,"custom-class":`wb-log-fullscreen-dialog`,onClosed:r.onFullscreenClosed},{default:z(()=>[o(`div`,mn,[r.hasOutput?(P(),a(r.MarkdownRenderer,{key:0,source:r.fullscreenSource,class:`wb-log-fullscreen__render`},null,8,[`source`])):(P(),W(`div`,hn,U(r.$t(`@WORKBENCH:(暂无输出)`)),1))],512)]),_:1},8,[`modelValue`,`title`])],512),[[Y,!r.isCollapsed]]),T(` /.wb-log-details__body `)],2)}var _n=Ae(Jt,[[`render`,gn],[`__scopeId`,`data-v-a4bb55c4`],[`__file`,`C:/workspace/github_workspace/xz333221/zen-gitsync/src/ui/client/src/components/JobLogDetails.vue`]]);t(),J();var vn=50,yn=h({__name:`ExecutionLogManager`,setup(e,{expose:t}){t();function n(e){return e instanceof Error?e.message:String(e)}let r=R([]),i=R(0),a=ye({count:0,sizeMB:0,byStatus:{}}),o=R(!1),s=R(new Set),c=ye({q:``,status:``,page:1}),l=R({maxCount:500,maxSizeMB:256}),u=ye({maxCount:500,maxSizeMB:256}),d=R(!1),f=[{value:`pending`,label:Q(`@WORKBENCH:排队中`)},{value:`running`,label:Q(`@WORKBENCH:执行中`)},{value:`done`,label:Q(`@WORKBENCH:已完成`)},{value:`error`,label:Q(`@WORKBENCH:出错`)},{value:`cancelled`,label:Q(`@WORKBENCH:已取消`)}],m=k(()=>r.value.length>0&&r.value.every(e=>s.value.has(e.id))),h=k(()=>r.value.some(e=>s.value.has(e.id))&&!m.value);async function g(){o.value=!0;try{let e=new URLSearchParams;c.q&&e.set(`q`,c.q),c.status&&e.set(`status`,c.status),e.set(`limit`,String(vn)),e.set(`offset`,String((c.page-1)*vn));let t=await fetch(`/api/workbench/jobs/list?${e.toString()}`).then(e=>e.json());if(!t.success)throw Error(t.error||`list failed`);r.value=t.jobs,i.value=t.total,a.count=t.stats.count,a.sizeMB=t.stats.sizeMB,a.byStatus=t.stats.byStatus;let n=new Set(r.value.map(e=>e.id));for(let e of Array.from(s.value))n.has(e)||s.value.delete(e)}catch(e){I.error(Q(`@WORKBENCH:加载失败`)+`: `+n(e))}finally{o.value=!1}}async function _(){try{let e=await fetch(`/api/workbench/jobs/config`).then(e=>e.json());e.success&&(l.value=e.config,u.maxCount=e.config.maxCount,u.maxSizeMB=e.config.maxSizeMB)}catch{}}async function v(){d.value=!0;try{let e=await fetch(`/api/workbench/jobs/config`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify({maxCount:u.maxCount,maxSizeMB:u.maxSizeMB})}).then(e=>e.json());if(!e.success)throw Error(e.error||`save failed`);l.value=e.config,I.success(Q(`@WORKBENCH:已保存策略`)),await g()}catch(e){I.error(Q(`@WORKBENCH:保存失败`)+`: `+n(e))}finally{d.value=!1}}function y(){c.page=1,g()}function b(){c.q=``,c.status=``,c.page=1,g()}function x(e,t){t?s.value.add(e):s.value.delete(e),s.value=new Set(s.value)}function S(e){if(e)for(let e of r.value)s.value.add(e.id);else for(let e of r.value)s.value.delete(e.id);s.value=new Set(s.value)}function C(e){I.info(Q(`@WORKBENCH:请到工作台主面板的对应任务上点击「重新执行」`))}async function w(e){try{await le.confirm(Q(`@WORKBENCH:确定要删除所选的 {count} 条日志吗?`,{count:1}),Q(`@WORKBENCH:删除`),{type:`warning`})}catch{return}try{let t=await fetch(`/api/workbench/jobs/${e}`,{method:`DELETE`}).then(e=>e.json());if(!t.success)throw Error(t.error||`delete failed`);s.value.delete(e),s.value=new Set(s.value),await g()}catch(e){I.error(Q(`@WORKBENCH:保存失败`)+`: `+n(e))}}async function T(){let e=Array.from(s.value);if(e.length!==0){try{await le.confirm(Q(`@WORKBENCH:确定要删除所选的 {count} 条日志吗?`,{count:e.length}),Q(`@WORKBENCH:批量删除`),{type:`warning`})}catch{return}try{let t=await fetch(`/api/workbench/jobs/batch-delete`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({ids:e})}).then(e=>e.json());if(!t.success)throw Error(t.error||`batch delete failed`);I.success(Q(`@WORKBENCH:成功删除 {count} 条`,{count:t.removed||e.length})),s.value=new Set,await g()}catch(e){I.error(Q(`@WORKBENCH:保存失败`)+`: `+n(e))}}}async function E(){let e=a.count;if(e!==0){try{await le.confirm(Q(`@WORKBENCH:确定要清空所有 {count} 条执行日志吗?此操作不可恢复。`,{count:e}),Q(`@WORKBENCH:清空全部`),{type:`warning`,confirmButtonText:Q(`@WORKBENCH:清空全部`)})}catch{return}try{let t=await fetch(`/api/workbench/jobs/clear`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({confirm:!0})}).then(e=>e.json());if(!t.success)throw Error(t.error||`clear failed`);I.success(Q(`@WORKBENCH:成功删除 {count} 条`,{count:t.removed||e})),s.value=new Set,await g()}catch(e){I.error(Q(`@WORKBENCH:保存失败`)+`: `+n(e))}}}function D(e,t){if(!e)return``;let n=new Date(e).getTime(),r=t?new Date(t).getTime():Date.now(),i=Math.max(0,r-n);return i<1e3?`${i}ms`:i<6e4?`${(i/1e3).toFixed(1)}s`:i<36e5?`${Math.floor(i/6e4)}m ${Math.floor(i%6e4/1e3)}s`:`${Math.floor(i/36e5)}h ${Math.floor(i%36e5/6e4)}m`}re(()=>{g(),_()});let O={errMsg:n,list:r,total:i,stats:a,loading:o,selectedIds:s,pageSize:vn,filter:c,config:l,configDraft:u,configSaving:d,STATUS_OPTIONS:f,isAllOnPageSelected:m,isSomeOnPageSelected:h,load:g,loadConfig:_,saveConfig:v,onFilterChange:y,resetFilter:b,toggleSelect:x,toggleSelectAllOnPage:S,onReExecuteInLog:C,deleteOne:w,batchDelete:T,clearAll:E,formatDuration:D,get Document(){return me},get Refresh(){return p},get $t(){return Q},get statusLabel(){return Tt},get statusColor(){return Et},JobLogDetails:_n};return Object.defineProperty(O,"__isScriptSetup",{enumerable:!1,value:!0}),O}});t(),l(),V();var bn={class:`exec-logs`},xn={class:`exec-logs__head`},Sn={class:`exec-logs__title-block`},Cn={class:`exec-logs__stats`},wn={class:`exec-logs__head-actions`},Tn={class:`exec-logs__config`},En={class:`exec-logs__config-label`},Dn={class:`exec-logs__config-field`},On={class:`exec-logs__config-name`},kn={class:`exec-logs__config-field`},An={class:`exec-logs__config-name`},jn={class:`exec-logs__filter`},Mn={key:0,class:`exec-logs__batch-meta`},Nn={key:0,class:`exec-logs__batch`},Pn={class:`exec-logs__list`},Fn={key:0,class:`exec-logs__empty`},In={class:`exec-logs__empty-art`,"aria-hidden":`true`},Ln={class:`exec-logs__empty-title`},Rn={class:`exec-logs__empty-hint`},zn={class:`exec-card__head`},Bn=[`title`],Vn={class:`exec-card__meta`},Hn={key:0,class:`exec-card__task`},Un={key:1,class:`exec-card__time`},Wn={key:2,class:`exec-card__exit`},Gn=[`title`,`onClick`],Kn={key:0,class:`exec-card__error`},qn={key:1,class:`exec-logs__pager`};function Jn(t,n,r,i,a,s){let l=Ce,u=xe,d=A,f=c,p=m,h=C,v=g,y=ve,b=fe;return P(),W(`div`,bn,[T(` 头部:统计 + 刷新 + 清空。
|
|
27
|
+
标题已由外层 el-dialog 提供,这里不再重复 h2。 `),o(`header`,xn,[o(`div`,Sn,[o(`span`,Cn,U(i.$t(`@WORKBENCH:共 {count} 条,占 {size} MB`,{count:i.stats.count,size:i.stats.sizeMB})),1)]),o(`div`,wn,[E(l,{icon:i.Refresh,size:`small`,loading:i.loading,onClick:i.load},{default:z(()=>[w(U(i.$t(`@WORKBENCH:刷新`)),1)]),_:1},8,[`icon`,`loading`]),E(l,{type:`danger`,plain:``,size:`small`,disabled:i.stats.count===0,onClick:i.clearAll},{default:z(()=>[w(U(i.$t(`@WORKBENCH:清空全部`)),1)]),_:1},8,[`disabled`])])]),T(` 保留策略 `),o(`div`,Tn,[o(`span`,En,U(i.$t(`@WORKBENCH:保存策略`)),1),o(`span`,Dn,[o(`span`,On,U(i.$t(`@WORKBENCH:最大条数`)),1),E(u,{modelValue:i.configDraft.maxCount,"onUpdate:modelValue":n[0]||=e=>i.configDraft.maxCount=e,min:0,max:1e4,step:50,size:`small`,"controls-position":`right`,style:{width:`130px`}},null,8,[`modelValue`])]),o(`span`,kn,[o(`span`,An,U(i.$t(`@WORKBENCH:最大体积 (MB)`)),1),E(u,{modelValue:i.configDraft.maxSizeMB,"onUpdate:modelValue":n[1]||=e=>i.configDraft.maxSizeMB=e,min:0,max:10240,step:32,size:`small`,"controls-position":`right`,style:{width:`140px`}},null,8,[`modelValue`])]),E(l,{type:`primary`,size:`small`,loading:i.configSaving,onClick:i.saveConfig},{default:z(()=>[w(U(i.$t(`@WORKBENCH:保存策略`)),1)]),_:1},8,[`loading`])]),T(` 过滤栏 `),o(`div`,jn,[E(d,{modelValue:i.filter.q,"onUpdate:modelValue":n[2]||=e=>i.filter.q=e,placeholder:i.$t(`@WORKBENCH:搜索标题 / 任务`),clearable:``,size:`small`,style:{width:`240px`},onKeyup:Z(i.onFilterChange,[`enter`]),onClear:i.onFilterChange},null,8,[`modelValue`,`placeholder`]),E(p,{modelValue:i.filter.status,"onUpdate:modelValue":n[3]||=e=>i.filter.status=e,placeholder:i.$t(`@WORKBENCH:全部状态`),clearable:``,size:`small`,style:{width:`130px`},onChange:i.onFilterChange},{default:z(()=>[(P(),W(X,null,e(i.STATUS_OPTIONS,e=>E(f,{key:e.value,label:e.label,value:e.value},null,8,[`label`,`value`])),64))]),_:1},8,[`modelValue`,`placeholder`]),E(l,{size:`small`,onClick:i.resetFilter},{default:z(()=>[w(U(i.$t(`@WORKBENCH:重置`)),1)]),_:1}),n[5]||=o(`span`,{class:`exec-logs__filter-spacer`},null,-1),i.selectedIds.size>0?(P(),W(`span`,Mn,U(i.$t(`@WORKBENCH:已选择 {count} 项`,{count:i.selectedIds.size})),1)):T(`v-if`,!0)]),T(` 批量操作条 `),i.selectedIds.size>0?(P(),W(`div`,Nn,[E(h,{"model-value":i.isAllOnPageSelected,indeterminate:i.isSomeOnPageSelected,onChange:i.toggleSelectAllOnPage},{default:z(()=>[w(U(i.isAllOnPageSelected?i.$t(`@WORKBENCH:取消全选`):i.$t(`@WORKBENCH:全选`)),1)]),_:1},8,[`model-value`,`indeterminate`]),E(l,{type:`danger`,size:`small`,onClick:i.batchDelete},{default:z(()=>[w(U(i.$t(`@WORKBENCH:批量删除`)),1)]),_:1})])):T(`v-if`,!0),T(` 列表 `),G((P(),W(`div`,Pn,[!i.loading&&i.list.length===0?(P(),W(`div`,Fn,[o(`div`,In,[E(v,null,{default:z(()=>[E(i.Document)]),_:1})]),o(`div`,Ln,U(i.$t(`@WORKBENCH:暂无执行日志`)),1),o(`div`,Rn,U(i.$t(`@WORKBENCH:点击「执行任务」开始一次执行,日志会出现在这里。`)),1)])):T(`v-if`,!0),(P(!0),W(X,null,e(i.list,e=>(P(),W(`article`,{key:e.id,class:_([`exec-card`,{"is-selected":i.selectedIds.has(e.id)}])},[o(`header`,zn,[E(h,{"model-value":i.selectedIds.has(e.id),onChange:t=>i.toggleSelect(e.id,t)},null,8,[`model-value`,`onChange`]),o(`span`,{class:`exec-card__status`,style:N({color:i.statusColor(e.status),borderColor:i.statusColor(e.status)})},U(i.statusLabel(e.status)),5),o(`span`,{class:`exec-card__title`,title:e.title||i.$t(`@WORKBENCH:无标题`)},U(e.title||i.$t(`@WORKBENCH:无标题`)),9,Bn),n[6]||=o(`span`,{class:`exec-card__spacer`},null,-1),o(`span`,Vn,[e.taskTitle?(P(),W(`span`,Hn,`📁 `+U(e.taskTitle),1)):T(`v-if`,!0),e.startedAt?(P(),W(`span`,Un,`⏱ `+U(i.formatDuration(e.startedAt,e.endedAt)),1)):T(`v-if`,!0),e.exitCode===null?T(`v-if`,!0):(P(),W(`span`,Wn,`exit `+U(e.exitCode),1))]),o(`button`,{type:`button`,class:`exec-card__del`,title:i.$t(`@WORKBENCH:删除`),onClick:t=>i.deleteOne(e.id)},`×`,8,Gn)]),e.error?(P(),W(`p`,Kn,`⚠ `+U(e.error),1)):T(`v-if`,!0),E(i.JobLogDetails,{job:e,onReExecute:i.onReExecuteInLog},null,8,[`job`])],2))),128))])),[[b,i.loading]]),T(` 分页 `),i.total>i.pageSize?(P(),W(`footer`,qn,[E(y,{"current-page":i.filter.page,"onUpdate:currentPage":n[4]||=e=>i.filter.page=e,"page-size":i.pageSize,total:i.total,layout:`prev, pager, next, total`,background:``,small:``,onCurrentChange:i.load},null,8,[`current-page`,`total`])])):T(`v-if`,!0)])}var Yn=Ae(yn,[[`render`,Jn],[`__scopeId`,`data-v-d3ebe953`],[`__file`,`C:/workspace/github_workspace/xz333221/zen-gitsync/src/ui/client/src/components/ExecutionLogManager.vue`]]);J();var Xn=new Set([`image/png`,`image/jpeg`,`image/jpg`,`image/gif`,`image/webp`,`image/bmp`,`image/svg+xml`,`application/pdf`,`text/plain`,`text/markdown`,`text/x-markdown`,`text/csv`,`application/json`,`text/json`,`text/x-log`]),Zn=`.png,.jpg,.jpeg,.gif,.webp,.bmp,.svg,.pdf,.txt,.md,.csv,.json,.log`,Qn=20971520,$n=3840,er=new Set([`image/png`,`image/jpeg`,`image/jpg`,`image/webp`,`image/bmp`]);function tr(e){if(e.size<=3670016)return!1;let t=String(e.type||``).toLowerCase();return t?er.has(t):/\.(png|jpe?g|webp|bmp)$/i.test(e.name)}function nr(e,t){return`${String(e||`attachment`).replace(/\.[^./\\]+$/,``)}.${t}`}async function rr(e){if(typeof createImageBitmap==`function`)try{let t=await createImageBitmap(e);return{source:t,width:t.width,height:t.height,release:()=>t.close()}}catch{}return await new Promise(t=>{let n=URL.createObjectURL(e),r=new Image;r.onload=()=>t({source:r,width:r.naturalWidth,height:r.naturalHeight,release:()=>URL.revokeObjectURL(n)}),r.onerror=()=>{URL.revokeObjectURL(n),t(null)},r.src=n})}function ir(e,t,n){return new Promise(r=>{try{e.toBlob(e=>r(e&&e.type===t?e:null),t,n)}catch{r(null)}})}async function ar(e){let t=await rr(e);if(!t)return null;try{let n=[{edge:$n,quality:.95},{edge:$n,quality:.85},{edge:2560,quality:.85},{edge:1920,quality:.8}],r=null;for(let e of n){let n=Math.min(1,e.edge/Math.max(t.width,t.height)),i=Math.max(1,Math.round(t.width*n)),a=Math.max(1,Math.round(t.height*n)),o=document.createElement(`canvas`);o.width=i,o.height=a;let s=o.getContext(`2d`);if(!s)return null;s.drawImage(t.source,0,0,i,a);let c=await ir(o,`image/webp`,e.quality)||await ir(o,`image/jpeg`,e.quality);if(!c)return null;if((!r||c.size<r.size)&&(r=c),c.size<=3670016)break}return!r||r.size>=e.size?null:{blob:r,ext:r.type===`image/webp`?`webp`:`jpg`}}catch{return null}finally{t.release()}}function or(){let e=R({}),t=R(null);function n(t){return!!e.value[t]}function r(e,t){if(e instanceof File)return e;let n=e.type||`application/octet-stream`;return new File([e],t,{type:n})}function i(e){return e.kind===`draft`?`draft`:`task-${e.task?.id??``}`}function a(e){if(e.kind===`draft`)return e.list;let t=e.task?.attachments;return Array.isArray(t)?t:[]}function o(e,t){if(e.kind===`draft`){e.replace(t);return}e.task&&(e.task.attachments=t)}function s(e){return e.kind===`draft`?`/api/workbench/orchestrator/attachments`:`/api/workbench/tasks/${e.task?.id??``}/attachments`}function c(e,t){return e.kind===`draft`?`/api/workbench/orchestrator/attachments/${t}`:`/api/workbench/tasks/${e.task?.id??``}/attachments/${t}`}function l(e,t){if(!e.clipboardData)return;let n=Array.from(e.clipboardData.items).filter(e=>e.kind===`file`&&e.type.startsWith(`image/`));if(n.length>0){e.preventDefault();for(let e of n){let n=e.getAsFile();if(!n)continue;let i=(n.type.split(`/`)[1]||`png`).replace(`jpeg`,`jpg`);d(t,r(n,`paste-${new Date().toISOString().replace(/[:.]/g,`-`)}.${i}`))}return}let i=Array.from(e.clipboardData.items).filter(e=>e.kind===`file`&&!e.type.startsWith(`image/`));if(i.length>0){e.preventDefault();for(let e of i){let n=e.getAsFile();n&&d(t,r(n,n.name||`pasted-file`))}}}function u(e,n){t.value=null,Array.from(e.dataTransfer?.files||[]).forEach(e=>d(n,e))}async function d(t,n){if(!Xn.has(n.type)&&!n.name.match(/\.(png|jpg|jpeg|gif|webp|bmp|svg|pdf|txt|md|markdown|csv|json|log)$/i)){I.error(`${Q(`@WORKBENCH:不支持的文件类型`)}(${n.name})`);return}if(a(t).find(e=>e.originalName===n.name&&e.size===n.size)){I.info(`${n.name} ${Q(`@WORKBENCH:已存在,已复用`)}`);return}let c=i(t);e.value[c]=!0;try{let e=n;if(tr(n)){let t=await ar(n);t&&(e=r(t.blob,nr(n.name,t.ext)),I.info(Q(`@WORKBENCH:图片过大,已压缩后上传:{from} → {to}`,{from:g(n.size),to:g(e.size)})))}if(e.size>20971520){I.error(`「${n.name}」${Q(`@WORKBENCH:超过 {size} 限制`,{size:g(Qn)})}`);return}let i=await fetch(s(t),{method:`POST`,headers:{"Content-Type":`application/octet-stream`,"X-Original-Name":e.name,"X-Mime-Type":e.type||`application/octet-stream`},body:e}).then(e=>e.json());if(i.success){let n=a(t);n.push(i.attachment),o(t,n),I.success(`${Q(`@WORKBENCH:已添加:`)}${e.name}`)}else I.error(i.error||Q(`@WORKBENCH:上传失败`))}catch(e){I.error(Q(`@WORKBENCH:上传失败`)+`:`+(e&&e.message||e))}finally{e.value[c]=!1}}async function f(e,t){try{await le.confirm(Q(`@WORKBENCH:删除附件「{name}」?`,{name:t.originalName}),Q(`@WORKBENCH:确认`),{type:`warning`})}catch{return}let n=await fetch(c(e,t.id),{method:`DELETE`}).then(e=>e.json());n.success?(o(e,a(e).filter(e=>e.id!==t.id)),I.success(Q(`@WORKBENCH:已删除`))):I.error(n.error||Q(`@WORKBENCH:删除失败`))}function p(e){let t=document.createElement(`input`);t.type=`file`,t.accept=Zn,t.multiple=!0,t.onchange=()=>{Array.from(t.files||[]).forEach(t=>d(e,t))},t.click()}let m=new Set([`png`,`jpg`,`jpeg`,`gif`,`webp`,`bmp`,`svg`]);function h(e){let t=String(e?.ext||``).toLowerCase();if(t&&m.has(t)||String(e?.mimeType||``).toLowerCase().startsWith(`image/`))return!0;let n=String(e?.originalName||``).toLowerCase();return/\.(png|jpe?g|gif|webp|bmp|svg)$/.test(n)}function g(e){return e<1024?`${e} B`:e<1048576?`${(e/1024).toFixed(1)} KB`:`${(e/1024/1024).toFixed(2)} MB`}return{uploadingTargets:e,pasteHoverId:t,isUploading:n,ensureFile:r,isImageAttachment:h,humanSize:g,targetKey:i,targetAttachments:a,setTargetAttachments:o,targetUploadUrl:s,targetDeleteUrl:c,onAttachmentPaste:l,onAttachmentDrop:u,uploadAttachment:d,removeAttachment:f,pickAttachmentFile:p}}t();var sr=`__simple`,cr=65536;function lr(e,t){function n(t){if(!t)return[];let n=`${t.id}${sr}`;return e.value.filter(e=>e.subId===n||e.subId.startsWith(`${n}__r`)).sort((e,t)=>{let n=e.startedAt||``,r=t.startedAt||``;return n&&r?n.localeCompare(r):n?-1:+!!r})}function r(e){if(!e)return null;let t=n(e);return t.length>0?t[t.length-1]:null}function i(e){return e?e.status===`pending`||e.status===`running`?`running`:e.status===`done`?`done`:e.status===`cancelled`?`cancelled`:`error`:`idle`}return{simpleConversationMessages:k(()=>{if(!t.value)return[];let e=n(t.value);if(e.length===0)return[];let r=[];return e.forEach((t,n)=>{let i=n===e.length-1,a=t.startedAt?new Date(t.startedAt).getTime():Date.now();if(t.prompt){let e=Lt(t.prompt);e&&r.push({id:`${t.id}-u`,role:`user`,content:e,status:`done`,createdAt:a})}let o=t.output||``,s=t.thinking||``,c=o.length>cr?`\u2026(前文已截断)\n${o.slice(-65536)}`:o,l=s.length>cr?`\u2026(前文已截断)\n${s.slice(-65536)}`:s,u=!!c,d=!!l,f=At(t),p=f.length>0,m=u||d||p,h;if(!i)h=`done`;else{let e=t.status;h=e===`running`||e===`pending`?m?`streaming`:`pending`:e===`error`?`error`:`done`}r.push({id:`${t.id}-a`,role:`assistant`,content:Kt(c,t.id),reasoning:d?l:void 0,reasoningStatus:d?!i&&u||u?`done`:h===`streaming`?`streaming`:`done`:void 0,toolCalls:p?f:void 0,status:h,error:h===`error`&&t.error||void 0,createdAt:a})}),r}),simpleAllJobsFor:n,simpleJobFor:r,simpleJobState:i,SIMPLE_SUB_ID_SUFFIX:sr,MAX_LOG_DISPLAY_SIMPLE:cr}}function ur(e){let t=e?new Date(e):new Date;if(Number.isNaN(t.getTime()))return``;let n=e=>String(e).padStart(2,`0`);return`${t.getFullYear()}-${n(t.getMonth()+1)}-${n(t.getDate())} ${n(t.getHours())}:${n(t.getMinutes())}`}function dr(e,t=120){let n=e.replace(/\s+/g,` `).trim();return n.length>t?`${n.slice(0,t-1)}…`:n}function fr(e){let t=(e.match(/`+/g)||[]).reduce((e,t)=>Math.max(e,t.length),0),n="`".repeat(Math.max(3,t+1));return`${n}\n${e}\n${n}`}function pr(e,t){return`### ${e}\n\n${t.trim()}`}function mr(e){let t=[];return e.forEach((e,n)=>{let r=e.name||Q(`@WORKBENCH:工具`),i=dr(e.argsPreview||``);t.push(`${n+1}. **${r}**${i?` — \`${i}\``:``}`);let a=(e.status===`error`?e.error:e.result)||e.result||e.error||``;a.trim()&&t.push(``,fr(a.trim()))}),t.join(`
|
|
28
|
+
`)}function hr(e,t={}){let n=Array.isArray(e)?e.filter(Boolean):[],r=[];if(n.forEach((e,t)=>{let n=[],i=Lt(e.prompt);i&&n.push(pr(Q(`@WORKBENCH:用户提示词`),i));let a=(e.thinking||``).trim();a&&n.push(pr(Q(`@WORKBENCH:Claude 思考`),a));let o=mr(At(e));o&&n.push(pr(Q(`@WORKBENCH:工具调用`),o));let s=(e.output||``).trim();s&&n.push(pr(Q(`@WORKBENCH:模型返回`),s));let c=(e.error||e.agentError||``).trim();if(c&&n.push(pr(Q(`@WORKBENCH:出错`),c)),n.length===0)return;let l=[Pe(e.agent),Tt(e.status),ur(e.startedAt)].filter(Boolean);r.push(`## ${Q(`@WORKBENCH:第 {n} 轮`,{n:t+1})}\n\n*${l.join(` · `)}*\n\n${n.join(`
|
|
29
|
+
|
|
30
|
+
`)}`)}),r.length===0)return``;let i=[`# ${(t.title||``).trim()||Q(`@WORKBENCH:未命名任务`)}`],a=(t.projectName||``).trim();return a&&i.push(``,`- ${Q(`@WORKBENCH:项目:{name}`,{name:a})}`),i.push(`- ${Q(`@WORKBENCH:导出时间:{time}`,{time:ur((t.now||new Date).toISOString())})}`),`${i.join(`
|
|
31
|
+
`)}\n\n---\n\n${r.join(`
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
`)}\n`}function gr(e,t,n,r){function i(){return{executor:r.getExecutor()}}async function a(e){if(!n.value||n.value.id!==e.id)return!0;let i=t.value.find(t=>t.id===e.id);return i&&i.title===n.value.title&&i.desc===n.value.desc&&i.promptId===n.value.promptId&&(i.simpleOverride||``)===(n.value.simpleOverride||``)?!0:await r.persistTask(!1)}async function o(e){if(!await a(e))return;await r.clearJobsByTask(e.id);let t=await fetch(`/api/workbench/tasks/${encodeURIComponent(e.id)}/run`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(i())}).then(e=>e.json()).catch(e=>({success:!1,error:e?.message||String(e)}));t.success?I.success(t.message||Q(`@WORKBENCH:已加入执行队列`)):I.error(t.error||Q(`@WORKBENCH:执行失败`))}async function s(t,n){let r=e.value.filter(e=>e.taskId===t.id).slice(-1)[0];if(!r){I.error(Q(`@WORKBENCH:没有可续接的会话`));return}let i=Array.isArray(t.attachments)?t.attachments:[],a=await fetch(`/api/workbench/jobs/${r.id}/continue`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({userMessage:n,attachments:i})}).then(e=>e.json()).catch(e=>({success:!1,error:e?.message||String(e)}));a.success?I.success(a.message||Q(`@WORKBENCH:已加入续接队列`)):I.error(a.error||Q(`@WORKBENCH:续接失败`))}async function c(e,t){let n=t.text.trim();if(n){for(let n of t.files)await r.uploadAttachment({kind:`task`,task:e},n.file);await s(e,n)}}async function l(e){let n=t.value.find(t=>t.id===e.taskId)||t.value.find(t=>t.id===String(e.subId||``).replace(/__simple(?:__r\d+)?$/,``));if(!n){I.error(Q(`@WORKBENCH:找不到对应任务,无法重新执行`));return}await o(n)}async function u(e){try{await le.confirm(Q(`@WORKBENCH:确认停止执行?已输出的内容会保留。`),Q(`@WORKBENCH:停止执行`),{confirmButtonText:Q(`@WORKBENCH:停止`),cancelButtonText:Q(`@WORKBENCH:取消`),type:`warning`})}catch{return}let t=await fetch(`/api/workbench/jobs/${e.id}/cancel`,{method:`POST`}).then(e=>e.json()).catch(e=>({success:!1,error:e?.message||String(e)}));t.success?I.success(Q(`@WORKBENCH:已发送停止信号`)):I.error(t.error||Q(`@WORKBENCH:停止失败`))}async function d(){if(!n.value)return;let t=n.value,i=e.value.filter(e=>e.taskId===t.id),a=i.filter(e=>e.status===`running`||e.status===`pending`).length,o=i.length===0?Q(`@WORKBENCH:当前任务还没有执行内容,确认仍要清空?`):Q(`@WORKBENCH:将清空 {m} 条执行记录,任务描述/附件保留。`,{m:i.length});try{await le.confirm(o,Q(`@WORKBENCH:清空执行内容`),{confirmButtonText:Q(`@WORKBENCH:清空`),cancelButtonText:Q(`@WORKBENCH:取消`),type:`warning`})}catch{return}if(a>0){I.warning(Q(`@WORKBENCH:任务正在执行,请先停止`));return}let s=await fetch(`/api/workbench/tasks/${encodeURIComponent(t.id)}/clear-execution`,{method:`POST`,headers:{"Content-Type":`application/json`}}).then(e=>e.json()).catch(e=>({success:!1,error:e?.message||String(e)}));s?.success?(e.value=e.value.filter(e=>e.taskId!==t.id),r.syncRunningCount(),I.success(s.message||Q(`@WORKBENCH:已清空执行内容`))):I.error(s?.error||Q(`@WORKBENCH:清空失败`))}return{runTask:o,continueChat:s,onContinueSendFromChat:c,onReExecuteJob:l,cancelJob:u,clearExecutionForSelectedTask:d}}t();function _r(){let e=Fe(),t=Ie(),n=k({get:()=>e.resolvedTaskExecutor,set:t=>{Me(t)&&e.setLastTaskExecutor(t)}}),r=k(()=>({claude:t.claudeAvailable,opencode:t.opencodeAvailable,codex:t.codexAvailable})),i=k(()=>Ne.some(e=>r.value[e.id])),a=k(()=>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)}function s(e){return t.executorModelText(e)}function c(e){return[s(e),t.executorModelDetail(e)].filter(Boolean).join(` · `)}return{selected:n,active:a,availability:r,hasAnyExecutor:i,choose:o,executorModelText:s,executorModelTitle:c}}J();function vr(){let e=R([]),t=R([]),n=R([]),r=R({path:``,name:``}),i=Ge();function a(){i.setRunning(n.value.filter(e=>e.status===`running`).length)}function o(e,r){if(e===`hello`){n.value=r.jobs||[],a();return}if(e===`job:update`){let e=r,t=n.value.findIndex(t=>t.id===e.id);t>=0?n.value[t]=e:n.value.push(e),a();return}if(e===`job:thinking-delta`||e===`job:output-delta`){let t=e===`job:thinking-delta`?`thinking`:`output`,i=r?.delta||``;if(!i)return;let a=n.value.findIndex(e=>e.id===r.id);if(a<0)return;let o=n.value[a][t]||``;n.value[a][t]=o+i;return}if(e===`job:toolcalls`){let e=Array.isArray(r?.updates)?r.updates:[];if(!e.length)return;let t=n.value.findIndex(e=>e.id===r.id);if(t<0)return;let i=n.value[t];for(let t of e){if(!t||!t.id)continue;Array.isArray(i.toolCalls)||(i.toolCalls=[]);let e=i.toolCalls.findIndex(e=>e.id===t.id);e>=0?i.toolCalls[e]={...i.toolCalls[e],...t}:i.toolCalls.push(t)}return}if(e===`task:update`){let e=t.value.findIndex(e=>e.id===r.id);e>=0&&(t.value[e]=r)}if(e===`tasks:reordered`){if(Array.isArray(r?.tasks)){if(r.tasks.length<t.value.length){console.warn(`[SSE tasks:reordered] 数据丢失风险:当前 ${t.value.length} 个任务,服务端只返回 ${r.tasks.length} 个,拒绝覆盖`);return}t.value=r.tasks}return}e===`task:error`&&I.error(r.error||Q(`@WORKBENCH:执行出错`))}let s=null;function c(){s&&=(s.close(),null),s=new EventSource(`/api/workbench/events`),s.onmessage=e=>{try{let t=JSON.parse(e.data);o(t.event,t.payload)}catch{}},s.onerror=()=>{s&&=(s.close(),null),setTimeout(c,3e3)}}function l(){s&&=(s.close(),null)}async function u(){let t=await fetch(`/api/workbench/prompts`).then(e=>e.json()).catch(()=>({prompts:[]}));e.value=t.prompts||[]}async function d(e){let n=await fetch(`/api/workbench/tasks`).then(e=>e.json()).catch(()=>({tasks:[]}));t.value=n.tasks||[],e?.()}async function f(){let e=await fetch(`/api/workbench/current-project`).then(e=>e.json()).catch(()=>({}));e&&typeof e.projectPath==`string`&&(r.value={path:e.projectPath,name:e.projectName||``})}async function p(){let e=await fetch(`/api/workbench/jobs`).then(e=>e.json()).catch(()=>({jobs:[]}));n.value=e.jobs||[],a()}async function m(e){try{let t=await fetch(`/api/workbench/jobs/by-task/${encodeURIComponent(e)}`,{method:`DELETE`}).then(e=>e.json());return t?.success?(n.value=n.value.filter(t=>t.taskId!==e),a(),t.removed||0):(console.warn(`[clearJobsByTask] failed:`,t?.error),0)}catch(e){return console.warn(`[clearJobsByTask] error:`,e),0}}async function h(e){let t={title:``,desc:``,promptId:null,simpleOverride:``};e&&(t.projectPath=e);try{let e=await fetch(`/api/workbench/tasks`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(t)}).then(e=>e.json());return e.success?e.task||null:(I.error(e.error||Q(`@WORKBENCH:保存失败`)),null)}catch{return I.error(Q(`@WORKBENCH:保存失败`)),null}}return{prompts:e,tasks:t,jobs:n,currentProject:r,syncRunningCount:a,applyJobEvent:o,connectSSE:c,disconnectSSE:l,loadPrompts:u,loadTasks:d,loadCurrentProject:f,loadJobs:p,clearJobsByTask:m,createTask:h}}J(),t();var yr=`__no_project__`,br=`wb.collapsedGroupPaths.v1`,xr=`wb.seenGroupPaths.v1`;function Sr(e){try{let t=localStorage.getItem(e);if(!t)return new Set;let n=JSON.parse(t);return new Set(Array.isArray(n)?n.filter(e=>typeof e==`string`):[])}catch{return new Set}}function Cr(e,t){try{localStorage.setItem(e,JSON.stringify(Array.from(t)))}catch{}}function wr(e,t){let n=R(Sr(br)),r=R(Sr(xr));q(n,e=>Cr(br,e),{deep:!1}),q(r,e=>Cr(xr,e),{deep:!1});function i(e){return n.value.has(e)}function a(e){n.value.has(e)?n.value.delete(e):n.value.add(e),n.value=new Set(n.value);let t=new Set(r.value);t.add(e),r.value=t}let o=k(()=>{let r=e.value,i=new Map;for(let e of r){let t=$(e.projectPath)||yr;i.has(t)||i.set(t,[]),i.get(t).push(e)}let a=$(t.value.path),o=Array.from(i.keys()).sort((e,t)=>e===a?-1:t===a||e===yr?1:t===yr?-1:e.localeCompare(t));return{groups:o.map(e=>({path:e,label:e===yr?Q(`@WORKBENCH:未关联项目`):e,tasks:i.get(e)})),hasMultiple:o.length>1||o.length===1&&n.value.has(o[0])}});function s(e){if(!e||e===yr)return e;let t=e.split(/[\\/]/).filter(Boolean);return t.length<=1?e:t.slice(-2).join(`/`)}let c=k(()=>`${$(t.value.path)}|${o.value.groups.map(e=>e.path).join(`
|
|
36
|
+
`)}`);return q(c,()=>{let e=$(t.value.path);if(!e)return;let i=new Set(n.value),a=new Set(r.value),s=!1;for(let t of o.value.groups)a.has(t.path)||(a.add(t.path),t.path!==e&&(i.add(t.path),s=!0));s&&(n.value=i),r.value=a},{immediate:!0}),{groupedTasksList:o,isGroupCollapsed:i,toggleGroupCollapsed:a,shortProjectLabel:s}}t(),J();var Tr=5,Er=h({__name:`WorkbenchSidebar`,props:{tasks:{type:Array,required:!0},prompts:{type:Array,required:!0},selectedTaskId:{type:[String,null],required:!0},currentProject:{type:Object,required:!0},creatingTask:{type:Boolean,required:!0},isTaskRunning:{type:Function,required:!0}},emits:[`select-task`,`delete-task`,`copy-task`,`create-task`,`open-create-prompt`,`open-edit-prompt`,`delete-prompt`,`reorder-tasks`],setup(e,{expose:t,emit:n}){t();let r=e,i=n,a=k(()=>r.currentProject),o=k(()=>r.tasks),{groupedTasksList:s,isGroupCollapsed:c,toggleGroupCollapsed:l,shortProjectLabel:u}=wr(o,a),d=k(()=>$(r.currentProject.path));function f(e){return!!e.projectPath&&$(e.projectPath)!==d.value}let p=k(()=>{let e=d.value;return r.prompts.filter(t=>!t.projectPath||$(t.projectPath)===e)});function m(e){return(e.title||``).trim()||(e.desc||``).replace(/\s+/g,` `).trim()}function h(e){let t=m(e),n=Q(`@WORKBENCH:拖动排序提示`);return t?`${t} · ${n}`:n}function g(e){return r.isTaskRunning(e)}let _=R(null),v=R(null),y=R(null),b=R(null),x=R(null),C=null;function w(){_.value=null,v.value=null,y.value=null,b.value=null,x.value=null,C=null}function T(e,t,n,r){e.button===0&&(C={pointerY:e.clientY,li:r,taskId:t.id,groupPath:n},window.addEventListener(`mousemove`,E),window.addEventListener(`mouseup`,D,{once:!0}))}function E(e){if(!C)return;if(_.value===null){if(Math.abs(e.clientY-C.pointerY)<Tr)return;_.value=C.taskId,v.value=C.groupPath,window.getSelection()?.removeAllRanges(),document.body.style.userSelect=`none`}let t=document.elementFromPoint(e.clientX,e.clientY);if(!t)return;let n=t.closest(`.wb-task-item`);if(!n){y.value=null,b.value=null,x.value=null;return}let r=n.getAttribute(`data-task-id`),i=n.getAttribute(`data-group-path`);if(!r||!i)return;if(i!==v.value){y.value=null,b.value=null,x.value=null;return}let a=n.getBoundingClientRect(),o=a.top+a.height/2;y.value=r,b.value=i,x.value=e.clientY<o?`before`:`after`}function D(e){if(window.removeEventListener(`mousemove`,E),document.body.style.userSelect=``,!C){w();return}let t=C.groupPath,n=C.taskId,r=y.value,a=x.value,o=b.value;if(w(),!r||!a||o!==t)return;let c=s.value.groups.find(e=>e.path===t);if(!c)return;let l=c.tasks.map(e=>e.id),u=l.indexOf(n);if(u<0)return;l.splice(u,1);let d=l.indexOf(r)+ +(a===`after`);l.splice(d,0,n),i(`reorder-tasks`,{groupPath:t,orderedIds:l})}let O={props:r,emit:i,currentProjectRef:a,tasksRef:o,groupedTasksList:s,isGroupCollapsed:c,toggleGroupCollapsed:l,shortProjectLabel:u,currentProjectKey:d,isOtherProject:f,availablePrompts:p,taskDisplayName:m,taskTooltip:h,taskIsRunning:g,draggingTaskId:_,dragStartGroupPath:v,dragOverTaskId:y,dragOverGroupPath:b,dragPosition:x,get dragStart(){return C},set dragStart(e){C=e},DRAG_THRESHOLD_PX:Tr,resetDragState:w,onTaskMouseDown:T,onWindowMouseMove:E,onWindowMouseUp:D,get $t(){return Q},get Plus(){return we},get Close(){return pe},get DocumentAdd(){return H},get Memo(){return S},get Folder(){return ee},get ArrowDown(){return ne},get ArrowRight(){return ie},get CopyDocument(){return B}};return Object.defineProperty(O,"__isScriptSetup",{enumerable:!1,value:!0}),O}});t(),l(),V();var Dr={class:`wb-sidebar`},Or={class:`wb-section`},kr=[`disabled`],Ar=[`aria-expanded`,`title`,`onClick`,`onKeydown`],jr=[`title`],Mr={class:`wb-pill wb-task-group__count`},Nr=[`data-task-id`,`data-group-path`,`title`,`aria-pressed`,`onClick`,`onKeydown`,`onMousedown`],Pr={class:`wb-task-item__body`},Fr=[`title`],Ir=[`title`],Lr={class:`wb-task-item__action-group`},Rr=[`title`,`aria-label`,`onClick`],zr=[`onClick`,`title`,`aria-label`],Br={key:0,class:`wb-empty wb-empty--rich`},Vr={class:`wb-empty__art`,"aria-hidden":`true`},Hr={class:`wb-empty__title`},Ur={class:`wb-empty__hint`},Wr={class:`wb-empty__cta`},Gr={class:`wb-section`},Kr={class:`wb-section__head`},qr={class:`wb-section__tag wb-section__tag--accent`},Jr={class:`wb-section__title`},Yr={class:`wb-pill wb-section__count`},Xr=[`title`,`aria-label`],Zr={class:`wb-prompt-list`},Qr={class:`wb-prompt-item__icon`},$r=[`onClick`,`title`],ei=[`title`],ti=[`title`],ni=[`onClick`,`title`,`aria-label`],ri={key:0,class:`wb-empty wb-empty--compact`};function ii(t,n,r,i,s,c){let l=g,u=Ce;return P(),W(`aside`,Dr,[o(`section`,Or,[T(` 任务分组 header 已去掉:"任务"/"任务列表"/计数 三件套冗余,下方任务项本身已能自我说明。
|
|
37
|
+
提示词分组保留 header(含 + 新建按钮 + 计数),信息密度不一对齐,后续按需统一。 `),o(`button`,{class:`wb-new-btn`,disabled:r.creatingTask,onClick:n[0]||=e=>i.emit(`create-task`)},[E(l,{class:`wb-new-btn__icon`},{default:z(()=>[E(i.Plus)]),_:1}),o(`span`,null,U(i.$t(`@WORKBENCH:新建任务`)),1),n[5]||=o(`span`,{class:`wb-new-btn__shortcut`},`N`,-1)],8,kr),o(`ul`,{class:_([`wb-task-list`,{"is-grouped":i.groupedTasksList.hasMultiple}])},[(P(!0),W(X,null,e(i.groupedTasksList.groups,t=>(P(),W(X,{key:t.path},[i.groupedTasksList.hasMultiple?(P(),W(`li`,{key:0,class:_([`wb-task-group__head`,{"is-current":t.path===i.currentProjectKey,"is-collapsed":i.isGroupCollapsed(t.path)}]),role:`button`,tabindex:`0`,"aria-expanded":!i.isGroupCollapsed(t.path),title:i.isGroupCollapsed(t.path)?i.$t(`@WORKBENCH:展开`):i.$t(`@WORKBENCH:收起`),onClick:e=>i.toggleGroupCollapsed(t.path),onKeydown:[Z(L(e=>i.toggleGroupCollapsed(t.path),[`prevent`]),[`enter`]),Z(L(e=>i.toggleGroupCollapsed(t.path),[`prevent`]),[`space`])]},[E(l,{class:`wb-task-group__caret`},{default:z(()=>[(P(),a(K(i.isGroupCollapsed(t.path)?i.ArrowRight:i.ArrowDown)))]),_:2},1024),E(l,{class:`wb-task-group__icon`},{default:z(()=>[E(i.Folder)]),_:1}),o(`span`,{class:`wb-task-group__name`,title:t.path===i.currentProjectKey?r.currentProject.path:t.label},U(t.path===i.currentProjectKey?r.currentProject.name:i.shortProjectLabel(t.label)),9,jr),o(`span`,Mr,U(t.tasks.length),1)],42,Ar)):T(`v-if`,!0),i.isGroupCollapsed(t.path)?T(`v-if`,!0):(P(!0),W(X,{key:1},e(t.tasks,e=>(P(),W(`li`,{key:e.id,class:_([`wb-task-item`,{active:e.id===r.selectedTaskId,"is-other-project":i.isOtherProject(e),"is-running":i.taskIsRunning(e),"is-dragging":i.draggingTaskId===e.id,"is-drop-before":i.dragOverTaskId===e.id&&i.dragPosition===`before`,"is-drop-after":i.dragOverTaskId===e.id&&i.dragPosition===`after`}]),"data-task-id":e.id,"data-group-path":t.path,title:i.taskTooltip(e),role:`button`,tabindex:`0`,"aria-pressed":e.id===r.selectedTaskId,onClick:t=>i.emit(`select-task`,e),onKeydown:[Z(L(t=>i.emit(`select-task`,e),[`prevent`]),[`enter`]),Z(L(t=>i.emit(`select-task`,e),[`prevent`]),[`space`])],onMousedown:n=>i.onTaskMouseDown(n,e,t.path,n.currentTarget)},[T(` 单行展示:只显示标题;没写标题用任务描述压平后顶上(CSS ellipsis 截断)。
|
|
38
|
+
子任务数 / 附件数 等 meta 行已移除,降噪 `),o(`div`,Pr,[o(`div`,{class:`wb-task-item__title`,title:i.taskDisplayName(e)},U(i.taskDisplayName(e)),9,Fr)]),i.taskIsRunning(e)?(P(),W(`span`,{key:0,class:`wb-task-item__running-dot`,title:i.$t(`@WORKBENCH:执行中`),"aria-hidden":`true`},null,8,Ir)):T(`v-if`,!0),o(`div`,Lr,[o(`button`,{class:`wb-task-item__copy`,title:i.$t(`@WORKBENCH:复制任务`),"aria-label":i.$t(`@WORKBENCH:复制任务`),onClick:L(t=>i.emit(`copy-task`,e),[`stop`]),onKeydown:n[1]||=L(()=>{},[`stop`])},[E(l,null,{default:z(()=>[E(i.CopyDocument)]),_:1})],40,Rr),T(` 执行中不允许删除:避免误杀正在跑的实例(jobs 还在内存里,
|
|
39
|
+
任务从 tasks.json 消失后,runSingleSubtask 读不到 task
|
|
40
|
+
会留一堆孤儿 job)。后端 DELETE 路由也加了同样的 live-job 守卫兜底 `),i.taskIsRunning(e)?T(`v-if`,!0):(P(),W(`button`,{key:0,class:`wb-task-item__del`,onClick:L(t=>i.emit(`delete-task`,e),[`stop`]),onKeydown:n[2]||=L(()=>{},[`stop`]),title:i.$t(`@WORKBENCH:删除`),"aria-label":i.$t(`@WORKBENCH:删除`)},[E(l,null,{default:z(()=>[E(i.Close)]),_:1})],40,zr))])],42,Nr))),128))],64))),128)),r.tasks.length===0?(P(),W(`li`,Br,[o(`div`,Vr,[E(l,null,{default:z(()=>[E(i.DocumentAdd)]),_:1})]),o(`div`,Hr,U(i.$t(`@WORKBENCH:暂无任务`)),1),o(`div`,Ur,U(i.$t(`@WORKBENCH:点击上方按钮新建`)),1),o(`div`,Wr,[E(u,{type:`primary`,size:`small`,icon:i.Plus,loading:r.creatingTask,onClick:n[3]||=e=>i.emit(`create-task`)},{default:z(()=>[w(U(i.$t(`@WORKBENCH:新建任务`)),1)]),_:1},8,[`icon`,`loading`])])])):T(`v-if`,!0)],2)]),o(`section`,Gr,[o(`header`,Kr,[o(`span`,qr,U(i.$t(`@WORKBENCH:提示`)),1),o(`h3`,Jr,U(i.$t(`@WORKBENCH:预置提示词`)),1),o(`span`,Yr,U(i.availablePrompts.length),1),o(`button`,{class:`wb-section__action`,onClick:n[4]||=e=>i.emit(`open-create-prompt`),title:i.$t(`@WORKBENCH:新建提示词`),"aria-label":i.$t(`@WORKBENCH:新建提示词`)},[E(l,null,{default:z(()=>[E(i.Plus)]),_:1})],8,Xr)]),o(`ul`,Zr,[(P(!0),W(X,null,e(i.availablePrompts,e=>(P(),W(`li`,{key:e.id,class:`wb-prompt-item`},[o(`div`,Qr,[E(l,null,{default:z(()=>[E(i.Memo)]),_:1})]),o(`button`,{type:`button`,class:`wb-prompt-item__name`,onClick:t=>i.emit(`open-edit-prompt`,e),title:e.content},U(e.name),9,$r),e.projectPath?(P(),W(`span`,{key:1,class:`wb-prompt-item__tag wb-prompt-item__tag--project`,title:e.projectPath},U(i.shortProjectLabel(e.projectPath)),9,ti)):(P(),W(`span`,{key:0,class:`wb-prompt-item__tag`,title:i.$t(`@WORKBENCH:全局(所有项目可用)`)},U(i.$t(`@WORKBENCH:全局(所有项目可用)`)),9,ei)),o(`button`,{class:`wb-prompt-item__del`,onClick:t=>i.emit(`delete-prompt`,e),title:i.$t(`@WORKBENCH:删除`),"aria-label":i.$t(`@WORKBENCH:删除`)},[E(l,null,{default:z(()=>[E(i.Close)]),_:1})],8,ni)]))),128)),i.availablePrompts.length===0?(P(),W(`li`,ri,U(i.$t(`@WORKBENCH:暂无提示词`)),1)):T(`v-if`,!0)])])])}var ai=Ae(Er,[[`render`,ii],[`__scopeId`,`data-v-458e9455`],[`__file`,`C:/workspace/github_workspace/xz333221/zen-gitsync/src/ui/client/src/views/components/WorkbenchSidebar.vue`]]);J();function oi(){let e=R([]),t=R([]),n=R(``),r=R(!1),i=R(!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||I.error(r?.error||Q(`@WORKBENCH:读取项目列表失败`)),!1)}catch(e){return a||I.error(Q(`@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}:(I.error(t?.error||Q(`@WORKBENCH:移除项目失败`)),{ok:!1,keptTasks:0})}catch(e){return I.error(Q(`@WORKBENCH:网络错误: `)+(e?.message||e)),{ok:!1,keptTasks:0}}}return{projects:e,boardTasks:t,currentProjectPath:n,loading:r,loaded:i,loadProjects:a,removeProject:o}}var si=[0,5,10,15,30,60].map(e=>e*60*1e3),ci=6e5;function li(e){let t=Number(e);return si.includes(t)?t:ci}function ui(e){return e?e>=36e5?`@WORKBENCH:每 {n} 小时报告`:`@WORKBENCH:每 {n} 分钟报告`:`@WORKBENCH:关闭自动报告`}function di(e){return e?{n:Math.round(e>=36e5?e/36e5:e/6e4)}:{}}function fi(e){switch(e){case`NO_MODEL`:return`@WORKBENCH:没有可用的 AI 模型,只记录了任务事实`;case`LLM_TIMEOUT`:return`@WORKBENCH:生成超时,只记录了任务事实`;case`LLM_EMPTY`:return`@WORKBENCH:模型没有返回正文,只记录了任务事实`;case`LLM_FAILED`:return`@WORKBENCH:生成失败,只记录了任务事实`;default:return`@WORKBENCH:生成失败,只记录了任务事实`}}function pi(e){if(e==null||e===``)return null;let t=Number(e);if(!Number.isFinite(t))return null;let n=Math.round(t);return n>=0&&n<=100?n:null}var mi=`@WORKBENCH:AI 估计`,hi=`@WORKBENCH:百分比是主 Agent 根据任务思考与工具调用推测的大致估计,不是精确进度`;J();var gi=1e5;function _i(){let e=R(!0),t=R([]),n=R([]),r=R(gi),i=R([]),a=R(null),o=R(!1),s=R(!1),c=R(!1),l=R(``),u=R({}),d=R([]),f=R(!1),p=R(!1),m=R(ci);async function h(s=!1){try{let c=await fetch(`/api/workbench/orchestrator`,{cache:`no-store`}).then(e=>e.json());return c?.success?(e.value=c.active!==!1,Number.isInteger(c.maxInstructionChars)&&c.maxInstructionChars>0&&(r.value=c.maxInstructionChars),t.value=Array.isArray(c.instructions)?c.instructions:[],n.value=Array.isArray(c.activity)?c.activity:[],i.value=Array.isArray(c.running)?c.running:[],a.value=c.updatedAt||null,l.value=typeof c.defaultPrompt==`string`?c.defaultPrompt:``,u.value=c.projectPrompts&&typeof c.projectPrompts==`object`?c.projectPrompts:{},m.value=li(c.reportIntervalMs),o.value=!0,!0):(s||I.error(c?.error||Q(`@WORKBENCH:读取编排状态失败`)),!1)}catch(e){return s||I.error(Q(`@WORKBENCH:网络错误: `)+(e?.message||e)),!1}}async function g(e=!1){if(f.value)return!1;f.value=!0;try{let t=await fetch(`/api/workbench/orchestrator/reports`,{cache:`no-store`}).then(e=>e.json());return t?.success?(d.value=Array.isArray(t.reports)?t.reports:[],!0):(e||I.error(t?.error||Q(`@WORKBENCH:读取进度报告失败`)),!1)}catch(t){return e||I.error(Q(`@WORKBENCH:网络错误: `)+(t?.message||t)),!1}finally{f.value=!1}}async function _(){if(p.value)return null;p.value=!0;try{let e=String(Fe().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?(d.value=[t.report,...d.value].slice(0,20),t.report):(I.info(Q(`@WORKBENCH:当前没有正在执行的任务,没有可汇报的进度`)),null):(I.error(t?.error||Q(`@WORKBENCH:生成进度报告失败`)),null)}catch(e){return I.error(Q(`@WORKBENCH:网络错误: `)+(e?.message||e)),null}finally{p.value=!1}}async function v(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?(m.value=li(t.reportIntervalMs),!0):(I.error(t?.error||Q(`@WORKBENCH:保存失败`)),!1)}catch(e){return I.error(Q(`@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?(l.value=typeof t.defaultPrompt==`string`?t.defaultPrompt:``,I.success(Q(`@WORKBENCH:已保存全局默认提示词`)),!0):(I.error(t?.error||Q(`@WORKBENCH:保存失败`)),!1)}catch(e){return I.error(Q(`@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?(u.value=n.projectPrompts&&typeof n.projectPrompts==`object`?n.projectPrompts:{},I.success(Q(`@WORKBENCH:已保存项目默认提示词`)),!0):(I.error(n?.error||Q(`@WORKBENCH:保存失败`)),!1)}catch(e){return I.error(Q(`@WORKBENCH:网络错误: `)+(e?.message||e)),!1}}async function x(t){if(s.value)return!1;let n=e.value;e.value=t,s.value=!0;try{let r=await fetch(`/api/workbench/orchestrator/state`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({active:t})}).then(e=>e.json());return r?.success?(e.value=r.active!==!1,I.success(e.value?Q(`@WORKBENCH:已恢复调度`):Q(`@WORKBENCH:已暂停调度,派发将只建任务不执行`)),!0):(e.value=n,I.error(r?.error||Q(`@WORKBENCH:切换调度状态失败`)),!1)}catch(t){return e.value=n,I.error(Q(`@WORKBENCH:网络错误: `)+(t?.message||t)),!1}finally{s.value=!1}}async function S(e){if(c.value)return null;c.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,attachments:(e.attachments||[]).map(e=>({id:e.id,ext:e.ext,originalName:e.originalName}))})}).then(e=>e.json());return t?.success?(await h(!0),{task:t.task||null,ran:!!t.ran}):(I.error(t?.error||Q(`@WORKBENCH:派发失败`)),null)}catch(e){return I.error(Q(`@WORKBENCH:网络错误: `)+(e?.message||e)),null}finally{c.value=!1}}return{active:e,instructions:t,activity:n,running:i,updatedAt:a,loaded:o,togglingSchedule:s,dispatching:c,maxInstructionChars:r,defaultPrompt:l,projectPrompts:u,reports:d,loadingReports:f,generatingReport:p,reportIntervalMs:m,loadOrchestrator:h,setSchedulingActive:x,dispatch:S,saveDefaultPrompt:y,saveProjectPrompt:b,loadReports:g,generateReport:_,setReportInterval:v}}var vi=6e4,yi=60*vi,bi=24*yi;function xi(e,t=Date.now()){if(!e)return``;let n=new Date(e).getTime();if(Number.isNaN(n))return``;let r=Math.max(0,t-n);return r<vi?Q(`@WORKBENCH:刚刚`):r<yi?Q(`@WORKBENCH:N 分钟前`,{n:Math.floor(r/vi)}):r<bi?Q(`@WORKBENCH:N 小时前`,{n:Math.floor(r/yi)}):r<30*bi?Q(`@WORKBENCH:N 天前`,{n:Math.floor(r/bi)}):new Date(n).toLocaleDateString()}function Si(e){if(typeof e!=`number`||!Number.isFinite(e)||e<0)return``;let t=Math.floor(e/1e3),n=Math.floor(t/3600),r=Math.floor(t%3600/60),i=t%60;return n>0?Q(`@WORKBENCH:N 小时 M 分`,{n,m:r}):r>0?Q(`@WORKBENCH:N 分 M 秒`,{n:r,m:i}):Q(`@WORKBENCH:N 秒`,{n:i})}function Ci(e,t){return e.getFullYear()===t.getFullYear()&&e.getMonth()===t.getMonth()&&e.getDate()===t.getDate()}function wi(e,t=Date.now()){if(!e)return``;let n=new Date(e);if(Number.isNaN(n.getTime()))return``;let r=e=>String(e).padStart(2,`0`),i=`${r(n.getHours())}:${r(n.getMinutes())}:${r(n.getSeconds())}`,a=new Date(t);if(Ci(n,a))return i;if(Ci(n,new Date(a.getFullYear(),a.getMonth(),a.getDate()-1)))return Q(`@WORKBENCH:昨天 {time}`,{time:i});let o=`${n.getMonth()+1}/${n.getDate()}`;return n.getFullYear()===a.getFullYear()?`${o} ${i}`:`${n.getFullYear()}/${o} ${i}`}t(),J();var Ti=h({__name:`WorkbenchProjectPanel`,props:{projects:{type:Array,required:!0},selectedKey:{type:String,required:!0},loading:{type:Boolean,required:!0}},emits:[`select`,`remove`],setup(e,{expose:t,emit:n}){t();let r=e,a=n,o=k(()=>[...r.projects].sort((e,t)=>{if(e.stats.runningJobs>0!=t.stats.runningJobs>0)return e.stats.runningJobs>0?-1:1;let n=e.stats.lastActiveAt||``,r=t.stats.lastActiveAt||``;return n===r?e.name.localeCompare(t.name):r.localeCompare(n)})),c=R(``),l=R(!1),d=R(!1),p=k(()=>!!c.value.trim()||l.value||d.value),m=k(()=>{let e=c.value.trim().toLowerCase();return o.value.filter(t=>l.value&&t.stats.total===0||d.value&&t.git&&t.git.isGitRepo===!1?!1:!e||t.name.toLowerCase().includes(e)||t.path.toLowerCase().includes(e))});function h(){c.value=``,l.value=!1,d.value=!1}let g=k(()=>r.projects.reduce((e,t)=>({running:e.running+t.stats.runningJobs,done:e.done+t.stats.done,total:e.total+t.stats.total}),{running:0,done:0,total:0})),_=k(()=>g.value.total>0?Math.round(g.value.done/g.value.total*100):0);function v(e){return e.git?e.git.isGitRepo===null?Q(`@WORKBENCH:未知`):e.git.isGitRepo?e.git.detached?Q(`@WORKBENCH:游离 HEAD`):e.git.branch||Q(`@WORKBENCH:未知`):``:``}function y(e){return!!(e.git&&e.git.isGitRepo&&(e.git.detached||e.git.branch))}let x=R(null),S=R(null);function C(e,t){if(x.value===e.key){x.value=null;return}S.value=t.currentTarget,x.value=e.key}function w(){x.value=null}function T(e){if(!x.value)return;let t=e.target;if(t&&!S.value?.contains(t)){for(let e of Array.from(document.querySelectorAll(`.proj-open-menu`)))if(e.contains(t))return;x.value=null}}re(()=>document.addEventListener(`mousedown`,T,!0)),he(()=>document.removeEventListener(`mousedown`,T,!0));let E=Ie(),D=R(!1),O=R(null);function A(e){return E.lastCheckedAt!==null&&!E.isToolAvailable(e)}async function M(e){w();let t=await We(e.path);t.success?I.success(t.message||Q(`@WORKBENCH:已在文件管理器中打开文件夹`)):I.error(t.error||Q(`@WORKBENCH:打开文件夹失败`))}async function te(e){w();let t=await Ue(e.path);t.success?I.success(t.message||Q(`@67CE7:已在终端中打开目录`)):I.error(t.error||Q(`@WORKBENCH:打开终端失败`))}async function N(e){w();let t=await Ke(e.path);t.success?I.success(Q(`@WORKBENCH:已在新标签页启动 g ui`)):I.error(t.error||Q(`@WORKBENCH:启动 g ui 失败`))}async function ne(e){if(w(),e.name)try{await navigator.clipboard.writeText(e.name),I.success(Q(`@67CE7:已复制文件夹名称`))}catch{I.error(Q(`@67CE7:复制失败`))}}async function ie(e){let t=e.name||e.path,n=e.stats.total>0?Q(`@WORKBENCH:移除项目「{name}」?会从常用目录和项目列表中去掉它。该项目的 {n} 条任务不会被删除,仍可在「全部项目」下查看。`,{name:t,n:e.stats.total}):Q(`@WORKBENCH:移除项目「{name}」?会从常用目录和项目列表中去掉它。`,{name:t});try{await le.confirm(n,Q(`@WORKBENCH:移除项目`),{confirmButtonText:Q(`@WORKBENCH:移除`),cancelButtonText:Q(`@WORKBENCH:取消`),type:`warning`})}catch{return}a(`remove`,e)}async function P(e,t,n){if(w(),!await Ve()){I.warning(Q(`@67CE7:工具检测失败,请稍后重试`));return}if(!E.isToolAvailable(t)){O.value=t,D.value=!0;return}let r=await He(t,e.path,n);r.success?I.success(r.message||Q(`@67CE7:已用 {tool} 打开目录`,{tool:Be[t]})):I.error(`${Q(`@67CE7:打开失败: `)}${r.error??``}`)}let F={props:r,emit:a,ordered:o,query:c,onlyWithTasks:l,hideNonGit:d,filtering:p,visible:m,clearFilters:h,totals:g,overallProgress:_,gitLine:v,hasBranchIcon:y,openMenuKey:x,menuTriggerEl:S,toggleOpenMenu:C,closeOpenMenu:w,onDocumentMouseDown:T,toolsStore:E,installVisible:D,installTool:O,toolMissing:A,openInFileManager:M,openInTerminal:te,launchGui:N,copyFolderName:ne,confirmRemove:ie,openWithTool:P,get $t(){return Q},get CopyDocument(){return B},get Delete(){return ue},get Folder(){return ee},get FolderOpened(){return i},get Grid(){return s},get Monitor(){return u},get MoreFilled(){return b},get Promotion(){return j},get Search(){return f},SvgIcon:je,ToolInstallDialog:Ye,get claudeCodeIcon(){return ze},get OPEN_WITH_TOOLS(){return Je},get relativeTimeFromIso(){return xi}};return Object.defineProperty(F,"__isScriptSetup",{enumerable:!1,value:!0}),F}});l(),t(),V();var Ei={class:`proj`},Di={class:`proj__head`},Oi={class:`proj__title`},ki={class:`proj__count`},Ai={key:0,class:`proj__tools`},ji={class:`proj__search`},Mi=[`placeholder`,`aria-label`],Ni={class:`proj__toggles`},Pi=[`aria-pressed`,`title`],Fi=[`aria-pressed`,`title`],Ii={class:`proj__list`},Li=[`title`],Ri={class:`proj-item__row1`},zi={class:`proj-item__name`},Bi={key:0,class:`proj-item__running`,"aria-hidden":`true`},Vi={class:`proj-item__num`},Hi={class:`proj-item__row2`},Ui={key:0,class:`proj-item__running-text`},Wi={key:0,class:`proj-item__row3`},Gi={class:`proj-item__bar`,"aria-hidden":`true`},Ki={class:`proj-item__progress-text`},qi=[`title`,`onClick`,`onKeydown`],Ji={class:`proj-item__row1`},Yi={class:`proj-item__name`},Xi={class:`proj-item__signals`},Zi={key:0,class:`proj-item__running`,"aria-hidden":`true`},Qi={key:1,class:`proj-item__badge`},$i={class:`proj-item__row2`},ea={key:0,class:`proj-chip proj-chip--missing`},ta={key:0,class:`proj-item__branch`},na={class:`proj-item__branch-name`},ra={key:1,class:`proj-chip proj-chip--ahead`},ia={key:2,class:`proj-chip proj-chip--behind`},aa={key:3,class:`proj-chip proj-chip--dirty`},oa={class:`proj-item__time`},sa={key:0,class:`proj-item__row3`},ca={class:`proj-item__bar`,"aria-hidden":`true`},la={class:`proj-item__progress-text`},ua={class:`proj-item__actions`},da=[`title`,`aria-label`,`onClick`],fa=[`title`,`aria-label`,`onClick`],pa=[`title`,`aria-label`,`aria-expanded`,`onClick`],ma=[`aria-label`],ha=[`onClick`,`onKeydown`],ga={class:`proj-menu__icon`},_a={class:`proj-menu__label`},va=[`onClick`,`onKeydown`],ya={class:`proj-menu__icon`},ba={class:`proj-menu__label`},xa=[`onClick`,`onKeydown`],Sa={class:`proj-menu__icon`},Ca={class:`proj-menu__label`},wa=[`onClick`,`onKeydown`],Ta={class:`proj-menu__icon`},Ea={class:`proj-menu__label`},Da={class:`proj-menu__title`,role:`presentation`},Oa=[`onClick`,`onKeydown`],ka={class:`proj-menu__icon`},Aa={class:`proj-menu__label`},ja={key:0,class:`proj-menu__hint`},Ma=[`onClick`,`onKeydown`],Na={class:`proj-menu__icon`},Pa=[`src`],Fa={class:`proj-menu__label`},Ia={class:`proj-menu__hint`},La=[`onClick`,`onKeydown`],Ra={class:`proj-menu__icon`},za=[`src`],Ba={class:`proj-menu__label`},Va=[`onClick`,`onKeydown`],Ha={class:`proj-menu__icon`},Ua={class:`proj-menu__label`},Wa=[`onClick`,`onKeydown`],Ga={class:`proj-menu__icon`},Ka={class:`proj-menu__label`},qa={key:0,class:`proj-menu__hint`},Ja={key:1,class:`proj-menu__hint`},Ya=[`onClick`,`onKeydown`],Xa={class:`proj-menu__icon`},Za={class:`proj-menu__label`},Qa={key:0,class:`proj-empty`},$a={class:`proj-empty__title`},eo={class:`proj-empty__hint`},to={key:1,class:`proj-empty`},no={class:`proj-empty__title`};function ro(t,n,r,i,s,c){let l=g,u=ge;return P(),W(`section`,Ei,[o(`header`,Di,[o(`h3`,Oi,U(i.$t(`@WORKBENCH:项目列表`)),1),o(`span`,ki,[i.filtering?(P(),W(X,{key:0},[w(U(i.$t(`@WORKBENCH:匹配 {n}/{total} 个项目`,{n:i.visible.length,total:r.projects.length})),1)],64)):(P(),W(X,{key:1},[w(U(r.projects.length),1)],64))])]),T(` 一个项目都没有时不渲染筛选条:没有可筛的东西,这一行只是占位 `),r.projects.length>0?(P(),W(`div`,Ai,[o(`div`,ji,[E(l,{class:`proj__search-icon`,"aria-hidden":`true`},{default:z(()=>[E(i.Search)]),_:1}),G(o(`input`,{"onUpdate:modelValue":n[0]||=e=>i.query=e,class:`proj__search-input`,type:`search`,placeholder:i.$t(`@WORKBENCH:搜索项目名称或路径`),"aria-label":i.$t(`@WORKBENCH:搜索项目名称或路径`),onKeydown:n[1]||=Z(e=>i.query=``,[`esc`])},null,40,Mi),[[F,i.query]])]),o(`div`,Ni,[o(`button`,{type:`button`,class:_([`proj__toggle`,{"is-on":i.onlyWithTasks}]),"aria-pressed":i.onlyWithTasks,title:i.$t(`@WORKBENCH:只显示有任务的项目`),onClick:n[2]||=e=>i.onlyWithTasks=!i.onlyWithTasks},[o(`span`,null,U(i.$t(`@WORKBENCH:只看有任务`)),1)],10,Pi),o(`button`,{type:`button`,class:_([`proj__toggle`,{"is-on":i.hideNonGit}]),"aria-pressed":i.hideNonGit,title:i.$t(`@WORKBENCH:只显示 Git 仓库`),onClick:n[3]||=e=>i.hideNonGit=!i.hideNonGit},[o(`span`,null,U(i.$t(`@WORKBENCH:隐藏非 Git`)),1)],10,Fi)])])):T(`v-if`,!0),o(`ul`,Ii,[o(`li`,{class:_([`proj-item proj-item--all`,{"is-active":r.selectedKey===``}]),role:`button`,tabindex:`0`,title:i.$t(`@WORKBENCH:全部项目`),onClick:n[4]||=e=>i.emit(`select`,null),onKeydown:[n[5]||=Z(L(e=>i.emit(`select`,null),[`prevent`]),[`enter`]),n[6]||=Z(L(e=>i.emit(`select`,null),[`prevent`]),[`space`])]},[o(`div`,Ri,[E(l,{class:`proj-item__icon`},{default:z(()=>[E(i.Grid)]),_:1}),o(`span`,zi,U(i.$t(`@WORKBENCH:全部项目`)),1),i.totals.running>0?(P(),W(`span`,Bi)):T(`v-if`,!0),o(`span`,Vi,U(r.projects.length),1)]),o(`div`,Hi,[o(`span`,null,U(i.$t(`@WORKBENCH:{n} 个项目`,{n:r.projects.length})),1),i.totals.running>0?(P(),W(`span`,Ui,U(i.$t(`@WORKBENCH:{n} 个执行中`,{n:i.totals.running})),1)):T(`v-if`,!0)]),T(` 一个任务都没有时整行不渲染(「0/0 任务完成」+ 空进度条是纯噪声) `),i.totals.total>0?(P(),W(`div`,Wi,[o(`span`,Gi,[o(`i`,{class:`proj-item__bar-fill`,style:N({width:i.overallProgress+`%`})},null,4)]),o(`span`,Ki,U(i.$t(`@WORKBENCH:{done}/{total} 任务完成`,{done:i.totals.done,total:i.totals.total})),1)])):T(`v-if`,!0)],42,Li),(P(!0),W(X,null,e(i.visible,t=>(P(),W(`li`,{key:t.key,class:_([`proj-item`,{"is-active":t.key===r.selectedKey,"is-running":t.stats.runningJobs>0,"is-missing":t.exists===!1}]),role:`button`,tabindex:`0`,title:t.path,onClick:e=>i.emit(`select`,t),onKeydown:[Z(L(e=>i.emit(`select`,t),[`self`,`prevent`]),[`enter`]),Z(L(e=>i.emit(`select`,t),[`self`,`prevent`]),[`space`])]},[o(`div`,Ji,[E(l,{class:`proj-item__icon`},{default:z(()=>[E(i.Folder)]),_:1}),o(`span`,Yi,U(t.name),1),T(` 运行中 / 当前 这两个信号与 hover 才出现的操作按钮锚在同一个右端点:
|
|
41
|
+
hover 时整组淡出让位给按钮,而不是让图标压在徽标上 `),o(`span`,Xi,[t.stats.runningJobs>0?(P(),W(`span`,Zi)):T(`v-if`,!0),t.isCurrent?(P(),W(`span`,Qi,U(i.$t(`@WORKBENCH:当前`)),1)):T(`v-if`,!0)])]),o(`div`,$i,[t.exists===!1?(P(),W(`span`,ea,U(i.$t(`@WORKBENCH:目录不存在`)),1)):(P(),W(X,{key:1},[T(` gitLine 为空即"不是 Git 仓库":不给文字,也不给图标 `),i.gitLine(t)?(P(),W(`span`,ta,[i.hasBranchIcon(t)?(P(),a(i.SvgIcon,{key:0,"icon-class":`git-branch`,"class-name":`proj-item__branch-icon`})):T(`v-if`,!0),o(`span`,na,U(i.gitLine(t)),1)])):T(`v-if`,!0),t.git&&t.git.ahead>0?(P(),W(`span`,ra,`↑`+U(t.git.ahead),1)):T(`v-if`,!0),t.git&&t.git.behind>0?(P(),W(`span`,ia,`↓`+U(t.git.behind),1)):T(`v-if`,!0),t.git&&t.git.changed>0?(P(),W(`span`,aa,`●`+U(t.git.changed),1)):T(`v-if`,!0)],64)),o(`span`,oa,U(i.relativeTimeFromIso(t.stats.lastActiveAt)),1)]),T(` 同上:这个项目一个任务都没有就不给进度行 `),t.stats.total>0?(P(),W(`div`,sa,[o(`span`,ca,[o(`i`,{class:`proj-item__bar-fill`,style:N({width:t.stats.progress+`%`})},null,4)]),o(`span`,la,U(i.$t(`@WORKBENCH:{done}/{total} 任务完成`,{done:t.stats.done,total:t.stats.total})),1)])):T(`v-if`,!0),T(` 打开动作:与行主体平级,绝对定位锚在 row1 右端(不占位,否则「当前」徽标
|
|
42
|
+
永远离右边缘一条);.stop 阻止冒泡到行的选中逻辑。目录都不存在时**一个打开
|
|
43
|
+
动作都不给** —— 点了只会弹一个「无法打开目录」的报错 —— 只留一颗「从清单移除」:
|
|
44
|
+
那一行存在的唯一理由就是提醒这里有个没了的目录,能做的也只有把它清掉。
|
|
45
|
+
两个按钮:最常用的「打开文件夹」留一键直达,其余打开方式(终端 / 编辑器 /
|
|
46
|
+
AI 工具 / 新标签页跑 g ui)收进「打开方式」菜单 —— 一行放不下七个图标,
|
|
47
|
+
而项目名被挤成省略号比多点一次更难受。
|
|
48
|
+
⚠️ 行上的 keydown 必须带 .self:事件从按钮冒泡上来,不带 .self 时
|
|
49
|
+
焦点在按钮上按回车会「选中该行 + preventDefault 掉按钮自己的激活」,
|
|
50
|
+
键盘用户反而打不开文件夹。 `),o(`div`,ua,[t.exists===!1?(P(),W(`button`,{key:0,type:`button`,class:`proj-item__action proj-item__action--danger`,title:i.$t(`@WORKBENCH:从清单移除`),"aria-label":`${i.$t(`@WORKBENCH:从清单移除`)} ${t.name}`,onClick:L(e=>i.confirmRemove(t),[`stop`])},[E(l,{"aria-hidden":`true`},{default:z(()=>[E(i.Delete)]),_:1})],8,da)):(P(),W(`button`,{key:1,type:`button`,class:`proj-item__action`,title:i.$t(`@WORKBENCH:打开文件夹`),"aria-label":`${i.$t(`@WORKBENCH:打开文件夹`)} ${t.name}`,onClick:L(e=>i.openInFileManager(t),[`stop`])},[E(l,{"aria-hidden":`true`},{default:z(()=>[E(i.FolderOpened)]),_:1})],8,fa)),t.exists===!1?T(`v-if`,!0):(P(),a(u,{key:2,visible:i.openMenuKey===t.key,trigger:`manual`,placement:`right-start`,width:272,"show-arrow":!1,offset:6,"popper-class":`proj-open-menu`},{reference:z(()=>[o(`button`,{type:`button`,class:_([`proj-item__action`,{"is-open":i.openMenuKey===t.key}]),title:i.$t(`@WORKBENCH:打开方式`),"aria-label":`${i.$t(`@WORKBENCH:打开方式`)} ${t.name}`,"aria-expanded":i.openMenuKey===t.key,"aria-haspopup":`menu`,onClick:L(e=>i.toggleOpenMenu(t,e),[`stop`])},[E(l,{"aria-hidden":`true`},{default:z(()=>[E(i.MoreFilled)]),_:1})],10,pa)]),default:z(()=>[i.openMenuKey===t.key?(P(),W(`ul`,{key:0,class:`proj-menu`,role:`menu`,"aria-label":i.$t(`@WORKBENCH:打开方式`)},[o(`li`,{class:`proj-menu__item`,role:`menuitem`,tabindex:`-1`,onClick:e=>i.openInFileManager(t),onKeydown:[Z(L(e=>i.openInFileManager(t),[`prevent`]),[`enter`]),Z(L(e=>i.openInFileManager(t),[`prevent`]),[`space`])]},[o(`span`,ga,[E(l,{"aria-hidden":`true`},{default:z(()=>[E(i.FolderOpened)]),_:1})]),o(`span`,_a,U(i.$t(`@WORKBENCH:在文件管理器中打开`)),1)],40,ha),o(`li`,{class:`proj-menu__item`,role:`menuitem`,tabindex:`-1`,onClick:e=>i.openInTerminal(t),onKeydown:[Z(L(e=>i.openInTerminal(t),[`prevent`]),[`enter`]),Z(L(e=>i.openInTerminal(t),[`prevent`]),[`space`])]},[o(`span`,ya,[E(l,{"aria-hidden":`true`},{default:z(()=>[E(i.Monitor)]),_:1})]),o(`span`,ba,U(i.$t(`@WORKBENCH:在终端中打开`)),1)],40,va),o(`li`,{class:`proj-menu__item`,role:`menuitem`,tabindex:`-1`,onClick:e=>i.launchGui(t),onKeydown:[Z(L(e=>i.launchGui(t),[`prevent`]),[`enter`]),Z(L(e=>i.launchGui(t),[`prevent`]),[`space`])]},[o(`span`,Sa,[E(l,{"aria-hidden":`true`},{default:z(()=>[E(i.Promotion)]),_:1})]),o(`span`,Ca,U(i.$t(`@WORKBENCH:在新标签页启动 g ui`)),1)],40,xa),T(` 复制文件夹名称:放在"打开"这一组里,因为它操作的是项目目录本身,
|
|
51
|
+
而不是"用哪个工具打开"(下面那组有独立标题)。 `),o(`li`,{class:`proj-menu__item`,role:`menuitem`,tabindex:`-1`,onClick:e=>i.copyFolderName(t),onKeydown:[Z(L(e=>i.copyFolderName(t),[`prevent`]),[`enter`]),Z(L(e=>i.copyFolderName(t),[`prevent`]),[`space`])]},[o(`span`,Ta,[E(l,{"aria-hidden":`true`},{default:z(()=>[E(i.CopyDocument)]),_:1})]),o(`span`,Ea,U(i.$t(`@67CE7:复制文件夹名称`)),1)],40,wa),n[8]||=o(`li`,{class:`proj-menu__sep`,role:`separator`},null,-1),o(`li`,Da,U(i.$t(`@WORKBENCH:用工具打开`)),1),(P(!0),W(X,null,e(i.OPEN_WITH_TOOLS,e=>(P(),W(`li`,{key:e.id,class:_([`proj-menu__item`,{"is-missing":i.toolMissing(e.id)}]),role:`menuitem`,tabindex:`-1`,onClick:n=>i.openWithTool(t,e.id),onKeydown:[Z(L(n=>i.openWithTool(t,e.id),[`prevent`]),[`enter`]),Z(L(n=>i.openWithTool(t,e.id),[`prevent`]),[`space`])]},[o(`span`,ka,[E(i.SvgIcon,{"icon-class":e.icon},null,8,[`icon-class`])]),o(`span`,Aa,U(i.$t(e.labelKey)),1),i.toolMissing(e.id)?(P(),W(`span`,ja,U(i.$t(`@67CE7:未安装`)),1)):T(`v-if`,!0)],42,Oa))),128)),T(` claude 有两种权限模式,不混进上面的工具列表(顶栏也是单独排布的) `),o(`li`,{class:_([`proj-menu__item`,{"is-missing":i.toolMissing(`claude`)}]),role:`menuitem`,tabindex:`-1`,onClick:e=>i.openWithTool(t,`claude`),onKeydown:[Z(L(e=>i.openWithTool(t,`claude`),[`prevent`]),[`enter`]),Z(L(e=>i.openWithTool(t,`claude`),[`prevent`]),[`space`])]},[o(`span`,Na,[o(`img`,{src:i.claudeCodeIcon,alt:``,class:`proj-menu__img`},null,8,Pa)]),o(`span`,Fa,U(i.$t(`@67CE7:用 Claude Code 打开`)),1),o(`span`,Ia,U(i.toolMissing(`claude`)?i.$t(`@67CE7:未安装`):i.$t(`@67CE7:默认权限`)),1)],42,Ma),o(`li`,{class:_([`proj-menu__item proj-menu__item--danger`,{"is-missing":i.toolMissing(`claude`)}]),role:`menuitem`,tabindex:`-1`,onClick:e=>i.openWithTool(t,`claude`,`bypassPermissions`),onKeydown:[Z(L(e=>i.openWithTool(t,`claude`,`bypassPermissions`),[`prevent`]),[`enter`]),Z(L(e=>i.openWithTool(t,`claude`,`bypassPermissions`),[`prevent`]),[`space`])]},[o(`span`,Ra,[o(`img`,{src:i.claudeCodeIcon,alt:``,class:`proj-menu__img`},null,8,za)]),o(`span`,Ba,U(i.$t(`@67CE7:用 Claude Code 打开(完全批准)`)),1)],42,La),T(` opencode 的「完全批准」(\`--auto\`)与 claude 的 bypass 档并列收在末尾:
|
|
52
|
+
它带警示色,混进上面的普通工具列表会把"一行一个工具"的节奏打乱,
|
|
53
|
+
而它又确实得单独成项(默认档已经在上面那条 v-for 里了)。 `),o(`li`,{class:_([`proj-menu__item proj-menu__item--danger`,{"is-missing":i.toolMissing(`opencode`)}]),role:`menuitem`,tabindex:`-1`,onClick:e=>i.openWithTool(t,`opencode`,`auto`),onKeydown:[Z(L(e=>i.openWithTool(t,`opencode`,`auto`),[`prevent`]),[`enter`]),Z(L(e=>i.openWithTool(t,`opencode`,`auto`),[`prevent`]),[`space`])]},[o(`span`,Ha,[E(i.SvgIcon,{"icon-class":`opencode`})]),o(`span`,Ua,U(i.$t(`@67CE7:用 OpenCode 打开(完全批准)`)),1)],42,Va),T(` codex 天然有三档(默认档已在上面那条 v-for 里):自动批准但仍有沙箱 →
|
|
54
|
+
免批准 + 免沙箱。两档都单独成项,理由同 claude / opencode 那两项。 `),o(`li`,{class:_([`proj-menu__item`,{"is-missing":i.toolMissing(`codex`)}]),role:`menuitem`,tabindex:`-1`,onClick:e=>i.openWithTool(t,`codex`,`sandboxed`),onKeydown:[Z(L(e=>i.openWithTool(t,`codex`,`sandboxed`),[`prevent`]),[`enter`]),Z(L(e=>i.openWithTool(t,`codex`,`sandboxed`),[`prevent`]),[`space`])]},[o(`span`,Ga,[E(i.SvgIcon,{"icon-class":`codex`})]),o(`span`,Ka,U(i.$t(`@67CE7:用 Codex 打开(自动批准)`)),1),i.toolMissing(`codex`)?(P(),W(`span`,Ja,U(i.$t(`@67CE7:未安装`)),1)):(P(),W(`span`,qa,U(i.$t(`@67CE7:沙箱内`)),1))],42,Wa),o(`li`,{class:_([`proj-menu__item proj-menu__item--danger`,{"is-missing":i.toolMissing(`codex`)}]),role:`menuitem`,tabindex:`-1`,onClick:e=>i.openWithTool(t,`codex`,`bypass`),onKeydown:[Z(L(e=>i.openWithTool(t,`codex`,`bypass`),[`prevent`]),[`enter`]),Z(L(e=>i.openWithTool(t,`codex`,`bypass`),[`prevent`]),[`space`])]},[o(`span`,Xa,[E(i.SvgIcon,{"icon-class":`codex`})]),o(`span`,Za,U(i.$t(`@67CE7:用 Codex 打开(完全批准)`)),1)],42,Ya)],8,ma)):T(`v-if`,!0)]),_:2},1032,[`visible`]))])],42,qi))),128)),!r.loading&&r.projects.length===0?(P(),W(`li`,Qa,[o(`p`,$a,U(i.$t(`@WORKBENCH:尚无项目`)),1),o(`p`,eo,U(i.$t(`@WORKBENCH:常用目录与建过任务的目录都会出现在这里`)),1)])):T(`v-if`,!0),T(` 有项目、只是被筛没了:这必须说出来。
|
|
55
|
+
空着会让人以为项目列表坏了,而"没有匹配"和"一个项目都没有"是两件事。
|
|
56
|
+
刻意写成两个互斥的 v-if(而不是 v-else-if):条件里带上了 projects.length,
|
|
57
|
+
读代码时不用回头找上一段才敢确定它们不重叠。 `),!r.loading&&r.projects.length>0&&i.visible.length===0?(P(),W(`li`,to,[o(`p`,no,U(i.$t(`@WORKBENCH:没有匹配的项目`)),1),o(`button`,{type:`button`,class:`proj-empty__clear`,onClick:i.clearFilters},U(i.$t(`@WORKBENCH:清除筛选`)),1)])):T(`v-if`,!0)]),T(` 未安装的工具:复用顶栏那套安装引导(同一个组件),不在这里另写一份说明。
|
|
58
|
+
挂在面板根上只渲染一份,而不是每行一个 —— 同时最多只可能开一个。 `),E(i.ToolInstallDialog,{modelValue:i.installVisible,"onUpdate:modelValue":n[7]||=e=>i.installVisible=e,tool:i.installTool},null,8,[`modelValue`,`tool`])])}var io=Ae(Ti,[[`render`,ro],[`__scopeId`,`data-v-de1af726`],[`__file`,`C:/workspace/github_workspace/xz333221/zen-gitsync/src/ui/client/src/views/components/WorkbenchProjectPanel.vue`]]),ao=[140,170,200,230,260,290,320,350];function oo(e){return(e||``).replace(/\\/g,`/`).trim().toLowerCase()}function so(e){let t=oo(e),n=2166136261;for(let e=0;e<t.length;e++)n^=t.charCodeAt(e),n=Math.imul(n,16777619);return n^=n>>>16,n=Math.imul(n,2246822507),n^=n>>>13,n=Math.imul(n,3266489909),n^=n>>>16,ao[(n>>>0)%ao.length]}function co(e){return{"--tag-hue":String(so(e))}}t(),J();var lo=`wb.boardView.v1`,uo=h({__name:`WorkbenchKanban`,props:{tasks:{type:Array,required:!0},projectLabels:{type:Object,required:!0},showProjectLabel:{type:Boolean,required:!0},openedTaskId:{type:[String,null],required:!0}},emits:[`open-task`,`run-task`,`stop-task`,`complete-task`,`reopen-task`,`delete-task`,`create-task`],setup(e,{expose:t,emit:n}){t();let r=e,i=n,a=R((()=>{try{return localStorage.getItem(lo)===`list`?`list`:`kanban`}catch{return`kanban`}})());q(a,e=>{try{localStorage.setItem(lo,e)}catch{}});let o=R(``),s=[{key:`todo`,labelKey:`@WORKBENCH:待处理`},{key:`doing`,labelKey:`@WORKBENCH:进行中`},{key:`done`,labelKey:`@WORKBENCH:已完成`}],c=k(()=>{let e=o.value.trim().toLowerCase();return r.tasks.filter(t=>!e||(t.title||``).toLowerCase().includes(e)||(t.desc||``).toLowerCase().includes(e))}),l=k(()=>s.map(e=>e.key===`done`?{...e,tasks:c.value.filter(t=>t.column===e.key).sort(d)}:{...e,tasks:c.value.filter(t=>t.column===e.key)}));function u(e){return String(e.manualDoneAt||e.lastJobEndedAt||e.updatedAt||e.createdAt||``)}function d(e,t){return u(t).localeCompare(u(e))}function p(e){return e.column===`done`?u(e):e.updatedAt||e.createdAt||``}function m(e){return e.live?``:Si(e.lastDurationMs)}function h(e){let t=m(e);if(!t)return``;let n=wi(e.lastJobStartedAt),r=wi(e.lastJobEndedAt);return!n||!r?t:`${t} · ${n} → ${r}`}function g(e){let t=(e.autoCompleted?.reason||``).trim(),n=Q(`@WORKBENCH:静默超时后由 AI 核对,判定这条任务已经完成`);return t?`${n}\n${t}`:n}let _=k(()=>[...c.value].sort((e,t)=>p(t).localeCompare(p(e)))),v=k(()=>({gridTemplateColumns:`repeat(${l.value.length}, minmax(0, 1fr))`}));function y(e){return(e.title||``).trim()||(e.desc||``).replace(/\s+/g,` `).trim()}function b(e){return r.projectLabels[e.projectPath]||``}function x(e){return e.lastJobStatus===`error`}function S(e){return e.live?.agent||e.lastJobAgent||``}function C(e){let t=Q(`@WORKBENCH:已运行 {elapsed}`,{elapsed:Si(e.elapsedMs)}),n=e.lastLine||e.lastThought||e.lastTool;return n?`${t} · ${n}`:t}let w={props:r,emit:i,VIEW_KEY:lo,view:a,search:o,COLUMNS:s,filtered:c,columns:l,doneAt:u,byDoneAtDesc:d,cardTime:p,cardDuration:m,cardTimeTitle:h,autoDoneTitle:g,listRows:_,columnsStyle:v,cardTitle:y,projectLabel:b,hasError:x,cardAgent:S,liveSummary:C,get $t(){return Q},get Search(){return f},TaskExecutorIcon:qe,get taskExecutorName(){return Pe},get projectTagStyle(){return co},get formatDurationMs(){return Si},get relativeTimeFromIso(){return xi}};return Object.defineProperty(w,"__isScriptSetup",{enumerable:!1,value:!0}),w}});l(),t(),V();var fo={class:`kb`},po={class:`kb__toolbar`},mo={class:`kb__views`,role:`tablist`},ho=[`aria-selected`],go=[`aria-selected`],_o={class:`kb__filters`},vo={class:`kb__search`},yo=[`placeholder`,`aria-label`],bo={class:`kb-col__head`},xo={class:`kb-col__title`},So={class:`kb-col__count`},Co={class:`kb-col__list`},wo=[`data-task-id`,`aria-current`,`onClick`,`onKeydown`],To={class:`kb-card__row1`},Eo=[`title`],Do=[`title`],Oo={class:`kb-card__time`},ko=[`title`],Ao=[`title`],jo={key:2,class:`kb-card__live`},Mo={class:`kb-card__live-meta`},No=[`title`],Po=[`title`],Fo={key:2,class:`kb-card__live-pid`},Io={key:3,class:`kb-card__live-silent`},Lo=[`title`],Ro=[`title`],zo={class:`kb-card__live-tag`},Bo=[`title`],Vo={class:`kb-card__live-tag`},Ho=[`title`],Uo=[`title`],Wo={class:`kb-card__reply-text`},Go={class:`kb-card__actions`},Ko=[`title`,`onClick`],qo=[`title`,`aria-label`,`onClick`],Jo=[`title`,`aria-label`,`onClick`],Yo=[`title`,`aria-label`,`onClick`],Xo=[`title`,`aria-label`,`onClick`],Zo={key:0,class:`kb-col__add`},Qo={key:1,class:`kb-col__empty`},$o={class:`kb__table-wrap`},es={class:`kb-table`},ts={class:`kb-table__th`},ns={class:`kb-table__th kb-table__th--narrow`},rs={class:`kb-table__th kb-table__th--time`},is=[`onClick`,`onKeydown`],as={class:`kb-table__td`},os={class:`kb-table__name`},ss=[`title`],cs={key:1,class:`kb-table__live`},ls=[`title`],us={key:1,class:`kb-table__live-silent`},ds={class:`kb-table__live kb-table__live--reply`},fs=[`title`],ps={class:`kb-table__td`},ms={class:`kb-table__td kb-table__td--num`},hs=[`title`],gs={class:`kb-table__dur`},_s=[`title`],vs={key:0},ys={class:`kb-table__td kb-table__empty`,colspan:`3`};function bs(t,n,r,i,a,s){let c=g;return P(),W(`div`,fo,[o(`div`,po,[o(`div`,mo,[o(`button`,{type:`button`,role:`tab`,class:_([`kb__view-btn`,{"is-active":i.view===`kanban`}]),"aria-selected":i.view===`kanban`,onClick:n[0]||=e=>i.view=`kanban`},U(i.$t(`@WORKBENCH:看板视图`)),11,ho),o(`button`,{type:`button`,role:`tab`,class:_([`kb__view-btn`,{"is-active":i.view===`list`}]),"aria-selected":i.view===`list`,onClick:n[1]||=e=>i.view=`list`},U(i.$t(`@WORKBENCH:列表视图`)),11,go)]),o(`div`,_o,[o(`div`,vo,[E(c,{class:`kb__search-icon`},{default:z(()=>[E(i.Search)]),_:1}),G(o(`input`,{class:`kb__search-input`,type:`search`,"onUpdate:modelValue":n[2]||=e=>i.search=e,placeholder:i.$t(`@WORKBENCH:搜索任务标题或描述`),"aria-label":i.$t(`@WORKBENCH:搜索任务标题或描述`)},null,8,yo),[[F,i.search]])])])]),T(` 看板视图 `),i.view===`kanban`?(P(),W(`div`,{key:0,class:`kb__columns`,style:N(i.columnsStyle)},[(P(!0),W(X,null,e(i.columns,t=>(P(),W(`section`,{key:t.key,class:_([`kb-col`,`kb-col--`+t.key])},[o(`header`,bo,[n[9]||=o(`span`,{class:`kb-col__dot`,"aria-hidden":`true`},null,-1),o(`h3`,xo,U(i.$t(t.labelKey)),1),o(`span`,So,U(t.tasks.length),1)]),o(`ul`,Co,[(P(!0),W(X,null,e(t.tasks,e=>(P(),W(`li`,{key:e.id,class:_([`kb-card`,{"is-running":e.runningJobs>0,"has-error":i.hasError(e),"is-opened":e.id===r.openedTaskId}]),"data-task-id":e.id,"aria-current":e.id===r.openedTaskId?`true`:void 0,role:`button`,tabindex:`0`,onClick:t=>i.emit(`open-task`,e),onKeydown:[Z(L(t=>i.emit(`open-task`,e),[`prevent`]),[`enter`]),Z(L(t=>i.emit(`open-task`,e),[`prevent`]),[`space`])]},[T(`
|
|
59
|
+
首行 = 所属项目色标 + 标题 + 时间,三样同一行。
|
|
60
|
+
· 色标原先自己占一行(一枚 60px 的胶囊推着标题和活动区往下走),
|
|
61
|
+
现在跟标题并排:卡片窄,能省一行是一行。
|
|
62
|
+
· 进行中那枚黄点去掉了 —— "在跑"由列本身 + 卡片上的活动区表达,
|
|
63
|
+
再来一枚一闪一闪的圆点属于重复编码,而且它是这张卡上唯一的纯装饰动效。
|
|
64
|
+
· 标题不再单独占行,跟着一起上移。
|
|
65
|
+
title 给完整路径:项目名可能重名(两个都叫 notebook),路径才是唯一答案。
|
|
66
|
+
`),o(`div`,To,[r.showProjectLabel&&i.projectLabel(e)?(P(),W(`span`,{key:0,class:`kb-card__project-chip`,style:N(i.projectTagStyle(e.projectPath)),title:e.projectPath},U(i.projectLabel(e)),13,Eo)):T(`v-if`,!0),o(`p`,{class:`kb-card__title`,title:i.cardTitle(e)},U(i.cardTitle(e)||i.$t(`@WORKBENCH:未命名任务`)),9,Do),o(`span`,Oo,U(i.relativeTimeFromIso(i.cardTime(e))),1)]),T(`
|
|
67
|
+
跑完的任务:用时**独占一行**,不挤进上面那个时间位。
|
|
68
|
+
实测首行(项目色标 + 标题 + 时间)在真实数据上已经排满,
|
|
69
|
+
再塞一串「用时 30 分 0 秒」会把项目色标压出 1px 的省略号
|
|
70
|
+
(verify-wb-card-row1 的 C 组守的正是"色标一枚都不许被压窄")。
|
|
71
|
+
竖着放只多一行 16px,横向一个字节都不占;而且「什么时候跑的」与
|
|
72
|
+
「跑了多久」本来就是两个维度,分两行读比挤在一行清楚 ——
|
|
73
|
+
同理它也没去挤活动区那行"已运行 x · 工具 n 次"。
|
|
74
|
+
`),i.cardDuration(e)?(P(),W(`p`,{key:0,class:`kb-card__spent`,title:i.cardTimeTitle(e)},U(i.$t(`@WORKBENCH:用时 {d}`,{d:i.cardDuration(e)})),9,ko)):T(`v-if`,!0),T(`
|
|
75
|
+
「这条不是跑完的,是**判**完的」—— 紧跟在那行用时下面(它修饰的就是上面那个时长)。
|
|
76
|
+
|
|
77
|
+
为什么**另起一行**、而不是挂在那行用时后面:那行有探针按逐字相等断言
|
|
78
|
+
(verify-wb-task-duration 的 A1「与服务端 lastDurationMs 逐字一致」,A3 还要求
|
|
79
|
+
它不被裁掉尾巴),往里面塞一枚标会同时踩到这两条 —— 而且那行本来就窄。
|
|
80
|
+
竖着放只多一行 16px,横向一个字节都不占。
|
|
81
|
+
|
|
82
|
+
为什么要标出来:自动收尾与"进程自己正常退出"在看板上长得一模一样
|
|
83
|
+
(都是「已完成」+ 一段用时),但含义差很远 —— 后者是跑完了,
|
|
84
|
+
前者是**模型读了它的思考与最后那段话,认为活已经干完**。不标的话,
|
|
85
|
+
用户看到的就是一条任务不声不响换了列,而模型给的依据(悬停可见)
|
|
86
|
+
只躺在 jobs.json 里没人看得到。
|
|
87
|
+
`),e.autoCompleted?(P(),W(`p`,{key:1,class:`kb-card__auto-done`,title:i.autoDoneTitle(e)},U(i.$t(`@WORKBENCH:AI 判定完成`)),9,Ao)):T(`v-if`,!0),T(`
|
|
88
|
+
正在跑的任务:把"现在在干嘛"直接写在卡片上。
|
|
89
|
+
在此之前卡片只有右上角一个圆点 —— 一次跑二十分钟的任务,
|
|
90
|
+
用户盯着看只知道"还在跑",是在改代码还是卡住了完全看不出来,
|
|
91
|
+
只能点进编辑器翻输出。服务端随卡片一起把事实摘要发过来
|
|
92
|
+
(decorateTaskForBoard 的 live,与右栏进度报告同一份实现)。
|
|
93
|
+
证据顺序沿用进度报告面板:工具调用(正在做什么)→ 思考(为什么)
|
|
94
|
+
→ 最新回复;每一行没有内容就整行不渲染,不写"暂无"。
|
|
95
|
+
`),e.live?(P(),W(`div`,jo,[o(`p`,Mo,[T(` 执行器只留图标 + 悬停提示:卡片这一行本来就窄(已运行 x 分 y 秒 · 工具 n 次),
|
|
96
|
+
再钉一个 "Claude Code" 文本会把工具次数挤到第二行去。
|
|
97
|
+
v-if 挡住的是"认不出"(老记录没写 agent 字段)——那时宁可不画 `),i.cardAgent(e)?(P(),W(`span`,{key:0,class:`kb-card__live-agent`,title:i.taskExecutorName(i.cardAgent(e))},[E(i.TaskExecutorIcon,{executor:i.cardAgent(e),class:`kb-card__live-agent-icon`},null,8,[`executor`])],8,No)):T(`v-if`,!0),o(`span`,null,U(i.$t(`@WORKBENCH:已运行 {elapsed}`,{elapsed:i.formatDurationMs(e.live.elapsedMs)})),1),T(` 次数看总数,鼠标停上去看分布:119 次里 118 次都是 Bash,
|
|
98
|
+
和"改了三处代码"是完全不同的两件事 `),e.live.toolCallCount?(P(),W(`span`,{key:1,title:e.live.toolMix||``},U(i.$t(`@WORKBENCH:工具 {n} 次`,{n:e.live.toolCallCount})),9,Po)):T(`v-if`,!0),T(`
|
|
99
|
+
PID:左栏那个「执行监控」面板去掉了,它的字段里只有这一个卡片上没有,
|
|
100
|
+
所以并到这一行来(面板其余字段卡片本来就都有,且比它更全)。
|
|
101
|
+
不走 $t:PID 是中英文都这么写的通用缩写,没有可翻译的余地。
|
|
102
|
+
放静默之前:静默是"它可能卡住了"的信号,该留在行尾最显眼。
|
|
103
|
+
`),e.live.pid?(P(),W(`span`,Fo,`PID `+U(e.live.pid),1)):T(`v-if`,!0),T(` 静默只在**显然静默**时才有值(服务端有阈值),所以这里不用再过滤 `),typeof e.live.silentMs==`number`?(P(),W(`span`,Io,U(i.$t(`@WORKBENCH:静默 {elapsed}`,{elapsed:i.formatDurationMs(e.live.silentMs)})),1)):T(`v-if`,!0)]),e.live.lastTool?(P(),W(`p`,{key:0,class:`kb-card__live-line is-tool`,title:e.live.lastTool},U(e.live.lastTool),9,Lo)):T(`v-if`,!0),e.live.lastThought?(P(),W(`p`,{key:1,class:`kb-card__live-line is-thought`,title:e.live.lastThought},[o(`span`,zo,U(i.$t(`@WORKBENCH:最近思考`)),1),w(U(e.live.lastThought),1)],8,Ro)):T(`v-if`,!0),e.live.lastLine?(P(),W(`p`,{key:2,class:`kb-card__live-line`,title:e.live.lastLine},[o(`span`,Vo,U(i.$t(`@WORKBENCH:最新回复`)),1),w(U(e.live.lastLine),1)],8,Bo)):T(`v-if`,!0)])):e.lastReply?(P(),W(X,{key:3},[T(`
|
|
104
|
+
已经跑完的任务:留下"它最后说了什么"。
|
|
105
|
+
卡片过去只有标题 + 时间,而模型收尾时常常反问一句「要 push 吗?」——
|
|
106
|
+
这类任务看着是完成了,其实在等用户回话,用户却只能点进去翻日志才知道。
|
|
107
|
+
live 覆盖不到这一段:它只在 running 时有值、跑完就消失,恰好把最有信息量的
|
|
108
|
+
收尾丢掉(服务端 decorateTaskForBoard 的 lastReply,与这里二选一)。
|
|
109
|
+
样式沿用 live 里「思考」那行的竖线 —— 同一个含义(这是它说的原话);
|
|
110
|
+
不加标签:卡片窄,一行放不下 4 个字的标签还挤掉正文。
|
|
111
|
+
|
|
112
|
+
执行器图标(有才渲染)摆在引文开头:这句收尾的话是**它**说的,
|
|
113
|
+
图标就贴着它,比跑到卡片别处去找更直接。
|
|
114
|
+
`),o(`p`,{class:`kb-card__reply`,title:e.lastReply},[i.cardAgent(e)?(P(),W(`span`,{key:0,class:`kb-card__quote-agent`,title:i.taskExecutorName(i.cardAgent(e))},[E(i.TaskExecutorIcon,{executor:i.cardAgent(e),class:`kb-card__quote-agent-icon`},null,8,[`executor`])],8,Uo)):T(`v-if`,!0),o(`span`,Wo,U(e.lastReply),1)],8,Ho)],2112)):T(`v-if`,!0),o(`div`,Go,[T(`
|
|
115
|
+
这一格是「对这条任务现在能做什么」。头两颗互斥、**不并排**:
|
|
116
|
+
空闲时能做的只有"跑一轮",在跑时能做的只有"停掉这一轮",
|
|
117
|
+
两个按钮同时摆着会让人以为"在跑也能再跑一轮"(服务端也确实拒绝)。
|
|
118
|
+
位置固定在同一格还有个几何上的理由:两个标签都是 2 个汉字、同字号同内边距,
|
|
119
|
+
操作组宽度因此**一个像素都不变** —— 下面那段按组宽反推的渐隐距离不用跟着改。
|
|
120
|
+
(2026-10-01 加的「完成 / 撤销」也是 2 个汉字、且每张卡上最多出现一颗,
|
|
121
|
+
组宽仍是常数:96px。改动组宽就必须同步改那两组数字,否则按钮会露出半截字形。)
|
|
122
|
+
`),e.runningJobs===0?(P(),W(`button`,{key:0,type:`button`,class:`kb-card__btn`,title:i.$t(`@WORKBENCH:执行`),onClick:L(t=>i.emit(`run-task`,e),[`stop`]),onKeydown:n[3]||=L(()=>{},[`stop`])},U(i.$t(`@WORKBENCH:执行`)),41,Ko)):(P(),W(X,{key:1},[T(`
|
|
123
|
+
停止:只有真在跑(runningJobs > 0 ⟺ 服务端推导出的「进行中」列)时才在。
|
|
124
|
+
条件用 runningJobs 而不是 \`!!t.live\`:两者在服务端同源(都是"有 running/pending
|
|
125
|
+
的 job"),但 runningJobs 是这张卡片列归属的判据本身,跟着它走不会出现
|
|
126
|
+
"卡片在待处理列却带个停止按钮"这种自相矛盾的状态。
|
|
127
|
+
点了做什么(确认弹窗、调哪个接口、jobId 从哪来)全在上层 —— 卡片只管发出意图,
|
|
128
|
+
与 run / delete 一致。
|
|
129
|
+
`),o(`button`,{type:`button`,class:`kb-card__btn kb-card__btn--stop`,title:i.$t(`@WORKBENCH:停止`),"aria-label":i.$t(`@WORKBENCH:停止`),onClick:L(t=>i.emit(`stop-task`,e),[`stop`]),onKeydown:n[4]||=L(()=>{},[`stop`])},U(i.$t(`@WORKBENCH:停止`)),41,qo)],2112)),T(`
|
|
130
|
+
手动「完成」:这颗按钮是看板上唯一一个**不由执行事实决定**的动作源头
|
|
131
|
+
(列仍然是推导的,只是推导时多听一句人话 —— 详见文件头那段)。
|
|
132
|
+
待处理 / 进行中都给:待处理里那条可能早在别处干完了,
|
|
133
|
+
进行中那条可能只是模型不说话了,两件都只有用户知道。
|
|
134
|
+
|
|
135
|
+
已完成列上的卡片不给这颗按钮 —— 列本身已经是答案了;真正需要它的只有
|
|
136
|
+
**手动标进去**的那种卡(它的最近一条 job 并不是 done,撤销才有意义),
|
|
137
|
+
所以那里换成一个「撤销」。自己跑完的卡上放撤销会是个骗人的按钮:
|
|
138
|
+
撤掉标记它还是"最近一条 job 跑完了",下次刷新照样在已完成列。
|
|
139
|
+
|
|
140
|
+
在跑的那张卡上点「完成」会连这一轮一起停掉(一张卡不能既已完成又在跑),
|
|
141
|
+
代价说明与确认弹窗在上层 —— 卡片只管发出意图,与 run / stop / delete 一致。
|
|
142
|
+
`),e.column===`done`?e.manualDoneAt?(P(),W(`button`,{key:3,type:`button`,class:`kb-card__btn`,title:i.$t(`@WORKBENCH:撤销完成标记,退回待处理`),"aria-label":i.$t(`@WORKBENCH:撤销完成标记`),onClick:L(t=>i.emit(`reopen-task`,e),[`stop`]),onKeydown:n[6]||=L(()=>{},[`stop`])},U(i.$t(`@WORKBENCH:撤销`)),41,Yo)):T(`v-if`,!0):(P(),W(`button`,{key:2,type:`button`,class:`kb-card__btn kb-card__btn--done`,title:i.$t(`@WORKBENCH:标记为已完成`),"aria-label":i.$t(`@WORKBENCH:标记为已完成`),onClick:L(t=>i.emit(`complete-task`,e),[`stop`]),onKeydown:n[5]||=L(()=>{},[`stop`])},U(i.$t(`@WORKBENCH:完成`)),41,Jo)),o(`button`,{type:`button`,class:`kb-card__btn kb-card__btn--danger`,title:i.$t(`@WORKBENCH:删除`),"aria-label":i.$t(`@WORKBENCH:删除`),onClick:L(t=>i.emit(`delete-task`,e),[`stop`]),onKeydown:n[7]||=L(()=>{},[`stop`])},`×`,40,Xo)])],42,wo))),128)),T(`
|
|
143
|
+
「新建任务」常驻待处理列末尾,不再只在列空时出现。
|
|
144
|
+
之前入口和空状态是同一个 \`v-if="col.tasks.length === 0"\`:列里一有卡片,
|
|
145
|
+
新建入口就整块消失,用户只能绕到左侧栏去建(看板里无处可点)。
|
|
146
|
+
两件事本来就无关——空状态说的是"这列没有卡片",新建入口说的是"能往这儿加卡片"。
|
|
147
|
+
列空时它顺带兼任空状态(--solo 撑高),所以待处理列不会再渲染下面的 kb-col__empty。
|
|
148
|
+
位置沿用 Trello「Add a card」的做法:跟着列表滚(不吸底),长列表滚到底就是它。
|
|
149
|
+
`),t.key===`todo`?(P(),W(`li`,Zo,[o(`button`,{type:`button`,class:_([`kb-col__add-btn`,{"kb-col__add-btn--solo":t.tasks.length===0}]),onClick:n[8]||=e=>i.emit(`create-task`)},[n[10]||=o(`span`,{class:`kb-col__add-plus`,"aria-hidden":`true`},`+`,-1),o(`span`,null,U(i.$t(`@WORKBENCH:新建任务`)),1)],2)])):t.tasks.length===0?(P(),W(`li`,Qo,[o(`span`,null,U(i.$t(`@WORKBENCH:暂无任务`)),1)])):T(`v-if`,!0)])],2))),128))],4)):(P(),W(X,{key:1},[T(` 列表视图 `),o(`div`,$o,[o(`table`,es,[o(`thead`,null,[o(`tr`,null,[o(`th`,ts,U(i.$t(`@WORKBENCH:任务`)),1),o(`th`,ns,U(i.$t(`@WORKBENCH:状态`)),1),o(`th`,rs,U(i.$t(`@WORKBENCH:时间`)),1)])]),o(`tbody`,null,[(P(!0),W(X,null,e(i.listRows,e=>(P(),W(`tr`,{key:e.id,class:`kb-table__row`,tabindex:`0`,onClick:t=>i.emit(`open-task`,e),onKeydown:[Z(L(t=>i.emit(`open-task`,e),[`prevent`]),[`enter`]),Z(L(t=>i.emit(`open-task`,e),[`prevent`]),[`space`])]},[o(`td`,as,[o(`span`,os,U(i.cardTitle(e)||i.$t(`@WORKBENCH:未命名任务`)),1),T(` 项目色标:与看板卡片同一枚(见 .kb-card__project-chip 的样式注释),
|
|
150
|
+
列表视图是同一批任务的另一种画法,两处长得不一样会让人以为是两份数据 `),r.showProjectLabel&&i.projectLabel(e)?(P(),W(`span`,{key:0,class:`kb-table__project`,style:N(i.projectTagStyle(e.projectPath)),title:e.projectPath},U(i.projectLabel(e)),13,ss)):T(`v-if`,!0),T(` 状态列的"进行中"太粗,跑起来之后一眼看不出进度:这里补一行
|
|
151
|
+
最新回复 / 思考 / 工具(与卡片上的 live 同一份数据)。
|
|
152
|
+
执行器图标摆最前(与看板卡片同一个位置:整块执行事实的开头) `),e.live?(P(),W(`span`,cs,[i.cardAgent(e)?(P(),W(`span`,{key:0,class:`kb-table__agent`,title:i.taskExecutorName(i.cardAgent(e))},[E(i.TaskExecutorIcon,{executor:i.cardAgent(e),class:`kb-table__agent-icon`},null,8,[`executor`])],8,ls)):T(`v-if`,!0),w(` `+U(i.liveSummary(e.live))+` `,1),typeof e.live.silentMs==`number`?(P(),W(`span`,us,U(i.$t(`@WORKBENCH:静默 {elapsed}`,{elapsed:i.formatDurationMs(e.live.silentMs)})),1)):T(`v-if`,!0)])):e.lastReply?(P(),W(X,{key:2},[T(` 跑完的任务同理给一行"最后说了什么":列表视图与看板卡片是同一批任务的
|
|
153
|
+
两种画法,一边有、一边没有会让人以为是两份数据 `),o(`span`,ds,[i.cardAgent(e)?(P(),W(`span`,{key:0,class:`kb-table__agent`,title:i.taskExecutorName(i.cardAgent(e))},[E(i.TaskExecutorIcon,{executor:i.cardAgent(e),class:`kb-table__agent-icon`},null,8,[`executor`])],8,fs)):T(`v-if`,!0),w(U(e.lastReply),1)])],2112)):T(`v-if`,!0)]),o(`td`,ps,[o(`span`,{class:_([`kb-table__status`,`is-`+e.column])},U(i.$t(i.COLUMNS.find(t=>t.key===e.column).labelKey)),3)]),o(`td`,ms,[T(` 与看板卡片首行同一个口径:同一批任务的两种画法,一边有一边没有
|
|
154
|
+
会让人以为是两份数据 `),o(`span`,{class:`kb-table__time`,title:i.cardTimeTitle(e)},[i.cardDuration(e)?(P(),W(X,{key:0},[o(`span`,gs,U(i.$t(`@WORKBENCH:用时 {d}`,{d:i.cardDuration(e)})),1),n[11]||=o(`span`,{class:`kb-table__time-sep`,"aria-hidden":`true`},`·`,-1)],64)):T(`v-if`,!0),T(` 「AI 判定完成」在列表视图里也得有:同一批任务的两种画法,
|
|
155
|
+
一边有一边没有会让人以为是两份数据(卡片那边见 .kb-card__spent 的注释) `),e.autoCompleted?(P(),W(X,{key:1},[o(`span`,{class:`kb-table__auto-done`,title:i.autoDoneTitle(e)},U(i.$t(`@WORKBENCH:AI 判定完成`)),9,_s),n[12]||=o(`span`,{class:`kb-table__time-sep`,"aria-hidden":`true`},`·`,-1)],64)):T(`v-if`,!0),o(`span`,null,U(i.relativeTimeFromIso(i.cardTime(e))),1)],8,hs)])],40,is))),128)),i.listRows.length===0?(P(),W(`tr`,vs,[o(`td`,ys,U(i.$t(`@WORKBENCH:暂无任务`)),1)])):T(`v-if`,!0)])])])],2112))])}var xs=Ae(uo,[[`render`,bs],[`__scopeId`,`data-v-0b8fc27c`],[`__file`,`C:/workspace/github_workspace/xz333221/zen-gitsync/src/ui/client/src/views/components/WorkbenchKanban.vue`]]);t();var Ss=h({__name:`TaskExecutorPicker`,props:{title:{type:String,required:!1}},setup(e,{expose:t}){t();let n=e,{active:r,availability:i,choose:a,executorModelText:o,executorModelTitle:s}=_r(),c=Ie();re(()=>{c.fetchExecutorModels()});function l(){return[n.title,s(r.value)].filter(Boolean).join(` · `)}let u={props:n,active:r,availability:i,choose:a,executorModelText:o,executorModelTitle:s,toolsStore:c,btnTitle:l,get ArrowDown(){return ne},get Check(){return _e},get $t(){return Q},TaskExecutorIcon:qe,get TASK_EXECUTOR_OPTIONS(){return Ne},get taskExecutorName(){return Pe}};return Object.defineProperty(u,"__isScriptSetup",{enumerable:!1,value:!0}),u}});t(),l();var Cs=[`title`,`aria-label`],ws={class:`tep__btn-name`},Ts={class:`tep__item`},Es={class:`tep__item-name`},Ds=[`title`],Os={key:2,class:`tep__item-missing`};function ks(t,r,i,s,c,l){let u=g,d=n,f=be,p=O;return P(),a(p,{trigger:`click`,class:`tep`,onCommand:s.choose},{dropdown:z(()=>[E(f,null,{default:z(()=>[(P(!0),W(X,null,e(s.TASK_EXECUTOR_OPTIONS,e=>(P(),a(d,{key:e.id,command:e.id,disabled:!s.availability[e.id]},{default:z(()=>[o(`span`,Ts,[E(s.TaskExecutorIcon,{executor:e.id,class:`tep__item-icon`},null,8,[`executor`]),o(`span`,Es,U(e.name),1),s.executorModelText(e.id)?(P(),W(`span`,{key:0,class:`tep__item-model`,title:s.executorModelTitle(e.id)},U(s.executorModelText(e.id)),9,Ds)):T(`v-if`,!0),s.active===e.id?(P(),a(u,{key:1,class:`tep__item-check`},{default:z(()=>[E(s.Check)]),_:1})):s.availability[e.id]?T(`v-if`,!0):(P(),W(`span`,Os,U(s.$t(`@42BB9:未安装`)),1))])]),_:2},1032,[`command`,`disabled`]))),128))]),_:1})]),default:z(()=>[o(`button`,{type:`button`,class:`tep__btn`,title:s.btnTitle(),"aria-label":s.$t(`@WORKBENCH:任务执行器`)},[E(s.TaskExecutorIcon,{executor:s.active,class:`tep__btn-icon`},null,8,[`executor`]),o(`span`,ws,U(s.taskExecutorName(s.active)),1),E(u,{class:`tep__btn-caret`},{default:z(()=>[E(s.ArrowDown)]),_:1})],8,Cs)]),_:1},8,[`onCommand`])}var As=Ae(Ss,[[`render`,ks],[`__scopeId`,`data-v-7674ee77`],[`__file`,`C:/workspace/github_workspace/xz333221/zen-gitsync/src/ui/client/src/components/TaskExecutorPicker.vue`]]);t(),J();var js=h({__name:`AgentChatSurface`,props:{title:{type:String,required:!1},active:{type:Boolean,required:!1},allowDispatch:{type:Boolean,required:!1},dispatchUseDefaultPrompt:{type:Boolean,required:!1},placeholder:{type:String,required:!1}},setup(e,{expose:t}){t();let n=e,{active:r}=_r(),{theme:i}=Le(),a=k(()=>i.value===`dark`?`dark`:`light`),{sessions:o,sessionsLoading:s,currentSessionId:c,messages:l,isStreaming:u,pendingQuestion:d,answeringQuestion:f,isSessionGenerating:p,currentEngine:m,pendingEngine:h,isEngineLocked:g,pickEngine:_,loadSessions:v,loadSession:y,deleteSession:b,renameSession:x,newSession:S,sendMessage:C,answerQuestion:w,stop:T}=tt(),E=k(()=>g.value?m.value:h.value);function D(e){g.value||_(e)}let O=k(()=>n.allowDispatch!==!1&&E.value!==`gai`),ee=k(()=>Xe(o.value,p)),A=et(),j=Ze(),te=R(null),{width:N,narrow:ne}=it(te),ie=R(`chat`),P=R(null);function F(e=!0){P.value?.scrollToBottom?.(e)}async function ae(e){await C(e.text,e.files,{allowDispatch:n.allowDispatch===!0,dispatchExecutor:r.value,dispatchUseDefaultPrompt:n.dispatchUseDefaultPrompt!==!1}),await M(),F()}function I(e){y(e),ie.value=`chat`}function oe(){S(),ie.value=`chat`}q(()=>l.value.length,()=>{M(()=>F(!1))}),q(()=>n.active,e=>{e&&(v().catch(()=>{}),M(()=>F(!1)))}),q(ne,e=>{e||(ie.value=`chat`)}),re(()=>{v().catch(()=>{}),M(()=>F(!1))});let se={props:n,executor:r,theme:i,chatTheme:a,sessions:o,sessionsLoading:s,currentSessionId:c,messages:l,isStreaming:u,pendingQuestion:d,answeringQuestion:f,isSessionGenerating:p,currentEngine:m,pendingEngine:h,isEngineLocked:g,pickEngine:_,loadSessions:v,loadSession:y,deleteSession:b,renameSession:x,newSession:S,sendMessage:C,answerQuestion:w,stop:T,displayEngine:E,onEngineSelect:D,engineCantDispatch:O,conversationItems:ee,conversationLabels:A,questionLabels:j,rootRef:te,width:N,narrow:ne,page:ie,chatRef:P,scrollToBottom:F,onSend:ae,onSelectSession:I,onNewSession:oe,get $t(){return Q},get ChatContainer(){return Te},get ChatInput(){return Oe},get ConversationList(){return ke},get AGENT_UPLOAD_ACCEPT(){return $e},get agentEngineName(){return rt},get AGENT_ASSISTANT_NAME(){return Qe},get AGENT_ASSISTANT_AVATAR(){return nt},AgentEngineSelector:at,TaskExecutorPicker:As};return Object.defineProperty(se,"__isScriptSetup",{enumerable:!1,value:!0}),se}});t(),l(),V();var Ms={ref:`rootRef`,class:`acs`},Ns={class:`acs__head`},Ps=[`title`,`aria-label`],Fs={class:`acs__title`},Is=[`title`,`aria-label`],Ls={class:`acs__convs`},Rs={class:`acs__chat`},zs=[`data-theme`],Bs={key:0,class:`acs__foot`},Vs={key:0,class:`acs__notice`},Hs={class:`acs__foot-label`},Us={class:`acs__foot-hint`};function Ws(e,t,n,r,i,s){return P(),W(`div`,Ms,[o(`div`,Ns,[T(` 窄屏的列表页:整条头让给「返回对话 + 标题」 `),r.narrow&&r.page===`list`?(P(),W(`button`,{key:0,type:`button`,class:`acs__icon-btn`,title:r.$t(`@EDITOR:返回对话`),"aria-label":r.$t(`@EDITOR:返回对话`),onClick:t[0]||=e=>r.page=`chat`},[...t[2]||=[o(`svg`,{viewBox:`0 0 24 24`,width:`12`,height:`12`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[o(`line`,{x1:`19`,y1:`12`,x2:`5`,y2:`12`}),o(`polyline`,{points:`12 19 5 12 12 5`})],-1)]],8,Ps)):T(`v-if`,!0),o(`span`,Fs,U(n.title||r.$t(`@WORKBENCH:g ai 对话`)),1),t[4]||=o(`span`,{class:`acs__spacer`},null,-1),T(` 引擎切换:与「智能体」视图 / 编辑器面板同一个选择器(唯一那份实现)。
|
|
156
|
+
宽屏对话区一直在,所以常驻;窄屏只在对话页出现 —— 列表页摆它只会挤占标题。 `),!r.narrow||r.page===`chat`?(P(),a(r.AgentEngineSelector,{key:1,class:`acs__engine`,engine:r.displayEngine,locked:r.isEngineLocked,onSelect:r.onEngineSelect},null,8,[`engine`,`locked`])):T(`v-if`,!0),T(` 会话列表按钮:只有"列表是独立一页"时才需要它(宽屏列表就在旁边) `),r.narrow&&r.page===`chat`?(P(),W(`button`,{key:2,type:`button`,class:`acs__icon-btn`,title:r.$t(`@EDITOR:会话列表`),"aria-label":r.$t(`@EDITOR:会话列表`),onClick:t[1]||=e=>r.page=`list`},[...t[3]||=[x(`<svg viewBox="0 0 24 24" width="12" height="12" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" data-v-9e75d420><line x1="8" y1="6" x2="21" y2="6" data-v-9e75d420></line><line x1="8" y1="12" x2="21" y2="12" data-v-9e75d420></line><line x1="8" y1="18" x2="21" y2="18" data-v-9e75d420></line><line x1="3" y1="6" x2="3.01" y2="6" data-v-9e75d420></line><line x1="3" y1="12" x2="3.01" y2="12" data-v-9e75d420></line><line x1="3" y1="18" x2="3.01" y2="18" data-v-9e75d420></line></svg>`,1)]],8,Is)):T(`v-if`,!0)]),o(`div`,{class:_([`acs__body`,{"is-wide":!r.narrow}])},[T(` 会话历史:宽屏是常驻左列,窄屏是独享整页 `),G(o(`div`,Ls,[E(r.ConversationList,{"show-search":!0,items:r.conversationItems,"active-id":r.currentSessionId,loading:r.sessionsLoading,labels:r.conversationLabels,onSelect:r.onSelectSession,onNew:r.onNewSession,onRename:r.renameSession,onDelete:r.deleteSession},null,8,[`items`,`active-id`,`loading`,`labels`,`onRename`,`onDelete`])],512),[[Y,!r.narrow||r.page===`list`]]),T(` 气泡区:输入框已经不在这里了(show-input=false),见下面常驻的那一条 `),G(o(`div`,Rs,[E(r.ChatContainer,{ref:`chatRef`,"show-input":!1,messages:r.messages,"assistant-name":r.AGENT_ASSISTANT_NAME,"assistant-avatar":r.AGENT_ASSISTANT_AVATAR,theme:r.chatTheme,question:r.pendingQuestion,"question-submitting":r.answeringQuestion,"question-labels":r.questionLabels,"plan-config":{labels:{title:r.$t(`@AGENT:计划`),raw:r.$t(`@AGENT:原始参数`)}},onAnswer:r.answerQuestion},null,8,[`messages`,`assistant-name`,`assistant-avatar`,`theme`,`question`,`question-submitting`,`question-labels`,`plan-config`,`onAnswer`])],512),[[Y,!r.narrow||r.page===`chat`]]),T(`
|
|
157
|
+
输入框常驻:两种形态、两个页面都在最下方。
|
|
158
|
+
它被拆到 ChatContainer 外面,所以 acu-root 与 data-theme 得自己套上:
|
|
159
|
+
库把盒模型重置限定在 .acu-root 子树里,而 ChatInput 根节点是 div(不是 button),
|
|
160
|
+
少了它就会退回 content-box、横着溢出这条栏。
|
|
161
|
+
|
|
162
|
+
v-if="width > 0":**等量到本面板的宽度再挂载输入框**。库的 ChatInput 只在
|
|
163
|
+
onMounted 里量一次 scrollHeight,量到的宽度不对就再也纠不回来 —— 实测首帧挂载时
|
|
164
|
+
容器还没宽度,占位文案被折成十几行,textarea 直接顶到 200px 上限并一直卡在那里
|
|
165
|
+
(切走再切回才对)。宽度是 useNarrowPane 在 onMounted 里同步量到的,所以这里
|
|
166
|
+
晚的只是一次重渲染,同一帧内就补上了,看不到闪烁。
|
|
167
|
+
`),r.width>0?(P(),W(`div`,{key:0,class:`acs__composer acu-root`,"data-theme":r.chatTheme},[E(r.ChatInput,{disabled:r.isStreaming,generating:r.isStreaming,placeholder:n.placeholder||(r.isStreaming?r.$t(`@AGENT:正在生成中...`):r.$t(`@AGENT:输入消息,Enter 发送`)),"upload-config":{accept:r.AGENT_UPLOAD_ACCEPT},onSend:r.onSend,onStop:r.stop},null,8,[`disabled`,`generating`,`placeholder`,`upload-config`,`onStop`])],8,zs)):T(`v-if`,!0)],2),T(` 底部:派发执行器。放在输入框下面而不是头部 —— 它修饰的是"派出去的活谁跑",
|
|
168
|
+
不是"我在跟谁聊",和引擎选择器挤在一行会让人分不清哪个管哪件事 `),n.allowDispatch&&r.page===`chat`?(P(),W(`div`,Bs,[r.engineCantDispatch?(P(),W(`p`,Vs,U(r.$t(`@WORKBENCH:当前引擎「{name}」只能对话,不能派发任务 —— 切到内置 g ai 才能派活`,{name:r.agentEngineName(r.displayEngine)})),1)):(P(),W(X,{key:1},[o(`span`,Hs,U(r.$t(`@WORKBENCH:派发执行器`)),1),E(r.TaskExecutorPicker,{title:r.$t(`@WORKBENCH:它派出去的任务由这个执行器跑(与执行按钮的临时切换共用)`)},null,8,[`title`]),o(`span`,Us,U(r.$t(`@WORKBENCH:任务会落到看板,跑完有完成提示`)),1)],64))])):T(`v-if`,!0)],512)}var Gs=Ae(js,[[`render`,Ws],[`__scopeId`,`data-v-9e75d420`],[`__file`,`C:/workspace/github_workspace/xz333221/zen-gitsync/src/ui/client/src/components/AgentChatSurface.vue`]]);t(),J();var Ks=`wb.ocMode.v2`,qs=`/api/workbench/orchestrator/attachments`,Js=`wb.ocInputHeight.v1`,Ys=76,Xs=20,Zs=h({__name:`OrchestratorConsole`,props:{active:{type:Boolean,required:!0},runningCount:{type:Number,required:!0},selectedProject:{type:[Object,null],required:!0},dispatching:{type:Boolean,required:!0},togglingSchedule:{type:Boolean,required:!0},todayDone:{type:Number,required:!0},collapsed:{type:Boolean,required:!1},defaultPrompt:{type:String,required:!1},projectPrompts:{type:Object,required:!1},reports:{type:Array,required:!1},reportIntervalMs:{type:Number,required:!1},generatingReport:{type:Boolean,required:!1},maxInstructionChars:{type:Number,required:!1}},emits:[`toggle-schedule`,`toggle-collapse`,`open-prompt-settings`,`generate-report`,`set-report-interval`,`dispatch`],setup(e,{expose:t,emit:n}){let r=e,i=n,a=R(``),o=R(!0),s=R(!0),{active:c}=_r(),l=R((()=>{try{return localStorage.getItem(Ks)===`chat`?`chat`:`command`}catch{return`command`}})());function u(e){l.value=e;try{localStorage.setItem(Ks,e)}catch{}}let d=R([]),f=k(()=>({kind:`draft`,list:d.value,replace:e=>{d.value=e}})),{isUploading:m,isImageAttachment:h,humanSize:g,onAttachmentPaste:_,onAttachmentDrop:y,removeAttachment:b,pickAttachmentFile:x}=or(),S=k(()=>m(`draft`)),C=R(!1);function w(e){e.stopPropagation(),_(e,f.value)}function T(e){C.value=!1,y(e,f.value)}function E(){x(f.value)}function O(e){b(f.value,e)}function ee(){d.value=[]}function A(){a.value=``}t({clearAttachments:ee,clearDraft:A});let te=k(()=>r.selectedProject?.key||``),N=k(()=>(r.defaultPrompt||``).trim()),ne=k(()=>{let e=te.value;return e?(r.projectPrompts?.[e]?.prompt||``).trim():``}),ie=k(()=>Object.values(r.projectPrompts||{}).some(e=>(e?.prompt||``).trim().length>0)),P=k(()=>!!N.value||ie.value),F=k(()=>{let e=!!N.value,t=te.value?ne.value?`project`:`none`:ie.value?`target`:`none`;return Q(e&&t===`project`?`@WORKBENCH:全局 + 本项目`:e&&t===`target`?`@WORKBENCH:全局 + 落点项目`:e?`@WORKBENCH:全局`:t===`project`?`@WORKBENCH:本项目`:t===`target`?`@WORKBENCH:落点项目`:`@WORKBENCH:未设置`)}),I=k(()=>a.value.trim().length),oe=k(()=>r.maxInstructionChars||1e5),se=k(()=>I.value>oe.value),L=k(()=>!se.value&&I.value>=oe.value*.9),z=k(()=>a.value.trim().length>0&&!r.dispatching&&!S.value&&!se.value);function B(){z.value&&i(`dispatch`,{text:a.value.trim(),autoRun:o.value,attachments:d.value,projectPath:r.selectedProject?r.selectedProject.path:``,useDefaultPrompt:s.value,executor:c.value})}function V(e){e.isComposing||e.keyCode===229||e.key!==`Enter`||e.shiftKey||(e.preventDefault(),B())}function H(){try{let e=localStorage.getItem(Js);if(!e)return null;let t=Number(e);return Number.isFinite(t)&&t>=Ys?Math.round(t):null}catch{return null}}let U=R(null),ce=R(H()),le=k(()=>{let e={};return ce.value&&(e.height=`${ce.value}px`),e}),W=null,G=!1,ue=!0;function de(e){let t=U.value;if(!t)return;let n=t.getBoundingClientRect();G=n.right-e.clientX<=Xs&&n.bottom-e.clientY<=Xs}function K(){G=!1}function fe(e){let t=Math.round(e.offsetHeight);if(!(t<Ys||t===ce.value)){ce.value=t;try{localStorage.setItem(Js,String(t))}catch{}}}re(()=>{let e=U.value;e&&(window.addEventListener(`mouseup`,K),typeof ResizeObserver<`u`&&(W=new ResizeObserver(()=>{if(ue){ue=!1;return}let t=parseFloat(getComputedStyle(e).maxHeight),n=Number.isFinite(t)&&e.offsetHeight>=t-1;(G||!n)&&fe(e)}),W.observe(e)))}),he(()=>{window.removeEventListener(`mouseup`,K),W?.disconnect(),W=null});let pe=R(null),J=k(()=>{let e=r.reports||[];return e.length?e.find(e=>e.id===pe.value)||e[0]:null});function me(e){pe.value=e.id}let ge=R(null),_e=R(!1),ve=R(!1);function Y(){let e=ge.value;e&&!_e.value&&(ve.value=e.scrollHeight-e.clientHeight>2)}function ye(){_e.value=!_e.value,_e.value||M(Y)}let be=null;q(ge,e=>{be?.disconnect(),be=null,e&&(be=new ResizeObserver(()=>Y()),be.observe(e))}),he(()=>{be?.disconnect(),be=null}),q(()=>J.value?.id,()=>{_e.value=!1,ve.value=!1,M(Y)});function X(e){let t=pi(e.percent);return t===null?``:t+`%`}let xe=k(()=>pi(J.value?.percent)),Z=k(()=>(J.value?.tasks||[]).map(e=>({...e,pct:pi(e.percent)})));function Ce(e){let t=String(e.text||``).replace(/\s+/g,` `).trim();return t?t.length>42?t.slice(0,42)+`…`:t:e.errorCode?Q(fi(e.errorCode)):Q(`@WORKBENCH:当时没有任务在执行`)}function we(e){return e.errorCode?Q(fi(e.errorCode)):e.tasks.length?Q(`@WORKBENCH:模型没有返回内容`):Q(`@WORKBENCH:生成这份报告时没有任务在执行`)}function Te(e){let t=e.target,n=Number(t.value);si.includes(n)&&i(`set-report-interval`,n)}let Ee={props:r,emit:i,draft:a,autoRun:o,useDefaultPrompt:s,selectedExecutor:c,MODE_KEY:Ks,mode:l,setMode:u,draftAttachments:d,DRAFT_RAW_BASE:qs,attachTarget:f,isUploading:m,isImageAttachment:h,humanSize:g,onAttachmentPaste:_,onAttachmentDrop:y,removeAttachment:b,pickAttachmentFile:x,attachBusy:S,attachDragging:C,onPaste:w,onDrop:T,onPickAttachment:E,onRemoveAttachment:O,clearAttachments:ee,clearDraft:A,projectKey:te,globalPromptText:N,projectPromptText:ne,anyProjectPrompt:ie,anyPromptConfigured:P,promptStateLabel:F,draftChars:I,charLimit:oe,overLimit:se,nearLimit:L,canSend:z,send:B,onInputKeydown:V,INPUT_H_KEY:Js,OC_INPUT_MIN_H:Ys,readInputH:H,inputRef:U,inputH:ce,inputStyle:le,get inputRO(){return W},set inputRO(e){W=e},get inputDragging(){return G},set inputDragging(e){G=e},get inputROFirst(){return ue},set inputROFirst(e){ue=e},INPUT_GRIP_PX:Xs,onInputMouseDown:de,onWindowMouseUp:K,commitInputH:fe,selectedReportId:pe,currentReport:J,pickReport:me,textEl:ge,textExpanded:_e,textClamped:ve,measureText:Y,toggleText:ye,get textRO(){return be},set textRO(e){be=e},historyPct:X,currentPercent:xe,currentTasks:Z,reportBrief:Ce,reportNotice:we,onIntervalChange:Te,gitSummary:k(()=>{let e=r.selectedProject;if(!e)return[];let t=[];if(e.exists===!1)return t.push({label:Q(`@WORKBENCH:工作区`),value:Q(`@WORKBENCH:目录不存在`),tone:`danger`}),t;let n=e.git;return!n||n.isGitRepo===null?(t.push({label:Q(`@WORKBENCH:Git 状态`),value:Q(`@WORKBENCH:未知`),tone:``}),t):n.isGitRepo?(t.push({label:Q(`@WORKBENCH:分支`),value:n.detached?Q(`@WORKBENCH:游离 HEAD`):n.branch||Q(`@WORKBENCH:未知`),tone:``}),t.push({label:Q(`@WORKBENCH:工作区`),value:n.changed>0?Q(`@WORKBENCH:未提交 {n} 项`,{n:n.changed}):Q(`@WORKBENCH:干净`),tone:n.changed>0?`warn`:``}),n.hasUpstream&&(n.ahead>0||n.behind>0)&&t.push({label:Q(`@WORKBENCH:与上游`),value:Q(`@WORKBENCH:领先 {ahead} / 落后 {behind}`,{ahead:n.ahead,behind:n.behind}),tone:n.behind>0?`warn`:``}),t):(t.push({label:Q(`@WORKBENCH:Git 状态`),value:Q(`@WORKBENCH:不是 Git 仓库`),tone:``}),t)}),get $t(){return Q},get Paperclip(){return D},get Promotion(){return j},get Expand(){return ae},get Fold(){return Se},get Setting(){return v},get Refresh(){return p},get clockFromIso(){return wi},get formatDurationMs(){return Si},get relativeTimeFromIso(){return xi},get REPORT_INTERVAL_OPTIONS_MS(){return si},get REPORT_PERCENT_HINT_KEY(){return hi},get REPORT_PERCENT_LABEL_KEY(){return mi},get reportIntervalLabelKey(){return ui},get reportIntervalLabelParams(){return di},AttachmentZone:bt,AgentChatSurface:Gs,TaskExecutorPicker:As};return Object.defineProperty(Ee,"__isScriptSetup",{enumerable:!1,value:!0}),Ee}});t(),l(),V();var Qs=[`title`,`aria-label`],$s={class:`oc__rail-text`},ec={class:`oc__head`},tc={class:`oc__title`},nc=[`disabled`,`title`],rc=[`title`,`aria-label`],ic={class:`oc__state-label`},ac={class:`oc__state-value`},oc={class:`oc__state-meta`},sc=[`aria-label`],cc=[`aria-selected`],lc=[`aria-selected`],uc={class:`oc__report`},dc={class:`oc__report-head`},fc={class:`oc__panel-title`},pc=[`value`,`title`,`aria-label`],mc=[`value`],hc=[`disabled`,`title`],gc={class:`oc__report-list`},_c={key:0,class:`rp`},vc={class:`rp__head`},yc={class:`rp__count`},bc={class:`rp__time`},xc=[`title`],Sc=[`aria-valuenow`,`aria-label`],Cc={class:`rp__percent`},wc={class:`rp__percent-tag`},Tc={key:1,class:`rp__body`},Ec=[`title`],Dc={key:3,class:`rp__facts`},Oc=[`title`],kc={class:`rp__tasks`},Ac={class:`rpt__title`},jc={class:`rpt__meta`},Mc={key:0,class:`rpt__project`},Nc={key:1,class:`rpt__agent`},Pc=[`title`],Fc={key:3,class:`rpt__silent`},Ic=[`title`],Lc=[`aria-valuenow`,`aria-label`],Rc={class:`rpt__percent`},zc=[`title`],Bc={class:`rpt__tag`},Vc=[`title`],Hc={class:`rpt__tag`},Uc=[`title`],Wc={class:`rpt__tag`},Gc={key:1,class:`oc-empty`},Kc={key:0,class:`oc__history`},qc={class:`oc__history-title`},Jc={class:`oc__history-list`},Yc=[`onClick`],Xc={class:`oc__history-time`},Zc={class:`oc__history-pct`},Qc={class:`oc__history-sum`},$c={class:`oc__git`},el={class:`oc__panel-title`},tl={class:`oc__git-name`},nl={class:`oc__git-list`},rl={class:`oc__git-label`},il={class:`oc__git-label`},al={class:`oc__git-value`},ol={class:`oc__git-label`},sl={class:`oc__git-value`},cl=[`placeholder`],ll={key:0},ul={key:1},dl={class:`oc__compose-foot`},fl=[`disabled`,`title`,`aria-label`],pl=[`title`,`aria-label`],ml=[`title`],hl=[`title`],gl=[`disabled`],_l={class:`oc__hint`};function vl(t,n,r,i,s,c){let l=g;return P(),W(`aside`,{class:_([`oc`,{"is-collapsed":r.collapsed}])},[T(` 折叠后的收纳条:只剩一枚展开按钮 + 竖排标题,宽度收到 32px。
|
|
169
|
+
折叠不是"把宽度压成 0"—— 那样就再没有能点回来的地方了。 `),r.collapsed?(P(),W(`button`,{key:0,type:`button`,class:`oc__rail`,title:i.$t(`@WORKBENCH:展开主 Agent 控制台`),"aria-label":i.$t(`@WORKBENCH:展开主 Agent 控制台`),"aria-expanded":!1,onClick:n[0]||=e=>i.emit(`toggle-collapse`)},[E(l,{class:`oc__rail-icon`},{default:z(()=>[E(i.Fold)]),_:1}),o(`span`,{class:_([`oc__rail-live`,{"is-off":!r.active}]),"aria-hidden":`true`},null,2),o(`span`,$s,U(i.$t(`@WORKBENCH:主 Agent 控制台`)),1)],8,Qs)):T(`v-if`,!0),T(` 折叠时这几块整体隐藏而不是销毁(v-show 而不是 v-if):
|
|
170
|
+
草稿指令和已贴的附件都还留着,展开回来能接着发 `),G(o(`header`,ec,[o(`span`,{class:_([`oc__live`,{"is-off":!r.active}]),"aria-hidden":`true`},null,2),o(`h3`,tc,U(i.$t(`@WORKBENCH:主 Agent 控制台`)),1),o(`button`,{type:`button`,class:`oc__toggle`,disabled:r.togglingSchedule,title:r.active?i.$t(`@WORKBENCH:暂停后派发只建任务,不会自动执行`):i.$t(`@WORKBENCH:恢复后派发会自动执行`),onClick:n[1]||=e=>i.emit(`toggle-schedule`,!r.active)},U(r.active?i.$t(`@WORKBENCH:暂停调度`):i.$t(`@WORKBENCH:恢复调度`)),9,nc),o(`button`,{type:`button`,class:`oc__collapse`,title:i.$t(`@WORKBENCH:收起主 Agent 控制台`),"aria-label":i.$t(`@WORKBENCH:收起主 Agent 控制台`),"aria-expanded":!0,onClick:n[2]||=e=>i.emit(`toggle-collapse`)},[E(l,null,{default:z(()=>[E(i.Expand)]),_:1})],8,rc)],512),[[Y,!r.collapsed]]),G(o(`div`,{class:_([`oc__state`,{"is-paused":!r.active}])},[o(`span`,ic,U(i.$t(`@WORKBENCH:调度状态`)),1),o(`span`,ac,U(r.active?i.$t(`@WORKBENCH:调度中`):i.$t(`@WORKBENCH:已暂停`)),1),o(`span`,oc,U(i.$t(`@WORKBENCH:{n} 个执行中`,{n:r.runningCount})),1)],2),[[Y,!r.collapsed]]),T(` 工作方式:对话 = g ai 边聊边派(可以多轮、可以反问你);指令 = 你自己敲一句话派一条。
|
|
171
|
+
两种方式落到的是**同一条派发链路、同一条指令流水**,变的只是"谁决定派什么"。 `),G(o(`div`,{class:`oc__mode`,role:`tablist`,"aria-label":i.$t(`@WORKBENCH:切换主 Agent 控制台的工作方式`)},[o(`button`,{type:`button`,role:`tab`,class:_([`oc__mode-btn`,{"is-active":i.mode===`chat`}]),"aria-selected":i.mode===`chat`,onClick:n[3]||=e=>i.setMode(`chat`)},U(i.$t(`@WORKBENCH:对话`)),11,cc),o(`button`,{type:`button`,role:`tab`,class:_([`oc__mode-btn`,{"is-active":i.mode===`command`}]),"aria-selected":i.mode===`command`,onClick:n[4]||=e=>i.setMode(`command`)},U(i.$t(`@WORKBENCH:指令`)),11,lc)],8,sc),[[Y,!r.collapsed]]),G(E(i.AgentChatSurface,{class:`oc__chat`,active:!r.collapsed&&i.mode===`chat`,"allow-dispatch":``,"dispatch-use-default-prompt":i.useDefaultPrompt,title:i.$t(`@WORKBENCH:g ai 对话`)},null,8,[`active`,`dispatch-use-default-prompt`,`title`]),[[Y,!r.collapsed&&i.mode===`chat`]]),T(` 进度报告:主 Agent 隔一会儿读一遍正在跑的 job,写一段"现在到哪一步了"。
|
|
172
|
+
报告由服务端生成(自动那份由服务端定时器产生),这里只渲染 + 两个入口:
|
|
173
|
+
改间隔、立即报告。 `),G(o(`div`,uc,[o(`div`,dc,[o(`p`,fc,U(i.$t(`@WORKBENCH:进度报告`)),1),T(` 间隔设置。做成下拉而不是输入框:这个值直接决定每多久烧一次模型额度,
|
|
174
|
+
自由填一个 5(分钟写成了秒)会让额度很快见底,而用户不会立刻意识到 `),o(`select`,{class:`oc__interval`,value:String(r.reportIntervalMs??0),title:i.$t(`@WORKBENCH:自动报告的间隔(关掉后仍可随时点「立即报告」)`),"aria-label":i.$t(`@WORKBENCH:自动报告间隔`),onChange:i.onIntervalChange},[(P(!0),W(X,null,e(i.REPORT_INTERVAL_OPTIONS_MS,e=>(P(),W(`option`,{key:e,value:String(e)},U(i.$t(i.reportIntervalLabelKey(e),i.reportIntervalLabelParams(e))),9,mc))),128))],40,pc),o(`button`,{type:`button`,class:`oc__report-run`,disabled:r.generatingReport,title:i.$t(`@WORKBENCH:让主 Agent 现在汇报一次正在执行的任务进度`),onClick:n[5]||=e=>i.emit(`generate-report`)},[E(l,{class:_([`oc__report-run-icon`,{"is-spin":r.generatingReport}])},{default:z(()=>[E(i.Refresh)]),_:1},8,[`class`]),o(`span`,null,U(r.generatingReport?i.$t(`@WORKBENCH:生成中…`):i.$t(`@WORKBENCH:立即报告`)),1)],8,hc)]),o(`ul`,gc,[i.currentReport?(P(),W(`li`,_c,[o(`div`,vc,[o(`span`,{class:_([`rp__trigger`,{"is-auto":i.currentReport.trigger===`auto`}])},U(i.currentReport.trigger===`auto`?i.$t(`@WORKBENCH:自动`):i.$t(`@WORKBENCH:手动`)),3),o(`span`,yc,U(i.$t(`@WORKBENCH:{n} 个任务进行中`,{n:i.currentReport.tasks.length})),1),o(`span`,bc,U(i.clockFromIso(i.currentReport.at)),1)]),T(` 进度条:主 Agent 自己给的百分比(不是我们拿时长算的 —— 跑多久跟还剩多少活
|
|
175
|
+
没有固定关系)。它没给就不画这一行,见 currentPercent。
|
|
176
|
+
形状与左栏项目列表的进度条同一套(4px / pill / --gradient-progress),
|
|
177
|
+
两处的"进度"看起来得是一个东西 `),i.currentPercent===null?T(`v-if`,!0):(P(),W(`div`,{key:0,class:`rp__progress`,title:i.$t(i.REPORT_PERCENT_HINT_KEY)},[o(`span`,{class:`rp__bar`,role:`progressbar`,"aria-valuenow":i.currentPercent,"aria-valuemin":`0`,"aria-valuemax":`100`,"aria-label":i.$t(i.REPORT_PERCENT_LABEL_KEY)},[o(`i`,{class:`rp__bar-fill`,style:N({width:i.currentPercent+`%`})},null,4)],8,Sc),T(` 「AI 估计」四个字不能省:这个数字是模型看着思考与工具调用估的,
|
|
178
|
+
光甩一个 62% 会被当成实测值 `),o(`span`,Cc,[o(`span`,wc,U(i.$t(i.REPORT_PERCENT_LABEL_KEY)),1),w(U(i.currentPercent)+`% `,1)])],8,xc)),T(` 正文:主 Agent 写的**判断**。默认只露 6 行 —— 右栏只有 ~300px 宽,
|
|
179
|
+
模型那种"任务1…任务2…任务3…"连着几段的汇报不截一下会把下面三组
|
|
180
|
+
任务事实整个顶出视口,而事实才是扫得动的那部分。折起来时底下压一层
|
|
181
|
+
渐隐(不是硬切),配一个「展开全文」,不用拖滚动条去找结尾。 `),i.currentReport.text?(P(),W(`div`,Tc,[o(`p`,{ref:`textEl`,class:_([`rp__text`,{"is-clamped":i.textClamped&&!i.textExpanded,"is-expanded":i.textExpanded}])},U(i.currentReport.text),3),i.textClamped||i.textExpanded?(P(),W(`button`,{key:0,type:`button`,class:`rp__more`,onClick:i.toggleText},U(i.textExpanded?i.$t(`@WORKBENCH:收起`):i.$t(`@WORKBENCH:展开全文`)),1)):T(`v-if`,!0)])):(P(),W(X,{key:2},[T(` 没有正文时给的是**实话**:没任务 / 没配模型 / 模型没返回内容,
|
|
182
|
+
三种情况的处理办法完全不同,一律写"暂无"会让人白等 `),o(`p`,{class:`rp__notice`,title:i.currentReport.errorDetail},U(i.reportNotice(i.currentReport)),9,Ec)],2112)),T(` 事实区:给一个区块标题是为了把"判断"与"依据"分开 —— 上面那段是模型说的,
|
|
183
|
+
下面这几张卡是从正在跑的任务里抄出来的事实,两者对不上时用户得能一眼
|
|
184
|
+
看出是模型在编(见服务端 progressReport.js 的 buildReportPrompt)。 `),i.currentTasks.length?(P(),W(`div`,Dc,[o(`p`,{class:`rp__facts-cap`,title:i.$t(`@WORKBENCH:上面是主 Agent 的判断,下面这些是从正在跑的任务里抄出来的事实`)},U(i.$t(`@WORKBENCH:任务事实`)),9,Oc),o(`ul`,kc,[(P(!0),W(X,null,e(i.currentTasks,(e,t)=>(P(),W(`li`,{key:e.taskId||t,class:_([`rpt`,{"is-silent":typeof e.silentMs==`number`}])},[o(`p`,Ac,U(e.taskTitle||i.$t(`@WORKBENCH:未命名任务`)),1),o(`p`,jc,[e.projectName?(P(),W(`span`,Mc,U(e.projectName),1)):T(`v-if`,!0),o(`span`,null,U(i.$t(`@WORKBENCH:已运行 {elapsed}`,{elapsed:i.formatDurationMs(e.elapsedMs)})),1),e.agent?(P(),W(`span`,Nc,U(e.agent),1)):T(`v-if`,!0),T(` 次数看总数,鼠标停上去看**分布** —— 119 次里 118 次都是 Bash
|
|
185
|
+
和"改了三处代码",是完全不同的两件事,而一行放不下分布 `),e.toolCallCount?(P(),W(`span`,{key:2,title:e.toolMix||``},U(i.$t(`@WORKBENCH:工具 {n} 次`,{n:e.toolCallCount})),9,Pc)):T(`v-if`,!0),T(` 静默只在**显然静默**时才有值(服务端有阈值),所以这里不用再过滤 `),typeof e.silentMs==`number`?(P(),W(`span`,Fc,U(i.$t(`@WORKBENCH:静默 {elapsed}`,{elapsed:i.formatDurationMs(e.silentMs)})),1)):T(`v-if`,!0)]),T(` 每个任务自己的进度。整体那条说不清"是哪两个任务拖着的" —— 这一行就是
|
|
186
|
+
为它准备的。主 Agent 只给整体、没给单个时(老模型 / 判断不出来)整行不渲染 `),e.pct===null?T(`v-if`,!0):(P(),W(`p`,{key:0,class:`rpt__progress`,title:i.$t(i.REPORT_PERCENT_HINT_KEY)},[o(`span`,{class:`rpt__bar`,role:`progressbar`,"aria-valuenow":e.pct,"aria-valuemin":`0`,"aria-valuemax":`100`,"aria-label":e.taskTitle||i.$t(`@WORKBENCH:未命名任务`)},[o(`i`,{class:`rpt__bar-fill`,style:N({width:e.pct+`%`})},null,4)],8,Lc),o(`span`,Rc,U(e.pct)+`%`,1)],8,Ic)),T(` 证据按可靠程度排:工具调用(正在做什么)→ 思考(为什么)→ 正文。
|
|
187
|
+
思考这一行是 2026-09-29 补的:很多任务一句正文都不写,只靠工具调用
|
|
188
|
+
根本看不出它在干嘛,而它的思考当时就在库里。
|
|
189
|
+
三行都带标签:窄栏放得下,标签比左侧竖线更能让三行左对齐、一列扫下来
|
|
190
|
+
(看板卡片上没有标签是因为卡片更窄,见 WorkbenchKanban 的 kb-card__live-tag) `),e.lastTool?(P(),W(`p`,{key:1,class:`rpt__line is-tool`,title:e.lastTool},[o(`span`,Bc,U(i.$t(`@WORKBENCH:工具`)),1),w(U(e.lastTool),1)],8,zc)):T(`v-if`,!0),e.lastThought?(P(),W(`p`,{key:2,class:`rpt__line is-thought`,title:e.lastThought},[o(`span`,Hc,U(i.$t(`@WORKBENCH:最近思考`)),1),w(U(e.lastThought),1)],8,Vc)):T(`v-if`,!0),e.lastLine?(P(),W(`p`,{key:3,class:`rpt__line`,title:e.lastLine},[o(`span`,Wc,U(i.$t(`@WORKBENCH:最新回复`)),1),w(U(e.lastLine),1)],8,Uc)):T(`v-if`,!0)],2))),128))])])):T(`v-if`,!0)])):(P(),W(`li`,Gc,U(i.$t(`@WORKBENCH:暂无进度报告`)),1))]),T(` 历史:一行一份,点一条就把它换到上面看。只在有两份以上时出现 ——
|
|
191
|
+
只有一份时这个列表纯粹是噪音 `),(r.reports||[]).length>1?(P(),W(`div`,Kc,[o(`p`,qc,U(i.$t(`@WORKBENCH:历史报告`)),1),o(`ul`,Jc,[(P(!0),W(X,null,e(r.reports,e=>(P(),W(`li`,{key:e.id},[o(`button`,{type:`button`,class:_([`oc__history-item`,{"is-active":e.id===i.currentReport?.id}]),onClick:t=>i.pickReport(e)},[o(`span`,Xc,U(i.clockFromIso(e.at)),1),T(` 历史里也带上进度:一眼看出"这条是 20 分钟前那会儿 40%,现在 70%"。
|
|
192
|
+
没有进度的那几条这一格是空的但**占着位**(见 historyPct) `),o(`span`,Zc,U(i.historyPct(e)),1),o(`span`,Qc,U(i.reportBrief(e)),1)],10,Yc)]))),128))])])):T(`v-if`,!0)],512),[[Y,!r.collapsed&&i.mode===`command`]]),G(o(`div`,$c,[o(`p`,el,[w(U(i.$t(`@WORKBENCH:项目概览`))+` `,1),T(` 无选中项目即「全部项目」:显式标出来,否则底下只剩「今日完成」一行,看着像数据没加载出来 `),o(`span`,tl,U(r.selectedProject?r.selectedProject.name:i.$t(`@WORKBENCH:全部项目`)),1)]),o(`dl`,nl,[(P(!0),W(X,null,e(i.gitSummary,e=>(P(),W(X,{key:e.label},[o(`dt`,rl,U(e.label),1),o(`dd`,{class:_([`oc__git-value`,{"is-warn":e.tone===`warn`,"is-danger":e.tone===`danger`}])},U(e.value),3)],64))),128)),o(`dt`,il,U(i.$t(`@WORKBENCH:今日完成`)),1),o(`dd`,al,U(r.todayDone),1),o(`dt`,ol,U(i.$t(`@WORKBENCH:最后活跃`)),1),o(`dd`,sl,U(r.selectedProject&&i.relativeTimeFromIso(r.selectedProject.stats.lastActiveAt)||`—`),1)])],512),[[Y,!r.collapsed&&i.mode===`command`]]),G(o(`div`,{class:`oc__compose`,onPaste:i.onPaste,onDrop:L(i.onDrop,[`prevent`]),onDragover:n[13]||=L(e=>i.attachDragging=!0,[`prevent`]),onDragleave:n[14]||=e=>i.attachDragging=!1},[T(` 粘贴事件必须同时挂在 textarea 上:在输入框里按 Ctrl+V 时事件只到 textarea,
|
|
193
|
+
不会冒泡经过下面的附件区 `),G(o(`textarea`,{ref:`inputRef`,class:_([`oc__input`,{"is-over":i.overLimit}]),"onUpdate:modelValue":n[6]||=e=>i.draft=e,style:N(i.inputStyle),rows:`4`,placeholder:i.$t(`@WORKBENCH:给主 Agent 下一条指令,例如:把登录模块的错误处理重构一遍`),onKeydown:i.onInputKeydown,onPaste:i.onPaste,onMousedown:i.onInputMouseDown},null,46,cl),[[F,i.draft]]),i.draftAttachments.length>0||i.attachBusy?(P(),a(i.AttachmentZone,{key:0,attachments:i.draftAttachments,"is-image":i.isImageAttachment,"human-size":i.humanSize,"is-uploading":i.attachBusy,"is-paste-hover":i.attachDragging,"on-pick":i.onPickAttachment,"on-remove":i.onRemoveAttachment,"raw-base":i.DRAFT_RAW_BASE,onPaste:i.onPaste,onDrop:i.onDrop,onDragover:n[7]||=L(e=>i.attachDragging=!0,[`prevent`]),onDragenter:n[8]||=L(e=>i.attachDragging=!0,[`prevent`]),onDragleave:n[9]||=e=>i.attachDragging=!1},null,8,[`attachments`,`is-image`,`human-size`,`is-uploading`,`is-paste-hover`])):T(`v-if`,!0),T(`
|
|
194
|
+
字数:单独占输入框下方一行,不挤底部那一排按钮。
|
|
195
|
+
空草稿时不渲染("0 / 100000" 是噪音),接近上限转黄、超了转红 ——
|
|
196
|
+
目的是让"粘太长发不出去"在**点之前**看得见,而不是点完等服务端 400 才知道
|
|
197
|
+
(而超长恰恰是最容易失败的那一类,必须能改一改再发)。
|
|
198
|
+
`),i.draftChars>0?(P(),W(`p`,{key:1,class:_([`oc__count`,{"is-warn":i.nearLimit,"is-over":i.overLimit}])},[i.overLimit?(P(),W(`span`,ll,U(i.$t(`@WORKBENCH:超出上限 {max} 字,请精简后再派发(超出的部分不会被发出)`,{max:i.charLimit})),1)):(P(),W(`span`,ul,U(i.draftChars)+` / `+U(i.charLimit),1))],2)):T(`v-if`,!0),o(`div`,dl,[o(`button`,{type:`button`,class:`oc__attach`,disabled:i.attachBusy,title:i.$t(`@WORKBENCH:添加附件(也可直接粘贴或拖入文件)`),"aria-label":i.$t(`@WORKBENCH:添加附件`),onClick:i.onPickAttachment},[E(l,null,{default:z(()=>[E(i.Paperclip)]),_:1})],8,fl),T(` 默认提示词设置入口:图标按钮按项目惯例不加底色,
|
|
199
|
+
有没有设过看右侧"附加默认提示词"那个勾选(它是真实生效状态,这个只是入口) `),o(`button`,{type:`button`,class:_([`oc__attach`,{"is-on":i.anyPromptConfigured}]),title:i.$t(`@WORKBENCH:设置派发时自动附加的默认提示词(全局 / 各项目)`),"aria-label":i.$t(`@WORKBENCH:默认提示词设置`),onClick:n[10]||=e=>i.emit(`open-prompt-settings`)},[E(l,null,{default:z(()=>[E(i.Setting)]),_:1})],10,pl),o(`label`,{class:`oc__autorn`,title:i.$t(`@WORKBENCH:取消勾选则只建任务草稿,不自动执行`)},[G(o(`input`,{type:`checkbox`,"onUpdate:modelValue":n[11]||=e=>i.autoRun=e},null,512),[[de,i.autoRun]]),o(`span`,null,U(i.$t(`@WORKBENCH:立即执行`)),1)],8,ml),T(` 一条都没设过时不出现:一个永远勾着、点了也没区别的开关只会占地方 `),i.anyPromptConfigured?(P(),W(`label`,{key:0,class:`oc__autorn`,title:i.$t(`@WORKBENCH:取消勾选则本次派发的任务不带默认提示词(设置本身不受影响)`)},[G(o(`input`,{type:`checkbox`,"onUpdate:modelValue":n[12]||=e=>i.useDefaultPrompt=e},null,512),[[de,i.useDefaultPrompt]]),o(`span`,null,U(i.$t(`@WORKBENCH:默认提示词({state})`,{state:i.promptStateLabel})),1)],8,hl)):T(`v-if`,!0),T(` 执行器:与工作台执行按钮、看板「执行」共用同一份选择。
|
|
200
|
+
下拉本体收口在 TaskExecutorPicker(对话模式底下那个也是它),
|
|
201
|
+
它自己读 composable 的共享状态,这里不用再传 v-model `),E(i.TaskExecutorPicker,{title:i.$t(`@WORKBENCH:本次派发使用的执行器(与执行按钮的临时切换共用)`)},null,8,[`title`]),o(`button`,{type:`button`,class:`oc__send`,disabled:!i.canSend,onClick:i.send},[E(l,{class:`oc__send-icon`},{default:z(()=>[E(i.Promotion)]),_:1}),o(`span`,null,U(r.dispatching?i.$t(`@WORKBENCH:派发中…`):i.$t(`@WORKBENCH:派发`)),1)],8,gl)]),o(`p`,_l,[r.selectedProject?(P(),W(X,{key:0},[w(U(i.$t(`@WORKBENCH:指令会在「{name}」下新建一个任务;Enter 派发,Shift+Enter 换行`,{name:r.selectedProject.name})),1)],64)):(P(),W(X,{key:1},[w(U(i.$t(`@WORKBENCH:指令落到哪个项目由主 Agent 判断;Enter 派发,Shift+Enter 换行`)),1)],64))])],544),[[Y,!r.collapsed&&i.mode===`command`]])],2)}var yl=Ae(Zs,[[`render`,vl],[`__scopeId`,`data-v-4c030231`],[`__file`,`C:/workspace/github_workspace/xz333221/zen-gitsync/src/ui/client/src/views/components/OrchestratorConsole.vue`]]);t(),J();var bl=4e3,xl=h({__name:`WorkbenchDefaultPromptDialog`,props:{modelValue:{type:Boolean,required:!0},defaultPrompt:{type:String,required:!0},projectPath:{type:String,required:!0},projectName:{type:String,required:!0},projectPrompt:{type:String,required:!0},saving:{type:Boolean,required:!0}},emits:[`update:modelValue`,`save`],setup(e,{expose:t,emit:n}){t();let r=e,i=n,a=R(``),o=R(``);q(()=>r.modelValue,e=>{e&&(a.value=r.defaultPrompt||``,o.value=r.projectPrompt||``)});let s=k(()=>!!r.projectPath),c=k(()=>a.value.trim()!==(r.defaultPrompt||``).trim()||s.value&&o.value.trim()!==(r.projectPrompt||``).trim());function l(){r.saving||i(`save`,{globalPrompt:a.value,projectPrompt:o.value})}function u(){i(`update:modelValue`,!1)}let d={props:r,emit:i,MAX_CHARS:bl,globalDraft:a,projectDraft:o,hasProject:s,dirty:c,submit:l,close:u,get $t(){return Q},CommonDialog:Re};return Object.defineProperty(d,"__isScriptSetup",{enumerable:!1,value:!0}),d}});l(),t(),V();var Sl={class:`pd`},Cl={class:`pd__intro`},wl={class:`pd__field`},Tl={class:`pd__head`},El={class:`pd__label`,for:`pd-global`},Dl={class:`pd__count`},Ol=[`placeholder`],kl={class:`pd__field`},Al={class:`pd__head`},jl={class:`pd__label`,for:`pd-project`},Ml={key:0,class:`pd__count`},Nl=[`disabled`,`placeholder`],Pl={class:`pd__hint`},Fl={class:`pd__foot`},Il=[`disabled`];function Ll(e,t,n,r,i,s){return P(),a(r.CommonDialog,{"model-value":n.modelValue,title:r.$t(`@WORKBENCH:默认提示词`),width:`min(640px, 94vw)`,"close-on-click-modal":!1,"onUpdate:modelValue":t[2]||=e=>r.emit(`update:modelValue`,e)},{footer:z(()=>[o(`div`,Fl,[o(`button`,{type:`button`,class:`pd__btn`,onClick:r.close},U(r.$t(`@WORKBENCH:取消`)),1),t[3]||=o(`span`,{class:`pd__foot-spacer`},null,-1),o(`button`,{type:`button`,class:`pd__btn pd__btn--primary`,disabled:n.saving||!r.dirty,onClick:r.submit},U(n.saving?r.$t(`@WORKBENCH:保存中…`):r.$t(`@WORKBENCH:保存`)),9,Il)])]),default:z(()=>[o(`div`,Sl,[o(`p`,Cl,U(r.$t(`@WORKBENCH:派发指令时自动附加在指令之前,让每个任务都带上这些约束。只影响之后派发的任务,不会改动已经建好的任务。`)),1),o(`div`,wl,[o(`div`,Tl,[o(`label`,El,U(r.$t(`@WORKBENCH:全局默认提示词`)),1),o(`span`,Dl,U(r.globalDraft.length)+` / `+U(r.MAX_CHARS),1)]),G(o(`textarea`,{id:`pd-global`,"onUpdate:modelValue":t[0]||=e=>r.globalDraft=e,class:`pd__area`,rows:`5`,maxlength:r.MAX_CHARS,placeholder:r.$t(`@WORKBENCH:对所有项目生效。例如:回答用中文;改完代码必须跑一遍测试;不要动 dist 目录`)},null,8,Ol),[[F,r.globalDraft]])]),o(`div`,kl,[o(`div`,Al,[o(`label`,jl,U(r.hasProject?r.$t(`@WORKBENCH:「{name}」的项目提示词`,{name:n.projectName}):r.$t(`@WORKBENCH:项目提示词`)),1),r.hasProject?(P(),W(`span`,Ml,U(r.projectDraft.length)+` / `+U(r.MAX_CHARS),1)):T(`v-if`,!0)]),G(o(`textarea`,{id:`pd-project`,"onUpdate:modelValue":t[1]||=e=>r.projectDraft=e,class:`pd__area`,rows:`5`,maxlength:r.MAX_CHARS,disabled:!r.hasProject,placeholder:r.hasProject?r.$t(`@WORKBENCH:只在这个项目派发时附加。例如:包管理器用 pnpm;改动集中在 src/ui 下`):r.$t(`@WORKBENCH:先在左侧选中一个具体项目,才能设置它的提示词`)},null,8,Nl),[[F,r.projectDraft]]),o(`p`,Pl,U(r.hasProject?r.$t(`@WORKBENCH:项目提示词追加在全局提示词之后(不覆盖全局),派发到「{name}」时一起带上`,{name:n.projectName}):r.$t(`@WORKBENCH:选中的是「全部项目」,落点由主 Agent 判断 —— 想给某个项目单设提示词,先选中它`)),1)])])]),_:1},8,[`model-value`,`title`])}var Rl=Ae(xl,[[`render`,Ll],[`__scopeId`,`data-v-766f470f`],[`__file`,`C:/workspace/github_workspace/xz333221/zen-gitsync/src/ui/client/src/views/components/WorkbenchDefaultPromptDialog.vue`]]);t(),J();var zl=h({__name:`WorkbenchTaskCreateDialog`,props:{modelValue:{type:Boolean,required:!0},projects:{type:Array,required:!0},defaultProjectPath:{type:String,required:!0}},emits:[`update:modelValue`,`created`],setup(e,{expose:t,emit:n}){t();let r=e,i=n,a=R(``),o=R(``),s=R(``),c=R(!1),l=R(``);function u(e){let t=$(e);if(!t)return``;let n=r.projects.find(e=>$(e.path)===t);return n?n.path:``}q(()=>r.modelValue,e=>{e&&(a.value=``,o.value=``,s.value=u(r.defaultProjectPath),l.value=``,c.value=!1)});let d=k(()=>r.projects),f=k(()=>!c.value&&(a.value.trim().length>0||o.value.trim().length>0)),p=k(()=>{let e=$(s.value);if(!e)return``;let t=d.value.find(t=>$(t.path)===e);return t?t.name:``});async function m(e){if(f.value){c.value=!0,l.value=``;try{let t={title:a.value.trim(),desc:o.value,promptId:null,simpleOverride:``};s.value&&(t.projectPath=s.value);let n=await fetch(`/api/workbench/tasks`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(t)}).then(e=>e.json()).catch(()=>null);if(!n?.success){l.value=n?.error||Q(`@WORKBENCH:保存失败`);return}i(`update:modelValue`,!1),i(`created`,{task:n.task,openEditor:e})}finally{c.value=!1}}}let h={props:r,emit:i,title:a,desc:o,projectPath:s,submitting:c,error:l,matchOptionPath:u,projectOptions:d,canSubmit:f,projectName:p,submit:m,get $t(){return Q},CommonDialog:Re};return Object.defineProperty(h,"__isScriptSetup",{enumerable:!1,value:!0}),h}});l(),t(),V();var Bl={class:`nc`},Vl={class:`nc__field`},Hl={class:`nc__label`,for:`nc-project`},Ul={value:``},Wl=[`value`],Gl=[`title`],Kl={class:`nc__field`},ql={class:`nc__label`,for:`nc-title`},Jl=[`placeholder`],Yl={class:`nc__field`},Xl={class:`nc__label`,for:`nc-desc`},Zl=[`placeholder`],Ql={key:0,class:`nc__error`},$l={class:`nc__foot`},eu=[`disabled`],tu=[`disabled`];function nu(t,n,r,i,s,c){return P(),a(i.CommonDialog,{"model-value":r.modelValue,title:i.$t(`@WORKBENCH:新建开发任务`),width:`min(600px, 94vw)`,"close-on-click-modal":!1,"onUpdate:modelValue":n[9]||=e=>i.emit(`update:modelValue`,e)},{footer:z(()=>[o(`div`,$l,[o(`button`,{type:`button`,class:`nc__btn`,onClick:n[6]||=e=>i.emit(`update:modelValue`,!1)},U(i.$t(`@WORKBENCH:取消`)),1),n[10]||=o(`span`,{class:`nc__foot-spacer`},null,-1),o(`button`,{type:`button`,class:`nc__btn`,disabled:!i.canSubmit,onClick:n[7]||=e=>i.submit(!0)},U(i.$t(`@WORKBENCH:创建并打开编辑器`)),9,eu),o(`button`,{type:`button`,class:`nc__btn nc__btn--primary`,disabled:!i.canSubmit,onClick:n[8]||=e=>i.submit(!1)},U(i.submitting?i.$t(`@WORKBENCH:创建中…`):i.$t(`@WORKBENCH:创建`)),9,tu)])]),default:z(()=>[o(`div`,Bl,[o(`div`,Vl,[o(`label`,Hl,U(i.$t(`@WORKBENCH:项目`)),1),G(o(`select`,{id:`nc-project`,"onUpdate:modelValue":n[0]||=e=>i.projectPath=e,class:`nc__select`},[o(`option`,Ul,U(i.$t(`@WORKBENCH:跟随当前项目`)),1),(P(!0),W(X,null,e(i.projectOptions,e=>(P(),W(`option`,{key:e.key,value:e.path},U(e.name)+U(e.exists===!1?` · ${i.$t(`@WORKBENCH:目录不存在`)}`:``),9,Wl))),128))],512),[[ce,i.projectPath]]),o(`p`,{class:`nc__hint`,title:i.projectPath},U(i.projectName?i.$t(`@WORKBENCH:任务会在「{name}」目录下执行`,{name:i.projectName}):i.$t(`@WORKBENCH:任务会跟随应用当前的工作目录`)),9,Gl)]),o(`div`,Kl,[o(`label`,ql,U(i.$t(`@WORKBENCH:标题`)),1),G(o(`input`,{id:`nc-title`,"onUpdate:modelValue":n[1]||=e=>i.title=e,class:`nc__input`,type:`text`,maxlength:`200`,placeholder:i.$t(`@WORKBENCH:一句话说清要做什么`),onKeydown:n[2]||=Z(L(e=>i.submit(!1),[`prevent`]),[`enter`])},null,40,Jl),[[F,i.title]])]),o(`div`,Yl,[o(`label`,Xl,U(i.$t(`@WORKBENCH:描述`)),1),G(o(`textarea`,{id:`nc-desc`,"onUpdate:modelValue":n[3]||=e=>i.desc=e,class:`nc__input nc__input--area`,rows:`6`,placeholder:i.$t(`@WORKBENCH:把背景、验收标准、相关文件路径写进来,执行时用它当上下文`),onKeydown:[n[4]||=Z(L(e=>i.submit(!1),[`ctrl`,`prevent`]),[`enter`]),n[5]||=Z(L(e=>i.submit(!1),[`meta`,`prevent`]),[`enter`])]},null,40,Zl),[[F,i.desc]])]),i.error?(P(),W(`p`,Ql,U(i.error),1)):T(`v-if`,!0)])]),_:1},8,[`model-value`,`title`])}var ru=Ae(zl,[[`render`,nu],[`__scopeId`,`data-v-c60e660a`],[`__file`,`C:/workspace/github_workspace/xz333221/zen-gitsync/src/ui/client/src/views/components/WorkbenchTaskCreateDialog.vue`]]);t(),J();var iu=`wb.boardProject.v1`,au=5e3,ou=3e4,su=`wb.boardLayout.v1`,cu=180,lu=420,uu=260,du=900,fu=.26,pu=.46,mu=h({__name:`WorkbenchBoard`,props:{openedTaskId:{type:[String,null],required:!0}},emits:[`open-task`],setup(e,{expose:t,emit:n}){t();let r=e,i=n,{projects:a,boardTasks:o,currentProjectPath:s,loading:c,loadProjects:l,removeProject:u}=oi(),{active:d,activity:f,running:p,dispatching:m,togglingSchedule:h,maxInstructionChars:g,defaultPrompt:_,projectPrompts:v,reports:y,generatingReport:b,reportIntervalMs:x,loadOrchestrator:S,setSchedulingActive:C,dispatch:w,saveDefaultPrompt:T,saveProjectPrompt:E,loadReports:D,generateReport:O,setReportInterval:ee}=_i(),{active:A}=_r(),j=(()=>{try{return localStorage.getItem(iu)}catch{return null}})(),M=R(j||``);q(M,e=>{try{localStorage.setItem(iu,e)}catch{}});let te=k(()=>M.value&&a.value.find(e=>e.key===M.value)||null);q(a,e=>{M.value&&(e.some(e=>e.key===M.value)||(M.value=``))});let N=!1;function ne(){if(N||(N=!0,j!==null))return;let e=s.value?$(s.value):``;e&&a.value.some(t=>t.key===e)&&(M.value=e)}let ie=k(()=>{let e=new Map(a.value.map(e=>[e.key,e.name])),t={};for(let n of o.value)n.projectPath&&(t[n.projectPath]=e.get($(n.projectPath))||``);return t}),P=k(()=>{if(!M.value)return o.value;let e=M.value;return o.value.filter(t=>$(t.projectPath)===e)}),F=k(()=>{let e=new Date;e.setHours(0,0,0,0);let t=e.getTime();return{projects:a.value.length,tasks:o.value.length,running:p.value.length,todayDone:f.value.filter(e=>e.kind===`done`&&e.at&&new Date(e.at).getTime()>=t).length}});function oe(e){i(`open-task`,{taskId:e.id,projectPath:e.projectPath})}let se=null,L=!1,z=null;async function B(e=!0){if(!L){L=!0;try{await Promise.all([l(e),S(e)])}finally{L=!1}}}function V(){document.hidden||(B(!0),D(!0))}re(async()=>{window.addEventListener(`resize`,G),await B(!1),D(!0),ne(),se=setInterval(()=>{document.hidden||B(!0)},au),z=setInterval(()=>{document.hidden||D(!0)},ou),document.addEventListener(`visibilitychange`,V)}),he(()=>{window.removeEventListener(`resize`,G),se&&=(clearInterval(se),null),z&&=(clearInterval(z),null),document.removeEventListener(`visibilitychange`,V)});let H=ye({left:null,right:null,leftCollapsed:!1,rightCollapsed:!1});function U(){try{let e=localStorage.getItem(su);if(!e)return;let t=JSON.parse(e);typeof t.left==`number`&&Number.isFinite(t.left)&&(H.left=t.left),typeof t.right==`number`&&Number.isFinite(t.right)&&(H.right=t.right),H.leftCollapsed=t.leftCollapsed===!0,H.rightCollapsed=t.rightCollapsed===!0}catch{}}U();function ce(){try{localStorage.setItem(su,JSON.stringify(H))}catch{}}let W=R(typeof window>`u`?1920:window.innerWidth);function G(){W.value=window.innerWidth}let ue=k(()=>W.value<=1024),de=k(()=>W.value<=860);function K(e,t){let n=e===`left`?cu:uu,r=Math.min(e===`left`?lu:du,W.value*(e===`left`?fu:pu));return Math.round(Math.min(Math.max(t,n),Math.max(n,r)))}let fe=k(()=>{let e={};return H.left!=null&&(e[`--wb-left-w`]=K(`left`,H.left)+`px`),H.right!=null&&!de.value&&(e[`--wb-right-w`]=K(`right`,H.right)+`px`),e}),pe=R(null),J=R(null);function me(e){return pe.value?.querySelector(e===`left`?`.board__left`:`.oc`)}function ge(e){window.removeEventListener(`mousemove`,e),document.body.style.userSelect=``,document.body.style.cursor=``,J.value=null,ce()}function _e(e,t){if(e===`left`?ue.value:de.value)return;let n=me(e);if(!n)return;t.preventDefault();let r=t.clientX,i=n.getBoundingClientRect().width;J.value=e,document.body.style.userSelect=`none`,document.body.style.cursor=`col-resize`;let a=t=>{let n=(t.clientX-r)*(e===`left`?1:-1);H[e]=K(e,i+n)};window.addEventListener(`mousemove`,a),window.addEventListener(`mouseup`,()=>ge(a),{once:!0})}function ve(e){H[e]=null,ce()}let Y=R(!1),be=k(()=>ue.value?!Y.value:H.leftCollapsed);function X(){if(ue.value){Y.value=!Y.value;return}H.leftCollapsed=!H.leftCollapsed,ce()}function xe(){ue.value&&(Y.value=!1)}let Z=k(()=>H.rightCollapsed&&!de.value);function Ce(){H.rightCollapsed=!H.rightCollapsed,ce()}function we(e){M.value=e?e.key:``,Y.value=!1}let Te=R(!1);function Ee(){Te.value=!0}async function De(e){if(await B(!0),e.openEditor){i(`open-task`,{taskId:e.task.id,projectPath:e.task.projectPath||``});return}I.success(Q(`@WORKBENCH:已创建任务`))}async function Oe(e){if(e.runningJobs>0)return;let t=`/api/workbench/tasks/${encodeURIComponent(e.id)}/run`,n=await fetch(t,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({executor:A.value})}).then(e=>e.json()).catch(()=>null);if(!n?.success){I.error(n?.error||Q(`@WORKBENCH:执行失败`));return}I.success(Q(`@WORKBENCH:已开始执行`)),await B(!0)}let ke=new Set;async function Ae(e){if(ke.has(e.id))return;let t=e.live?.jobId;if(!t){I.error(Q(`@WORKBENCH:停止失败`));return}try{await le.confirm(Q(`@WORKBENCH:确认停止执行?已输出的内容会保留。`),Q(`@WORKBENCH:停止执行`),{confirmButtonText:Q(`@WORKBENCH:停止`),cancelButtonText:Q(`@WORKBENCH:取消`),type:`warning`})}catch{return}ke.add(e.id);try{let e=await fetch(`/api/workbench/jobs/${encodeURIComponent(t)}/cancel`,{method:`POST`}).then(e=>e.json()).catch(()=>null);if(!e?.success){I.error(e?.error||Q(`@WORKBENCH:停止失败`));return}I.success(Q(`@WORKBENCH:已发送停止信号`)),await B(!0)}finally{ke.delete(e.id)}}let je=new Set;async function Me(e){if(!je.has(e.id)){if(e.runningJobs>0)try{await le.confirm(Q(`@WORKBENCH:这条任务还在执行,标记完成会同时把它停掉。已输出的内容会保留。`),Q(`@WORKBENCH:标记为已完成`),{confirmButtonText:Q(`@WORKBENCH:标记完成`),cancelButtonText:Q(`@WORKBENCH:取消`),type:`warning`})}catch{return}je.add(e.id);try{let t=await fetch(`/api/workbench/tasks/${encodeURIComponent(e.id)}/done`,{method:`POST`}).then(e=>e.json()).catch(()=>null);if(!t?.success){I.error(t?.error||Q(`@WORKBENCH:标记失败`));return}I.success(Q(`@WORKBENCH:已标记为已完成`)),await B(!0)}finally{je.delete(e.id)}}}async function Ne(e){if(!je.has(e.id)){je.add(e.id);try{let t=await fetch(`/api/workbench/tasks/${encodeURIComponent(e.id)}/done`,{method:`DELETE`}).then(e=>e.json()).catch(()=>null);if(!t?.success){I.error(t?.error||Q(`@WORKBENCH:撤销失败`));return}I.success(Q(`@WORKBENCH:已撤销完成标记`)),await B(!0)}finally{je.delete(e.id)}}}async function Pe(e){let{ok:t,keptTasks:n}=await u(e.path);t&&(I.success(n>0?Q(`@WORKBENCH:已移除项目,{n} 条任务仍保留在「全部项目」下`,{n}):Q(`@WORKBENCH:已移除项目`)),await B(!0))}async function Fe(e){let t=(e.title||``).trim()||Q(`@WORKBENCH:未命名任务`);try{await le.confirm(Q(`@WORKBENCH:删除任务「{title}」?`,{title:t}),Q(`@WORKBENCH:确认`),{type:`warning`})}catch{return}let n=await fetch(`/api/workbench/tasks/${encodeURIComponent(e.id)}`,{method:`DELETE`}).then(e=>e.json()).catch(()=>null);if(n&&n.success===!1){I.error(n.error||Q(`@WORKBENCH:删除失败`));return}await B(!0)}let Ie=R(null),Le=k(()=>te.value?.path||s.value);async function Re(e){let t=await w({text:e.text,projectPath:e.projectPath,autoRun:e.autoRun,attachments:e.attachments,useDefaultPrompt:e.useDefaultPrompt,executor:e.executor});t&&(Ie.value?.clearAttachments(),Ie.value?.clearDraft(),I.success(t.ran?Q(`@WORKBENCH:已派发并开始执行`):Q(`@WORKBENCH:已派发(只建任务未执行)`)),await B(!0))}async function ze(e){await C(e)}let Be=R(!1),Ve=R(!1),He=k(()=>{let e=te.value?.key;return e&&v.value?.[e]?.prompt||``});async function Ue(e){if(Ve.value)return;let t=e.globalPrompt.trim(),n=e.projectPrompt.trim(),r=te.value;Ve.value=!0;try{let e=!0;t!==(_.value||``).trim()&&(e=await T(t)),e&&r&&n!==He.value.trim()&&(e=await E(r.path,n)),e&&(Be.value=!1)}finally{Ve.value=!1}}let We={props:r,emit:i,projects:a,boardTasks:o,currentProjectPath:s,loading:c,loadProjects:l,removeProject:u,active:d,activity:f,running:p,dispatching:m,togglingSchedule:h,maxInstructionChars:g,defaultPrompt:_,projectPrompts:v,reports:y,generatingReport:b,reportIntervalMs:x,loadOrchestrator:S,setSchedulingActive:C,dispatch:w,saveDefaultPrompt:T,saveProjectPrompt:E,loadReports:D,generateReport:O,setReportInterval:ee,boardExecutor:A,SELECTED_KEY:iu,savedSelection:j,selectedKey:M,selectedProject:te,get defaultSelectionApplied(){return N},set defaultSelectionApplied(e){N=e},applyDefaultSelection:ne,projectLabels:ie,visibleTasks:P,headerStats:F,onOpenTask:oe,POLL_MS:au,get pollTimer(){return se},set pollTimer(e){se=e},get inFlight(){return L},set inFlight(e){L=e},REPORT_POLL_MS:ou,get reportPollTimer(){return z},set reportPollTimer(e){z=e},refresh:B,onVisibilityChange:V,LAYOUT_KEY:su,LEFT_W_MIN:cu,LEFT_W_MAX:lu,RIGHT_W_MIN:uu,RIGHT_W_MAX:du,LEFT_W_SHARE:fu,RIGHT_W_SHARE:pu,layout:H,readLayout:U,saveLayout:ce,viewportW:W,onWindowResize:G,isNarrow:ue,isStacked:de,clampWidth:K,boardStyle:fe,colsRef:pe,dragging:J,panelEl:me,endDrag:ge,onSplitterMouseDown:_e,onSplitterDblClick:ve,leftDrawerOpen:Y,leftHidden:be,toggleLeft:X,onLeftEsc:xe,rightHidden:Z,toggleRight:Ce,onSelectProject:we,createOpen:Te,onCreateClick:Ee,onTaskCreated:De,runTask:Oe,stoppingTaskIds:ke,stopTask:Ae,completingTaskIds:je,completeTask:Me,reopenTask:Ne,onRemoveProject:Pe,deleteTask:Fe,consoleRef:Ie,defaultProjectPath:Le,onDispatch:Re,onToggleSchedule:ze,promptDialogOpen:Be,savingPrompt:Ve,selectedProjectPrompt:He,onSavePromptDraft:Ue,get $t(){return Q},get Fold(){return Se},get Expand(){return ae},WorkbenchProjectPanel:io,WorkbenchKanban:xs,OrchestratorConsole:yl,WorkbenchDefaultPromptDialog:Rl,WorkbenchTaskCreateDialog:ru};return Object.defineProperty(We,"__isScriptSetup",{enumerable:!1,value:!0}),We}});t(),l(),V();var hu={class:`board__top`},gu=[`title`,`aria-label`,`aria-expanded`],_u={class:`board__brand`},vu={class:`board__brand-text`},yu={class:`board__title`},bu={class:`board__subtitle`},xu={class:`board__stats`},Su={class:`board__stat`},Cu={class:`board__stat-label`},wu={class:`board__stat-value`},Tu={class:`board__stat`},Eu={class:`board__stat-label`},Du={class:`board__stat-value`},Ou={class:`board__stat`},ku={class:`board__stat-label`},Au={class:`board__stat`},ju={class:`board__stat-label`},Mu={class:`board__stat-value`},Nu=[`title`],Pu={class:`board__main`},Fu={class:`board__main-head`},Iu={class:`board__main-title`},Lu={class:`board__project-name`},Ru=[`title`],zu={key:1,class:`board__project-path`},Bu={key:0,class:`board__project-meta`},Vu=[`title`];function Hu(e,t,n,r,i,s){let c=g;return P(),W(`div`,{class:`board`,style:N(r.boardStyle)},[o(`header`,hu,[T(` 左栏的开合。宽屏=收起/展开常驻那一栏;窄屏=抽屉 `),o(`button`,{type:`button`,class:_([`board__icon-btn board__fold-btn`,{"is-on":!r.leftHidden}]),title:r.leftHidden?r.$t(`@WORKBENCH:展开项目列表`):r.$t(`@WORKBENCH:收起项目列表`),"aria-label":r.leftHidden?r.$t(`@WORKBENCH:展开项目列表`):r.$t(`@WORKBENCH:收起项目列表`),"aria-expanded":!r.leftHidden,onClick:r.toggleLeft},[r.leftHidden?(P(),a(c,{key:1},{default:z(()=>[E(r.Expand)]),_:1})):(P(),a(c,{key:0},{default:z(()=>[E(r.Fold)]),_:1}))],10,gu),o(`div`,_u,[o(`span`,{class:_([`board__live`,{"is-off":!r.active}]),"aria-hidden":`true`},null,2),o(`div`,vu,[o(`h1`,yu,U(r.$t(`@WORKBENCH:多项目编排台`)),1),o(`p`,bu,U(r.active?r.$t(`@WORKBENCH:主 Agent 调度中`):r.$t(`@WORKBENCH:主 Agent 已暂停`)),1)])]),o(`div`,xu,[o(`span`,Su,[o(`span`,Cu,U(r.$t(`@WORKBENCH:项目`)),1),o(`strong`,wu,U(r.headerStats.projects),1)]),o(`span`,Tu,[o(`span`,Eu,U(r.$t(`@WORKBENCH:任务`)),1),o(`strong`,Du,U(r.headerStats.tasks),1)]),o(`span`,Ou,[o(`span`,ku,U(r.$t(`@WORKBENCH:活跃执行`)),1),o(`strong`,{class:_([`board__stat-value`,{"is-live":r.headerStats.running>0}])},U(r.headerStats.running),3)]),o(`span`,Au,[o(`span`,ju,U(r.$t(`@WORKBENCH:今日完成`)),1),o(`strong`,Mu,U(r.headerStats.todayDone),1)])])]),o(`div`,{ref:`colsRef`,class:_([`board__cols`,{"is-resizing":r.dragging!==null}])},[T(` 抽屉打开时的点击捕获层:点空白处收起。
|
|
202
|
+
只在窄屏 + 打开时才 display:block(见媒体查询),宽屏下是个不占位的空 div。
|
|
203
|
+
不加遮罩底色而是全透明 —— 只是为了接住点击,不是为了压暗看板;
|
|
204
|
+
真要压暗就得处理深色主题下半透明背景叠不实的老问题(见 NOTES §2)。 `),o(`div`,{class:_([`board__scrim`,{"is-on":r.leftDrawerOpen}]),"aria-hidden":`true`,onClick:t[0]||=e=>r.leftDrawerOpen=!1},null,2),o(`aside`,{class:_([`board__left`,{"is-collapsed":r.leftHidden}]),onKeydown:Z(r.onLeftEsc,[`esc`])},[E(r.WorkbenchProjectPanel,{projects:r.projects,"selected-key":r.selectedKey,loading:r.loading,onSelect:r.onSelectProject,onRemove:r.onRemoveProject},null,8,[`projects`,`selected-key`,`loading`])],34),T(` 左栏分隔条:左栏收起 / 窄屏抽屉模式下不占位(不渲染 / 媒体查询里 display:none) `),r.leftHidden?T(`v-if`,!0):(P(),W(`div`,{key:0,class:`board__splitter board__splitter--left`,role:`separator`,"aria-orientation":`vertical`,title:r.$t(`@WORKBENCH:拖动调整项目列表宽度,双击恢复默认`),onMousedown:t[1]||=e=>r.onSplitterMouseDown(`left`,e),onDblclick:t[2]||=e=>r.onSplitterDblClick(`left`)},null,40,Nu)),o(`main`,Pu,[o(`div`,Fu,[o(`div`,Iu,[o(`h2`,Lu,U(r.selectedProject?r.selectedProject.name:r.$t(`@WORKBENCH:全部项目`)),1),r.selectedProject?(P(),W(`span`,{key:0,class:`board__project-path`,title:r.selectedProject.path},U(r.selectedProject.path),9,Ru)):(P(),W(`span`,zu,U(r.$t(`@WORKBENCH:共 {n} 个项目的任务`,{n:r.projects.length})),1))]),r.selectedProject?(P(),W(`span`,Bu,U(r.$t(`@WORKBENCH:{done}/{total} 任务完成`,{done:r.selectedProject.stats.done,total:r.selectedProject.stats.total})),1)):T(`v-if`,!0)]),E(r.WorkbenchKanban,{tasks:r.visibleTasks,"project-labels":r.projectLabels,"show-project-label":!r.selectedProject,"opened-task-id":r.props.openedTaskId,onOpenTask:r.onOpenTask,onRunTask:r.runTask,onStopTask:r.stopTask,onCompleteTask:r.completeTask,onReopenTask:r.reopenTask,onDeleteTask:r.deleteTask,onCreateTask:r.onCreateClick},null,8,[`tasks`,`project-labels`,`show-project-label`,`opened-task-id`])]),T(` 右栏分隔条:右栏收起 / 竖排(≤860)时不占位 `),!r.rightHidden&&!r.isStacked?(P(),W(`div`,{key:1,class:`board__splitter board__splitter--right`,role:`separator`,"aria-orientation":`vertical`,title:r.$t(`@WORKBENCH:拖动调整主 Agent 控制台宽度,双击恢复默认`),onMousedown:t[3]||=e=>r.onSplitterMouseDown(`right`,e),onDblclick:t[4]||=e=>r.onSplitterDblClick(`right`)},null,40,Vu)):T(`v-if`,!0),E(r.OrchestratorConsole,{ref:`consoleRef`,active:r.active,"running-count":r.running.length,"selected-project":r.selectedProject,dispatching:r.dispatching,"toggling-schedule":r.togglingSchedule,"today-done":r.headerStats.todayDone,collapsed:r.rightHidden,"default-prompt":r.defaultPrompt,"project-prompts":r.projectPrompts,reports:r.reports,"report-interval-ms":r.reportIntervalMs,"generating-report":r.generatingReport,"max-instruction-chars":r.maxInstructionChars,onToggleCollapse:r.toggleRight,onToggleSchedule:r.onToggleSchedule,onDispatch:r.onDispatch,onGenerateReport:r.generateReport,onSetReportInterval:r.setReportInterval,onOpenPromptSettings:t[5]||=e=>r.promptDialogOpen=!0},null,8,[`active`,`running-count`,`selected-project`,`dispatching`,`toggling-schedule`,`today-done`,`collapsed`,`default-prompt`,`project-prompts`,`reports`,`report-interval-ms`,`generating-report`,`max-instruction-chars`,`onGenerateReport`,`onSetReportInterval`])],2),T(` 派发默认提示词:全局一条 + 选中项目一条,写完即生效于之后的派发 `),E(r.WorkbenchDefaultPromptDialog,{modelValue:r.promptDialogOpen,"onUpdate:modelValue":t[6]||=e=>r.promptDialogOpen=e,"default-prompt":r.defaultPrompt,"project-path":r.selectedProject?.path||``,"project-name":r.selectedProject?.name||``,"project-prompt":r.selectedProjectPrompt,saving:r.savingPrompt,onSave:r.onSavePromptDraft},null,8,[`modelValue`,`default-prompt`,`project-path`,`project-name`,`project-prompt`,`saving`]),T(` 新建任务:弹窗里问清字段,建完就关 `),E(r.WorkbenchTaskCreateDialog,{modelValue:r.createOpen,"onUpdate:modelValue":t[7]||=e=>r.createOpen=e,projects:r.projects,"default-project-path":r.defaultProjectPath,onCreated:r.onTaskCreated},null,8,[`modelValue`,`projects`,`default-project-path`])],4)}var Uu=Ae(mu,[[`render`,Hu],[`__scopeId`,`data-v-dd2dc7b4`],[`__file`,`C:/workspace/github_workspace/xz333221/zen-gitsync/src/ui/client/src/views/components/WorkbenchBoard.vue`]]);t(),J();var Wu=`wb.lastTaskByProject.v1`,Gu=`__no_project__`,Ku=`wb.sidebarWidth.v1`,qu=200,Ju=480,Yu=268,Xu=3e3,Zu=52,Qu=320,$u=500,ed=h({__name:`WorkbenchView`,setup(e,{expose:t}){t();let n=Fe(),r=Ie(),i=R((()=>{try{let e=parseInt(localStorage.getItem(Ku)||``,10);return Number.isFinite(e)?Math.min(Ju,Math.max(qu,e)):Yu}catch{return Yu}})());function a(e){e.preventDefault();let t=e.clientX,n=i.value;document.body.style.userSelect=`none`,document.body.style.cursor=`col-resize`;let r=e=>{i.value=Math.min(Ju,Math.max(qu,n+e.clientX-t))};window.addEventListener(`mousemove`,r),window.addEventListener(`mouseup`,()=>{window.removeEventListener(`mousemove`,r),document.body.style.userSelect=``,document.body.style.cursor=``;try{localStorage.setItem(Ku,String(i.value))}catch{}},{once:!0})}function o(e){i.value=Math.min(Ju,Math.max(qu,i.value+e));try{localStorage.setItem(Ku,String(i.value))}catch{}}function s(){try{let e=localStorage.getItem(Wu),t=e?JSON.parse(e):{};return t&&typeof t==`object`&&!Array.isArray(t)?t:{}}catch{return{}}}function c(e){try{localStorage.setItem(Wu,JSON.stringify(e))}catch{}}function l(e,t){let n=s();n[e||Gu]=t,c(n)}let u=R(!1);function d(){u.value=!1}let f=R(null);async function p(e){await T(),A.value=e.taskId,f.value=e.taskId,F(),j.value&&l($(_.value.path),e.taskId),u.value=!0}let{prompts:m,tasks:h,jobs:g,currentProject:_,syncRunningCount:v,connectSSE:y,disconnectSSE:b,loadPrompts:x,loadCurrentProject:S,loadJobs:C,clearJobsByTask:w,loadTasks:T}=vr();function E(){let e=$(_.value.path),t=h.value.filter(t=>!t.projectPath||$(t.projectPath)===e),n=s(),r=e&&n[e]||!e&&n[Gu]||``,i=r?h.value.find(e=>e.id===r):null,a=t[0]||h.value[0]||null,o=i&&i.projectPath&&$(i.projectPath)!==e?null:i?i.id:a?a.id:null;A.value=o,F()}async function D(){let e=A.value;if(await T(),e&&h.value.some(t=>t.id===e)){F();return}E()}async function O(){await T(),E()}let ee=R(!1),A=R(null),j=k(()=>h.value.find(e=>e.id===A.value)||null),N=k(()=>{let e=j.value?.projectPath||``;return!e||$(e)===$(_.value.path)?null:{name:e.replace(/[\\/]+$/,``).split(/[\\/]/).pop()||e,path:e}}),P=R({title:``,desc:``,promptId:null,simpleOverride:``});function F(){j.value?P.value={title:j.value.title,desc:j.value.desc,promptId:j.value.promptId,simpleOverride:j.value.simpleOverride||``}:P.value={title:``,desc:``,promptId:null,simpleOverride:``}}let ae=R(`idle`),se=R(0),L=null,z=k(()=>{if(!j.value)return!1;let e=j.value;return P.value.title!==e.title||P.value.desc!==e.desc||P.value.promptId!==e.promptId||P.value.simpleOverride!==(e.simpleOverride||``)});function V(){L!==null&&(clearTimeout(L),L=null)}function H(e){return!(!e||(e.title||``).trim()||(e.desc||``).trim()||e.promptId||(e.simpleOverride||``).trim()||Array.isArray(e.attachments)&&e.attachments.length>0)}async function U(e){try{await fetch(`/api/workbench/tasks/${e.id}`,{method:`DELETE`})}catch{}let t=h.value.findIndex(t=>t.id===e.id);t!==-1&&h.value.splice(t,1)}async function ce(){let e=h.value.filter(e=>e.id!==A.value&&H(e));for(let t of e)await U(t)}async function W(){if(!j.value)return!1;if(!z.value)return!0;if(ae.value=`saving`,await dt(!1))return se.value=Date.now(),ae.value=`saved`,setTimeout(()=>{ae.value===`saved`&&Date.now()-se.value>=4e3&&(ae.value=`idle`)},4e3),!0;ae.value=`error`;let e=Date.now();return setTimeout(()=>{ae.value===`error`&&Date.now()-e>=4e3&&(ae.value=`idle`)},4e3),!1}q(()=>j.value?{id:j.value.id,title:j.value.title,desc:j.value.desc,promptId:j.value.promptId,simpleOverride:j.value.simpleOverride||``}:null,(e,t)=>{e&&t&&e.id===t.id&&(L!==null&&clearTimeout(L),L=window.setTimeout(()=>{W()},1500))},{deep:!0}),q(A,async(e,t)=>{V(),j.value&&z.value&&await W()}),q(_,async e=>{if(!e.path)return;let t=$(e.path),n=j.value;n&&n.projectPath&&$(n.projectPath)!==t&&await O()});function G(e){try{let t=new Blob([JSON.stringify(e)],{type:`application/json`});navigator.sendBeacon?.(`/api/workbench/tasks`,t)}catch{}}function de(){j.value&&z.value&&!H(j.value)&&G(j.value)}let K=ye({visible:!1,editing:null,name:``,content:``,aiLoading:!1,projectPath:``}),fe=ye({visible:!1,text:``,loading:!1,saving:!1}),pe=R(!0),J=k(()=>{let e=$(_.value.path);return m.value.filter(t=>!t.projectPath||$(t.projectPath)===e)});async function ge(e){try{if(navigator.clipboard&&window.isSecureContext)return await navigator.clipboard.writeText(e),!0}catch{}try{let t=document.createElement(`textarea`);t.value=e,t.style.position=`fixed`,t.style.left=`-9999px`,document.body.appendChild(t),t.select();let n=document.execCommand(`copy`);return document.body.removeChild(t),n}catch{return!1}}let ve=R(null),Y=R(null);async function be(e){if(e){if(!await ge((e.title||``).trim()||Q(`@WORKBENCH:未命名任务`))){I.error(Q(`@WORKBENCH:复制失败`));return}ve.value=e.id,I.success(Q(`@WORKBENCH:已复制任务标题`)),window.setTimeout(()=>{ve.value===e.id&&(ve.value=null)},1500)}}async function X(e){if(!e)return;let t=(e.desc||``).trim();if(!t){I.warning(Q(`@WORKBENCH:任务描述为空,无需复制`));return}if(!await ge(t)){I.error(Q(`@WORKBENCH:复制失败`));return}Y.value=e.id,I.success(Q(`@WORKBENCH:已复制任务描述`)),window.setTimeout(()=>{Y.value===e.id&&(Y.value=null)},1500)}let{simpleConversationMessages:xe,simpleAllJobsFor:Z,simpleJobFor:Se,simpleJobState:Ce}=lr(g,j),we=R(null);function Ee(e){let t=(e?.projectPath||``).trim().replace(/[\\/]+$/,``);return t?t.split(/[\\/]/).pop()||t:_.value.name||``}async function De(e){if(!e)return;let t=hr(Z(e),{title:e.title,projectName:Ee(e)});if(!t){I.warning(Q(`@WORKBENCH:暂无执行内容可复制`));return}if(!await ge(t)){I.error(Q(`@WORKBENCH:复制失败`));return}we.value=e.id,I.success(Q(`@WORKBENCH:已复制执行内容`)),window.setTimeout(()=>{we.value===e.id&&(we.value=null)},1500)}let ke=[`wheel`,`touchstart`,`pointerdown`,`keydown`],Ae=R(null),je=R(null),Me=null,Le=null,ze=null;function Be(){if(Me&&=(Me.disconnect(),null),Le!==null&&(clearTimeout(Le),Le=null),ze){for(let e of ke)ze.removeEventListener(e,Be);ze=null}}function Ve(){Be();let e=Ae.value;if(!e)return;e.scrollToBottom?.(!1);let t=je.value?.querySelector(`.acu-message-list`);if(t&&typeof ResizeObserver<`u`){ze=t;for(let e of ke)t.addEventListener(e,Be,{passive:!0});Me=new ResizeObserver(()=>Ae.value?.scrollToBottom?.(!1)),Me.observe(t),t.firstElementChild&&Me.observe(t.firstElementChild),Le=setTimeout(Be,Xu)}}let He=k(()=>u.value&&j.value&&Z(j.value).length>0?j.value.id:``);q(He,async e=>{Be(),e&&(await M(),Ve())}),he(Be);function Ue(e){if(!e)return!1;let t=Se(e);return!!t&&(t.status===`running`||t.status===`pending`)}let We=k(()=>Z(j.value).length>0),Ge=k(()=>Ue(j.value)),Ke=k(()=>j.value?Ge.value?Q(`@WORKBENCH:正在执行中,请先「停止」再重新执行`):We.value?Q(`@WORKBENCH:重新跑一轮:上一轮的执行记录会被清空`):``:``);function Je(){K.editing=null,K.name=``,K.content=``,K.aiLoading=!1,K.projectPath=(_.value.path||``).trim(),K.visible=!0}function Ye(e){K.editing=e,K.name=e.name,K.content=e.content,K.aiLoading=!1,K.projectPath=(e.projectPath||``).trim(),K.visible=!0}async function Xe(){if(!K.aiLoading){K.aiLoading=!0;try{let e=await fetch(`/api/workbench/prompts/ai-generate`,{method:`POST`}).then(e=>e.json());e.success?(K.name=e.name||K.name,K.content=e.result||``,I.success(Q(`@WORKBENCH:已生成,可继续编辑`))):I.error(e.error||Q(`@WORKBENCH:生成失败`))}catch(e){I.error(Q(`@WORKBENCH:网络错误: `)+(e&&e.message||e))}finally{K.aiLoading=!1}}}async function Ze(){fe.visible=!0,fe.loading=!0;try{let e=await fetch(`/api/workbench/prompts/ai-instruction`).then(e=>e.json());e.success?fe.text=e.instruction||``:I.error(e.error||Q(`@WORKBENCH:读取指令失败`))}catch(e){I.error(Q(`@WORKBENCH:读取指令失败`)+`: `+(e&&e.message||e))}finally{fe.loading=!1}}async function Qe(){if(!fe.text.trim()){I.warning(Q(`@WORKBENCH:指令内容不能为空`));return}fe.saving=!0;try{let e=await fetch(`/api/workbench/prompts/ai-instruction`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify({instruction:fe.text})}).then(e=>e.json());e.success?(I.success(Q(`@WORKBENCH:已保存指令`)),fe.visible=!1):I.error(e.error||Q(`@WORKBENCH:保存失败`))}catch(e){I.error(Q(`@WORKBENCH:网络错误: `)+(e&&e.message||e))}finally{fe.saving=!1}}async function $e(){if(!K.name.trim()||!K.content.trim()){I.warning(Q(`@WORKBENCH:名称和内容不能为空`));return}let e={id:K.editing?.id,name:K.name.trim(),content:K.content,projectPath:(K.projectPath||``).trim()},t=await fetch(`/api/workbench/prompts`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(e)}).then(e=>e.json());t.success?(I.success(Q(`@WORKBENCH:已保存`)),K.visible=!1,x()):I.error(t.error||Q(`@WORKBENCH:保存失败`))}async function et(e){await le.confirm(Q(`@WORKBENCH:删除提示词「{name}」?`,{name:e.name}),Q(`@WORKBENCH:确认`),{type:`warning`}),await fetch(`/api/workbench/prompts/${e.id}`,{method:`DELETE`}),x();for(let t of h.value)t.promptId===e.id&&(t.promptId=null,await fetch(`/api/workbench/tasks`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(t)}));await D()}let tt=R(!1),nt=R(null),rt=R(null);function it(e){let t=e?.currentTarget||rt.value;if(!t)return;t.style.height=`auto`;let n=document.activeElement===t?$u:Qu,r=Math.min(Math.max(t.scrollHeight,Zu),n);t.style.height=`${r}px`,t.style.overflowY=t.scrollHeight>n?`auto`:`hidden`}q(pe,async e=>{e&&(await M(),it())}),q(()=>j.value?.id,async()=>{pe.value&&(await M(),it())});async function at(){if(tt.value)return;tt.value=!0;let e={title:``,desc:``,promptId:null,simpleOverride:``};_.value.path&&(e.projectPath=_.value.path);try{let t=await fetch(`/api/workbench/tasks`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(e)}).then(e=>e.json());if(!t.success){I.error(t.error||Q(`@WORKBENCH:保存失败`));return}V(),j.value&&H(j.value)?await U(j.value):j.value&&z.value&&await W(),await O(),t.task?.id&&(A.value=t.task.id,F(),I.success(Q(`@WORKBENCH:已新建任务`)),await M(),nt.value?.focus())}finally{tt.value=!1}}async function ot(e){await le.confirm(Q(`@WORKBENCH:删除任务「{title}」?`,{title:e.title}),Q(`@WORKBENCH:确认`),{type:`warning`}),await fetch(`/api/workbench/tasks/${e.id}`,{method:`DELETE`}),A.value===e.id&&(A.value=null),O()}async function st(e){let t=(e.title||Q(`@WORKBENCH:未命名任务`)).trim(),n={title:Q(`@WORKBENCH:{title} (副本)`,{title:t}),desc:e.desc||``,promptId:e.promptId||null,simpleOverride:e.simpleOverride||``};_.value.path&&(n.projectPath=_.value.path);try{let e=await fetch(`/api/workbench/tasks`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(n)}).then(e=>e.json());if(!e.success){I.error(e.error||Q(`@WORKBENCH:复制失败`));return}await O(),e.task?.id&&(A.value=e.task.id,F()),I.success(Q(`@WORKBENCH:已复制任务`))}catch(e){I.error(Q(`@WORKBENCH:网络错误: `)+(e&&e.message||e))}}async function ct(e){if(A.value===e.id)return;V();let t=j.value;t&&H(t)?await U(t):t&&z.value&&await W(),A.value=e.id,F(),l($(_.value.path),e.id)}async function lt(e){let{groupPath:t,orderedIds:n}=e;if(!Array.isArray(n)||n.length===0)return;let r=h.value.slice(),i=ut(h.value,t,n);if(i!==h.value){h.value=i;try{let e=await fetch(`/api/workbench/tasks/reorder`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify({orderedIds:n,groupPath:t})}).then(e=>e.json()).catch(()=>({success:!1,error:Q(`@WORKBENCH:排序保存失败`)}));e?.success||(h.value=r,I.error(e?.error||Q(`@WORKBENCH:排序保存失败`)))}catch(e){h.value=r,I.error(Q(`@WORKBENCH:排序保存失败`)+`: `+(e?.message||e))}}}function ut(e,t,n){let r=e=>$(e)||Gu,i=e.filter(e=>r(e.projectPath)===t).map(e=>e.id),a=new Set(i);if(n.length!==a.size||n.some(e=>!a.has(e)))return e;let o=new Map(e.map(e=>[e.id,e])),s=n.map(e=>o.get(e)).filter(Boolean),c=[],l=0;for(let n of e)r(n.projectPath)===t?c.push(s[l++]):c.push(n);return c}async function dt(e){if(!j.value)return!1;let t=await fetch(`/api/workbench/tasks`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(j.value)}).then(e=>e.json());return t.success?(e&&I.success(Q(`@WORKBENCH:已保存`)),await D(),!0):(I.error(t.error||Q(`@WORKBENCH:保存失败`)),!1)}re(async()=>{await Promise.all([x(),O(),S(),C()]),await ce(),y(),window.addEventListener(`beforeunload`,de),r.fetchExecutorModels()}),he(()=>{b(),window.removeEventListener(`beforeunload`,de),j.value&&z.value&&!H(j.value)&&G(j.value)});let{pasteHoverId:ft,isUploading:pt,isImageAttachment:mt,humanSize:ht,onAttachmentPaste:gt,onAttachmentDrop:_t,uploadAttachment:vt,removeAttachment:yt,pickAttachmentFile:xt}=or(),{runTask:St,onContinueSendFromChat:Ct,cancelJob:Tt,clearExecutionForSelectedTask:Et}=gr(g,h,j,{syncRunningCount:v,clearJobsByTask:w,persistTask:dt,uploadAttachment:vt,getExecutor:()=>Dt.value}),{active:Dt,availability:Ot,hasAnyExecutor:kt,choose:At,executorModelText:jt,executorModelTitle:Mt}=_r();function Nt(e){return Pe(e)}let Pt=k(()=>Z(j.value).slice(-1)[0]),Ft={configStore:n,toolsStore:r,LAST_TASK_BY_PROJECT_KEY:Wu,NO_PROJECT_KEY:Gu,SIDEBAR_WIDTH_KEY:Ku,SIDEBAR_MIN_W:qu,SIDEBAR_MAX_W:Ju,SIDEBAR_DEFAULT_W:Yu,sidebarWidth:i,onSidebarSplitterMouseDown:a,nudgeSidebarWidth:o,readLastTaskMap:s,writeLastTaskMap:c,rememberLastTask:l,editorOpen:u,closeEditor:d,boardOpenedTaskId:f,openTaskFromBoard:p,prompts:m,tasks:h,jobs:g,currentProject:_,syncRunningCount:v,connectSSE:y,disconnectSSE:b,loadPrompts:x,loadCurrentProject:S,loadJobs:C,clearJobsByTask:w,_loadDataTasks:T,applyRestoredSelection:E,refreshTasks:D,loadTasks:O,logsDialogVisible:ee,selectedTaskId:A,selectedTask:j,foreignRepo:N,metaSnapshot:P,captureSnapshot:F,metaSaveState:ae,metaSavedAt:se,get metaSaveTimer(){return L},set metaSaveTimer(e){L=e},metaDirty:z,clearMetaSaveTimers:V,isTaskBlank:H,discardBlankTask:U,pruneBlankTasks:ce,flushMetaSave:W,beaconPersist:G,onBeforeUnloadPersist:de,promptDialog:K,instructionDialog:fe,taskDescExpanded:pe,availablePrompts:J,copyToClipboard:ge,copyTitleFlashId:ve,copyDescFlashId:Y,copyTaskTitle:be,copyTaskDesc:X,simpleConversationMessages:xe,simpleAllJobsFor:Z,simpleJobFor:Se,simpleJobState:Ce,copyExecFlashId:we,taskRepoName:Ee,copyTaskExecution:De,CHAT_PIN_WINDOW_MS:Xu,CHAT_PIN_USER_EVENTS:ke,chatRef:Ae,chatWrapRef:je,get chatPinRO(){return Me},set chatPinRO(e){Me=e},get chatPinTimer(){return Le},set chatPinTimer(e){Le=e},get chatPinEl(){return ze},set chatPinEl(e){ze=e},stopChatPin:Be,pinChatToBottom:Ve,chatRenderKey:He,isTaskRunning:Ue,selectedTaskHasRun:We,selectedTaskRunning:Ge,runButtonTitle:Ke,openCreatePrompt:Je,openEditPrompt:Ye,aiGeneratePrompt:Xe,openEditInstruction:Ze,saveInstruction:Qe,savePrompt:$e,deletePrompt:et,creatingTask:tt,titleInputRef:nt,taskDescTextareaRef:rt,DESC_TEXTAREA_MIN_PX:Zu,DESC_TEXTAREA_MAX_PX:Qu,DESC_TEXTAREA_MAX_PX_FOCUS:$u,autoGrowTextarea:it,createTaskDirect:at,deleteTask:ot,copyTask:st,selectTask:ct,reorderTasks:lt,applyLocalReorder:ut,persistTask:dt,pasteHoverId:ft,isUploading:pt,isImageAttachment:mt,humanSize:ht,onAttachmentPaste:gt,onAttachmentDrop:_t,uploadAttachment:vt,removeAttachment:yt,pickAttachmentFile:xt,runTask:St,onContinueSendFromChat:Ct,cancelJob:Tt,clearExecutionForSelectedTask:Et,selectedTaskExecutor:Dt,executorAvailability:Ot,hasAnyExecutor:kt,pickExecutor:At,executorModelText:jt,executorModelTitle:Mt,executorLabel:Nt,lastSimpleJob:Pt,simpleAssistantLabel:k(()=>Pe(Pt.value?.agent)),simpleAssistantAvatar:k(()=>wt(Pt.value?.agent)),get $t(){return Q},get ArrowDown(){return ne},get ArrowLeft(){return te},get ArrowRight(){return ie},get Check(){return _e},get Document(){return me},get Delete(){return ue},get CopyDocument(){return B},get Warning(){return oe},AttachmentZone:bt,get ChatInput(){return Oe},get ChatContainer(){return Te},ExecutionLogManager:Yn,get ALLOWED_EXT_HINT(){return Zn},get MAX_ATTACHMENT_BYTES(){return Qn},get TASK_EXECUTOR_OPTIONS(){return Ne},TaskExecutorIcon:qe,WorkbenchSidebar:ai,WorkbenchBoard:Uu,CommonDialog:Re};return Object.defineProperty(Ft,"__isScriptSetup",{enumerable:!1,value:!0}),Ft}});t(),l(),V();var td={class:`workbench`},nd={class:`wb-editor`},rd={class:`wb-editor-bar`},id=[`title`],ad=[`title`],od=[`title`],sd={class:`wb-editor-bar__hint`},cd={class:`workbench__editor-row`},ld=[`aria-label`,`aria-valuenow`,`title`],ud={class:`wb-split`},dd={key:0,class:`wb-placeholder`},fd={class:`wb-split__header`},pd={class:`wb-split__title-wrap`},md=[`placeholder`,`aria-label`],hd=[`title`,`aria-label`],gd=[`title`],_d={key:0,class:`wb-meta-save__dot`},vd={key:1,class:`wb-meta-save__check`},yd={key:2,class:`wb-meta-save__bang`},bd={key:3,class:`wb-meta-save__dot`},xd=[`aria-label`],Sd={value:null},Cd=[`value`],wd=[`title`],Td={class:`wb-executor-item`},Ed={class:`wb-executor-item__name`},Dd=[`title`],Od={key:2,class:`wb-executor-item__missing`},kd={key:2,class:`wb-no-claude-hint`,role:`status`},Ad={class:`wb-no-claude-hint__text`},jd={class:`wb-no-claude-hint__link`,href:`https://docs.claude.com/en/docs/claude-code/setup`,target:`_blank`,rel:`noopener noreferrer`},Md=[`title`,`aria-label`],Nd=[`title`,`aria-label`],Pd=[`title`,`aria-label`],Fd=[`open`],Id={class:`wb-task-desc__summary`},Ld={class:`wb-task-desc__label`},Rd=[`title`,`aria-label`],zd={key:0,class:`wb-task-desc__tag`},Bd={key:0},Vd={key:1,class:`wb-task-desc__tag-attachment`},Hd=[`placeholder`,`aria-label`],Ud={class:`wb-execution-body`},Wd={class:`wb-exec-detail`},Gd={class:`wb-form-item__label wb-simple__override-summary`},Kd=[`title`],qd=[`placeholder`,`aria-label`],Jd={key:0,class:`wb-simple-chat-wrap`,ref:`chatWrapRef`},Yd={class:`wb-simple-chat`},Xd={key:0,class:`wb-simple-chat__footer`},Zd={style:{display:`flex`,gap:`8px`,"align-items":`center`}};function Qd(t,r,i,s,l,u){let f=g,p=n,h=be,v=O,b=A,x=y,S=c,C=m,D=Ce,ee=d;return P(),W(`div`,td,[T(` L1:多项目编排台 —— **常驻底图**,不再与编辑器互斥 `),E(s.WorkbenchBoard,{"opened-task-id":s.boardOpenedTaskId,onOpenTask:s.openTaskFromBoard},null,8,[`opened-task-id`]),T(` L2:单任务编辑器 —— 大弹窗浮在看板之上,关掉即回到原位,全程无跳转 `),E(s.CommonDialog,{modelValue:s.editorOpen,"onUpdate:modelValue":r[24]||=e=>s.editorOpen=e,title:s.$t(`@WORKBENCH:任务执行`),type:`flex`,"height-mode":`fixed`,"height-offset":`88px`,top:`2vh`,width:`min(1520px, 96vw)`},{default:z(()=>[o(`div`,nd,[T(` 顶部细栏:关闭入口做成独立一条,而不是塞进任务头 ——
|
|
205
|
+
没选中任务时(右侧是空态占位)也需要它,塞进任务头就会出现"进了编辑器却关不掉"的死角。 `),o(`div`,rd,[o(`button`,{type:`button`,class:`wb-back-btn`,title:s.$t(`@WORKBENCH:返回看板`),onClick:s.closeEditor},[E(f,{class:`wb-back-btn__icon`},{default:z(()=>[E(s.ArrowLeft)]),_:1}),o(`span`,null,U(s.$t(`@WORKBENCH:返回看板`)),1)],8,id),o(`span`,{class:`wb-editor-bar__project`,title:s.currentProject.path},U(s.currentProject.name),9,ad),s.foreignRepo?(P(),W(`span`,{key:0,class:`wb-editor-bar__repo`,title:s.foreignRepo.path},U(s.$t(`@WORKBENCH:执行于 {name}`,{name:s.foreignRepo.name})),9,od)):T(`v-if`,!0),o(`span`,sd,U(s.$t(`@WORKBENCH:任务执行`)),1)]),o(`div`,cd,[E(s.WorkbenchSidebar,{style:N({width:s.sidebarWidth+`px`}),tasks:s.tasks,prompts:s.prompts,"selected-task-id":s.selectedTaskId,"current-project":s.currentProject,"creating-task":s.creatingTask,"is-task-running":s.isTaskRunning,onSelectTask:s.selectTask,onDeleteTask:s.deleteTask,onCopyTask:s.copyTask,onCreateTask:s.createTaskDirect,onOpenCreatePrompt:s.openCreatePrompt,onOpenEditPrompt:s.openEditPrompt,onDeletePrompt:s.deletePrompt,onReorderTasks:s.reorderTasks},null,8,[`style`,`tasks`,`prompts`,`selected-task-id`,`current-project`,`creating-task`]),o(`div`,{class:`wb-splitter`,role:`separator`,tabindex:`0`,"aria-orientation":`vertical`,"aria-label":s.$t(`@WORKBENCH:拖动调整侧边栏宽度`),"aria-valuenow":s.sidebarWidth,"aria-valuemin":s.SIDEBAR_MIN_W,"aria-valuemax":s.SIDEBAR_MAX_W,title:s.$t(`@WORKBENCH:拖动调整侧边栏宽度`),onMousedown:s.onSidebarSplitterMouseDown,onKeydown:[r[0]||=Z(L(e=>s.nudgeSidebarWidth(-16),[`prevent`]),[`left`]),r[1]||=Z(L(e=>s.nudgeSidebarWidth(16),[`prevent`]),[`right`])]},null,40,ld),T(` 中:单任务编辑区 `),o(`section`,ud,[s.selectedTask?(P(),W(X,{key:1},[o(`div`,fd,[o(`div`,pd,[G(o(`input`,{ref:`titleInputRef`,class:`wb-input wb-input--title`,"onUpdate:modelValue":r[2]||=e=>s.selectedTask.title=e,placeholder:s.$t(`@WORKBENCH:任务标题`),"aria-label":s.$t(`@WORKBENCH:任务标题`)},null,8,md),[[F,s.selectedTask.title]]),o(`button`,{type:`button`,class:_([`wb-copy-btn`,{"is-flash":s.copyTitleFlashId===s.selectedTask.id}]),title:s.$t(`@WORKBENCH:复制任务标题`),"aria-label":s.$t(`@WORKBENCH:复制任务标题`),onClick:r[3]||=e=>s.copyTaskTitle(s.selectedTask)},[s.copyTitleFlashId===s.selectedTask.id?(P(),a(f,{key:1,class:`wb-copy-btn__icon wb-copy-btn__icon--check`},{default:z(()=>[...r[34]||=[w(`✓`,-1)]]),_:1})):(P(),a(f,{key:0,class:`wb-copy-btn__icon`},{default:z(()=>[E(s.CopyDocument)]),_:1}))],10,hd)]),s.metaSaveState!==`idle`||s.metaDirty?(P(),W(`span`,{key:0,class:_([`wb-meta-save`,{"is-saving":s.metaSaveState===`saving`,"is-saved":s.metaSaveState===`saved`,"is-error":s.metaSaveState===`error`,"is-dirty":s.metaDirty&&s.metaSaveState===`idle`}]),title:s.metaSaveState===`saving`?s.$t(`@WORKBENCH:保存中…`):s.metaSaveState===`error`?s.$t(`@WORKBENCH:保存失败`):s.metaSaveState===`saved`?s.$t(`@WORKBENCH:已保存`):``},[s.metaSaveState===`saving`?(P(),W(`span`,_d)):s.metaSaveState===`saved`?(P(),W(`span`,vd,`✓`)):s.metaSaveState===`error`?(P(),W(`span`,yd,`!`)):(P(),W(`span`,bd)),w(` `+U(s.metaSaveState===`saving`?s.$t(`@WORKBENCH:保存中…`):s.metaSaveState===`saved`?s.$t(`@WORKBENCH:已保存`):s.metaSaveState===`error`?s.$t(`@WORKBENCH:保存失败`):s.$t(`@WORKBENCH:有未保存的更改`)),1)],10,gd)):T(`v-if`,!0),G(o(`select`,{class:`wb-select`,"onUpdate:modelValue":r[4]||=e=>s.selectedTask.promptId=e,"aria-label":s.$t(`@WORKBENCH:预置提示词`)},[o(`option`,Sd,U(s.$t(`@WORKBENCH:不绑定预置提示词`)),1),(P(!0),W(X,null,e(s.availablePrompts,e=>(P(),W(`option`,{key:e.id,value:e.id},U(e.name),9,Cd))),128))],8,xd),[[ce,s.selectedTask.promptId]]),T(`
|
|
206
|
+
执行:split button —— 主体按当前选中执行器直接跑,下拉临时切换执行器。
|
|
207
|
+
文案随执行状态变(2026-10-01):这条任务已经有执行记录时改叫「重新执行任务」,
|
|
208
|
+
因为 runTask 会先清掉旧 job 再开新一轮 —— 挂着「执行任务」会让人以为是接着上一轮跑。
|
|
209
|
+
在跑的时候直接禁用:服务端本来就拒(400 该任务已有正在执行的 job),
|
|
210
|
+
点了只是白跑一趟,还想让人误以为新起了一轮。
|
|
211
|
+
`),s.hasAnyExecutor?(P(),a(v,{key:1,"split-button":``,type:`primary`,class:`wb-executor-split`,trigger:`click`,disabled:s.selectedTaskRunning,title:s.runButtonTitle,onClick:r[5]||=e=>s.runTask(s.selectedTask),onCommand:s.pickExecutor},{dropdown:z(()=>[E(h,null,{default:z(()=>[(P(!0),W(X,null,e(s.TASK_EXECUTOR_OPTIONS,e=>(P(),a(p,{key:e.id,command:e.id,disabled:!s.executorAvailability[e.id]},{default:z(()=>[o(`span`,Td,[E(s.TaskExecutorIcon,{executor:e.id,class:`wb-executor-item__icon`},null,8,[`executor`]),o(`span`,Ed,U(e.name),1),s.executorModelText(e.id)?(P(),W(`span`,{key:0,class:`wb-executor-item__model`,title:s.executorModelTitle(e.id)},U(s.executorModelText(e.id)),9,Dd)):T(`v-if`,!0),s.selectedTaskExecutor===e.id?(P(),a(f,{key:1,class:`wb-executor-item__check`},{default:z(()=>[E(s.Check)]),_:1})):s.executorAvailability[e.id]?T(`v-if`,!0):(P(),W(`span`,Od,U(s.$t(`@42BB9:未安装`)),1))])]),_:2},1032,[`command`,`disabled`]))),128))]),_:1})]),default:z(()=>[w(U(s.selectedTaskHasRun?s.$t(`@WORKBENCH:重新执行任务`):s.$t(`@WORKBENCH:执行任务`))+` `,1),o(`span`,{class:`wb-executor-split__hint`,title:s.executorModelTitle(s.selectedTaskExecutor)},[E(s.TaskExecutorIcon,{executor:s.selectedTaskExecutor,class:`wb-executor-split__hint-icon`},null,8,[`executor`]),w(` `+U(s.executorLabel(s.selectedTaskExecutor)),1)],8,wd)]),_:1},8,[`disabled`,`title`,`onCommand`])):(P(),W(`div`,kd,[E(f,{class:`wb-no-claude-hint__icon`},{default:z(()=>[E(s.Warning)]),_:1}),o(`span`,Ad,U(s.$t(`@WORKBENCH:未检测到本地 claude / opencode,无法执行任务`)),1),o(`a`,jd,U(s.$t(`@WORKBENCH:查看安装指引`)),1)])),T(` 一键复制执行内容:非破坏性动作,排在最前;「清空执行」这种危险动作留在后面 `),o(`button`,{type:`button`,class:_([`wb-logs-inline-btn wb-logs-inline-btn--copy`,{"is-flash":s.copyExecFlashId===s.selectedTask.id}]),title:s.$t(`@WORKBENCH:复制本任务的全部执行对话(提示词 / 思考 / 工具调用 / 模型返回)`),"aria-label":s.$t(`@WORKBENCH:复制执行内容`),onClick:r[6]||=e=>s.copyTaskExecution(s.selectedTask)},[s.copyExecFlashId===s.selectedTask.id?(P(),a(f,{key:1,class:`wb-logs-inline-btn__icon`},{default:z(()=>[...r[35]||=[w(`✓`,-1)]]),_:1})):(P(),a(f,{key:0,class:`wb-logs-inline-btn__icon`},{default:z(()=>[E(s.CopyDocument)]),_:1})),o(`span`,null,U(s.$t(`@WORKBENCH:复制执行内容`)),1)],10,Md),o(`button`,{type:`button`,class:`wb-logs-inline-btn wb-logs-inline-btn--danger`,title:s.$t(`@WORKBENCH:清空当前任务的所有执行内容`),"aria-label":s.$t(`@WORKBENCH:清空当前任务的所有执行内容`),onClick:r[7]||=(...e)=>s.clearExecutionForSelectedTask&&s.clearExecutionForSelectedTask(...e)},[E(f,{class:`wb-logs-inline-btn__icon`},{default:z(()=>[E(s.Delete)]),_:1}),o(`span`,null,U(s.$t(`@WORKBENCH:清空执行`)),1)],8,Nd),o(`button`,{type:`button`,class:`wb-logs-inline-btn`,title:s.$t(`@WORKBENCH:执行日志`),"aria-label":s.$t(`@WORKBENCH:执行日志`),onClick:r[8]||=e=>s.logsDialogVisible=!0},[E(f,{class:`wb-logs-inline-btn__icon`},{default:z(()=>[E(s.Document)]),_:1}),o(`span`,null,U(s.$t(`@WORKBENCH:执行日志`)),1)],8,Pd)]),T(` 任务描述区域:默认折叠,节省首屏空间;展开后可编辑/上传附件 `),o(`details`,{class:`wb-task-desc`,open:s.taskDescExpanded,onToggle:r[20]||=e=>s.taskDescExpanded=e.target.open},[o(`summary`,Id,[E(f,{class:`wb-task-desc__caret`},{default:z(()=>[(P(),a(K(s.taskDescExpanded?s.ArrowDown:s.ArrowRight)))]),_:1}),o(`span`,Ld,U(s.$t(`@WORKBENCH:任务描述(可选)`)),1),o(`button`,{type:`button`,class:_([`wb-copy-btn wb-copy-btn--inline`,{"is-flash":s.copyDescFlashId===s.selectedTask.id}]),title:s.selectedTask.desc&&s.selectedTask.desc.trim()?s.$t(`@WORKBENCH:复制任务描述`):s.$t(`@WORKBENCH:任务描述为空,无需复制`),"aria-label":s.$t(`@WORKBENCH:复制任务描述`),onClick:r[9]||=L(e=>s.copyTaskDesc(s.selectedTask),[`stop`,`prevent`])},[s.copyDescFlashId===s.selectedTask.id?(P(),a(f,{key:1,class:`wb-copy-btn__icon wb-copy-btn__icon--check`},{default:z(()=>[...r[36]||=[w(`✓`,-1)]]),_:1})):(P(),a(f,{key:0,class:`wb-copy-btn__icon`},{default:z(()=>[E(s.CopyDocument)]),_:1}))],10,Rd),s.selectedTask.desc&&s.selectedTask.desc.length>0||s.selectedTask.attachments&&s.selectedTask.attachments.length>0?(P(),W(`span`,zd,[s.selectedTask.desc&&s.selectedTask.desc.length>0?(P(),W(`span`,Bd,U(s.$t(`@WORKBENCH:已填写`)),1)):T(`v-if`,!0),s.selectedTask.attachments&&s.selectedTask.attachments.length>0?(P(),W(`span`,Vd,U(s.selectedTask.attachments.length),1)):T(`v-if`,!0)])):T(`v-if`,!0)]),G(o(`textarea`,{ref:`taskDescTextareaRef`,class:`wb-textarea wb-textarea--autogrow`,"onUpdate:modelValue":r[10]||=e=>s.selectedTask.desc=e,placeholder:s.$t(`@WORKBENCH:任务描述(可选)`),"aria-label":s.$t(`@WORKBENCH:任务描述(可选)`),onInput:r[11]||=e=>s.autoGrowTextarea(e),onFocus:r[12]||=e=>s.autoGrowTextarea(e),onBlur:r[13]||=e=>s.autoGrowTextarea(e),onPaste:r[14]||=e=>s.onAttachmentPaste(e,{kind:`task`,task:s.selectedTask})},null,40,Hd),[[F,s.selectedTask.desc]]),E(s.AttachmentZone,{attachments:s.selectedTask.attachments||[],"is-image":s.isImageAttachment,"human-size":s.humanSize,"is-uploading":s.isUploading(`task-`+s.selectedTask.id),"is-paste-hover":s.pasteHoverId===`task-`+s.selectedTask.id,"on-pick":()=>s.pickAttachmentFile({kind:`task`,task:s.selectedTask}),"on-remove":e=>s.removeAttachment({kind:`task`,task:s.selectedTask},e),onPaste:r[15]||=e=>s.onAttachmentPaste(e,{kind:`task`,task:s.selectedTask}),onDrop:r[16]||=L(e=>s.onAttachmentDrop(e,{kind:`task`,task:s.selectedTask}),[`prevent`]),onDragover:r[17]||=L(e=>s.pasteHoverId=`task-`+s.selectedTask.id,[`prevent`]),onDragenter:r[18]||=L(e=>s.pasteHoverId=`task-`+s.selectedTask.id,[`prevent`]),onDragleave:r[19]||=e=>s.pasteHoverId=s.pasteHoverId===`task-`+s.selectedTask.id?null:s.pasteHoverId},null,8,[`attachments`,`is-image`,`human-size`,`is-uploading`,`is-paste-hover`,`on-pick`,`on-remove`])],40,Fd),T(` ── 执行主体:一条任务 = 一次会话,详情面板占满整行 ── `),o(`div`,Ud,[T(` 详情面板(执行内容区) `),o(`div`,Wd,[T(` ⚠️ 这一层**不要**用裸 <template> 包起来(踩过,2026-09-22):
|
|
212
|
+
Vue 3 只把带 v-if / v-else / v-for / v-slot 的 <template> 编译成片段,
|
|
213
|
+
裸 <template> 会被当成真的 <template> 元素渲染 —— 浏览器把子节点全塞进
|
|
214
|
+
template.content(inert DocumentFragment),不产生任何布局盒。
|
|
215
|
+
症状:任务在跑、看板「执行中」,但对话区一片空白,
|
|
216
|
+
而 innerText 里明明有内容(元素 0×0)。重构移除子任务概念时留下的空壳。 `),o(`details`,{class:_([`wb-simple__override`,{"has-content":!!(s.selectedTask.simpleOverride&&s.selectedTask.simpleOverride.trim())}])},[o(`summary`,Gd,[E(f,{class:`wb-simple__override-caret`},{default:z(()=>[E(s.ArrowRight)]),_:1}),o(`span`,null,U(s.$t(`@WORKBENCH:覆盖预置提示词(可选)`)),1),s.selectedTask.simpleOverride&&s.selectedTask.simpleOverride.trim()?(P(),W(`span`,{key:0,class:`wb-simple__override-tag`,title:s.$t(`@WORKBENCH:已填写覆盖内容`)},U(s.$t(`@WORKBENCH:已填写`)),9,Kd)):T(`v-if`,!0),s.simpleJobState(s.simpleJobFor(s.selectedTask))===`running`&&s.simpleJobFor(s.selectedTask)?(P(),W(`button`,{key:1,class:`wb-simple__stop`,onClick:r[21]||=L(e=>s.cancelJob(s.simpleJobFor(s.selectedTask)),[`stop`])},U(s.$t(`@WORKBENCH:停止`)),1)):T(`v-if`,!0)]),G(o(`textarea`,{class:`wb-textarea`,"onUpdate:modelValue":r[22]||=e=>s.selectedTask.simpleOverride=e,placeholder:s.$t(`@WORKBENCH:留空则使用上方选定的「预置提示词」模板;可用变量:{{task.title}} {{task.desc}} {{repo.path}} {{branch}}`),"aria-label":s.$t(`@WORKBENCH:覆盖预置提示词(可选)`),rows:`6`},null,8,qd),[[F,s.selectedTask.simpleOverride]])],2),T(` 任务对话流:所有轮次合并到单个 ChatContainer `),s.simpleAllJobsFor(s.selectedTask).length>0?(P(),W(`div`,Jd,[T(` ⚠️ 这层 div 不是多余的,class 也**不要**挪回 ChatContainer 上(2026-09-29 踩过):
|
|
217
|
+
传给 zen-ai-chat-ui 组件的 class 在**生产构建**里不会落到组件根节点上
|
|
218
|
+
(同一份源码 dev 会落、prod 静默丢掉,实测 class 与父级 data-v-* 双双消失),
|
|
219
|
+
于是 \`.wb-simple-chat :deep(.acu-*)\` 这一组样式钩子在生产 bundle 里全是死的。
|
|
220
|
+
症状之一就是「已完成的任务点开后有 2 个输入框」:原来靠
|
|
221
|
+
\`.acu-chat-footer{display:none}\` 藏 ChatContainer 自带输入框,prod 里那条规则
|
|
222
|
+
根本没匹配上,lib 自带输入框与下面常驻的 ChatInput 同时显示。
|
|
223
|
+
把 class 挂在自己的 div 上,样式钩子才在 dev / prod 都成立。 `),o(`div`,Yd,[(P(),a(s.ChatContainer,{ref:`chatRef`,key:s.selectedTask.id,messages:s.simpleConversationMessages,"assistant-name":s.simpleAssistantLabel,"assistant-avatar":s.simpleAssistantAvatar,"show-avatar":!0,theme:s.configStore.theme,"tool-calls-config":{group:!0,collapseThreshold:2},"plan-config":{labels:{title:s.$t(`@AGENT:计划`),raw:s.$t(`@AGENT:原始参数`)}},"show-input":!1},null,8,[`messages`,`assistant-name`,`assistant-avatar`,`theme`,`plan-config`]))]),T(` 终态控件 `),s.simpleJobFor(s.selectedTask)&&[`done`,`error`,`cancelled`].includes(s.simpleJobState(s.simpleJobFor(s.selectedTask)))?(P(),W(`div`,Xd,[(P(),a(s.ChatInput,{key:`input-`+s.selectedTask.id,placeholder:s.$t(`@WORKBENCH:输入后续问题继续对话…(Ctrl+Enter 发送)`),"upload-config":{enabled:!0,accept:s.ALLOWED_EXT_HINT,multiple:!0,maxCount:0,maxSize:s.MAX_ATTACHMENT_BYTES},class:`wb-simple-chat__input`,onSend:r[23]||=e=>s.onContinueSendFromChat(s.selectedTask,e)},null,8,[`placeholder`,`upload-config`]))])):T(`v-if`,!0)],512)):T(`v-if`,!0)])])],64)):(P(),W(`div`,dd,[o(`p`,null,U(s.$t(`@WORKBENCH:左侧选择任务,或新建一个任务开始`)),1)]))])])])]),_:1},8,[`modelValue`,`title`]),T(` 执行日志管理:弹窗形式承载,原本独立 tab 切换会占用首屏。
|
|
224
|
+
|
|
225
|
+
⚠️ 必须 append-to-body。app shell 的 main.main-container 是 position:fixed + z-index:1001,
|
|
226
|
+
它自成一个层叠上下文:留在这里面的弹窗 z-index 再高,也只是跟"同一个上下文里的兄弟"比,
|
|
227
|
+
永远压不过挂在 body 下的 L2 编辑器弹窗(它 escape 了 1001 那层)。
|
|
228
|
+
现象就是点了「执行日志」没反应 —— 其实弹窗开了,只是被编辑器整个盖住。 `),E(s.CommonDialog,{modelValue:s.logsDialogVisible,"onUpdate:modelValue":r[25]||=e=>s.logsDialogVisible=e,title:s.$t(`@WORKBENCH:执行日志`),width:`1080px`,"close-on-click-modal":!1,top:`6vh`,type:`flex`,"custom-class":`wb-logs-dialog`,"append-to-body":``},{default:z(()=>[E(s.ExecutionLogManager)]),_:1},8,[`modelValue`,`title`]),T(` 提示词编辑对话框:同「执行日志」,从编辑器里打开,必须 append-to-body 才压得住编辑器弹窗 `),E(s.CommonDialog,{modelValue:s.promptDialog.visible,"onUpdate:modelValue":r[30]||=e=>s.promptDialog.visible=e,title:s.promptDialog.editing?s.$t(`@WORKBENCH:编辑提示词`):s.$t(`@WORKBENCH:新建提示词`),width:`640px`,type:`flex`,"append-to-body":``},{footer:z(()=>[E(D,{onClick:r[29]||=e=>s.promptDialog.visible=!1},{default:z(()=>[w(U(s.$t(`@WORKBENCH:取消`)),1)]),_:1}),E(D,{type:`primary`,onClick:s.savePrompt},{default:z(()=>[w(U(s.$t(`@WORKBENCH:保存`)),1)]),_:1})]),default:z(()=>[E(ee,{"label-position":`top`},{default:z(()=>[E(x,{label:s.$t(`@WORKBENCH:名称`)},{default:z(()=>[E(b,{modelValue:s.promptDialog.name,"onUpdate:modelValue":r[26]||=e=>s.promptDialog.name=e,placeholder:s.$t(`@WORKBENCH:如:代码审查 / 写测试`)},null,8,[`modelValue`,`placeholder`])]),_:1},8,[`label`]),E(x,{label:s.$t(`@WORKBENCH:所属项目`)},{default:z(()=>[E(C,{modelValue:s.promptDialog.projectPath,"onUpdate:modelValue":r[27]||=e=>s.promptDialog.projectPath=e,placeholder:s.$t(`@WORKBENCH:所属项目`),style:{width:`100%`},disabled:!s.currentProject.path},{default:z(()=>[T(` 「全局」选项 = projectPath 为空串,所有项目都能看到 `),E(S,{label:s.$t(`@WORKBENCH:全局(所有项目可用)`),value:``},null,8,[`label`]),T(` 仅当有当前项目时才允许绑定到当前项目,避免“绑到空项目”的兑犷数据 `),s.currentProject.path?(P(),a(S,{key:s.currentProject.path,label:s.currentProject.name||s.currentProject.path,value:s.currentProject.path},null,8,[`label`,`value`])):T(`v-if`,!0)]),_:1},8,[`modelValue`,`placeholder`,`disabled`])]),_:1},8,[`label`]),E(x,null,{default:z(()=>[o(`div`,Zd,[E(D,{type:`primary`,plain:``,loading:s.promptDialog.aiLoading,onClick:s.aiGeneratePrompt},{default:z(()=>[w(U(s.$t(`@WORKBENCH:AI 生成项目架构说明`)),1)]),_:1},8,[`loading`]),E(D,{onClick:s.openEditInstruction},{default:z(()=>[w(U(s.$t(`@WORKBENCH:编辑指令`)),1)]),_:1})])]),_:1}),E(x,{label:s.$t(`@WORKBENCH:内容`)},{default:z(()=>[E(b,{modelValue:s.promptDialog.content,"onUpdate:modelValue":r[28]||=e=>s.promptDialog.content=e,type:`textarea`,rows:10,placeholder:s.$t(`@WORKBENCH:可用变量:`)+`{{task.title}} {{task.desc}} {{sub.title}} {{sub.desc}} {{repo.path}} {{branch}}`},null,8,[`modelValue`,`placeholder`])]),_:1},8,[`label`])]),_:1})]),_:1},8,[`modelValue`,`title`]),T(` 生成指令编辑对话框 `),E(s.CommonDialog,{modelValue:s.instructionDialog.visible,"onUpdate:modelValue":r[33]||=e=>s.instructionDialog.visible=e,title:s.$t(`@WORKBENCH:编辑生成指令`),width:`720px`,type:`flex`,"append-to-body":``},{footer:z(()=>[E(D,{onClick:r[32]||=e=>s.instructionDialog.visible=!1},{default:z(()=>[w(U(s.$t(`@WORKBENCH:取消`)),1)]),_:1}),E(D,{type:`primary`,loading:s.instructionDialog.saving,onClick:s.saveInstruction},{default:z(()=>[w(U(s.$t(`@WORKBENCH:保存`)),1)]),_:1},8,[`loading`])]),default:z(()=>[E(ee,{"label-position":`top`},{default:z(()=>[E(x,{label:s.$t(`@WORKBENCH:指令内容`)},{default:z(()=>[E(b,{modelValue:s.instructionDialog.text,"onUpdate:modelValue":r[31]||=e=>s.instructionDialog.text=e,type:`textarea`,rows:18,placeholder:s.$t(`@WORKBENCH:指令内容`)},null,8,[`modelValue`,`placeholder`])]),_:1},8,[`label`])]),_:1})]),_:1},8,[`modelValue`,`title`])])}var $d=Ae(ed,[[`render`,Qd],[`__scopeId`,`data-v-28f2e82b`],[`__file`,`C:/workspace/github_workspace/xz333221/zen-gitsync/src/ui/client/src/views/WorkbenchView.vue`]]);export{$d as default};
|