zen-gitsync 2.18.26 → 2.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -4
- package/src/aiCommit.js +61 -54
- package/src/cli/ai/tools.js +71 -8
- package/src/cli/ai/webSearch.js +108 -21
- package/src/cli/peer.js +272 -0
- package/src/config.js +14 -4
- package/src/gitCommit.js +34 -1
- package/src/paths.js +6 -0
- package/src/peer/client.js +165 -0
- package/src/peer/localAsk.js +130 -0
- package/src/peer/server.js +183 -0
- package/src/peer/store.js +292 -0
- package/src/ui/public/assets/AgentView-BtnAYtte.js +42 -0
- package/src/ui/public/assets/{AgentView-Bslr4Bc8.css → AgentView-ByQ0iJFU.css} +1 -1
- package/src/ui/public/assets/AppVersionBadge-BcXo-yuu.js +2 -0
- package/src/ui/public/assets/{BranchSelector-D4Igm7sR.js → BranchSelector-5t-T3FB6.js} +1 -1
- package/src/ui/public/assets/{CommitForm-CXBA-E-6.js → CommitForm-BMfp3Eqh.js} +3 -3
- package/src/ui/public/assets/{CommonDialog-DrbQC1fm.js → CommonDialog-BiF2fMgr.js} +1 -1
- package/src/ui/public/assets/{EditorView-CXj7-8DC.js → EditorView-CtmZ7RZp.js} +1 -1
- package/src/ui/public/assets/{FlowExecutionViewer-CjL1DfmI.js → FlowExecutionViewer-D2lchSo7.js} +1 -1
- package/src/ui/public/assets/{FlowOrchestrationWorkspace-p7_NcaY-.js → FlowOrchestrationWorkspace-BY2zLwWB.js} +1 -1
- package/src/ui/public/assets/{LogList-SDV2f7R6.js → LogList-DTfAGnlt.js} +4 -4
- package/src/ui/public/assets/MindmapView-DArneR4u.js +2 -0
- package/src/ui/public/assets/MindmapView-PoMd2cab.css +1 -0
- package/src/ui/public/assets/{MonitorView-G1MQ7M0F.js → MonitorView-BQvMyjEj.js} +1 -1
- package/src/ui/public/assets/ProjectManagerView-BPnAWNBJ.css +1 -0
- package/src/ui/public/assets/{ProjectManagerView-Cg3GLLxQ.js → ProjectManagerView-BRUyrHfg.js} +1 -1
- package/src/ui/public/assets/{ProjectStartupButton-DMlDI4Xn.js → ProjectStartupButton-D0f8OAb-.js} +1 -1
- package/src/ui/public/assets/{RemoteManagerDialog-BZLYsW8E.js → RemoteManagerDialog-DXDXCfyD.js} +1 -1
- package/src/ui/public/assets/{RemoteRepoCard-BqHQho7O.js → RemoteRepoCard-BRnjC6vm.js} +1 -1
- package/src/ui/public/assets/{SourceMapView-CHl1yfAe.js → SourceMapView-B6xgG5mi.js} +2 -2
- package/src/ui/public/assets/{SvgIcon-EoI0db7X.js → SvgIcon-GLj_3KcS.js} +1 -1
- package/src/ui/public/assets/{UserInputNode-CbwrGTgh.js → UserInputNode-C6Z6Kys_.js} +1 -1
- package/src/ui/public/assets/{WorkbenchView-hSDyngLo.js → WorkbenchView-B2EUXleS.js} +98 -97
- package/src/ui/public/assets/WorkbenchView-DCL6zHAP.css +1 -0
- package/src/ui/public/assets/_plugin-vue_export-helper-DaO48JOV.js +19 -0
- package/src/ui/public/assets/configStore-B_2ifbl_.js +1 -0
- package/src/ui/public/assets/{index-CUUfiQYd.js → index-DUzH5036.js} +100 -98
- package/src/ui/public/assets/index-zdGFM_7W.css +1 -0
- package/src/ui/public/assets/{relativeTime-257j87Fm.js → relativeTime-DzYQUHQo.js} +1 -1
- package/src/ui/public/assets/taskExecutionExport-C3vFixdJ.js +15 -0
- package/src/ui/public/assets/{useWorkbenchProjects-Cj3XIq94.js → useWorkbenchProjects-0fWZsDRX.js} +1 -1
- package/src/ui/public/index.html +6 -7
- package/src/ui/server/index.js +130 -10
- package/src/ui/server/routes/codeAnalysis.js +39 -16
- package/src/ui/server/routes/config.js +1396 -1375
- package/src/ui/server/routes/git/aiDiffSummary.js +26 -11
- package/src/ui/server/routes/peerSettings.js +164 -0
- package/src/ui/server/routes/projectStartupAi.js +21 -11
- package/src/ui/server/routes/recentDirectoriesAiSummary.js +26 -13
- package/src/ui/server/routes/workbench/agentChat.js +811 -811
- package/src/ui/server/routes/workbench/agentRoutes.js +9 -0
- package/src/ui/server/routes/workbench/imageDescribe.js +52 -16
- package/src/ui/server/utils/ensureHub.js +101 -0
- package/src/ui/server/utils/instanceRegistry.js +8 -3
- package/src/ui/server/utils/peerRuntime.js +77 -0
- package/src/ui/server/utils/startServerOnAvailablePort.js +6 -0
- package/src/utils/aiModelFallback.js +180 -0
- package/src/utils/aiModelFallback.test.js +166 -0
- package/src/ui/public/assets/AgentView-BgsIfH1V.js +0 -27
- package/src/ui/public/assets/AppVersionBadge-vKeEhoxI.js +0 -2
- package/src/ui/public/assets/ChatSilenceBadge-D-lbhnwH.js +0 -16
- package/src/ui/public/assets/ChatSilenceBadge-aok2usEh.css +0 -1
- package/src/ui/public/assets/MindmapView-BWXQHyV7.js +0 -35
- package/src/ui/public/assets/MindmapView-CoUbyadF.css +0 -1
- package/src/ui/public/assets/ProjectManagerView-DhC-Y5PR.css +0 -1
- package/src/ui/public/assets/TaskExecutorPicker-cEgHnI-W.js +0 -1
- package/src/ui/public/assets/WorkbenchView-BVTi_0Mn.css +0 -1
- package/src/ui/public/assets/_plugin-vue_export-helper-Birg7-Pq.js +0 -19
- package/src/ui/public/assets/configStore-DPzIt2AS.js +0 -1
- package/src/ui/public/assets/index-BJJSr6Sb.css +0 -1
- package/src/ui/public/assets/taskExecutionExport-CplN8eIn.js +0 -15
- package/src/ui/public/assets/toolsStore-BjG-9k17.js +0 -1
- /package/src/ui/public/assets/{TaskExecutorPicker-CdRhuBxH.css → taskExecutionExport-CdRhuBxH.css} +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import"./rolldown-runtime-C0FnF6B9.js";import{An as e,Bn as t,C as n,Cn as r,F as i,Ft as a,Gn as o,I as s,In as c,J as l,Kr as u,Lt as d,Mn as f,N as p,Ot as m,Pt as h,Qn as g,Qt as _,Rt as v,S as y,Sn as b,Tn as x,U as S,Un as C,Wr as w,X as ee,Xr as T,Y as te,Yn as E,Z as ne,_ as D,_n as O,a as k,ar as A,at as re,b as ie,bt as ae,ct as oe,en as se,et as ce,ft as le,gn as j,gr as M,gt as ue,hn as N,i as P,ir as F,jr as I,kn as L,ln as de,lr as R,mn as fe,mr as pe,nr as z,on as B,pn as V,qn as H,r as U,st as
|
|
1
|
+
import"./rolldown-runtime-C0FnF6B9.js";import{An as e,Bn as t,C as n,Cn as r,F as i,Ft as a,Gn as o,I as s,In as c,J as l,Kr as u,Lt as d,Mn as f,N as p,Ot as m,Pt as h,Qn as g,Qt as _,Rt as v,S as y,Sn as b,Tn as x,U as S,Un as C,Wr as w,X as ee,Xr as T,Y as te,Yn as E,Z as ne,_ as D,_n as O,a as k,ar as A,at as re,b as ie,bt as ae,ct as oe,en as se,et as ce,ft as le,gn as j,gr as M,gt as ue,hn as N,i as P,ir as F,jr as I,kn as L,ln as de,lr as R,mn as fe,mr as pe,nr as z,on as B,pn as V,qn as H,r as U,st as me,ut as W,v as G,vt as he,w as K,wn as q,xn as J,xt as ge,y as Y,yn as X,z as _e}from"./element-plus-CosPN4uA.js";import{i as ve,l as ye,n as be,r as xe}from"./vendor-DSY591Nv.js";import{n as Z,t as Q}from"./_plugin-vue_export-helper-DaO48JOV.js";import{t as Se}from"./SvgIcon-GLj_3KcS.js";import{d as Ce,f as we,m as Te,t as Ee}from"./configStore-B_2ifbl_.js";import{t as De}from"./CommonDialog-BiF2fMgr.js";import{B as Oe,D as ke,F as Ae,I as je,L as Me,M as Ne,N as Pe,O as Fe,P as Ie,Q as Le,R as Re,h as ze,j as Be,k as Ve,p as He,rt as Ue,s as We,wt as $,xt as Ge,z as Ke}from"./index-DUzH5036.js";import{a as qe,c as Je,d as Ye,i as Xe,l as Ze,o as Qe,r as $e,s as et,t as tt}from"./taskExecutionExport-C3vFixdJ.js";import{n as nt,r as rt,t as it}from"./relativeTime-DzYQUHQo.js";import{n as at,t as ot}from"./useWorkbenchProjects-0fWZsDRX.js";c(),R();var st=f({__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=J(()=>r.attachments.filter(e=>r.isImage(e))),s=J(()=>o.value.map(e=>i(e))),c=M(0),l=M(!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=M({visible:!1,x:0,y:0,att:null}),p=M(!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`){P({type:`warning`,message:Z(`@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]),P({type:`success`,message:Z(`@WORKBENCH:图片已复制到剪贴板`),duration:1800})}catch(e){P({type:`error`,message:Z(`@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)),C(()=>{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 ie},get $t(){return Z}};return Object.defineProperty(_,"__isScriptSetup",{enumerable:!1,value:!0}),_}});I(),c(),B();var ct={class:`wb-attachments__head`},lt={class:`wb-attachments__label`},ut={class:`wb-attachments__count`},dt=[`disabled`],ft={key:0,class:`wb-attachments__paste-hint`},pt={key:1,class:`wb-attachments__list`},mt=[`title`,`onClick`,`onContextmenu`],ht=[`src`,`alt`],gt={key:1},_t={class:`wb-attachment__meta`},vt=[`title`],yt=[`onClick`,`title`];function bt(e,t,n,i,a,o){return H(),x(O,null,[b(`div`,{class:w([`wb-attachments`,{"is-paste-hover":n.isPasteHover}]),onPaste:t[1]||=e=>i.emit(`paste`,e),onDrop:t[2]||=j(e=>i.emit(`drop`,e),[`prevent`]),onDragover:t[3]||=j(e=>i.emit(`dragover`,e),[`prevent`]),onDragenter:t[4]||=j(e=>i.emit(`dragenter`,e),[`prevent`]),onDragleave:t[5]||=e=>i.emit(`dragleave`,e)},[b(`div`,ct,[b(`span`,lt,[L(T(i.$t(`@WORKBENCH:附件`))+` `,1),q(` 只报个数:数量不设上限,写成 "N / 9" 会让人以为还剩几个能加 `),b(`span`,ut,T(n.attachments.length),1)]),b(`button`,{class:`wb-attachments__add`,disabled:n.isUploading,onClick:t[0]||=(...e)=>n.onPick&&n.onPick(...e)},T(n.isUploading?i.$t(`@WORKBENCH:上传中…`):i.$t(`@WORKBENCH:添加附件`)),9,dt)]),n.isPasteHover?(H(),x(`div`,ft,T(i.$t(`@WORKBENCH:粘贴图片以快速添加`)),1)):q(`v-if`,!0),n.attachments.length>0?(H(),x(`ul`,pt,[(H(!0),x(O,null,E(n.attachments,e=>(H(),x(`li`,{key:e.id,class:`wb-attachment`},[b(`button`,{type:`button`,class:`wb-attachment__preview`,title:i.$t(`@WORKBENCH:点击预览`),onClick:t=>i.previewAttachment(e),onContextmenu:t=>i.openContextMenu(e,t)},[b(`div`,{class:w([`wb-attachment__icon`,{"wb-attachment__icon--img":n.isImage(e)}])},[n.isImage(e)?(H(),x(`img`,{key:0,src:i.rawOf(e),alt:e.originalName,loading:`lazy`},null,8,ht)):(H(),x(`span`,gt,T(e.ext.toUpperCase()),1))],2),b(`div`,_t,[b(`div`,{class:`wb-attachment__name`,title:`${e.originalName} (${n.humanSize(e.size)})`},T(e.originalName),9,vt)])],40,mt),b(`button`,{class:`wb-attachment__del`,onClick:j(t=>n.onRemove(e),[`stop`]),title:i.$t(`@WORKBENCH:删除`)},`×`,8,yt)]))),128))])):q(`v-if`,!0)],34),q(`
|
|
2
2
|
el-image-viewer 自己通过内部 <Teleport to="body" :disabled="!teleported"> 把遮罩渲染到 body。
|
|
3
3
|
不要在外面再包一层 <teleport to="body"> —— 嵌套 Teleport 在 element-plus 2.11.x 下会让组件
|
|
4
4
|
的 v-if 容器内残留占位、且内部 Teleport 因找不到正确锚点而不挂载,导致点击图片无反应。
|
|
5
5
|
显式传 :teleported="true" 是为了保证内部 Teleport 启用(默认是 undefined 关闭)。
|
|
6
|
-
`),i.previewVisible&&i.previewUrls.length>0?(H(),r(i.ElImageViewer,{key:0,"url-list":i.previewUrls,"initial-index":i.previewIndex,"hide-on-click-modal":!0,teleported:!0,onClose:i.closePreview},null,8,[`url-list`,`initial-index`])):
|
|
6
|
+
`),i.previewVisible&&i.previewUrls.length>0?(H(),r(i.ElImageViewer,{key:0,"url-list":i.previewUrls,"initial-index":i.previewIndex,"hide-on-click-modal":!0,teleported:!0,onClose:i.closePreview},null,8,[`url-list`,`initial-index`])):q(`v-if`,!0),q(` 右键菜单:仅图片附件可用 `),(H(),r(X,{to:`body`},[i.contextMenu.visible&&i.contextMenu.att&&n.isImage(i.contextMenu.att)?(H(),x(`ul`,{key:0,class:`wb-ctx-menu`,style:u({top:i.contextMenu.y+`px`,left:i.contextMenu.x+`px`}),onContextmenu:t[6]||=j(()=>{},[`prevent`])},[b(`li`,{class:w([`wb-ctx-menu__item`,{"is-disabled":i.copyBusy}]),onClick:i.copyImageToClipboard},[t[7]||=b(`span`,{class:`wb-ctx-menu__icon`,"aria-hidden":`true`},[b(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`1.8`,"stroke-linecap":`round`,"stroke-linejoin":`round`},[b(`rect`,{x:`9`,y:`9`,width:`11`,height:`11`,rx:`2`}),b(`path`,{d:`M5 15V5a2 2 0 0 1 2-2h10`})])],-1),b(`span`,null,T(i.$t(`@WORKBENCH:复制图片`)),1)],2)],36)):q(`v-if`,!0)]))],64)}var xt=Q(st,[[`render`,bt],[`__scopeId`,`data-v-d2df2361`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/components/AttachmentZone.vue`]]),St=ve(`claude`),Ct=ve(`opencode`),wt=ve(`codex`),Tt=Oe,Et=Ke,Dt=Re;function Ot(e){return e===`opencode`?Ct:e===`codex`?wt:e===`codebuddy`?Tt:e===`pi`?Et:e===`codearts`?Dt:St}function kt(e){if(typeof e!=`string`||!e)return;let t=Date.parse(e);return Number.isFinite(t)?t:void 0}function At(e){let t=kt(e?.thinkingStartedAt);return t===void 0?{}:{reasoningStartedAt:t,reasoningEndedAt:kt(e?.thinkingEndedAt)}}c(),R();var jt=65536,Mt=f({__name:`JobLogDetails`,props:{job:{type:Object,required:!0}},emits:[`re-execute`],setup(e,{expose:n,emit:r}){n();let i=Ee(),a=e,o=r,s=M(!1);function c(){s.value=!s.value}let l=J(()=>a.job.status===`running`||a.job.status===`pending`);z(()=>a.job.status,(e,t)=>{t!==`running`&&t!==`pending`&&(e===`running`||e===`pending`)&&(s.value=!1)});function u(){let e=a.job.output||``;if(!e)return``;let t=e.length<=jt?e:`${Z(`@WORKBENCH:…(前文已截断)`)}\n${e.slice(-65536)}`;return Ye(t,a.job.id)}function d(){let e=a.job.thinking||``;return e?e.length<=jt?e:`${Z(`@WORKBENCH:…(前文已截断)`)}\n${e.slice(-65536)}`:``}async function f(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 p(){let e=[];if(a.job.prompt&&e.push(`## ${Z(`@WORKBENCH:用户提示词`)}\n\n${a.job.prompt}`),a.job.thinking&&e.push(`## ${Z(`@WORKBENCH:Claude 思考`)}\n\n${a.job.thinking}`),a.job.output&&e.push(`## ${Z(`@WORKBENCH:模型返回`)}\n\n${a.job.output}`),!e.length){P.warning(Z(`@WORKBENCH:暂无内容可复制`));return}await f(e.join(`
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
10
|
-
`))?P.success(Z(`@WORKBENCH:已复制到剪贴板`)):P.error(Z(`@WORKBENCH:复制失败`))}let m=
|
|
10
|
+
`))?P.success(Z(`@WORKBENCH:已复制到剪贴板`)):P.error(Z(`@WORKBENCH:复制失败`))}let m=J(()=>{let e=a.job.status;return e===`done`||e===`error`||e===`cancelled`}),h=J(()=>a.job.status===`cancelled`?`wb-log-summary__status--cancelled`:a.job.status===`error`?`wb-log-summary__status--error`:`wb-log-summary__status--done`),g=J(()=>a.job.status===`cancelled`?`⏹`:a.job.status===`error`?`✗`:`✓`),_=J(()=>a.job.status===`cancelled`?Z(`@WORKBENCH:已停止`):a.job.status===`error`?Z(`@WORKBENCH:执行出错`):Z(`@WORKBENCH:执行完成`)),v=J(()=>Te(a.job?.agent)),y=ze(),b=J(()=>Ot(a.job?.agent));function x(e,t){return e===`running`||e===`pending`?t?`streaming`:`pending`:e===`error`?`error`:`done`}let S=J(()=>{let e=a.job,t=[],n=e.startedAt?new Date(e.startedAt).getTime():Date.now();if(e.prompt){let r=qe(e.prompt);r&&t.push({id:`${e.id}-u`,role:`user`,content:r,status:`done`,createdAt:n})}let r=u(),i=d(),o=!!r,s=!!i,c=Qe(e),l=c.length>0,f=o||s||l,p=x(e.status,f);return t.push({id:`${e.id}-a`,role:`assistant`,content:r,reasoning:s?i:void 0,reasoningStatus:s?o?`done`:p===`streaming`?`streaming`:`done`:void 0,...At(e),toolCalls:l?c:void 0,status:p,error:p===`error`&&e.error||void 0,createdAt:n}),t}),C=M(null);z(()=>a.job.status,(e,t)=>{e===`running`&&t!==`running`&&(C.value=C.value??Date.now())});let w=J(()=>{if(!C.value)return``;let e=C.value,t=a.job.endedAt?new Date(a.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`)}秒`}),ee=M(!1),T=J(()=>!!(a.job.output&&a.job.output.length)),te=J(()=>Ye(a.job.output||``,a.job.id)),E=M(null);z(ee,async e=>{e&&(await t(),E.value&&(E.value.scrollTop=E.value.scrollHeight))}),z(()=>(a.job.output||``).length,async()=>{ee.value&&(await t(),E.value&&(E.value.scrollTop=E.value.scrollHeight))});function ne(){}let D=J(()=>m.value&&!!a.job.prompt);function O(){o(`re-execute`,a.job)}let k={configStore:i,props:a,emit:o,isCollapsed:s,toggleOpen:c,isActive:l,MAX_LOG_DISPLAY:jt,displayOutput:u,displayThinking:d,copyToClipboard:f,copyAll:p,isFinished:m,finishedStatusClass:h,finishedStatusIcon:g,finishedStatusLabel:_,assistantLabel:v,fileChangeLabels:y,assistantAvatar:b,mapStatus:x,chatMessages:S,startedAt:C,elapsedLabel:w,fullscreenOpen:ee,hasOutput:T,fullscreenSource:te,fullscreenContainerRef:E,onFullscreenClosed:ne,canReExecute:D,onReExecute:O,get ChatContainer(){return be},get MarkdownRenderer(){return ye},get $t(){return Z},CommonDialog:De};return Object.defineProperty(k,"__isScriptSetup",{enumerable:!1,value:!0}),k}});I(),c(),B();var Nt=[`aria-expanded`],Pt={class:`wb-log-summary__left`},Ft={key:0,class:`wb-log-summary__status wb-log-summary__status--running`},It={class:`wb-log-summary__label`},Lt={key:0,class:`wb-log-summary__elapsed`},Rt={key:1,class:`wb-log-summary__status wb-log-summary__status--pending`},zt={class:`wb-log-summary__label`},Bt={class:`wb-log-summary__icon`},Vt={class:`wb-log-summary__label`},Ht={key:0,class:`wb-log-summary__elapsed`},Ut={key:3},Wt={class:`wb-log-summary__right`},Gt={class:`wb-log-summary__meta`},Kt=[`title`,`aria-label`],qt={class:`wb-log-details__body`},Jt={class:`wb-job-chat`},Yt={key:0,class:`wb-chat__foot`},Xt=[`title`,`aria-label`],Zt={ref:`fullscreenContainerRef`,class:`wb-log-fullscreen`},Qt={key:1,class:`wb-log-fullscreen__empty`};function $t(t,n,i,a,o,s){return H(),x(`div`,{class:w([`wb-log-details`,{"is-running":a.isActive,"is-pending":i.job.status===`pending`,"is-finished":a.isFinished}])},[b(`div`,{class:`wb-log-summary`,onClick:a.toggleOpen,role:`button`,"aria-expanded":!a.isCollapsed},[b(`span`,Pt,[i.job.status===`running`?(H(),x(`span`,Ft,[b(`span`,It,T(a.$t(`@WORKBENCH:正在执行…`)),1),n[1]||=b(`span`,{class:`wb-log-dots`,"aria-hidden":`true`},[b(`span`,{class:`wb-log-dots__dot`}),b(`span`,{class:`wb-log-dots__dot`}),b(`span`,{class:`wb-log-dots__dot`})],-1),a.elapsedLabel?(H(),x(`span`,Lt,T(a.elapsedLabel),1)):q(`v-if`,!0)])):i.job.status===`pending`?(H(),x(`span`,Rt,[b(`span`,zt,T(a.$t(`@WORKBENCH:排队中…`)),1),n[2]||=b(`span`,{class:`wb-log-dots`,"aria-hidden":`true`},[b(`span`,{class:`wb-log-dots__dot`}),b(`span`,{class:`wb-log-dots__dot`}),b(`span`,{class:`wb-log-dots__dot`})],-1)])):a.isFinished?(H(),x(`span`,{key:2,class:w([`wb-log-summary__status`,a.finishedStatusClass])},[b(`span`,Bt,T(a.finishedStatusIcon),1),b(`span`,Vt,T(a.finishedStatusLabel),1),a.elapsedLabel?(H(),x(`span`,Ht,T(a.elapsedLabel),1)):q(`v-if`,!0)],2)):(H(),x(`span`,Ut,T(a.$t(`@WORKBENCH:查看执行日志`)),1))]),b(`span`,Wt,[b(`span`,Gt,T((i.job.output||``).length)+` `+T(a.$t(`@WORKBENCH:字符`)),1),b(`button`,{type:`button`,class:`wb-log-copy`,title:a.$t(`@WORKBENCH:复制全部(含提示词与输出)`),"aria-label":a.$t(`@WORKBENCH:复制全部`),onClick:j(a.copyAll,[`stop`])},` ⧉ `,8,Kt)])],8,Nt),q(`\r
|
|
11
11
|
body 容器:用 zen-ai-chat-ui 的 ChatContainer 渲染单轮对话。\r
|
|
12
12
|
关掉 ChatContainer 自带的输入框(show-input=false —— 续聊输入由父组件统一承载),\r
|
|
13
13
|
下方保留"重新执行"footer。\r
|
|
@@ -17,40 +17,41 @@ import"./rolldown-runtime-C0FnF6B9.js";import{An as e,Bn as t,C as n,Cn as r,F a
|
|
|
17
17
|
就全成了死代码 —— 自带的输入框藏不住,背景/气泡密度也全是库默认值。\r
|
|
18
18
|
2026-09-29 在 WorkbenchView 上就是这个坑(「已完成任务点开有 2 个输入框」)。\r
|
|
19
19
|
所以外层套一个自己的 div 承载 class。\r
|
|
20
|
-
`),A(b(`div`,
|
|
21
|
-
标题已由外层 el-dialog 提供,这里不再重复 h2。 `),b(`header`,rn,[b(`div`,an,[b(`span`,on,T(a.$t(`@WORKBENCH:共 {count} 条,占 {size} MB`,{count:a.stats.count,size:a.stats.sizeMB})),1)]),b(`div`,sn,[e(d,{icon:a.Refresh,size:`small`,loading:a.loading,onClick:a.load},{default:F(()=>[L(T(a.$t(`@WORKBENCH:刷新`)),1)]),_:1},8,[`icon`,`loading`]),e(d,{type:`danger`,plain:``,size:`small`,disabled:a.stats.count===0,onClick:a.clearAll},{default:F(()=>[L(T(a.$t(`@WORKBENCH:清空全部`)),1)]),_:1},8,[`disabled`])])]),J(` 保留策略 `),b(`div`,cn,[b(`span`,ln,T(a.$t(`@WORKBENCH:保存策略`)),1),b(`span`,un,[b(`span`,dn,T(a.$t(`@WORKBENCH:最大条数`)),1),e(f,{modelValue:a.configDraft.maxCount,"onUpdate:modelValue":n[0]||=e=>a.configDraft.maxCount=e,min:0,max:1e4,step:50,size:`small`,"controls-position":`right`,style:{width:`130px`}},null,8,[`modelValue`])]),b(`span`,fn,[b(`span`,pn,T(a.$t(`@WORKBENCH:最大体积 (MB)`)),1),e(f,{modelValue:a.configDraft.maxSizeMB,"onUpdate:modelValue":n[1]||=e=>a.configDraft.maxSizeMB=e,min:0,max:10240,step:32,size:`small`,"controls-position":`right`,style:{width:`140px`}},null,8,[`modelValue`])]),e(d,{type:`primary`,size:`small`,loading:a.configSaving,onClick:a.saveConfig},{default:F(()=>[L(T(a.$t(`@WORKBENCH:保存策略`)),1)]),_:1},8,[`loading`])]),J(` 过滤栏 `),b(`div`,mn,[e(m,{modelValue:a.filter.q,"onUpdate:modelValue":n[2]||=e=>a.filter.q=e,placeholder:a.$t(`@WORKBENCH:搜索标题 / 任务`),clearable:``,size:`small`,style:{width:`240px`},onKeyup:N(a.onFilterChange,[`enter`]),onClear:a.onFilterChange},null,8,[`modelValue`,`placeholder`]),e(g,{modelValue:a.filter.status,"onUpdate:modelValue":n[3]||=e=>a.filter.status=e,placeholder:a.$t(`@WORKBENCH:全部状态`),clearable:``,size:`small`,style:{width:`130px`},onChange:a.onFilterChange},{default:F(()=>[(H(),x(O,null,E(a.STATUS_OPTIONS,t=>e(h,{key:t.value,label:t.label,value:t.value},null,8,[`label`,`value`])),64))]),_:1},8,[`modelValue`,`placeholder`]),e(d,{size:`small`,onClick:a.resetFilter},{default:F(()=>[L(T(a.$t(`@WORKBENCH:重置`)),1)]),_:1}),n[5]||=b(`span`,{class:`exec-logs__filter-spacer`},null,-1),a.selectedIds.size>0?(H(),x(`span`,hn,T(a.$t(`@WORKBENCH:已选择 {count} 项`,{count:a.selectedIds.size})),1)):J(`v-if`,!0)]),J(` 批量操作条 `),a.selectedIds.size>0?(H(),x(`div`,gn,[e(_,{"model-value":a.isAllOnPageSelected,indeterminate:a.isSomeOnPageSelected,onChange:a.toggleSelectAllOnPage},{default:F(()=>[L(T(a.isAllOnPageSelected?a.$t(`@WORKBENCH:取消全选`):a.$t(`@WORKBENCH:全选`)),1)]),_:1},8,[`model-value`,`indeterminate`]),e(d,{type:`danger`,size:`small`,onClick:a.batchDelete},{default:F(()=>[L(T(a.$t(`@WORKBENCH:批量删除`)),1)]),_:1})])):J(`v-if`,!0),J(` 列表 `),A((H(),x(`div`,_n,[!a.loading&&a.list.length===0?(H(),x(`div`,vn,[b(`div`,yn,[e(v,null,{default:F(()=>[e(a.Document)]),_:1})]),b(`div`,bn,T(a.$t(`@WORKBENCH:暂无执行日志`)),1),b(`div`,xn,T(a.$t(`@WORKBENCH:点击「执行任务」开始一次执行,日志会出现在这里。`)),1)])):J(`v-if`,!0),(H(!0),x(O,null,E(a.list,t=>(H(),x(`article`,{key:t.id,class:w([`exec-card`,{"is-selected":a.selectedIds.has(t.id)}])},[b(`header`,Sn,[e(_,{"model-value":a.selectedIds.has(t.id),onChange:e=>a.toggleSelect(t.id,e)},null,8,[`model-value`,`onChange`]),b(`span`,{class:`exec-card__status`,style:u({color:a.statusColor(t.status),borderColor:a.statusColor(t.status)})},T(a.statusLabel(t.status)),5),b(`span`,{class:`exec-card__title`,title:t.title||a.$t(`@WORKBENCH:无标题`)},T(t.title||a.$t(`@WORKBENCH:无标题`)),9,Cn),n[6]||=b(`span`,{class:`exec-card__spacer`},null,-1),b(`span`,wn,[t.taskTitle?(H(),x(`span`,Tn,`📁 `+T(t.taskTitle),1)):J(`v-if`,!0),t.startedAt?(H(),x(`span`,En,`⏱ `+T(a.formatDuration(t.startedAt,t.endedAt)),1)):J(`v-if`,!0),t.exitCode===null?J(`v-if`,!0):(H(),x(`span`,Dn,`exit `+T(t.exitCode),1))]),b(`button`,{type:`button`,class:`exec-card__del`,title:a.$t(`@WORKBENCH:删除`),onClick:e=>a.deleteOne(t.id)},`×`,8,On)]),t.error?(H(),x(`p`,kn,`⚠ `+T(t.error),1)):J(`v-if`,!0),e(a.JobLogDetails,{job:t,onReExecute:a.onReExecuteInLog},null,8,[`job`])],2))),128))])),[[C,a.loading]]),J(` 分页 `),a.total>a.pageSize?(H(),x(`footer`,An,[e(y,{"current-page":a.filter.page,"onUpdate:currentPage":n[4]||=e=>a.filter.page=e,"page-size":a.pageSize,total:a.total,layout:`prev, pager, next, total`,background:``,small:``,onCurrentChange:a.load},null,8,[`current-page`,`total`])])):J(`v-if`,!0)])}var Mn=Q(tn,[[`render`,jn],[`__scopeId`,`data-v-d3ebe953`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/components/ExecutionLogManager.vue`]]);function Nn(e){return String(e.manualDoneAt||e.lastJobEndedAt||e.updatedAt||e.createdAt||``)}function Pn(e){return e.column===`done`?Nn(e):e.updatedAt||e.createdAt||``}function Fn(e){return e.live?``:tt(e.lastDurationMs)}function In(e){let t=Fn(e);return t?Z(`@WORKBENCH:用时 {d}`,{d:t}):``}function Ln(e){return e.live?Z(`@WORKBENCH:已运行 {elapsed}`,{elapsed:tt(e.live.elapsedMs)}):``}function Rn(e){return Ln(e)||In(e)}function zn(e){let t=Fn(e);if(!t)return``;let n=rt(e.lastJobStartedAt),r=rt(e.lastJobEndedAt);return!n||!r?t:`${t} · ${n} → ${r}`}R();var Bn=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`]),Vn=`.png,.jpg,.jpeg,.gif,.webp,.bmp,.svg,.pdf,.txt,.md,.csv,.json,.log`,Hn=20971520,Un=3840,Wn=new Set([`image/png`,`image/jpeg`,`image/jpg`,`image/webp`,`image/bmp`]);function Gn(e){if(e.size<=3670016)return!1;let t=String(e.type||``).toLowerCase();return t?Wn.has(t):/\.(png|jpe?g|webp|bmp)$/i.test(e.name)}function Kn(e,t){return`${String(e||`attachment`).replace(/\.[^./\\]+$/,``)}.${t}`}async function qn(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 Jn(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 Yn(e){let t=await qn(e);if(!t)return null;try{let n=[{edge:Un,quality:.95},{edge:Un,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 Jn(o,`image/webp`,e.quality)||await Jn(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 Xn(){let e=M({}),t=M(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(!Bn.has(n.type)&&!n.name.match(/\.(png|jpg|jpeg|gif|webp|bmp|svg|pdf|txt|md|markdown|csv|json|log)$/i)){P.error(`${Z(`@WORKBENCH:不支持的文件类型`)}(${n.name})`);return}if(a(t).find(e=>e.originalName===n.name&&e.size===n.size)){P.info(`${n.name} ${Z(`@WORKBENCH:已存在,已复用`)}`);return}let c=i(t);e.value[c]=!0;try{let e=n;if(Gn(n)){let t=await Yn(n);t&&(e=r(t.blob,Kn(n.name,t.ext)),P.info(Z(`@WORKBENCH:图片过大,已压缩后上传:{from} → {to}`,{from:g(n.size),to:g(e.size)})))}if(e.size>20971520){P.error(`「${n.name}」${Z(`@WORKBENCH:超过 {size} 限制`,{size:g(Hn)})}`);return}let i=await fetch(s(t),{method:`POST`,headers:{"Content-Type":`application/octet-stream`,"X-Original-Name":encodeURIComponent(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),P.success(`${Z(`@WORKBENCH:已添加:`)}${e.name}`)}else P.error(i.error||Z(`@WORKBENCH:上传失败`))}catch(e){P.error(Z(`@WORKBENCH:上传失败`)+`:`+(e&&e.message||e))}finally{e.value[c]=!1}}async function f(e,t){try{await U.confirm(Z(`@WORKBENCH:删除附件「{name}」?`,{name:t.originalName}),Z(`@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)),P.success(Z(`@WORKBENCH:已删除`))):P.error(n.error||Z(`@WORKBENCH:删除失败`))}function p(e){let t=document.createElement(`input`);t.type=`file`,t.accept=Vn,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}}c();var Zn=`__simple`,Qn=65536;function $n(e,t){function n(t){if(!t)return[];let n=`${t.id}${Zn}`;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:Y(()=>{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=Ke(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>Qn?`\u2026(前文已截断)\n${o.slice(-65536)}`:o,l=s.length>Qn?`\u2026(前文已截断)\n${s.slice(-65536)}`:s,u=!!c,d=!!l,f=Ye(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:Je(c,t.id),reasoning:d?l:void 0,reasoningStatus:d?!i&&u||u?`done`:h===`streaming`?`streaming`:`done`:void 0,...kt(t),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:Zn,MAX_LOG_DISPLAY_SIMPLE:Qn}}c(),R();function er(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?!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?P.success(t.message||Z(`@WORKBENCH:已加入执行队列`)):P.error(t.error||Z(`@WORKBENCH:执行失败`))}async function s(t,n){let r=e.value.filter(e=>e.taskId===t.id).slice(-1)[0];if(!r)return P.error(Z(`@WORKBENCH:没有可续接的会话`)),!1;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)}));return a.success?(P.success(a.message||Z(`@WORKBENCH:已加入续接队列`)),!0):(P.error(a.error||Z(`@WORKBENCH:续接失败`)),!1)}let c=pe({}),l=new Set,u=0;function d(t){return e.value.some(e=>e.taskId===t&&(e.status===`running`||e.status===`pending`))}function f(e){return c[e]??[]}function p(e,t,n=[]){(c[e.id]??(c[e.id]=[])).push({id:`q-${Date.now()}-${++u}`,text:t,files:n})}function m(e,t){let n=c[e];if(!n)return;let r=n.findIndex(e=>e.id===t);r<0||(n.splice(r,1),n.length||delete c[e])}async function h(e,t){for(let n of t.files)await r.uploadAttachment({kind:`task`,task:e},n.file);return await s(e,t.text)}async function g(e){if(l.has(e))return;let n=c[e];if(!n||n.length===0||d(e))return;let r=t.value.find(t=>t.id===e);if(!r){delete c[e];return}let i=n[0];l.add(e);try{await h(r,i)&&m(e,i.id)}finally{l.delete(e)}}let _=Y(()=>{let t=new Set;for(let n of e.value)(n.status===`running`||n.status===`pending`)&&t.add(n.taskId);return t});z(_,(t,n)=>{if(n)for(let r of n)t.has(r)||c[r]?.length&&e.value.some(e=>e.taskId===r)&&g(r)});async function v(e,t){let n=t.text.trim();if(n){if(d(e.id)){p(e,n,t.files);return}await h(e,{text:n,files:t.files})}}async function y(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){P.error(Z(`@WORKBENCH:找不到对应任务,无法重新执行`));return}await o(n)}async function b(e){try{await U.confirm(Z(`@WORKBENCH:确认停止执行?已输出的内容会保留。`),Z(`@WORKBENCH:停止执行`),{confirmButtonText:Z(`@WORKBENCH:停止`),cancelButtonText:Z(`@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?P.success(Z(`@WORKBENCH:已发送停止信号`)):P.error(t.error||Z(`@WORKBENCH:停止失败`))}async function x(){if(!n.value)return;let t=n.value,r=e.value.filter(e=>e.taskId===t.id),i=r.filter(e=>e.status===`running`||e.status===`pending`).length,a=r.length===0?Z(`@WORKBENCH:当前任务还没有执行内容,确认仍要清空?`):Z(`@WORKBENCH:将清空 {m} 条执行记录,任务描述/附件保留。`,{m:r.length});try{await U.confirm(a,Z(`@WORKBENCH:清空执行内容`),{confirmButtonText:Z(`@WORKBENCH:清空`),cancelButtonText:Z(`@WORKBENCH:取消`),type:`warning`})}catch{return}if(i>0){P.warning(Z(`@WORKBENCH:任务正在执行,请先停止`));return}let o=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)}));o?.success?(e.value=e.value.filter(e=>e.taskId!==t.id),P.success(o.message||Z(`@WORKBENCH:已清空执行内容`))):P.error(o?.error||Z(`@WORKBENCH:清空失败`))}return{runTask:o,continueChat:s,onContinueSendFromChat:v,onReExecuteJob:y,cancelJob:b,clearExecutionForSelectedTask:x,isTaskRunning:d,queuedChatsOf:f,removeQueuedChat:m,flushNextQueued:g}}R();function tr(){let e=M([]),t=M([]),n=M({path:``,name:``});function r(n,r){if(n===`hello`){t.value=r.jobs||[];return}if(n===`job:update`){let e=r,n=t.value.findIndex(t=>t.id===e.id);if(n>=0){let r=t.value[n];!e.thinkingStartedAt&&r.thinkingStartedAt&&(e.thinkingStartedAt=r.thinkingStartedAt),!e.thinkingEndedAt&&r.thinkingEndedAt&&(e.thinkingEndedAt=r.thinkingEndedAt),t.value[n]=e}else t.value.push(e);return}if(n===`job:thinking-delta`||n===`job:output-delta`){let e=n===`job:thinking-delta`?`thinking`:`output`,i=r?.delta||``;if(!i)return;let a=t.value.findIndex(e=>e.id===r.id);if(a<0)return;let o=t.value[a];if(o[e]=(o[e]||``)+i,n===`job:thinking-delta`){let e=new Date().toISOString();o.thinkingStartedAt||=e,o.thinkingEndedAt=e}return}if(n===`job:toolcalls`){let e=Array.isArray(r?.updates)?r.updates:[];if(!e.length)return;let n=t.value.findIndex(e=>e.id===r.id);if(n<0)return;let i=t.value[n];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(n===`task:update`){let t=e.value.findIndex(e=>e.id===r.id);t>=0&&(e.value[t]=r)}if(n===`tasks:reordered`){if(Array.isArray(r?.tasks)){if(r.tasks.length<e.value.length){console.warn(`[SSE tasks:reordered] 数据丢失风险:当前 ${e.value.length} 个任务,服务端只返回 ${r.tasks.length} 个,拒绝覆盖`);return}e.value=r.tasks}return}n===`task:error`&&P.error(r.error||Z(`@WORKBENCH:执行出错`))}let i=null;function a(){i&&=(i.close(),null),i=new EventSource(`/api/workbench/events`),i.onmessage=e=>{try{let t=JSON.parse(e.data);r(t.event,t.payload)}catch{}},i.onerror=()=>{i&&=(i.close(),null),setTimeout(a,3e3)}}function o(){i&&=(i.close(),null)}async function s(t){let n=await fetch(`/api/workbench/tasks`).then(e=>e.json()).catch(()=>({tasks:[]}));e.value=n.tasks||[],t?.()}async function c(){let e=await fetch(`/api/workbench/current-project`).then(e=>e.json()).catch(()=>({}));e&&typeof e.projectPath==`string`&&(n.value={path:e.projectPath,name:e.projectName||``})}async function l(){let e=await fetch(`/api/workbench/jobs`).then(e=>e.json()).catch(()=>({jobs:[]}));t.value=e.jobs||[]}async function u(e){try{let n=await fetch(`/api/workbench/jobs/by-task/${encodeURIComponent(e)}`,{method:`DELETE`}).then(e=>e.json());return n?.success?(t.value=t.value.filter(t=>t.taskId!==e),n.removed||0):(console.warn(`[clearJobsByTask] failed:`,n?.error),0)}catch(e){return console.warn(`[clearJobsByTask] error:`,e),0}}async function d(e){let t={title:``,desc:``};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:(P.error(e.error||Z(`@WORKBENCH:保存失败`)),null)}catch{return P.error(Z(`@WORKBENCH:保存失败`)),null}}return{tasks:e,jobs:t,currentProject:n,applyJobEvent:r,connectSSE:a,disconnectSSE:o,loadTasks:s,loadCurrentProject:c,loadJobs:l,clearJobsByTask:u,createTask:d}}R(),c();var nr=`__no_project__`,rr=`wb.collapsedGroupPaths.v1`,ir=`wb.seenGroupPaths.v1`;function ar(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 or(e,t){try{localStorage.setItem(e,JSON.stringify(Array.from(t)))}catch{}}function sr(e,t){let n=M(ar(rr)),r=M(ar(ir));z(n,e=>or(rr,e),{deep:!1}),z(r,e=>or(ir,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=Y(()=>{let r=e.value,i=new Map;for(let e of r){let t=$(e.projectPath)||nr;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===nr?1:t===nr?-1:e.localeCompare(t));return{groups:o.map(e=>({path:e,label:e===nr?Z(`@WORKBENCH:未关联项目`):e,tasks:i.get(e)})),hasMultiple:o.length>1||o.length===1&&n.value.has(o[0])}});function s(e){if(!e||e===nr)return e;let t=e.split(/[\\/]/).filter(Boolean);return t.length<=1?e:t.slice(-2).join(`/`)}let c=Y(()=>`${$(t.value.path)}|${o.value.groups.map(e=>e.path).join(`
|
|
22
|
-
`)}`);return z(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}}c(),R();var
|
|
23
|
-
提示词分组保留 header(含 + 新建按钮 + 计数),信息密度不一对齐,后续按需统一。 `),b(`button`,{class:`wb-new-btn`,disabled:i.creatingTask,onClick:n[0]||=e=>a.emit(`create-task`)},[e(c,{class:`wb-new-btn__icon`},{default:F(()=>[e(a.Plus)]),_:1}),b(`span`,null,T(a.$t(`@WORKBENCH:新建任务`)),1),n[4]||=b(`span`,{class:`wb-new-btn__shortcut`},`N`,-1)],8,
|
|
24
|
-
.wb-task-group__list 那段:单项目攒到几十条时不会把别的项目顶出可视区。 `),b(`ul`,{class:w([`wb-task-list`,{"is-grouped":a.groupedTasksList.hasMultiple}])},[(H(!0),x(O,null,E(a.groupedTasksList.groups,t=>(H(),x(`li`,{key:t.path,class:`wb-task-group`},[a.groupedTasksList.hasMultiple?(H(),x(`div`,{key:0,class:w([`wb-task-group__head`,{"is-current":t.path===a.currentProjectKey,"is-collapsed":a.isGroupCollapsed(t.path)}]),role:`button`,tabindex:`0`,"aria-expanded":!a.isGroupCollapsed(t.path),title:a.isGroupCollapsed(t.path)?a.$t(`@WORKBENCH:展开`):a.$t(`@WORKBENCH:收起`),onClick:e=>a.toggleGroupCollapsed(t.path),onKeydown:[N(j(e=>a.toggleGroupCollapsed(t.path),[`prevent`]),[`enter`]),N(j(e=>a.toggleGroupCollapsed(t.path),[`prevent`]),[`space`])]},[e(c,{class:`wb-task-group__caret`},{default:F(()=>[(H(),r(g(a.isGroupCollapsed(t.path)?a.ArrowRight:a.ArrowDown)))]),_:2},1024),e(c,{class:`wb-task-group__icon`},{default:F(()=>[e(a.Folder)]),_:1}),b(`span`,{class:`wb-task-group__name`,title:t.path===a.currentProjectKey?i.currentProject.path:t.label},T(t.path===a.currentProjectKey?i.currentProject.name:a.shortProjectLabel(t.label)),9,
|
|
25
|
-
子任务数 / 附件数 等 meta 行已移除,降噪 `),b(`div`,
|
|
20
|
+
`),A(b(`div`,qt,[b(`div`,Jt,[e(a.ChatContainer,{messages:a.chatMessages,"assistant-name":a.assistantLabel,"assistant-avatar":a.assistantAvatar,"show-avatar":!0,theme:a.configStore.theme,"tool-calls-config":{group:!0,collapseThreshold:2},"plan-config":{labels:{title:a.$t(`@AGENT:计划`),raw:a.$t(`@AGENT:原始参数`)}},"file-changes-labels":a.fileChangeLabels,"show-input":!1},null,8,[`messages`,`assistant-name`,`assistant-avatar`,`theme`,`plan-config`,`file-changes-labels`])]),q(` footer:任务结束后显示"重新执行",运行中不显示 `),a.canReExecute?(H(),x(`footer`,Yt,[b(`button`,{type:`button`,class:`wb-chat__action`,title:a.$t(`@WORKBENCH:用相同的提示词重新执行此任务`),"aria-label":a.$t(`@WORKBENCH:重新执行`),onClick:a.onReExecute},` ↻ `,8,Xt)])):q(`v-if`,!0),q(` 全屏查看 dialog `),e(a.CommonDialog,{modelValue:a.fullscreenOpen,"onUpdate:modelValue":n[0]||=e=>a.fullscreenOpen=e,title:a.$t(`@WORKBENCH:模型返回 - 全屏查看`),size:`fullscreen`,type:`flex`,"close-on-click-modal":!1,"custom-class":`wb-log-fullscreen-dialog`,onClosed:a.onFullscreenClosed},{default:F(()=>[b(`div`,Zt,[a.hasOutput?(H(),r(a.MarkdownRenderer,{key:0,source:a.fullscreenSource,class:`wb-log-fullscreen__render`},null,8,[`source`])):(H(),x(`div`,Qt,T(a.$t(`@WORKBENCH:(暂无输出)`)),1))],512)]),_:1},8,[`modelValue`,`title`])],512),[[fe,!a.isCollapsed]]),q(` /.wb-log-details__body `)],2)}var en=Q(Mt,[[`render`,$t],[`__scopeId`,`data-v-a4bb55c4`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/components/JobLogDetails.vue`]]);c(),R();var tn=50,nn=f({__name:`ExecutionLogManager`,setup(e,{expose:t}){t();function n(e){return e instanceof Error?e.message:String(e)}let r=M([]),i=M(0),a=pe({count:0,sizeMB:0,byStatus:{}}),s=M(!1),c=M(new Set),l=pe({q:``,status:``,page:1}),u=M({maxCount:500,maxSizeMB:256}),d=pe({maxCount:500,maxSizeMB:256}),f=M(!1),p=[{value:`pending`,label:Z(`@WORKBENCH:排队中`)},{value:`running`,label:Z(`@WORKBENCH:执行中`)},{value:`done`,label:Z(`@WORKBENCH:已完成`)},{value:`error`,label:Z(`@WORKBENCH:出错`)},{value:`cancelled`,label:Z(`@WORKBENCH:已取消`)}],m=J(()=>r.value.length>0&&r.value.every(e=>c.value.has(e.id))),h=J(()=>r.value.some(e=>c.value.has(e.id))&&!m.value);async function g(){s.value=!0;try{let e=new URLSearchParams;l.q&&e.set(`q`,l.q),l.status&&e.set(`status`,l.status),e.set(`limit`,String(tn)),e.set(`offset`,String((l.page-1)*tn));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(c.value))n.has(e)||c.value.delete(e)}catch(e){P.error(Z(`@WORKBENCH:加载失败`)+`: `+n(e))}finally{s.value=!1}}async function _(){try{let e=await fetch(`/api/workbench/jobs/config`).then(e=>e.json());e.success&&(u.value=e.config,d.maxCount=e.config.maxCount,d.maxSizeMB=e.config.maxSizeMB)}catch{}}async function y(){f.value=!0;try{let e=await fetch(`/api/workbench/jobs/config`,{method:`PUT`,headers:{"Content-Type":`application/json`},body:JSON.stringify({maxCount:d.maxCount,maxSizeMB:d.maxSizeMB})}).then(e=>e.json());if(!e.success)throw Error(e.error||`save failed`);u.value=e.config,P.success(Z(`@WORKBENCH:已保存策略`)),await g()}catch(e){P.error(Z(`@WORKBENCH:保存失败`)+`: `+n(e))}finally{f.value=!1}}function b(){l.page=1,g()}function x(){l.q=``,l.status=``,l.page=1,g()}function S(e,t){t?c.value.add(e):c.value.delete(e),c.value=new Set(c.value)}function C(e){if(e)for(let e of r.value)c.value.add(e.id);else for(let e of r.value)c.value.delete(e.id);c.value=new Set(c.value)}function w(e){P.info(Z(`@WORKBENCH:请到工作台主面板的对应任务上点击「重新执行」`))}async function ee(e){try{await U.confirm(Z(`@WORKBENCH:确定要删除所选的 {count} 条日志吗?`,{count:1}),Z(`@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`);c.value.delete(e),c.value=new Set(c.value),await g()}catch(e){P.error(Z(`@WORKBENCH:保存失败`)+`: `+n(e))}}async function T(){let e=Array.from(c.value);if(e.length!==0){try{await U.confirm(Z(`@WORKBENCH:确定要删除所选的 {count} 条日志吗?`,{count:e.length}),Z(`@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`);P.success(Z(`@WORKBENCH:成功删除 {count} 条`,{count:t.removed||e.length})),c.value=new Set,await g()}catch(e){P.error(Z(`@WORKBENCH:保存失败`)+`: `+n(e))}}}async function te(){let e=a.count;if(e!==0){try{await U.confirm(Z(`@WORKBENCH:确定要清空所有 {count} 条执行日志吗?此操作不可恢复。`,{count:e}),Z(`@WORKBENCH:清空全部`),{type:`warning`,confirmButtonText:Z(`@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`);P.success(Z(`@WORKBENCH:成功删除 {count} 条`,{count:t.removed||e})),c.value=new Set,await g()}catch(e){P.error(Z(`@WORKBENCH:保存失败`)+`: `+n(e))}}}function E(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`}o(()=>{g(),_()});let ne={errMsg:n,list:r,total:i,stats:a,loading:s,selectedIds:c,pageSize:tn,filter:l,config:u,configDraft:d,configSaving:f,STATUS_OPTIONS:p,isAllOnPageSelected:m,isSomeOnPageSelected:h,load:g,loadConfig:_,saveConfig:y,onFilterChange:b,resetFilter:x,toggleSelect:S,toggleSelectAllOnPage:C,onReExecuteInLog:w,deleteOne:ee,batchDelete:T,clearAll:te,formatDuration:E,get Document(){return le},get Refresh(){return v},get $t(){return Z},get statusLabel(){return Xe},get statusColor(){return $e},JobLogDetails:en};return Object.defineProperty(ne,"__isScriptSetup",{enumerable:!1,value:!0}),ne}});c(),I(),B();var rn={class:`exec-logs`},an={class:`exec-logs__head`},on={class:`exec-logs__title-block`},sn={class:`exec-logs__stats`},cn={class:`exec-logs__head-actions`},ln={class:`exec-logs__config`},un={class:`exec-logs__config-label`},dn={class:`exec-logs__config-field`},fn={class:`exec-logs__config-name`},pn={class:`exec-logs__config-field`},mn={class:`exec-logs__config-name`},hn={class:`exec-logs__filter`},gn={key:0,class:`exec-logs__batch-meta`},_n={key:0,class:`exec-logs__batch`},vn={class:`exec-logs__list`},yn={key:0,class:`exec-logs__empty`},bn={class:`exec-logs__empty-art`,"aria-hidden":`true`},xn={class:`exec-logs__empty-title`},Sn={class:`exec-logs__empty-hint`},Cn={class:`exec-card__head`},wn=[`title`],Tn={class:`exec-card__meta`},En={key:0,class:`exec-card__task`},Dn={key:1,class:`exec-card__time`},On={key:2,class:`exec-card__exit`},kn=[`title`,`onClick`],An={key:0,class:`exec-card__error`},jn={key:1,class:`exec-logs__pager`};function Mn(t,n,r,a,o,c){let d=_e,f=Y,m=S,h=i,g=s,_=p,v=l,y=G,C=k;return H(),x(`div`,rn,[q(` 头部:统计 + 刷新 + 清空。
|
|
21
|
+
标题已由外层 el-dialog 提供,这里不再重复 h2。 `),b(`header`,an,[b(`div`,on,[b(`span`,sn,T(a.$t(`@WORKBENCH:共 {count} 条,占 {size} MB`,{count:a.stats.count,size:a.stats.sizeMB})),1)]),b(`div`,cn,[e(d,{icon:a.Refresh,size:`small`,loading:a.loading,onClick:a.load},{default:F(()=>[L(T(a.$t(`@WORKBENCH:刷新`)),1)]),_:1},8,[`icon`,`loading`]),e(d,{type:`danger`,plain:``,size:`small`,disabled:a.stats.count===0,onClick:a.clearAll},{default:F(()=>[L(T(a.$t(`@WORKBENCH:清空全部`)),1)]),_:1},8,[`disabled`])])]),q(` 保留策略 `),b(`div`,ln,[b(`span`,un,T(a.$t(`@WORKBENCH:保存策略`)),1),b(`span`,dn,[b(`span`,fn,T(a.$t(`@WORKBENCH:最大条数`)),1),e(f,{modelValue:a.configDraft.maxCount,"onUpdate:modelValue":n[0]||=e=>a.configDraft.maxCount=e,min:0,max:1e4,step:50,size:`small`,"controls-position":`right`,style:{width:`130px`}},null,8,[`modelValue`])]),b(`span`,pn,[b(`span`,mn,T(a.$t(`@WORKBENCH:最大体积 (MB)`)),1),e(f,{modelValue:a.configDraft.maxSizeMB,"onUpdate:modelValue":n[1]||=e=>a.configDraft.maxSizeMB=e,min:0,max:10240,step:32,size:`small`,"controls-position":`right`,style:{width:`140px`}},null,8,[`modelValue`])]),e(d,{type:`primary`,size:`small`,loading:a.configSaving,onClick:a.saveConfig},{default:F(()=>[L(T(a.$t(`@WORKBENCH:保存策略`)),1)]),_:1},8,[`loading`])]),q(` 过滤栏 `),b(`div`,hn,[e(m,{modelValue:a.filter.q,"onUpdate:modelValue":n[2]||=e=>a.filter.q=e,placeholder:a.$t(`@WORKBENCH:搜索标题 / 任务`),clearable:``,size:`small`,style:{width:`240px`},onKeyup:N(a.onFilterChange,[`enter`]),onClear:a.onFilterChange},null,8,[`modelValue`,`placeholder`]),e(g,{modelValue:a.filter.status,"onUpdate:modelValue":n[3]||=e=>a.filter.status=e,placeholder:a.$t(`@WORKBENCH:全部状态`),clearable:``,size:`small`,style:{width:`130px`},onChange:a.onFilterChange},{default:F(()=>[(H(),x(O,null,E(a.STATUS_OPTIONS,t=>e(h,{key:t.value,label:t.label,value:t.value},null,8,[`label`,`value`])),64))]),_:1},8,[`modelValue`,`placeholder`]),e(d,{size:`small`,onClick:a.resetFilter},{default:F(()=>[L(T(a.$t(`@WORKBENCH:重置`)),1)]),_:1}),n[5]||=b(`span`,{class:`exec-logs__filter-spacer`},null,-1),a.selectedIds.size>0?(H(),x(`span`,gn,T(a.$t(`@WORKBENCH:已选择 {count} 项`,{count:a.selectedIds.size})),1)):q(`v-if`,!0)]),q(` 批量操作条 `),a.selectedIds.size>0?(H(),x(`div`,_n,[e(_,{"model-value":a.isAllOnPageSelected,indeterminate:a.isSomeOnPageSelected,onChange:a.toggleSelectAllOnPage},{default:F(()=>[L(T(a.isAllOnPageSelected?a.$t(`@WORKBENCH:取消全选`):a.$t(`@WORKBENCH:全选`)),1)]),_:1},8,[`model-value`,`indeterminate`]),e(d,{type:`danger`,size:`small`,onClick:a.batchDelete},{default:F(()=>[L(T(a.$t(`@WORKBENCH:批量删除`)),1)]),_:1})])):q(`v-if`,!0),q(` 列表 `),A((H(),x(`div`,vn,[!a.loading&&a.list.length===0?(H(),x(`div`,yn,[b(`div`,bn,[e(v,null,{default:F(()=>[e(a.Document)]),_:1})]),b(`div`,xn,T(a.$t(`@WORKBENCH:暂无执行日志`)),1),b(`div`,Sn,T(a.$t(`@WORKBENCH:点击「执行任务」开始一次执行,日志会出现在这里。`)),1)])):q(`v-if`,!0),(H(!0),x(O,null,E(a.list,t=>(H(),x(`article`,{key:t.id,class:w([`exec-card`,{"is-selected":a.selectedIds.has(t.id)}])},[b(`header`,Cn,[e(_,{"model-value":a.selectedIds.has(t.id),onChange:e=>a.toggleSelect(t.id,e)},null,8,[`model-value`,`onChange`]),b(`span`,{class:`exec-card__status`,style:u({color:a.statusColor(t.status),borderColor:a.statusColor(t.status)})},T(a.statusLabel(t.status)),5),b(`span`,{class:`exec-card__title`,title:t.title||a.$t(`@WORKBENCH:无标题`)},T(t.title||a.$t(`@WORKBENCH:无标题`)),9,wn),n[6]||=b(`span`,{class:`exec-card__spacer`},null,-1),b(`span`,Tn,[t.taskTitle?(H(),x(`span`,En,`📁 `+T(t.taskTitle),1)):q(`v-if`,!0),t.startedAt?(H(),x(`span`,Dn,`⏱ `+T(a.formatDuration(t.startedAt,t.endedAt)),1)):q(`v-if`,!0),t.exitCode===null?q(`v-if`,!0):(H(),x(`span`,On,`exit `+T(t.exitCode),1))]),b(`button`,{type:`button`,class:`exec-card__del`,title:a.$t(`@WORKBENCH:删除`),onClick:e=>a.deleteOne(t.id)},`×`,8,kn)]),t.error?(H(),x(`p`,An,`⚠ `+T(t.error),1)):q(`v-if`,!0),e(a.JobLogDetails,{job:t,onReExecute:a.onReExecuteInLog},null,8,[`job`])],2))),128))])),[[C,a.loading]]),q(` 分页 `),a.total>a.pageSize?(H(),x(`footer`,jn,[e(y,{"current-page":a.filter.page,"onUpdate:currentPage":n[4]||=e=>a.filter.page=e,"page-size":a.pageSize,total:a.total,layout:`prev, pager, next, total`,background:``,small:``,onCurrentChange:a.load},null,8,[`current-page`,`total`])])):q(`v-if`,!0)])}var Nn=Q(nn,[[`render`,Mn],[`__scopeId`,`data-v-d3ebe953`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/components/ExecutionLogManager.vue`]]);function Pn(e){return String(e.manualDoneAt||e.lastJobEndedAt||e.updatedAt||e.createdAt||``)}function Fn(e){return e.column===`done`?Pn(e):e.updatedAt||e.createdAt||``}function In(e){return e.live?``:nt(e.lastDurationMs)}function Ln(e){let t=In(e);return t?Z(`@WORKBENCH:用时 {d}`,{d:t}):``}function Rn(e){return e.live?Z(`@WORKBENCH:已运行 {elapsed}`,{elapsed:nt(e.live.elapsedMs)}):``}function zn(e){return Rn(e)||Ln(e)}function Bn(e){let t=In(e);if(!t)return``;let n=it(e.lastJobStartedAt),r=it(e.lastJobEndedAt);return!n||!r?t:`${t} · ${n} → ${r}`}R();var Vn=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`]),Hn=`.png,.jpg,.jpeg,.gif,.webp,.bmp,.svg,.pdf,.txt,.md,.csv,.json,.log`,Un=20971520,Wn=3840,Gn=new Set([`image/png`,`image/jpeg`,`image/jpg`,`image/webp`,`image/bmp`]);function Kn(e){if(e.size<=3670016)return!1;let t=String(e.type||``).toLowerCase();return t?Gn.has(t):/\.(png|jpe?g|webp|bmp)$/i.test(e.name)}function qn(e,t){return`${String(e||`attachment`).replace(/\.[^./\\]+$/,``)}.${t}`}async function Jn(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 Yn(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 Xn(e){let t=await Jn(e);if(!t)return null;try{let n=[{edge:Wn,quality:.95},{edge:Wn,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 Yn(o,`image/webp`,e.quality)||await Yn(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 Zn(){let e=M({}),t=M(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(!Vn.has(n.type)&&!n.name.match(/\.(png|jpg|jpeg|gif|webp|bmp|svg|pdf|txt|md|markdown|csv|json|log)$/i)){P.error(`${Z(`@WORKBENCH:不支持的文件类型`)}(${n.name})`);return}if(a(t).find(e=>e.originalName===n.name&&e.size===n.size)){P.info(`${n.name} ${Z(`@WORKBENCH:已存在,已复用`)}`);return}let c=i(t);e.value[c]=!0;try{let e=n;if(Kn(n)){let t=await Xn(n);t&&(e=r(t.blob,qn(n.name,t.ext)),P.info(Z(`@WORKBENCH:图片过大,已压缩后上传:{from} → {to}`,{from:g(n.size),to:g(e.size)})))}if(e.size>20971520){P.error(`「${n.name}」${Z(`@WORKBENCH:超过 {size} 限制`,{size:g(Un)})}`);return}let i=await fetch(s(t),{method:`POST`,headers:{"Content-Type":`application/octet-stream`,"X-Original-Name":encodeURIComponent(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),P.success(`${Z(`@WORKBENCH:已添加:`)}${e.name}`)}else P.error(i.error||Z(`@WORKBENCH:上传失败`))}catch(e){P.error(Z(`@WORKBENCH:上传失败`)+`:`+(e&&e.message||e))}finally{e.value[c]=!1}}async function f(e,t){try{await U.confirm(Z(`@WORKBENCH:删除附件「{name}」?`,{name:t.originalName}),Z(`@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)),P.success(Z(`@WORKBENCH:已删除`))):P.error(n.error||Z(`@WORKBENCH:删除失败`))}function p(e){let t=document.createElement(`input`);t.type=`file`,t.accept=Hn,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}}c();var Qn=`__simple`,$n=65536;function er(e,t){function n(t){if(!t)return[];let n=`${t.id}${Qn}`;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:J(()=>{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=qe(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>$n?`\u2026(前文已截断)\n${o.slice(-65536)}`:o,l=s.length>$n?`\u2026(前文已截断)\n${s.slice(-65536)}`:s,u=!!c,d=!!l,f=Qe(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:Ye(c,t.id),reasoning:d?l:void 0,reasoningStatus:d?!i&&u||u?`done`:h===`streaming`?`streaming`:`done`:void 0,...At(t),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:Qn,MAX_LOG_DISPLAY_SIMPLE:$n}}c(),R();function tr(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?!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?P.success(t.message||Z(`@WORKBENCH:已加入执行队列`)):P.error(t.error||Z(`@WORKBENCH:执行失败`))}async function s(t,n,r){let i=r??e.value.filter(e=>e.taskId===t.id).slice(-1)[0];if(!i)return P.error(Z(`@WORKBENCH:没有可续接的会话`)),!1;let a=Array.isArray(t.attachments)?t.attachments:[],o=await fetch(`/api/workbench/jobs/${i.id}/continue`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({userMessage:n,attachments:a})}).then(e=>e.json()).catch(e=>({success:!1,error:e?.message||String(e)}));return o.success?(P.success(o.message||Z(`@WORKBENCH:已加入续接队列`)),!0):(P.error(o.error||Z(`@WORKBENCH:续接失败`)),!1)}async function c(t,n,r){if(!r.claudeSessionId)return P.error(Z(`@WORKBENCH:上一轮没有会话标识,无法重试这一轮,请重新发送`)),!1;let i=qe(n.prompt);if(!i)return P.error(Z(`@WORKBENCH:这一轮没有可重发的消息`)),!1;let a=await fetch(`/api/workbench/jobs/${encodeURIComponent(n.id)}`,{method:`DELETE`}).then(e=>e.json()).catch(e=>({success:!1,error:e?.message||String(e)}));return a?.success?(e.value=e.value.filter(e=>e.id!==n.id),await s(t,i,r)):(P.error(a?.error||Z(`@WORKBENCH:重试失败,请稍后再试`)),!1)}let l=pe({}),u=new Set,d=0;function f(t){return e.value.some(e=>e.taskId===t&&(e.status===`running`||e.status===`pending`))}function p(e){return l[e]??[]}function m(e,t,n=[]){(l[e.id]??(l[e.id]=[])).push({id:`q-${Date.now()}-${++d}`,text:t,files:n})}function h(e,t){let n=l[e];if(!n)return;let r=n.findIndex(e=>e.id===t);r<0||(n.splice(r,1),n.length||delete l[e])}async function g(e,t){for(let n of t.files)await r.uploadAttachment({kind:`task`,task:e},n.file);return await s(e,t.text)}async function _(e){if(u.has(e))return;let n=l[e];if(!n||n.length===0||f(e))return;let r=t.value.find(t=>t.id===e);if(!r){delete l[e];return}let i=n[0];u.add(e);try{await g(r,i)&&h(e,i.id)}finally{u.delete(e)}}let v=J(()=>{let t=new Set;for(let n of e.value)(n.status===`running`||n.status===`pending`)&&t.add(n.taskId);return t});z(v,(t,n)=>{if(n)for(let r of n)t.has(r)||l[r]?.length&&e.value.some(e=>e.taskId===r)&&_(r)});async function y(e,t){let n=t.text.trim();if(n){if(f(e.id)){m(e,n,t.files);return}await g(e,{text:n,files:t.files})}}async function b(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){P.error(Z(`@WORKBENCH:找不到对应任务,无法重新执行`));return}await o(n)}async function x(e){try{await U.confirm(Z(`@WORKBENCH:确认停止执行?已输出的内容会保留。`),Z(`@WORKBENCH:停止执行`),{confirmButtonText:Z(`@WORKBENCH:停止`),cancelButtonText:Z(`@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?P.success(Z(`@WORKBENCH:已发送停止信号`)):P.error(t.error||Z(`@WORKBENCH:停止失败`))}async function S(){if(!n.value)return;let t=n.value,r=e.value.filter(e=>e.taskId===t.id),i=r.filter(e=>e.status===`running`||e.status===`pending`).length,a=r.length===0?Z(`@WORKBENCH:当前任务还没有执行内容,确认仍要清空?`):Z(`@WORKBENCH:将清空 {m} 条执行记录,任务描述/附件保留。`,{m:r.length});try{await U.confirm(a,Z(`@WORKBENCH:清空执行内容`),{confirmButtonText:Z(`@WORKBENCH:清空`),cancelButtonText:Z(`@WORKBENCH:取消`),type:`warning`})}catch{return}if(i>0){P.warning(Z(`@WORKBENCH:任务正在执行,请先停止`));return}let o=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)}));o?.success?(e.value=e.value.filter(e=>e.taskId!==t.id),P.success(o.message||Z(`@WORKBENCH:已清空执行内容`))):P.error(o?.error||Z(`@WORKBENCH:清空失败`))}return{runTask:o,continueChat:s,onContinueSendFromChat:y,onReExecuteJob:b,retryRound:c,cancelJob:x,clearExecutionForSelectedTask:S,isTaskRunning:f,queuedChatsOf:p,removeQueuedChat:h,flushNextQueued:_}}R();function nr(){let e=M([]),t=M([]),n=M({path:``,name:``});function r(n,r){if(n===`hello`){t.value=r.jobs||[];return}if(n===`job:update`){let e=r,n=t.value.findIndex(t=>t.id===e.id);if(n>=0){let r=t.value[n];!e.thinkingStartedAt&&r.thinkingStartedAt&&(e.thinkingStartedAt=r.thinkingStartedAt),!e.thinkingEndedAt&&r.thinkingEndedAt&&(e.thinkingEndedAt=r.thinkingEndedAt),t.value[n]=e}else t.value.push(e);return}if(n===`job:thinking-delta`||n===`job:output-delta`){let e=n===`job:thinking-delta`?`thinking`:`output`,i=r?.delta||``;if(!i)return;let a=t.value.findIndex(e=>e.id===r.id);if(a<0)return;let o=t.value[a];if(o[e]=(o[e]||``)+i,n===`job:thinking-delta`){let e=new Date().toISOString();o.thinkingStartedAt||=e,o.thinkingEndedAt=e}return}if(n===`job:toolcalls`){let e=Array.isArray(r?.updates)?r.updates:[];if(!e.length)return;let n=t.value.findIndex(e=>e.id===r.id);if(n<0)return;let i=t.value[n];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(n===`task:update`){let t=e.value.findIndex(e=>e.id===r.id);t>=0&&(e.value[t]=r)}if(n===`tasks:reordered`){if(Array.isArray(r?.tasks)){if(r.tasks.length<e.value.length){console.warn(`[SSE tasks:reordered] 数据丢失风险:当前 ${e.value.length} 个任务,服务端只返回 ${r.tasks.length} 个,拒绝覆盖`);return}e.value=r.tasks}return}n===`task:error`&&P.error(r.error||Z(`@WORKBENCH:执行出错`))}let i=null;function a(){i&&=(i.close(),null),i=new EventSource(`/api/workbench/events`),i.onmessage=e=>{try{let t=JSON.parse(e.data);r(t.event,t.payload)}catch{}},i.onerror=()=>{i&&=(i.close(),null),setTimeout(a,3e3)}}function o(){i&&=(i.close(),null)}async function s(t){let n=await fetch(`/api/workbench/tasks`).then(e=>e.json()).catch(()=>({tasks:[]}));e.value=n.tasks||[],t?.()}async function c(){let e=await fetch(`/api/workbench/current-project`).then(e=>e.json()).catch(()=>({}));e&&typeof e.projectPath==`string`&&(n.value={path:e.projectPath,name:e.projectName||``})}async function l(){let e=await fetch(`/api/workbench/jobs`).then(e=>e.json()).catch(()=>({jobs:[]}));t.value=e.jobs||[]}async function u(e){try{let n=await fetch(`/api/workbench/jobs/by-task/${encodeURIComponent(e)}`,{method:`DELETE`}).then(e=>e.json());return n?.success?(t.value=t.value.filter(t=>t.taskId!==e),n.removed||0):(console.warn(`[clearJobsByTask] failed:`,n?.error),0)}catch(e){return console.warn(`[clearJobsByTask] error:`,e),0}}async function d(e){let t={title:``,desc:``};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:(P.error(e.error||Z(`@WORKBENCH:保存失败`)),null)}catch{return P.error(Z(`@WORKBENCH:保存失败`)),null}}return{tasks:e,jobs:t,currentProject:n,applyJobEvent:r,connectSSE:a,disconnectSSE:o,loadTasks:s,loadCurrentProject:c,loadJobs:l,clearJobsByTask:u,createTask:d}}R(),c();var rr=`__no_project__`,ir=`wb.collapsedGroupPaths.v1`,ar=`wb.seenGroupPaths.v1`;function or(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 sr(e,t){try{localStorage.setItem(e,JSON.stringify(Array.from(t)))}catch{}}function cr(e,t){let n=M(or(ir)),r=M(or(ar));z(n,e=>sr(ir,e),{deep:!1}),z(r,e=>sr(ar,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=J(()=>{let r=e.value,i=new Map;for(let e of r){let t=$(e.projectPath)||rr;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===rr?1:t===rr?-1:e.localeCompare(t));return{groups:o.map(e=>({path:e,label:e===rr?Z(`@WORKBENCH:未关联项目`):e,tasks:i.get(e)})),hasMultiple:o.length>1||o.length===1&&n.value.has(o[0])}});function s(e){if(!e||e===rr)return e;let t=e.split(/[\\/]/).filter(Boolean);return t.length<=1?e:t.slice(-2).join(`/`)}let c=J(()=>`${$(t.value.path)}|${o.value.groups.map(e=>e.path).join(`
|
|
22
|
+
`)}`);return z(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}}c(),R();var lr=5,ur=f({__name:`WorkbenchSidebar`,props:{tasks:{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`,`reorder-tasks`],setup(e,{expose:n,emit:r}){n();let i=e,o=r,s=J(()=>i.currentProject),c=J(()=>i.tasks),{groupedTasksList:l,isGroupCollapsed:u,toggleGroupCollapsed:d,shortProjectLabel:f}=cr(c,s),p=J(()=>$(i.currentProject.path));function m(e){return!!e.projectPath&&$(e.projectPath)!==p.value}z(()=>i.selectedTaskId,async e=>{e&&(await t(),document.querySelector(`.wb-task-item[data-task-id="${e}"]`)?.scrollIntoView({block:`nearest`}))},{immediate:!0});function h(e){return(e.title||``).trim()||(e.desc||``).replace(/\s+/g,` `).trim()||Z(`@WORKBENCH:未命名任务`)}function g(e){let t=h(e),n=Z(`@WORKBENCH:拖动排序提示`);return t?`${t} · ${n}`:n}function _(e){return i.isTaskRunning(e)}let v=M(null),y=M(null),b=M(null),x=M(null),S=M(null),C=null;function w(){v.value=null,y.value=null,b.value=null,x.value=null,S.value=null,C=null}function ee(e,t,n,r){e.button===0&&(C={pointerY:e.clientY,li:r,taskId:t.id,groupPath:n},window.addEventListener(`mousemove`,T),window.addEventListener(`mouseup`,E,{once:!0}))}function T(e){if(!C)return;if(v.value===null){if(Math.abs(e.clientY-C.pointerY)<lr)return;v.value=C.taskId,y.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){b.value=null,x.value=null,S.value=null;return}let r=n.getAttribute(`data-task-id`),i=n.getAttribute(`data-group-path`);if(!r||!i)return;if(i!==y.value){b.value=null,x.value=null,S.value=null;return}let a=n.getBoundingClientRect(),o=a.top+a.height/2;b.value=r,x.value=i,S.value=e.clientY<o?`before`:`after`}function E(e){if(window.removeEventListener(`mousemove`,T),document.body.style.userSelect=``,!C){w();return}let t=C.groupPath,n=C.taskId,r=b.value,i=S.value,a=x.value;if(w(),!r||!i||a!==t)return;let s=l.value.groups.find(e=>e.path===t);if(!s)return;let c=s.tasks.map(e=>e.id),u=c.indexOf(n);if(u<0)return;c.splice(u,1);let d=c.indexOf(r)+ +(i===`after`);c.splice(d,0,n),o(`reorder-tasks`,{groupPath:t,orderedIds:c})}let D={props:i,emit:o,currentProjectRef:s,tasksRef:c,groupedTasksList:l,isGroupCollapsed:u,toggleGroupCollapsed:d,shortProjectLabel:f,currentProjectKey:p,isOtherProject:m,taskDisplayName:h,taskTooltip:g,taskIsRunning:_,draggingTaskId:v,dragStartGroupPath:y,dragOverTaskId:b,dragOverGroupPath:x,dragPosition:S,get dragStart(){return C},set dragStart(e){C=e},DRAG_THRESHOLD_PX:lr,resetDragState:w,onTaskMouseDown:ee,onWindowMouseMove:T,onWindowMouseUp:E,get $t(){return Z},get Plus(){return a},get Close(){return re},get DocumentAdd(){return W},get Folder(){return ae},get ArrowDown(){return te},get ArrowRight(){return ne},get CopyDocument(){return me},EmptyState:We};return Object.defineProperty(D,"__isScriptSetup",{enumerable:!1,value:!0}),D}});c(),I(),B();var dr={class:`wb-sidebar`},fr={class:`wb-section`},pr=[`disabled`],mr=[`aria-expanded`,`title`,`onClick`,`onKeydown`],hr=[`title`],gr={class:`wb-pill wb-task-group__count`},_r={key:1,class:`wb-task-group__list`},vr=[`data-task-id`,`data-group-path`,`title`,`aria-pressed`,`onClick`,`onKeydown`,`onMousedown`],yr={class:`wb-task-item__body`},br=[`title`],xr=[`title`],Sr={class:`wb-task-item__action-group`},Cr=[`title`,`aria-label`,`onClick`],wr=[`onClick`,`title`,`aria-label`],Tr={key:0,class:`wb-empty`};function Er(t,n,i,a,o,s){let c=l,u=_e;return H(),x(`aside`,dr,[b(`section`,fr,[q(` 任务分组 header 已去掉:"任务"/"任务列表"/计数 三件套冗余,下方任务项本身已能自我说明。
|
|
23
|
+
提示词分组保留 header(含 + 新建按钮 + 计数),信息密度不一对齐,后续按需统一。 `),b(`button`,{class:`wb-new-btn`,disabled:i.creatingTask,onClick:n[0]||=e=>a.emit(`create-task`)},[e(c,{class:`wb-new-btn__icon`},{default:F(()=>[e(a.Plus)]),_:1}),b(`span`,null,T(a.$t(`@WORKBENCH:新建任务`)),1),n[4]||=b(`span`,{class:`wb-new-btn__shortcut`},`N`,-1)],8,pr),q(` 一个项目 = 一个块(组头 + 组内任务列表),块内列表限高自滚,见样式里
|
|
24
|
+
.wb-task-group__list 那段:单项目攒到几十条时不会把别的项目顶出可视区。 `),b(`ul`,{class:w([`wb-task-list`,{"is-grouped":a.groupedTasksList.hasMultiple}])},[(H(!0),x(O,null,E(a.groupedTasksList.groups,t=>(H(),x(`li`,{key:t.path,class:`wb-task-group`},[a.groupedTasksList.hasMultiple?(H(),x(`div`,{key:0,class:w([`wb-task-group__head`,{"is-current":t.path===a.currentProjectKey,"is-collapsed":a.isGroupCollapsed(t.path)}]),role:`button`,tabindex:`0`,"aria-expanded":!a.isGroupCollapsed(t.path),title:a.isGroupCollapsed(t.path)?a.$t(`@WORKBENCH:展开`):a.$t(`@WORKBENCH:收起`),onClick:e=>a.toggleGroupCollapsed(t.path),onKeydown:[N(j(e=>a.toggleGroupCollapsed(t.path),[`prevent`]),[`enter`]),N(j(e=>a.toggleGroupCollapsed(t.path),[`prevent`]),[`space`])]},[e(c,{class:`wb-task-group__caret`},{default:F(()=>[(H(),r(g(a.isGroupCollapsed(t.path)?a.ArrowRight:a.ArrowDown)))]),_:2},1024),e(c,{class:`wb-task-group__icon`},{default:F(()=>[e(a.Folder)]),_:1}),b(`span`,{class:`wb-task-group__name`,title:t.path===a.currentProjectKey?i.currentProject.path:t.label},T(t.path===a.currentProjectKey?i.currentProject.name:a.shortProjectLabel(t.label)),9,hr),b(`span`,gr,T(t.tasks.length),1)],42,mr)):q(`v-if`,!0),a.isGroupCollapsed(t.path)?q(`v-if`,!0):(H(),x(`ul`,_r,[(H(!0),x(O,null,E(t.tasks,r=>(H(),x(`li`,{key:r.id,class:w([`wb-task-item`,{active:r.id===i.selectedTaskId,"is-other-project":a.isOtherProject(r),"is-running":a.taskIsRunning(r),"is-dragging":a.draggingTaskId===r.id,"is-drop-before":a.dragOverTaskId===r.id&&a.dragPosition===`before`,"is-drop-after":a.dragOverTaskId===r.id&&a.dragPosition===`after`}]),"data-task-id":r.id,"data-group-path":t.path,title:a.taskTooltip(r),role:`button`,tabindex:`0`,"aria-pressed":r.id===i.selectedTaskId,onClick:e=>a.emit(`select-task`,r),onKeydown:[N(j(e=>a.emit(`select-task`,r),[`prevent`]),[`enter`]),N(j(e=>a.emit(`select-task`,r),[`prevent`]),[`space`])],onMousedown:e=>a.onTaskMouseDown(e,r,t.path,e.currentTarget)},[q(` 单行展示:只显示标题;没写标题用任务描述压平后顶上(CSS ellipsis 截断)。
|
|
25
|
+
子任务数 / 附件数 等 meta 行已移除,降噪 `),b(`div`,yr,[b(`div`,{class:`wb-task-item__title`,title:a.taskDisplayName(r)},T(a.taskDisplayName(r)),9,br)]),a.taskIsRunning(r)?(H(),x(`span`,{key:0,class:`wb-task-item__running-dot`,title:a.$t(`@WORKBENCH:执行中`),"aria-hidden":`true`},null,8,xr)):q(`v-if`,!0),b(`div`,Sr,[b(`button`,{class:`wb-task-item__copy`,title:a.$t(`@WORKBENCH:复制任务`),"aria-label":a.$t(`@WORKBENCH:复制任务`),onClick:j(e=>a.emit(`copy-task`,r),[`stop`]),onKeydown:n[1]||=j(()=>{},[`stop`])},[e(c,null,{default:F(()=>[e(a.CopyDocument)]),_:1})],40,Cr),q(` 执行中不允许删除:避免误杀正在跑的实例(jobs 还在内存里,
|
|
26
26
|
任务从 tasks.json 消失后,runSingleSubtask 读不到 task
|
|
27
|
-
会留一堆孤儿 job)。后端 DELETE 路由也加了同样的 live-job 守卫兜底 `),a.taskIsRunning(r)?
|
|
27
|
+
会留一堆孤儿 job)。后端 DELETE 路由也加了同样的 live-job 守卫兜底 `),a.taskIsRunning(r)?q(`v-if`,!0):(H(),x(`button`,{key:0,class:`wb-task-item__del`,onClick:j(e=>a.emit(`delete-task`,r),[`stop`]),onKeydown:n[2]||=j(()=>{},[`stop`]),title:a.$t(`@WORKBENCH:删除`),"aria-label":a.$t(`@WORKBENCH:删除`)},[e(c,null,{default:F(()=>[e(a.Close)]),_:1})],40,wr))])],42,vr))),128))]))]))),128)),q(` 空态走全应用同一套 EmptyState(原来是一张"渐变底 + 虚线圈 + 圆角图标砖"的卡,
|
|
28
|
+
同一句"暂无任务"在侧栏 / 看板 / 控制台长成三个样子;见 empty-state 组件头注释) `),i.tasks.length===0?(H(),x(`li`,Tr,[e(a.EmptyState,{size:`inline`,title:a.$t(`@WORKBENCH:暂无任务`),hint:a.$t(`@WORKBENCH:点击上方按钮新建`)},{icon:F(()=>[e(c,null,{default:F(()=>[e(a.DocumentAdd)]),_:1})]),default:F(()=>[e(u,{type:`primary`,size:`small`,icon:a.Plus,loading:i.creatingTask,onClick:n[3]||=e=>a.emit(`create-task`)},{default:F(()=>[L(T(a.$t(`@WORKBENCH:新建任务`)),1)]),_:1},8,[`icon`,`loading`])]),_:1},8,[`title`,`hint`])])):q(`v-if`,!0)],2)])])}var Dr=Q(ur,[[`render`,Er],[`__scopeId`,`data-v-458e9455`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/views/components/WorkbenchSidebar.vue`]]);c(),R();var Or=f({__name:`WorkbenchProjectPanel`,props:{projects:{type:Array,required:!0},selectedKey:{type:String,required:!0},loading:{type:Boolean,required:!0},collapsible:{type:Boolean,required:!1}},emits:[`select`,`remove`,`collapse`],setup(e,{expose:n,emit:r}){n();let i=e,a=r,s=J(()=>[...i.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=M(``),l=M(!1),u=M(!1),d=J(()=>!!c.value.trim()||l.value||u.value),f=J(()=>l.value||u.value),p=J(()=>{let e=c.value.trim().toLowerCase();return s.value.filter(t=>l.value&&t.stats.total===0||u.value&&t.git&&t.git.isGitRepo===!1?!1:!e||t.name.toLowerCase().includes(e)||t.path.toLowerCase().includes(e))});function m(){c.value=``,l.value=!1,u.value=!1}let g=M(!1),_=M(null);function v(){g.value=!g.value,g.value&&t(()=>_.value?.focus())}function y(){c.value.trim()||(g.value=!1)}let b=J(()=>i.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}));function x(e){return e.git?e.git.isGitRepo===null?Z(`@WORKBENCH:未知`):e.git.isGitRepo?e.git.detached?Z(`@WORKBENCH:游离 HEAD`):e.git.branch||Z(`@WORKBENCH:未知`):``:``}function S(e){return!!(e.git&&e.git.isGitRepo&&(e.git.detached||e.git.branch))}let{isIconBroken:w,markIconFailed:ee}=Ue(),T=M(null),te=M(null);function E(e,t){if(T.value===e.key){T.value=null;return}te.value=t.currentTarget,T.value=e.key}function ne(){T.value=null}function D(e){if(!T.value)return;let t=e.target;if(t&&!te.value?.contains(t)){for(let e of Array.from(document.querySelectorAll(`.proj-open-menu`)))if(e.contains(t))return;T.value=null}}o(()=>document.addEventListener(`mousedown`,D,!0)),C(()=>document.removeEventListener(`mousedown`,D,!0));async function O(e){ne();let t=await Le(e.path);t.success?P.success(t.message||Z(`@WORKBENCH:已在文件管理器中打开文件夹`)):P.error(t.error||Z(`@WORKBENCH:打开文件夹失败`))}async function k(e){let t=e.name||e.path,n=e.stats.total>0?Z(`@WORKBENCH:移除项目「{name}」?会从常用目录和项目列表中去掉它。该项目的 {n} 条任务不会被删除,仍可在「全部项目」下查看。`,{name:t,n:e.stats.total}):Z(`@WORKBENCH:移除项目「{name}」?会从常用目录和项目列表中去掉它。`,{name:t});try{await U.confirm(n,Z(`@WORKBENCH:移除项目`),{confirmButtonText:Z(`@WORKBENCH:移除`),cancelButtonText:Z(`@WORKBENCH:取消`),type:`warning`})}catch{return}a(`remove`,e)}let A={props:i,emit:a,ordered:s,query:c,onlyWithTasks:l,hideNonGit:u,filtering:d,filtersActive:f,visible:p,clearFilters:m,searchOpen:g,searchInputRef:_,toggleSearch:v,onSearchBlur:y,totals:b,gitLine:x,hasBranchIcon:S,isIconBroken:w,markIconFailed:ee,openMenuKey:T,menuTriggerEl:te,toggleOpenMenu:E,closeOpenMenu:ne,onDocumentMouseDown:D,openInFileManager:O,confirmRemove:k,get $t(){return Z},get Delete(){return oe},get FolderOpened(){return ge},get MoreFilled(){return h},SvgIcon:Se,ProjectOpenMenuList:at,get relativeTimeFromIso(){return rt}};return Object.defineProperty(A,"__isScriptSetup",{enumerable:!1,value:!0}),A}});c(),I(),B();var kr={class:`proj`},Ar={class:`proj__head`},jr=[`title`,`aria-label`],Mr={class:`proj__title`},Nr=[`aria-label`,`title`],Pr={class:`proj__toggles`},Fr=[`aria-pressed`],Ir={key:0,class:`proj__toggle-check`,viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,xmlns:`http://www.w3.org/2000/svg`},Lr=[`aria-pressed`],Rr={key:0,class:`proj__toggle-check`,viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,xmlns:`http://www.w3.org/2000/svg`},zr=[`placeholder`,`aria-label`],Br={key:0,class:`proj__search-meta`},Vr=[`title`,`aria-label`],Hr={class:`proj__list`},Ur=[`title`],Wr={class:`proj-item__body`},Gr={class:`proj-item__icon-slot`},Kr={class:`proj-item__row1`},qr={class:`proj-item__name`},Jr={key:0,class:`proj-item__running`,"aria-hidden":`true`},Yr={class:`proj-item__num`},Xr={key:0,class:`proj-item__row2`},Zr={class:`proj-item__running-text`},Qr=[`title`],$r={class:`proj-item__progress-text`},ei=[`title`,`onClick`,`onKeydown`],ti={class:`proj-item__body`},ni={class:`proj-item__icon-slot`},ri=[`src`,`onError`],ii={class:`proj-item__row1`},ai={class:`proj-item__name`},oi={class:`proj-item__signals`},si={key:0,class:`proj-item__running`,"aria-hidden":`true`},ci={key:1,class:`proj-item__badge`},li={class:`proj-item__row2`},ui={key:0,class:`proj-chip proj-chip--missing`},di={key:0,class:`proj-item__branch`},fi={class:`proj-item__branch-name`},pi={key:1,class:`proj-chip proj-chip--ahead`},mi={key:2,class:`proj-chip proj-chip--behind`},hi={key:3,class:`proj-chip proj-chip--dirty`},gi={class:`proj-item__time`},_i={key:0,class:`proj-item__row3`},vi={class:`proj-item__progress-text`},yi={class:`proj-item__actions`},bi=[`title`,`aria-label`,`onClick`],xi=[`title`,`aria-label`,`onClick`],Si=[`title`,`aria-label`,`aria-expanded`,`onClick`],Ci={key:0,class:`proj-empty`},wi={class:`proj-empty__title`},Ti={class:`proj-empty__hint`},Ei={key:1,class:`proj-empty`},Di={class:`proj-empty__title`};function Oi(t,n,i,a,o,s){let c=D,u=l;return H(),x(`section`,kr,[b(`header`,Ar,[q(` 收起左栏(2026-10-27 从看板顶栏搬来):放在标题最前,和「项目列表」同一行。
|
|
28
29
|
无边框图标按钮 —— 这一行右侧的漏斗/搜索是框式控件,两个不同职能不该同形。
|
|
29
|
-
收起后这枚随面板一起消失,宿主在看板标题行补一枚展开按钮(.board__fold-btn)。 `),i.collapsible?(H(),x(`button`,{key:0,type:`button`,class:`proj__fold-btn board__fold-btn`,title:a.$t(`@WORKBENCH:收起项目列表`),"aria-label":a.$t(`@WORKBENCH:收起项目列表`),"aria-expanded":`true`,onClick:n[0]||=e=>a.emit(`collapse`)},[
|
|
30
|
+
收起后这枚随面板一起消失,宿主在看板标题行补一枚展开按钮(.board__fold-btn)。 `),i.collapsible?(H(),x(`button`,{key:0,type:`button`,class:`proj__fold-btn board__fold-btn`,title:a.$t(`@WORKBENCH:收起项目列表`),"aria-label":a.$t(`@WORKBENCH:收起项目列表`),"aria-expanded":`true`,onClick:n[0]||=e=>a.emit(`collapse`)},[q(` chevrons-left(Tabler icons,MIT):展开态那枚(看板标题行)是反方向 `),n[9]||=b(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,xmlns:`http://www.w3.org/2000/svg`,"aria-hidden":`true`},[b(`path`,{d:`M11 7l-5 5l5 5`}),b(`path`,{d:`M17 7l-5 5l5 5`})],-1)],8,jr)):q(`v-if`,!0),b(`h3`,Mr,T(a.$t(`@WORKBENCH:项目列表`)),1),q(` 过滤入口(2026-10-16 用户要求):漏斗图标 + 点击展开下拉,
|
|
30
31
|
原来的「只看有任务 / 隐藏非 Git」两个开关从卡片下方那行搬进下拉 ——
|
|
31
32
|
那一行只剩两个按钮纯占位。开关收进下拉后靠漏斗图标的 is-on 变色提示
|
|
32
|
-
"有筛选在生效"(下拉藏了状态,入口必须自己会说话)。 `),i.projects.length>0?(H(),r(c,{key:1,trigger:`click`,placement:`bottom-end`,width:168,"show-arrow":!1,offset:6,teleported:!0,"popper-class":`proj-filter-popper`},{reference:F(()=>[b(`button`,{type:`button`,class:w([`proj__filter-btn`,{"is-on":a.filtersActive}]),"aria-label":a.$t(`@WORKBENCH:筛选项目`),title:a.$t(`@WORKBENCH:筛选项目`)},[
|
|
33
|
+
"有筛选在生效"(下拉藏了状态,入口必须自己会说话)。 `),i.projects.length>0?(H(),r(c,{key:1,trigger:`click`,placement:`bottom-end`,width:168,"show-arrow":!1,offset:6,teleported:!0,"popper-class":`proj-filter-popper`},{reference:F(()=>[b(`button`,{type:`button`,class:w([`proj__filter-btn`,{"is-on":a.filtersActive}]),"aria-label":a.$t(`@WORKBENCH:筛选项目`),title:a.$t(`@WORKBENCH:筛选项目`)},[q(` filter.svg(Tabler icons,MIT):漏斗 = 过滤 `),n[10]||=b(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,xmlns:`http://www.w3.org/2000/svg`},[b(`path`,{d:`M4 4h16v2.172a2 2 0 0 1-.586 1.414l-4.414 4.414v7l-6 2v-8.5l-4.48-4.928a2 2 0 0 1-.52-1.345v-2.227`})],-1)],10,Nr)]),default:F(()=>[b(`div`,Pr,[b(`button`,{type:`button`,class:w([`proj__toggle`,{"is-on":a.onlyWithTasks}]),"aria-pressed":a.onlyWithTasks,onClick:n[1]||=e=>a.onlyWithTasks=!a.onlyWithTasks},[b(`span`,null,T(a.$t(`@WORKBENCH:只看有任务`)),1),q(` check.svg(Tabler icons,MIT):选中打勾 `),a.onlyWithTasks?(H(),x(`svg`,Ir,[...n[11]||=[b(`path`,{d:`M5 12l5 5l10-10`},null,-1)]])):q(`v-if`,!0)],10,Fr),b(`button`,{type:`button`,class:w([`proj__toggle`,{"is-on":a.hideNonGit}]),"aria-pressed":a.hideNonGit,onClick:n[2]||=e=>a.hideNonGit=!a.hideNonGit},[b(`span`,null,T(a.$t(`@WORKBENCH:隐藏非 Git`)),1),a.hideNonGit?(H(),x(`svg`,Rr,[...n[12]||=[b(`path`,{d:`M5 12l5 5l10-10`},null,-1)]])):q(`v-if`,!0)],10,Lr)])]),_:1})):q(`v-if`,!0),q(` 搜索(2026-10-16 从下面的筛选条搬到这里):默认只露一枚放大镜,
|
|
33
34
|
点开输入框才展开。原标题右侧那枚常驻项目数(.proj__count)去掉 ——
|
|
34
35
|
同一个数字左栏「全部项目」行还有一份;筛选中的匹配数
|
|
35
|
-
不跟着常驻,改成展开态下输入框右边一枚小字(.proj__search-meta)。 `),i.projects.length>0?(H(),x(`div`,{key:2,class:w([`proj__search`,{"is-open":a.searchOpen}])},[A(b(`input`,{ref:`searchInputRef`,"onUpdate:modelValue":n[3]||=e=>a.query=e,class:`proj__search-input`,type:`search`,placeholder:a.$t(`@WORKBENCH:搜索项目名称或路径`),"aria-label":a.$t(`@WORKBENCH:搜索项目名称或路径`),onKeydown:n[4]||=N(e=>a.query=``,[`esc`]),onBlur:a.onSearchBlur},null,40,
|
|
36
|
+
不跟着常驻,改成展开态下输入框右边一枚小字(.proj__search-meta)。 `),i.projects.length>0?(H(),x(`div`,{key:2,class:w([`proj__search`,{"is-open":a.searchOpen}])},[A(b(`input`,{ref:`searchInputRef`,"onUpdate:modelValue":n[3]||=e=>a.query=e,class:`proj__search-input`,type:`search`,placeholder:a.$t(`@WORKBENCH:搜索项目名称或路径`),"aria-label":a.$t(`@WORKBENCH:搜索项目名称或路径`),onKeydown:n[4]||=N(e=>a.query=``,[`esc`]),onBlur:a.onSearchBlur},null,40,zr),[[fe,a.searchOpen],[V,a.query]]),q(` ⚠️ 必须带 searchOpen:只写 filtering 的话,"开关开着 + 搜索收起"时
|
|
36
37
|
这枚小字会挤进 34px 的收起容器,把放大镜顶出框外(实测按出 6px)。
|
|
37
|
-
原设计意图就是"展开态下"才显示,这里是补上漏掉的条件。 `),a.filtering&&a.searchOpen?(H(),x(`span`,
|
|
38
|
-
想收起"会变成 blur 收起 + click 又重新展开(同看板标题行那枚) `),b(`button`,{type:`button`,class:`proj__search-btn`,title:a.$t(`@WORKBENCH:搜索项目名称或路径`),"aria-label":a.$t(`@WORKBENCH:搜索项目名称或路径`),onMousedown:n[5]||=j(()=>{},[`prevent`]),onClick:a.toggleSearch},[
|
|
38
|
+
原设计意图就是"展开态下"才显示,这里是补上漏掉的条件。 `),a.filtering&&a.searchOpen?(H(),x(`span`,Br,T(a.visible.length)+`/`+T(i.projects.length),1)):q(`v-if`,!0),q(` mousedown.prevent:不让这一下先把输入框焦点弄丢,否则"点开 → 再点图标
|
|
39
|
+
想收起"会变成 blur 收起 + click 又重新展开(同看板标题行那枚) `),b(`button`,{type:`button`,class:`proj__search-btn`,title:a.$t(`@WORKBENCH:搜索项目名称或路径`),"aria-label":a.$t(`@WORKBENCH:搜索项目名称或路径`),onMousedown:n[5]||=j(()=>{},[`prevent`]),onClick:a.toggleSearch},[q(` search.svg(Tabler icons,MIT)。2026-10-16 从 EP <Search/> 换成 Tabler:
|
|
39
40
|
EP 图标是**实心填充**风,与左边漏斗(Tabler 描边)并排"颜色深浅不一样"
|
|
40
|
-
(用户反馈)——同为 14px / 描边 2 后两者才是一对。 `),n[13]||=b(`svg`,{class:`proj__search-icon`,viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,xmlns:`http://www.w3.org/2000/svg`,"aria-hidden":`true`},[b(`path`,{d:`M3 10a7 7 0 1 0 14 0a7 7 0 1 0 -14 0`}),b(`path`,{d:`M21 21l-6 -6`})],-1)],40,
|
|
41
|
+
(用户反馈)——同为 14px / 描边 2 后两者才是一对。 `),n[13]||=b(`svg`,{class:`proj__search-icon`,viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,xmlns:`http://www.w3.org/2000/svg`,"aria-hidden":`true`},[b(`path`,{d:`M3 10a7 7 0 1 0 14 0a7 7 0 1 0 -14 0`}),b(`path`,{d:`M21 21l-6 -6`})],-1)],40,Vr)],2)):q(`v-if`,!0)]),b(`ul`,Hr,[b(`li`,{class:w([`proj-item proj-item--all`,{"is-active":i.selectedKey===``,"is-running":a.totals.running>0,"is-complete":a.totals.total>0&&a.totals.done>=a.totals.total}]),role:`button`,tabindex:`0`,title:a.$t(`@WORKBENCH:全部项目`),onClick:n[6]||=e=>a.emit(`select`,null),onKeydown:[n[7]||=N(j(e=>a.emit(`select`,null),[`prevent`]),[`enter`]),n[8]||=N(j(e=>a.emit(`select`,null),[`prevent`]),[`space`])]},[b(`div`,Wr,[b(`span`,Gr,[e(u,{class:`proj-item__icon`},{default:F(()=>[q(` layout-grid(Tabler icons,MIT):全部项目 = 四方格。
|
|
41
42
|
2026-10-16 从 EP <Grid/> 换成 Tabler —— 与回退文件夹、行内其余
|
|
42
|
-
图标同族;EP 实心填充与 Tabler 描边混排会有"色差感"。 `),n[14]||=b(`svg`,{viewBox:`0 0 24 24`,width:`20`,height:`20`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,xmlns:`http://www.w3.org/2000/svg`,"aria-hidden":`true`},[b(`path`,{d:`M4 5a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -4`}),b(`path`,{d:`M14 5a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -4`}),b(`path`,{d:`M4 15a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -4`}),b(`path`,{d:`M14 15a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -4`})],-1)]),_:1})]),b(`div`,
|
|
43
|
+
图标同族;EP 实心填充与 Tabler 描边混排会有"色差感"。 `),n[14]||=b(`svg`,{viewBox:`0 0 24 24`,width:`20`,height:`20`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,xmlns:`http://www.w3.org/2000/svg`,"aria-hidden":`true`},[b(`path`,{d:`M4 5a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -4`}),b(`path`,{d:`M14 5a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -4`}),b(`path`,{d:`M4 15a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -4`}),b(`path`,{d:`M14 15a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -4`})],-1)]),_:1})]),b(`div`,Kr,[b(`span`,qr,T(a.$t(`@WORKBENCH:全部项目`)),1),a.totals.running>0?(H(),x(`span`,Jr)):q(`v-if`,!0),b(`span`,Yr,T(i.projects.length),1)]),q(` 第二行只在真有内容时说。原来这里写「{n} 个项目」,而同一个 28 就在上面
|
|
43
44
|
那枚 proj-item__num chip 里、面板标题也写了一遍 —— 一屏四个 28。
|
|
44
|
-
真正只有这一行能说的是"有几个在跑"。 `),a.totals.running>0?(H(),x(`div
|
|
45
|
+
真正只有这一行能说的是"有几个在跑"。 `),a.totals.running>0?(H(),x(`div`,Xr,[b(`span`,Zr,T(a.$t(`@WORKBENCH:{n} 个执行中`,{n:a.totals.running})),1)])):q(`v-if`,!0),q(` 只留数字不给进度条(用户 2026-10-13:数字有用,彩条占地方)。
|
|
45
46
|
title 交代口径:这里只加列表里这些项目的任务,与看板「全部项目」的总数不等
|
|
46
|
-
(实测差 10 条:9 条属于一个已从列表移除的项目 + 1 条属于容器目录)。 `),a.totals.total>0?(H(),x(`div`,{key:1,class:`proj-item__row3`,title:a.$t(`@WORKBENCH:只统计项目列表里这些项目名下的任务`)},[b(`span
|
|
47
|
+
(实测差 10 条:9 条属于一个已从列表移除的项目 + 1 条属于容器目录)。 `),a.totals.total>0?(H(),x(`div`,{key:1,class:`proj-item__row3`,title:a.$t(`@WORKBENCH:只统计项目列表里这些项目名下的任务`)},[b(`span`,$r,T(a.$t(`@WORKBENCH:{done}/{total} 任务完成`,{done:a.totals.done,total:a.totals.total})),1)],8,Qr)):q(`v-if`,!0)])],42,Ur),(H(!0),x(O,null,E(a.visible,t=>(H(),x(`li`,{key:t.key,class:w([`proj-item`,{"is-active":t.key===i.selectedKey,"is-running":t.stats.runningJobs>0,"is-complete":t.stats.total>0&&t.stats.done>=t.stats.total&&t.stats.runningJobs===0,"is-missing":t.exists===!1}]),role:`button`,tabindex:`0`,title:t.path,onClick:e=>a.emit(`select`,t),onKeydown:[N(j(e=>a.emit(`select`,t),[`self`,`prevent`]),[`enter`]),N(j(e=>a.emit(`select`,t),[`self`,`prevent`]),[`space`])]},[b(`div`,ti,[q(` 图标位跨 row1 + row2(见 .proj-item__icon-slot):项目自己的 favicon 是
|
|
47
48
|
32px 的方块,占两行文字的高度;没有 / 加载失败就退回一枚文件夹字形。
|
|
48
49
|
失败要记一笔:服务端重启过、或图标文件被删掉时,不记的话每次重渲染都会
|
|
49
|
-
再发一次注定失败的请求,行上还一直挂着个破图。 `),b(`span`,
|
|
50
|
+
再发一次注定失败的请求,行上还一直挂着个破图。 `),b(`span`,ni,[t.iconUrl&&!a.isIconBroken(t.iconUrl)?(H(),x(`img`,{key:0,class:`proj-item__icon proj-item__icon--img`,src:t.iconUrl,alt:``,onError:e=>a.markIconFailed(t.iconUrl)},null,40,ri)):(H(),r(u,{key:1,class:`proj-item__icon proj-item__icon--folder`,"aria-hidden":`true`},{default:F(()=>[q(` folder-filled.svg(Tabler icons,MIT):回退 = **直接一枚主色实心文件夹**。
|
|
50
51
|
2026-10-16 晚用户连提两轮"再大一点":不要"外框方块 + 小文件夹"两层套,
|
|
51
52
|
字形一路调大 20 → 24 → 32(顶满槽;字形自带边距,实际形宽 ≈24px)。
|
|
52
|
-
承载的 el-icon 仍是 32px 的透明槽(几何契约不变)。 `),n[15]||=b(`svg`,{viewBox:`0 0 24 24`,width:`32`,height:`32`,fill:`currentColor`,xmlns:`http://www.w3.org/2000/svg`},[b(`path`,{d:`M9 3a1 1 0 0 1 .608 .206l.1 .087l2.706 2.707h6.586a3 3 0 0 1 2.995 2.824l.005 .176v8a3 3 0 0 1 -2.824 2.995l-.176 .005h-14a3 3 0 0 1 -2.995 -2.824l-.005 -.176v-11a3 3 0 0 1 2.824 -2.995l.176 -.005h4z`})],-1)]),_:1}))]),b(`div`,
|
|
53
|
-
hover 时整组淡出让位给按钮,而不是让图标压在徽标上 `),b(`span`,
|
|
53
|
+
承载的 el-icon 仍是 32px 的透明槽(几何契约不变)。 `),n[15]||=b(`svg`,{viewBox:`0 0 24 24`,width:`32`,height:`32`,fill:`currentColor`,xmlns:`http://www.w3.org/2000/svg`},[b(`path`,{d:`M9 3a1 1 0 0 1 .608 .206l.1 .087l2.706 2.707h6.586a3 3 0 0 1 2.995 2.824l.005 .176v8a3 3 0 0 1 -2.824 2.995l-.176 .005h-14a3 3 0 0 1 -2.995 -2.824l-.005 -.176v-11a3 3 0 0 1 2.824 -2.995l.176 -.005h4z`})],-1)]),_:1}))]),b(`div`,ii,[b(`span`,ai,T(t.name),1),q(` 运行中 / 当前 这两个信号与 hover 才出现的操作按钮锚在同一个右端点:
|
|
54
|
+
hover 时整组淡出让位给按钮,而不是让图标压在徽标上 `),b(`span`,oi,[t.stats.runningJobs>0?(H(),x(`span`,si)):q(`v-if`,!0),t.isCurrent?(H(),x(`span`,ci,T(a.$t(`@WORKBENCH:当前`)),1)):q(`v-if`,!0)])]),b(`div`,li,[t.exists===!1?(H(),x(`span`,ui,T(a.$t(`@WORKBENCH:目录不存在`)),1)):(H(),x(O,{key:1},[q(` gitLine 为空即"不是 Git 仓库":不给文字,也不给图标 `),a.gitLine(t)?(H(),x(`span`,di,[a.hasBranchIcon(t)?(H(),r(a.SvgIcon,{key:0,"icon-class":`git-branch`,"class-name":`proj-item__branch-icon`})):q(`v-if`,!0),b(`span`,fi,T(a.gitLine(t)),1)])):q(`v-if`,!0),t.git&&t.git.ahead>0?(H(),x(`span`,pi,`↑`+T(t.git.ahead),1)):q(`v-if`,!0),t.git&&t.git.behind>0?(H(),x(`span`,mi,`↓`+T(t.git.behind),1)):q(`v-if`,!0),t.git&&t.git.changed>0?(H(),x(`span`,hi,`●`+T(t.git.changed),1)):q(`v-if`,!0)],64)),b(`span`,gi,T(a.relativeTimeFromIso(t.stats.lastActiveAt)),1)]),q(` 同上:这个项目一个任务都没有就不给进度行 `),t.stats.total>0?(H(),x(`div`,_i,[b(`span`,vi,T(a.$t(`@WORKBENCH:{done}/{total} 任务完成`,{done:t.stats.done,total:t.stats.total})),1)])):q(`v-if`,!0)]),q(` 打开动作:与行主体平级,绝对定位锚在 row1 右端(不占位,否则「当前」徽标
|
|
54
55
|
永远离右边缘一条);.stop 阻止冒泡到行的选中逻辑。目录都不存在时**一个打开
|
|
55
56
|
动作都不给** —— 点了只会弹一个「无法打开目录」的报错 —— 只留一颗「从清单移除」:
|
|
56
57
|
那一行存在的唯一理由就是提醒这里有个没了的目录,能做的也只有把它清掉。
|
|
@@ -59,15 +60,15 @@ import"./rolldown-runtime-C0FnF6B9.js";import{An as e,Bn as t,C as n,Cn as r,F a
|
|
|
59
60
|
而项目名被挤成省略号比多点一次更难受。
|
|
60
61
|
⚠️ 行上的 keydown 必须带 .self:事件从按钮冒泡上来,不带 .self 时
|
|
61
62
|
焦点在按钮上按回车会「选中该行 + preventDefault 掉按钮自己的激活」,
|
|
62
|
-
键盘用户反而打不开文件夹。 `),b(`div`,
|
|
63
|
+
键盘用户反而打不开文件夹。 `),b(`div`,yi,[t.exists===!1?(H(),x(`button`,{key:0,type:`button`,class:`proj-item__action proj-item__action--danger`,title:a.$t(`@WORKBENCH:从清单移除`),"aria-label":`${a.$t(`@WORKBENCH:从清单移除`)} ${t.name}`,onClick:j(e=>a.confirmRemove(t),[`stop`])},[e(u,{"aria-hidden":`true`},{default:F(()=>[e(a.Delete)]),_:1})],8,bi)):(H(),x(`button`,{key:1,type:`button`,class:`proj-item__action`,title:a.$t(`@WORKBENCH:打开文件夹`),"aria-label":`${a.$t(`@WORKBENCH:打开文件夹`)} ${t.name}`,onClick:j(e=>a.openInFileManager(t),[`stop`])},[e(u,{"aria-hidden":`true`},{default:F(()=>[e(a.FolderOpened)]),_:1})],8,xi)),t.exists===!1?q(`v-if`,!0):(H(),r(c,{key:2,visible:a.openMenuKey===t.key,trigger:`manual`,placement:`right-start`,width:272,"show-arrow":!1,offset:6,"popper-class":`proj-open-menu`},{reference:F(()=>[b(`button`,{type:`button`,class:w([`proj-item__action`,{"is-open":a.openMenuKey===t.key}]),title:a.$t(`@WORKBENCH:打开方式`),"aria-label":`${a.$t(`@WORKBENCH:打开方式`)} ${t.name}`,"aria-expanded":a.openMenuKey===t.key,"aria-haspopup":`menu`,onClick:j(e=>a.toggleOpenMenu(t,e),[`stop`])},[e(u,{"aria-hidden":`true`},{default:F(()=>[e(a.MoreFilled)]),_:1})],10,Si)]),default:F(()=>[a.openMenuKey===t.key?(H(),r(a.ProjectOpenMenuList,{key:0,path:t.path,name:t.name,onDone:a.closeOpenMenu},null,8,[`path`,`name`])):q(`v-if`,!0)]),_:2},1032,[`visible`]))])],42,ei))),128)),!i.loading&&i.projects.length===0?(H(),x(`li`,Ci,[b(`p`,wi,T(a.$t(`@WORKBENCH:尚无项目`)),1),b(`p`,Ti,T(a.$t(`@WORKBENCH:常用目录与建过任务的目录都会出现在这里`)),1)])):q(`v-if`,!0),q(` 有项目、只是被筛没了:这必须说出来。
|
|
63
64
|
空着会让人以为项目列表坏了,而"没有匹配"和"一个项目都没有"是两件事。
|
|
64
65
|
刻意写成两个互斥的 v-if(而不是 v-else-if):条件里带上了 projects.length,
|
|
65
|
-
读代码时不用回头找上一段才敢确定它们不重叠。 `),!i.loading&&i.projects.length>0&&a.visible.length===0?(H(),x(`li`,
|
|
66
|
+
读代码时不用回头找上一段才敢确定它们不重叠。 `),!i.loading&&i.projects.length>0&&a.visible.length===0?(H(),x(`li`,Ei,[b(`p`,Di,T(a.$t(`@WORKBENCH:没有匹配的项目`)),1),b(`button`,{type:`button`,class:`proj-empty__clear`,onClick:a.clearFilters},T(a.$t(`@WORKBENCH:清除筛选`)),1)])):q(`v-if`,!0)])])}var ki=Q(Or,[[`render`,Oi],[`__scopeId`,`data-v-de1af726`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/views/components/WorkbenchProjectPanel.vue`]]);c(),R();var Ai=f({__name:`WorkbenchTaskMoveMenu`,props:{visible:{type:Boolean,required:!0},x:{type:Number,required:!0},y:{type:Number,required:!0},task:{type:[Object,null],required:!0},projects:{type:Array,required:!0}},emits:[`move`,`close`],setup(e,{expose:n,emit:r}){n();let i=e,a=r,o=J(()=>{let e=$(i.task?.projectPath);return i.projects.filter(t=>$(t.path)!==e)}),s=M(null),c=M({x:0,y:0});z(()=>i.visible,async e=>{if(!e)return;await t();let n=s.value;if(!n)return;let r=n.getBoundingClientRect();c.value={x:Math.min(Math.max(8,i.x),Math.max(8,window.innerWidth-r.width-8)),y:Math.min(Math.max(8,i.y),Math.max(8,window.innerHeight-r.height-8))}});function l(e){let t=s.value;t&&e.target instanceof Node&&t.contains(e.target)||a(`close`)}function u(){a(`close`)}function d(e){e.key===`Escape`&&(e.stopPropagation(),a(`close`))}z(()=>i.visible,e=>{e&&(window.addEventListener(`pointerdown`,l,!0),window.addEventListener(`scroll`,u,!0),window.addEventListener(`keydown`,d,!0))},{immediate:!0}),z(()=>i.visible,e=>{e||(window.removeEventListener(`pointerdown`,l,!0),window.removeEventListener(`scroll`,u,!0),window.removeEventListener(`keydown`,d,!0))}),C(()=>{window.removeEventListener(`pointerdown`,l,!0),window.removeEventListener(`scroll`,u,!0),window.removeEventListener(`keydown`,d,!0)});function f(e){a(`move`,e.path)}let p={props:i,emit:a,options:o,menuRef:s,pos:c,onPointerDown:l,onScroll:u,onKeydown:d,onPick:f,get $t(){return Z}};return Object.defineProperty(p,"__isScriptSetup",{enumerable:!1,value:!0}),p}});I(),c(),B();var ji={class:`kb-move-menu__head`},Mi={class:`kb-move-menu__list`},Ni=[`title`,`onClick`],Pi={class:`kb-move-menu__name`},Fi={key:0,class:`kb-move-menu__warn`},Ii={key:0,class:`kb-move-menu__empty`};function Li(e,t,n,i,a,o){return H(),r(X,{to:`body`},[n.visible&&n.task?(H(),x(`div`,{key:0,ref:`menuRef`,class:`kb-move-menu`,role:`menu`,style:u({top:i.pos.y+`px`,left:i.pos.x+`px`}),onContextmenu:t[0]||=j(()=>{},[`prevent`])},[b(`p`,ji,T(i.$t(`@WORKBENCH:移动到其他项目`)),1),b(`div`,Mi,[(H(!0),x(O,null,E(i.options,e=>(H(),x(`button`,{key:e.key,type:`button`,class:`kb-move-menu__item`,role:`menuitem`,title:e.path,onClick:t=>i.onPick(e)},[b(`span`,Pi,T(e.name),1),e.exists===!1?(H(),x(`span`,Fi,T(i.$t(`@WORKBENCH:目录不存在`)),1)):q(`v-if`,!0)],8,Ni))),128)),i.options.length===0?(H(),x(`p`,Ii,T(i.$t(`@WORKBENCH:没有其他项目`)),1)):q(`v-if`,!0)])],36)):q(`v-if`,!0)])}var Ri=Q(Ai,[[`render`,Li],[`__scopeId`,`data-v-c9596078`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/views/components/WorkbenchTaskMoveMenu.vue`]]),zi=[140,170,200,230,260,290,320,350];function Bi(e){return(e||``).replace(/\\/g,`/`).trim().toLowerCase()}function Vi(e){let t=Bi(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,zi[(n>>>0)%zi.length]}function Hi(e){return{"--tag-hue":String(Vi(e))}}c(),R();var Ui=30,Wi=f({__name:`WorkbenchKanban`,props:{tasks:{type:Array,required:!0},projectLabels:{type:Object,required:!0},projects:{type:Array,required:!0},taskPercents:{type:Object,required:!1},showProjectLabel:{type:Boolean,required:!0},view:{type:String,required:!0},search:{type:String,required:!0},openedTaskId:{type:[String,null],required:!0}},emits:[`open-task`,`run-task`,`stop-task`,`complete-task`,`reopen-task`,`delete-task`,`move-task`,`create-task`,`update:view`,`update:search`],setup(e,{expose:n,emit:r}){n();let i=e,a=r,s=[{key:`todo`,labelKey:`@WORKBENCH:待处理`},{key:`doing`,labelKey:`@WORKBENCH:进行中`},{key:`done`,labelKey:`@WORKBENCH:已完成`}],c=M({visible:!1,x:0,y:0,task:null});function l(e,t,n){t===`todo`&&(n.preventDefault(),c.value={visible:!0,x:n.clientX,y:n.clientY,task:e})}function u(e){let t=c.value.task;c.value={...c.value,visible:!1},t&&a(`move-task`,t,e)}let d=J(()=>{let e=i.search.trim().toLowerCase();return i.tasks.filter(t=>!e||(t.title||``).toLowerCase().includes(e)||(t.desc||``).toLowerCase().includes(e))}),f=M(Ui);z(()=>i.search,()=>{f.value=Ui});let p=J(()=>{let e=s.map(e=>{let t=e.key===`done`?d.value.filter(t=>t.column===e.key).sort(_):d.value.filter(t=>t.column===e.key);return{...e,all:t}}),t=e.some(e=>e.all.length>0);return e.map(e=>({key:e.key,labelKey:e.labelKey,total:e.all.length,hidden:e.key===`done`?Math.max(0,e.all.length-f.value):0,tasks:e.key===`done`?e.all.slice(0,f.value):e.all,collapsed:t&&e.all.length===0&&e.key!==`todo`}))}),m=J(()=>({gridTemplateColumns:p.value.map(e=>e.collapsed?`minmax(0, 0fr)`:`minmax(0, 1fr)`).join(` `)})),h=M(!1);o(()=>{requestAnimationFrame(()=>requestAnimationFrame(()=>{h.value=!0}))}),z(()=>i.openedTaskId,e=>{e&&t(()=>{document.querySelector(`.kb-card[data-task-id="${e}"]`)?.scrollIntoView({block:`nearest`,inline:`nearest`})})});function g(e){return Pn(e)}function _(e,t){return g(t).localeCompare(g(e))}function v(e){return Fn(e)}function y(e){return In(e)}function b(e){return Bn(e)}function x(e){let t=(e.autoCompleted?.reason||``).trim(),n=Z(`@WORKBENCH:静默超时后由 AI 核对,判定这条任务已经完成`);return t?`${n}\n${t}`:n}let S=J(()=>[...d.value].sort((e,t)=>v(t).localeCompare(v(e))));function C(e){let t=(e.title||``).trim();if(t)return t;let n=(e.desc||``).replace(/\s+/g,` `).trim();return(/^[a-zA-Z]:[\\/]/.test(n)||n.startsWith(`\\\\`))&&n.split(/[\\/]/).filter(Boolean).pop()||n}function w(e){return i.projectLabels[e.projectPath]||``}function ee(e){return e.lastJobStatus===`error`}function T(e){return e.live?.agent||e.lastJobAgent||``}function te(e){if(!e.live)return null;let t=i.taskPercents?.[e.id];return typeof t==`number`?t:null}function E(e){let t=e.live;if(!t)return``;let n=Rn(e),r=t.lastLine||t.lastThought||t.lastTool;return r?`${n} · ${r}`:n}function ne(e){return Array.isArray(e.images)?e.images:[]}let D=M(new Set);function O(e){D.value=new Set(D.value).add(e)}function k(e){let t=ne(e);return D.value.size===0?t:t.filter(e=>!D.value.has(e.id))}function A(e){return`/api/workbench/attachments/${e}/raw`}let re=M(null);function ie(e,t=0){let n=k(e);n.length!==0&&(re.value={urls:n.map(e=>A(e.id)),index:t})}function ae(){re.value=null}function oe(e){return e.originalName?`${Z(`@WORKBENCH:查看图片`)} · ${e.originalName}`:Z(`@WORKBENCH:查看图片`)}let se={props:i,emit:a,COLUMNS:s,moveMenu:c,onCardContextMenu:l,onMoveToProject:u,filtered:d,DONE_PAGE:Ui,doneLimit:f,columns:p,columnsStyle:m,animateCollapse:h,doneAt:g,byDoneAtDesc:_,cardTime:v,cardDuration:y,cardTimeTitle:b,autoDoneTitle:x,listRows:S,cardTitle:C,projectLabel:w,hasError:ee,cardAgent:T,cardPercent:te,liveSummary:E,cardImages:ne,brokenCoverIds:D,onCoverError:O,coverImages:k,imageRawUrl:A,imageViewer:re,openImages:ie,closeImages:ae,coverTitle:oe,get $t(){return Z},TaskExecutorIcon:Me,WorkbenchTaskMoveMenu:Ri,get taskExecutorName(){return Te},get projectTagStyle(){return Hi},get formatDurationMs(){return nt},get relativeTimeFromIso(){return rt},get taskLiveText(){return Rn},get taskSpentText(){return Ln},get REPORT_PERCENT_HINT_KEY(){return Fe},get REPORT_PERCENT_LABEL_KEY(){return Ve},get reportSilentMs(){return Ae}};return Object.defineProperty(se,"__isScriptSetup",{enumerable:!1,value:!0}),se}});c(),I(),B();var Gi={class:`kb`},Ki=[`aria-hidden`],qi={class:`kb-col__head`},Ji={class:`kb-col__title`},Yi={class:`kb-col__count`},Xi={class:`kb-col__list`},Zi=[`data-task-id`,`aria-current`,`onClick`,`onKeydown`,`onContextmenu`],Qi=[`title`,`aria-label`,`onClick`],$i=[`src`,`alt`,`onError`],ea={key:0,class:`kb-card__cover-more`,"aria-hidden":`true`},ta={class:`kb-card__row1`},na=[`title`],ra=[`title`],ia={class:`kb-card__time`},aa=[`title`],oa=[`title`],sa={key:3,class:`kb-card__live`},ca={class:`kb-card__live-meta`},la=[`title`],ua=[`title`],da={key:2,class:`kb-card__live-pid`},fa={key:3,class:`kb-card__live-silent`},pa=[`title`],ma=[`aria-valuenow`,`aria-label`],ha={class:`kb-card__live-pct`},ga={class:`kb-card__live-pct-tag`},_a=[`title`],va=[`title`],ya={class:`kb-card__live-tag`},ba=[`title`],xa={class:`kb-card__live-tag`},Sa=[`title`],Ca=[`title`],wa={class:`kb-card__reply-text`},Ta=[`title`,`onClick`],Ea={class:`kb-card__actions`},Da=[`title`,`onClick`],Oa=[`title`,`aria-label`,`onClick`],ka=[`title`,`aria-label`,`onClick`],Aa=[`title`,`aria-label`,`onClick`],ja=[`title`,`aria-label`,`onClick`],Ma={key:0,class:`kb-col__add`},Na={key:1,class:`kb-col__empty`},Pa={key:2,class:`kb-col__more`},Fa={class:`kb__table-wrap`},Ia={class:`kb-table`},La={class:`kb-table__th`},Ra={class:`kb-table__th kb-table__th--narrow`},za={class:`kb-table__th kb-table__th--time`},Ba=[`onClick`,`onKeydown`],Va={class:`kb-table__td`},Ha=[`title`,`onClick`],Ua={class:`kb-table__name`},Wa=[`title`],Ga={key:2,class:`kb-table__live`},Ka=[`title`],qa=[`title`],Ja={key:2,class:`kb-table__live-silent`},Ya={class:`kb-table__live kb-table__live--reply`},Xa=[`title`],Za={class:`kb-table__td`},Qa={class:`kb-table__td kb-table__td--num`},$a=[`title`],eo={class:`kb-table__dur`},to=[`title`],no={key:0},ro={class:`kb-table__td kb-table__empty`,colspan:`3`};function io(t,n,i,a,o,s){let c=ie;return H(),x(`div`,Gi,[q(` 看板视图。
|
|
66
67
|
空列的宽度由 columnsStyle 给 0fr、由 .kb-col.is-collapsed 负责裁掉内容,
|
|
67
|
-
轨道宽度本身走 .kb__columns 的 transition(is-animated 挡住首屏那次抖动)。 `),i.view===`kanban`?(H(),x(`div`,{key:0,class:w([`kb__columns`,{"is-animated":a.animateCollapse}]),style:u(a.columnsStyle)},[(H(!0),x(O,null,E(a.columns,t=>(H(),x(`section`,{key:t.key,class:w([`kb-col`,[`kb-col--`+t.key,{"is-collapsed":t.collapsed}]]),"aria-hidden":t.collapsed?`true`:void 0},[b(`header`,
|
|
68
|
-
写 30 会让"一共完成了多少"这件事从界面上消失 `),b(`span`,
|
|
68
|
+
轨道宽度本身走 .kb__columns 的 transition(is-animated 挡住首屏那次抖动)。 `),i.view===`kanban`?(H(),x(`div`,{key:0,class:w([`kb__columns`,{"is-animated":a.animateCollapse}]),style:u(a.columnsStyle)},[(H(!0),x(O,null,E(a.columns,t=>(H(),x(`section`,{key:t.key,class:w([`kb-col`,[`kb-col--`+t.key,{"is-collapsed":t.collapsed}]]),"aria-hidden":t.collapsed?`true`:void 0},[b(`header`,qi,[q(` 脉冲只在列里真有东西时打:0 条的列上闪着"活着"的点,是这一屏唯一的装饰性假信号 `),b(`span`,{class:w([`kb-col__dot`,{"is-live":t.total>0}]),"aria-hidden":`true`},null,2),b(`h3`,Ji,T(a.$t(t.labelKey)),1),q(` 计数报**总数**而不是当前渲染条数:已完成列默认只铺最近 30 条,
|
|
69
|
+
写 30 会让"一共完成了多少"这件事从界面上消失 `),b(`span`,Yi,T(t.total),1)]),q(` 列表**始终渲染**(空列也渲染):塌缩是靠轨道宽度 + overflow 裁的,
|
|
69
70
|
内容得留在 DOM 里,收起那一瞬间才有东西可以跟着一起淡出。
|
|
70
|
-
空列本来就没有卡片,这里最坏也只是多渲染一条「暂无任务」。 `),b(`ul
|
|
71
|
+
空列本来就没有卡片,这里最坏也只是多渲染一条「暂无任务」。 `),b(`ul`,Xi,[(H(!0),x(O,null,E(t.tasks,r=>(H(),x(`li`,{key:r.id,class:w([`kb-card`,{"is-running":r.runningJobs>0,"has-error":a.hasError(r),"is-opened":r.id===i.openedTaskId}]),"data-task-id":r.id,"aria-current":r.id===i.openedTaskId?`true`:void 0,role:`button`,tabindex:`0`,onClick:e=>a.emit(`open-task`,r),onKeydown:[N(j(e=>a.emit(`open-task`,r),[`prevent`]),[`enter`]),N(j(e=>a.emit(`open-task`,r),[`prevent`]),[`space`])],onContextmenu:e=>a.onCardContextMenu(r,t.key,e)},[q(`
|
|
71
72
|
首行 = 所属项目色标 + 标题 + 时间,三样同一行。
|
|
72
73
|
· 色标原先自己占一行(一枚 60px 的胶囊推着标题和活动区往下走),
|
|
73
74
|
现在跟标题并排:卡片窄,能省一行是一行。
|
|
@@ -75,7 +76,7 @@ import"./rolldown-runtime-C0FnF6B9.js";import{An as e,Bn as t,C as n,Cn as r,F a
|
|
|
75
76
|
再来一枚一闪一闪的圆点属于重复编码,而且它是这张卡上唯一的纯装饰动效。
|
|
76
77
|
· 标题不再单独占行,跟着一起上移。
|
|
77
78
|
title 给完整路径:项目名可能重名(两个都叫 notebook),路径才是唯一答案。
|
|
78
|
-
`),
|
|
79
|
+
`),q(`
|
|
79
80
|
封面(第一条有图的附件):卡片上**看得见**的证据。
|
|
80
81
|
截图是这类任务最常带的附件,而在此之前卡片上一个字都没提它 ——
|
|
81
82
|
只能逐条点进去翻。图本身就是内容,摆出来比"有附件"的角标信息量大得多。
|
|
@@ -89,7 +90,7 @@ import"./rolldown-runtime-C0FnF6B9.js";import{An as e,Bn as t,C as n,Cn as r,F a
|
|
|
89
90
|
点开之后看图器能左右翻完整组(见 openImages)。
|
|
90
91
|
@click.stop / @keydown.stop:卡片整块是"打开任务"的可点区域,
|
|
91
92
|
封面得把自己摘出来 —— 否则点图会变成打开任务,看不成图。
|
|
92
|
-
`),a.coverImages(r).length>0?(H(),x(`button`,{key:0,type:`button`,class:`kb-card__cover`,title:a.coverTitle(a.coverImages(r)[0]),"aria-label":a.coverTitle(a.coverImages(r)[0]),onClick:j(e=>a.openImages(r),[`stop`]),onKeydown:n[0]||=j(()=>{},[`stop`])},[b(`img`,{class:`kb-card__cover-img`,src:a.imageRawUrl(a.coverImages(r)[0].id),alt:a.coverImages(r)[0].originalName,loading:`lazy`,decoding:`async`,onError:e=>a.onCoverError(a.coverImages(r)[0].id)},null,40
|
|
93
|
+
`),a.coverImages(r).length>0?(H(),x(`button`,{key:0,type:`button`,class:`kb-card__cover`,title:a.coverTitle(a.coverImages(r)[0]),"aria-label":a.coverTitle(a.coverImages(r)[0]),onClick:j(e=>a.openImages(r),[`stop`]),onKeydown:n[0]||=j(()=>{},[`stop`])},[b(`img`,{class:`kb-card__cover-img`,src:a.imageRawUrl(a.coverImages(r)[0].id),alt:a.coverImages(r)[0].originalName,loading:`lazy`,decoding:`async`,onError:e=>a.onCoverError(a.coverImages(r)[0].id)},null,40,$i),a.coverImages(r).length>1?(H(),x(`span`,ea,` +`+T(a.coverImages(r).length-1),1)):q(`v-if`,!0)],40,Qi)):q(`v-if`,!0),b(`div`,ta,[i.showProjectLabel&&a.projectLabel(r)?(H(),x(`span`,{key:0,class:`kb-card__project-chip`,style:u(a.projectTagStyle(r.projectPath)),title:r.projectPath},T(a.projectLabel(r)),13,na)):q(`v-if`,!0),b(`p`,{class:`kb-card__title`,title:a.cardTitle(r)},T(a.cardTitle(r)||a.$t(`@WORKBENCH:未命名任务`)),9,ra),b(`span`,ia,T(a.relativeTimeFromIso(a.cardTime(r))),1)]),q(`
|
|
93
94
|
跑完的任务:用时**独占一行**,不挤进上面那个时间位。
|
|
94
95
|
实测首行(项目色标 + 标题 + 时间)在真实数据上已经排满,
|
|
95
96
|
再塞一串「用时 30 分 0 秒」会把项目色标压出 1px 的省略号
|
|
@@ -97,7 +98,7 @@ import"./rolldown-runtime-C0FnF6B9.js";import{An as e,Bn as t,C as n,Cn as r,F a
|
|
|
97
98
|
竖着放只多一行 16px,横向一个字节都不占;而且「什么时候跑的」与
|
|
98
99
|
「跑了多久」本来就是两个维度,分两行读比挤在一行清楚 ——
|
|
99
100
|
同理它也没去挤活动区那行"已运行 x · 工具 n 次"。
|
|
100
|
-
`),a.cardDuration(r)?(H(),x(`p`,{key:1,class:`kb-card__spent`,title:a.cardTimeTitle(r)},T(a.taskSpentText(r)),9,
|
|
101
|
+
`),a.cardDuration(r)?(H(),x(`p`,{key:1,class:`kb-card__spent`,title:a.cardTimeTitle(r)},T(a.taskSpentText(r)),9,aa)):q(`v-if`,!0),q(`
|
|
101
102
|
「这条不是跑完的,是**判**完的」—— 紧跟在那行用时下面(它修饰的就是上面那个时长)。
|
|
102
103
|
|
|
103
104
|
为什么**另起一行**、而不是挂在那行用时后面:那行有探针按逐字相等断言
|
|
@@ -110,7 +111,7 @@ import"./rolldown-runtime-C0FnF6B9.js";import{An as e,Bn as t,C as n,Cn as r,F a
|
|
|
110
111
|
前者是**模型读了它的思考与最后那段话,认为活已经干完**。不标的话,
|
|
111
112
|
用户看到的就是一条任务不声不响换了列,而模型给的依据(悬停可见)
|
|
112
113
|
只躺在 jobs.json 里没人看得到。
|
|
113
|
-
`),r.autoCompleted?(H(),x(`p`,{key:2,class:`kb-card__auto-done`,title:a.autoDoneTitle(r)},T(a.$t(`@WORKBENCH:AI 判定完成`)),9,
|
|
114
|
+
`),r.autoCompleted?(H(),x(`p`,{key:2,class:`kb-card__auto-done`,title:a.autoDoneTitle(r)},T(a.$t(`@WORKBENCH:AI 判定完成`)),9,oa)):q(`v-if`,!0),q(`
|
|
114
115
|
正在跑的任务:把"现在在干嘛"直接写在卡片上。
|
|
115
116
|
在此之前卡片只有右上角一个圆点 —— 一次跑二十分钟的任务,
|
|
116
117
|
用户盯着看只知道"还在跑",是在改代码还是卡住了完全看不出来,
|
|
@@ -118,15 +119,15 @@ import"./rolldown-runtime-C0FnF6B9.js";import{An as e,Bn as t,C as n,Cn as r,F a
|
|
|
118
119
|
(decorateTaskForBoard 的 live,与右栏进度报告同一份实现)。
|
|
119
120
|
证据顺序沿用进度报告面板:工具调用(正在做什么)→ 思考(为什么)
|
|
120
121
|
→ 最新回复;每一行没有内容就整行不渲染,不写"暂无"。
|
|
121
|
-
`),r.live?(H(),x(`div`,
|
|
122
|
+
`),r.live?(H(),x(`div`,sa,[b(`p`,ca,[q(` 执行器只留图标 + 悬停提示:卡片这一行本来就窄(已运行 x 分 y 秒 · 工具 n 次),
|
|
122
123
|
再钉一个 "Claude Code" 文本会把工具次数挤到第二行去。
|
|
123
|
-
v-if 挡住的是"认不出"(老记录没写 agent 字段)——那时宁可不画 `),a.cardAgent(r)?(H(),x(`span`,{key:0,class:`kb-card__live-agent`,title:a.taskExecutorName(a.cardAgent(r))},[e(a.TaskExecutorIcon,{executor:a.cardAgent(r),class:`kb-card__live-agent-icon`},null,8,[`executor`])],8,
|
|
124
|
-
和"改了三处代码"是完全不同的两件事 `),r.live.toolCallCount?(H(),x(`span`,{key:1,title:r.live.toolMix||``},T(a.$t(`@WORKBENCH:工具 {n} 次`,{n:r.live.toolCallCount})),9,
|
|
124
|
+
v-if 挡住的是"认不出"(老记录没写 agent 字段)——那时宁可不画 `),a.cardAgent(r)?(H(),x(`span`,{key:0,class:`kb-card__live-agent`,title:a.taskExecutorName(a.cardAgent(r))},[e(a.TaskExecutorIcon,{executor:a.cardAgent(r),class:`kb-card__live-agent-icon`},null,8,[`executor`])],8,la)):q(`v-if`,!0),b(`span`,null,T(a.taskLiveText(r)),1),q(` 次数看总数,鼠标停上去看分布:119 次里 118 次都是 Bash,
|
|
125
|
+
和"改了三处代码"是完全不同的两件事 `),r.live.toolCallCount?(H(),x(`span`,{key:1,title:r.live.toolMix||``},T(a.$t(`@WORKBENCH:工具 {n} 次`,{n:r.live.toolCallCount})),9,ua)):q(`v-if`,!0),q(`
|
|
125
126
|
PID:左栏那个「执行监控」面板去掉了,它的字段里只有这一个卡片上没有,
|
|
126
127
|
所以并到这一行来(面板其余字段卡片本来就都有,且比它更全)。
|
|
127
128
|
不走 $t:PID 是中英文都这么写的通用缩写,没有可翻译的余地。
|
|
128
129
|
放静默之前:静默是"它可能卡住了"的信号,该留在行尾最显眼。
|
|
129
|
-
`),r.live.pid?(H(),x(`span`,
|
|
130
|
+
`),r.live.pid?(H(),x(`span`,da,`PID `+T(r.live.pid),1)):q(`v-if`,!0),q(` 静默只在**显然静默**时才有值(服务端有阈值);0 不画(reportSilentMs) `),a.reportSilentMs(r.live.silentMs)===null?q(`v-if`,!0):(H(),x(`span`,fa,T(a.$t(`@WORKBENCH:静默 {elapsed}`,{elapsed:a.formatDurationMs(a.reportSilentMs(r.live.silentMs))})),1))]),q(`
|
|
130
131
|
这条任务现在几成(主 Agent 估的)。2026-10-14 从右栏「任务事实」搬过来:
|
|
131
132
|
那一区列的就是这几行事实(工具 / 思考 / 回复 + 时长),与卡片几乎逐字重合,
|
|
132
133
|
两处并排显示时用户看到的是同一件事说两遍(用户截图反馈"左右都有,有点重叠")。
|
|
@@ -139,8 +140,8 @@ import"./rolldown-runtime-C0FnF6B9.js";import{An as e,Bn as t,C as n,Cn as r,F a
|
|
|
139
140
|
|
|
140
141
|
不画的情况全部交给 cardPercent 判(没在跑 / 报告里没提到它 / 模型没给数字),
|
|
141
142
|
绝不画一条 0% 的实心条 —— 那等于替模型说它没说过的话。
|
|
142
|
-
`),a.cardPercent(r)===null?
|
|
143
|
-
地方交代这个数字是怎么来的,光甩一个 22% 会被当成实测进度 `),b(`span`,
|
|
143
|
+
`),a.cardPercent(r)===null?q(`v-if`,!0):(H(),x(`p`,{key:0,class:`kb-card__live-progress`,title:a.$t(a.REPORT_PERCENT_HINT_KEY)},[b(`span`,{class:`kb-card__live-bar`,role:`progressbar`,"aria-valuenow":a.cardPercent(r),"aria-valuemin":`0`,"aria-valuemax":`100`,"aria-label":a.cardTitle(r)||a.$t(`@WORKBENCH:未命名任务`)},[b(`i`,{class:`kb-card__live-bar-fill`,style:u({width:a.cardPercent(r)+`%`})},null,4)],8,ma),q(` 「AI 估计」四个字不能省(与右栏整体那条同一取舍):卡片上再没有别的
|
|
144
|
+
地方交代这个数字是怎么来的,光甩一个 22% 会被当成实测进度 `),b(`span`,ha,[b(`span`,ga,T(a.$t(a.REPORT_PERCENT_LABEL_KEY)),1),L(T(a.cardPercent(r))+`% `,1)])],8,pa)),r.live.lastTool?(H(),x(`p`,{key:1,class:`kb-card__live-line is-tool`,title:r.live.lastTool},T(r.live.lastTool),9,_a)):q(`v-if`,!0),r.live.lastThought?(H(),x(`p`,{key:2,class:`kb-card__live-line is-thought`,title:r.live.lastThought},[b(`span`,ya,T(a.$t(`@WORKBENCH:最近思考`)),1),L(T(r.live.lastThought),1)],8,va)):q(`v-if`,!0),r.live.lastLine?(H(),x(`p`,{key:3,class:`kb-card__live-line`,title:r.live.lastLine},[b(`span`,xa,T(a.$t(`@WORKBENCH:最新回复`)),1),L(T(r.live.lastLine),1)],8,ba)):q(`v-if`,!0)])):r.lastReply?(H(),x(O,{key:4},[q(`
|
|
144
145
|
已经跑完的任务:留下"它最后说了什么"。
|
|
145
146
|
卡片过去只有标题 + 时间,而模型收尾时常常反问一句「要 push 吗?」——
|
|
146
147
|
这类任务看着是完成了,其实在等用户回话,用户却只能点进去翻日志才知道。
|
|
@@ -151,7 +152,7 @@ import"./rolldown-runtime-C0FnF6B9.js";import{An as e,Bn as t,C as n,Cn as r,F a
|
|
|
151
152
|
|
|
152
153
|
执行器图标(有才渲染)摆在引文开头:这句收尾的话是**它**说的,
|
|
153
154
|
图标就贴着它,比跑到卡片别处去找更直接。
|
|
154
|
-
`),b(`p`,{class:`kb-card__reply`,title:r.lastReply},[a.cardAgent(r)?(H(),x(`span`,{key:0,class:`kb-card__quote-agent`,title:a.taskExecutorName(a.cardAgent(r))},[e(a.TaskExecutorIcon,{executor:a.cardAgent(r),class:`kb-card__quote-agent-icon`},null,8,[`executor`])],8,
|
|
155
|
+
`),b(`p`,{class:`kb-card__reply`,title:r.lastReply},[a.cardAgent(r)?(H(),x(`span`,{key:0,class:`kb-card__quote-agent`,title:a.taskExecutorName(a.cardAgent(r))},[e(a.TaskExecutorIcon,{executor:a.cardAgent(r),class:`kb-card__quote-agent-icon`},null,8,[`executor`])],8,Ca)):q(`v-if`,!0),b(`span`,wa,T(r.lastReply),1)],8,Sa)],2112)):q(`v-if`,!0),q(`
|
|
155
156
|
出错卡上「重试」常驻。
|
|
156
157
|
卡片其余动作住在 hover 遮罩里(那是刻意的,见文件头:看板不是操作面板),
|
|
157
158
|
但出错是**跨列状态**里唯一需要立刻决策的一种:静态屏上那张红卡只有一句
|
|
@@ -159,7 +160,7 @@ import"./rolldown-runtime-C0FnF6B9.js";import{An as e,Bn as t,C as n,Cn as r,F a
|
|
|
159
160
|
单独一颗按钮、**不并进 .kb-card__actions** —— 那一组的宽度被
|
|
160
161
|
verify-wb-card-fade-band 按 96px 常数反推过渐隐距离,往里塞第三颗要连带改遮罩;
|
|
161
162
|
位置也必须在动作组**之前**,因为动作组是遮罩的锚点(卡片最后一行)。
|
|
162
|
-
`),a.hasError(r)&&r.runningJobs===0?(H(),x(`button`,{key:5,type:`button`,class:`kb-card__retry`,title:a.$t(`@WORKBENCH:重新执行这条任务`),onClick:j(e=>a.emit(`run-task`,r),[`stop`]),onKeydown:n[1]||=j(()=>{},[`stop`])},T(a.$t(`@WORKBENCH:重试`)),41,
|
|
163
|
+
`),a.hasError(r)&&r.runningJobs===0?(H(),x(`button`,{key:5,type:`button`,class:`kb-card__retry`,title:a.$t(`@WORKBENCH:重新执行这条任务`),onClick:j(e=>a.emit(`run-task`,r),[`stop`]),onKeydown:n[1]||=j(()=>{},[`stop`])},T(a.$t(`@WORKBENCH:重试`)),41,Ta)):q(`v-if`,!0),b(`div`,Ea,[q(`
|
|
163
164
|
这一格是「对这条任务现在能做什么」。头两颗互斥、**不并排**:
|
|
164
165
|
空闲时能做的只有"跑一轮",在跑时能做的只有"停掉这一轮",
|
|
165
166
|
两个按钮同时摆着会让人以为"在跑也能再跑一轮"(服务端也确实拒绝)。
|
|
@@ -167,14 +168,14 @@ import"./rolldown-runtime-C0FnF6B9.js";import{An as e,Bn as t,C as n,Cn as r,F a
|
|
|
167
168
|
操作组宽度因此**一个像素都不变** —— 下面那段按组宽反推的渐隐距离不用跟着改。
|
|
168
169
|
(2026-10-01 加的「完成 / 撤销」也是 2 个汉字、且每张卡上最多出现一颗,
|
|
169
170
|
组宽仍是常数:96px。改动组宽就必须同步改那两组数字,否则按钮会露出半截字形。)
|
|
170
|
-
`),r.runningJobs===0?(H(),x(`button`,{key:0,type:`button`,class:`kb-card__btn`,title:a.$t(`@WORKBENCH:执行`),onClick:j(e=>a.emit(`run-task`,r),[`stop`]),onKeydown:n[2]||=j(()=>{},[`stop`])},T(a.$t(`@WORKBENCH:执行`)),41,
|
|
171
|
+
`),r.runningJobs===0?(H(),x(`button`,{key:0,type:`button`,class:`kb-card__btn`,title:a.$t(`@WORKBENCH:执行`),onClick:j(e=>a.emit(`run-task`,r),[`stop`]),onKeydown:n[2]||=j(()=>{},[`stop`])},T(a.$t(`@WORKBENCH:执行`)),41,Da)):(H(),x(O,{key:1},[q(`
|
|
171
172
|
停止:只有真在跑(runningJobs > 0 ⟺ 服务端推导出的「进行中」列)时才在。
|
|
172
173
|
条件用 runningJobs 而不是 \`!!t.live\`:两者在服务端同源(都是"有 running/pending
|
|
173
174
|
的 job"),但 runningJobs 是这张卡片列归属的判据本身,跟着它走不会出现
|
|
174
175
|
"卡片在待处理列却带个停止按钮"这种自相矛盾的状态。
|
|
175
176
|
点了做什么(确认弹窗、调哪个接口、jobId 从哪来)全在上层 —— 卡片只管发出意图,
|
|
176
177
|
与 run / delete 一致。
|
|
177
|
-
`),b(`button`,{type:`button`,class:`kb-card__btn kb-card__btn--stop`,title:a.$t(`@WORKBENCH:停止`),"aria-label":a.$t(`@WORKBENCH:停止`),onClick:j(e=>a.emit(`stop-task`,r),[`stop`]),onKeydown:n[3]||=j(()=>{},[`stop`])},T(a.$t(`@WORKBENCH:停止`)),41,
|
|
178
|
+
`),b(`button`,{type:`button`,class:`kb-card__btn kb-card__btn--stop`,title:a.$t(`@WORKBENCH:停止`),"aria-label":a.$t(`@WORKBENCH:停止`),onClick:j(e=>a.emit(`stop-task`,r),[`stop`]),onKeydown:n[3]||=j(()=>{},[`stop`])},T(a.$t(`@WORKBENCH:停止`)),41,Oa)],2112)),q(`
|
|
178
179
|
手动「完成」:这颗按钮是看板上唯一一个**不由执行事实决定**的动作源头
|
|
179
180
|
(列仍然是推导的,只是推导时多听一句人话 —— 详见文件头那段)。
|
|
180
181
|
待处理 / 进行中都给:待处理里那条可能早在别处干完了,
|
|
@@ -187,28 +188,28 @@ import"./rolldown-runtime-C0FnF6B9.js";import{An as e,Bn as t,C as n,Cn as r,F a
|
|
|
187
188
|
|
|
188
189
|
在跑的那张卡上点「完成」会连这一轮一起停掉(一张卡不能既已完成又在跑),
|
|
189
190
|
代价说明与确认弹窗在上层 —— 卡片只管发出意图,与 run / stop / delete 一致。
|
|
190
|
-
`),r.column===`done`?r.manualDoneAt?(H(),x(`button`,{key:3,type:`button`,class:`kb-card__btn`,title:a.$t(`@WORKBENCH:撤销完成标记,退回待处理`),"aria-label":a.$t(`@WORKBENCH:撤销完成标记`),onClick:j(e=>a.emit(`reopen-task`,r),[`stop`]),onKeydown:n[5]||=j(()=>{},[`stop`])},T(a.$t(`@WORKBENCH:撤销`)),41,
|
|
191
|
+
`),r.column===`done`?r.manualDoneAt?(H(),x(`button`,{key:3,type:`button`,class:`kb-card__btn`,title:a.$t(`@WORKBENCH:撤销完成标记,退回待处理`),"aria-label":a.$t(`@WORKBENCH:撤销完成标记`),onClick:j(e=>a.emit(`reopen-task`,r),[`stop`]),onKeydown:n[5]||=j(()=>{},[`stop`])},T(a.$t(`@WORKBENCH:撤销`)),41,Aa)):q(`v-if`,!0):(H(),x(`button`,{key:2,type:`button`,class:`kb-card__btn kb-card__btn--done`,title:a.$t(`@WORKBENCH:标记为已完成`),"aria-label":a.$t(`@WORKBENCH:标记为已完成`),onClick:j(e=>a.emit(`complete-task`,r),[`stop`]),onKeydown:n[4]||=j(()=>{},[`stop`])},T(a.$t(`@WORKBENCH:完成`)),41,ka)),b(`button`,{type:`button`,class:`kb-card__btn kb-card__btn--danger`,title:a.$t(`@WORKBENCH:删除`),"aria-label":a.$t(`@WORKBENCH:删除`),onClick:j(e=>a.emit(`delete-task`,r),[`stop`]),onKeydown:n[6]||=j(()=>{},[`stop`])},`×`,40,ja)])],42,Zi))),128)),q(`
|
|
191
192
|
「新建任务」常驻待处理列末尾,不再只在列空时出现。
|
|
192
193
|
之前入口和空状态是同一个 \`v-if="col.tasks.length === 0"\`:列里一有卡片,
|
|
193
194
|
新建入口就整块消失,用户只能绕到左侧栏去建(看板里无处可点)。
|
|
194
195
|
两件事本来就无关——空状态说的是"这列没有卡片",新建入口说的是"能往这儿加卡片"。
|
|
195
196
|
列空时它顺带兼任空状态(--solo 撑高),所以待处理列不会再渲染下面的 kb-col__empty。
|
|
196
197
|
位置沿用 Trello「Add a card」的做法:跟着列表滚(不吸底),长列表滚到底就是它。
|
|
197
|
-
`),t.key===`todo`?(H(),x(`li`,
|
|
198
|
-
不是分页 —— 点一次在当前列表尾巴上续一批,不打断滚动位置。 `),t.hidden>0?(H(),x(`li`,
|
|
198
|
+
`),t.key===`todo`?(H(),x(`li`,Ma,[b(`button`,{type:`button`,class:w([`kb-col__add-btn`,{"kb-col__add-btn--solo":t.tasks.length===0}]),onClick:n[7]||=e=>a.emit(`create-task`)},[n[11]||=b(`span`,{class:`kb-col__add-plus`,"aria-hidden":`true`},`+`,-1),b(`span`,null,T(a.$t(`@WORKBENCH:新建任务`)),1)],2)])):t.tasks.length===0?(H(),x(`li`,Na,[b(`span`,null,T(a.$t(`@WORKBENCH:暂无任务`)),1)])):q(`v-if`,!0),q(` 「再多给我一点」:已完成列默认只铺最近 30 条(实测满载态 159 条约 20 屏滚动)。
|
|
199
|
+
不是分页 —— 点一次在当前列表尾巴上续一批,不打断滚动位置。 `),t.hidden>0?(H(),x(`li`,Pa,[b(`button`,{type:`button`,class:`kb-col__more-btn`,onClick:n[8]||=e=>a.doneLimit+=a.DONE_PAGE},T(a.$t(`@WORKBENCH:显示更早的 {n} 条`,{n:Math.min(a.DONE_PAGE,t.hidden)})),1)])):q(`v-if`,!0)])],10,Ki))),128))],6)):(H(),x(O,{key:1},[q(` 列表视图 `),b(`div`,Fa,[b(`table`,Ia,[b(`thead`,null,[b(`tr`,null,[b(`th`,La,T(a.$t(`@WORKBENCH:任务`)),1),b(`th`,Ra,T(a.$t(`@WORKBENCH:状态`)),1),b(`th`,za,T(a.$t(`@WORKBENCH:时间`)),1)])]),b(`tbody`,null,[(H(!0),x(O,null,E(a.listRows,t=>(H(),x(`tr`,{key:t.id,class:`kb-table__row`,tabindex:`0`,onClick:e=>a.emit(`open-task`,t),onKeydown:[N(j(e=>a.emit(`open-task`,t),[`prevent`]),[`enter`]),N(j(e=>a.emit(`open-task`,t),[`prevent`]),[`space`])]},[b(`td`,Va,[q(` 列表视图这边的"这条带图":与看板卡片的封面同一份数据、同一层含义。
|
|
199
200
|
看板默认视图是卡片,所以那边可以铺一张封面;这一格是一行密排的正文
|
|
200
201
|
(整格 width 按 table-layout: fixed 平分),塞缩略图会把行高顶出去 ——
|
|
201
202
|
.kb-table__time 那边有探针按"整格只有一行"断言,这一格没理由比它松。
|
|
202
203
|
所以退成**纯文字的计数标**:零字号变化、零内边距,行高一个像素不动,
|
|
203
204
|
但仍然是个按钮(点了看图)——"有图"这件事在两处视图里都消失不了。
|
|
204
|
-
同 .kb-table__auto-done:只给颜色,不给框。 `),a.coverImages(t).length>0?(H(),x(`button`,{key:0,type:`button`,class:`kb-table__shots`,title:a.coverTitle(a.coverImages(t)[0]),onClick:j(e=>a.openImages(t),[`stop`]),onKeydown:n[9]||=j(()=>{},[`stop`])},T(a.$t(`@WORKBENCH:{n} 张图`,{n:a.coverImages(t).length})),41,
|
|
205
|
-
列表视图是同一批任务的另一种画法,两处长得不一样会让人以为是两份数据 `),i.showProjectLabel&&a.projectLabel(t)?(H(),x(`span`,{key:1,class:`kb-table__project`,style:u(a.projectTagStyle(t.projectPath)),title:t.projectPath},T(a.projectLabel(t)),13,
|
|
205
|
+
同 .kb-table__auto-done:只给颜色,不给框。 `),a.coverImages(t).length>0?(H(),x(`button`,{key:0,type:`button`,class:`kb-table__shots`,title:a.coverTitle(a.coverImages(t)[0]),onClick:j(e=>a.openImages(t),[`stop`]),onKeydown:n[9]||=j(()=>{},[`stop`])},T(a.$t(`@WORKBENCH:{n} 张图`,{n:a.coverImages(t).length})),41,Ha)):q(`v-if`,!0),b(`span`,Ua,T(a.cardTitle(t)||a.$t(`@WORKBENCH:未命名任务`)),1),q(` 项目色标:与看板卡片同一枚(见 .kb-card__project-chip 的样式注释),
|
|
206
|
+
列表视图是同一批任务的另一种画法,两处长得不一样会让人以为是两份数据 `),i.showProjectLabel&&a.projectLabel(t)?(H(),x(`span`,{key:1,class:`kb-table__project`,style:u(a.projectTagStyle(t.projectPath)),title:t.projectPath},T(a.projectLabel(t)),13,Wa)):q(`v-if`,!0),q(` 状态列的"进行中"太粗,跑起来之后一眼看不出进度:这里补一行
|
|
206
207
|
最新回复 / 思考 / 工具(与卡片上的 live 同一份数据)。
|
|
207
|
-
执行器图标摆最前(与看板卡片同一个位置:整块执行事实的开头) `),t.live?(H(),x(`span`,
|
|
208
|
-
会让人以为是两份数据。列表这行只有一行,所以只给数字不给条 `),a.cardPercent(t)===null?
|
|
209
|
-
两种画法,一边有、一边没有会让人以为是两份数据 `),b(`span`,
|
|
210
|
-
会让人以为是两份数据 `),b(`span`,{class:`kb-table__time`,title:a.cardTimeTitle(t)},[a.cardDuration(t)?(H(),x(O,{key:0},[b(`span`,
|
|
211
|
-
一边有一边没有会让人以为是两份数据(卡片那边见 .kb-card__spent 的注释) `),t.autoCompleted?(H(),x(O,{key:1},[b(`span`,{class:`kb-table__auto-done`,title:a.autoDoneTitle(t)},T(a.$t(`@WORKBENCH:AI 判定完成`)),9,
|
|
208
|
+
执行器图标摆最前(与看板卡片同一个位置:整块执行事实的开头) `),t.live?(H(),x(`span`,Ga,[a.cardAgent(t)?(H(),x(`span`,{key:0,class:`kb-table__agent`,title:a.taskExecutorName(a.cardAgent(t))},[e(a.TaskExecutorIcon,{executor:a.cardAgent(t),class:`kb-table__agent-icon`},null,8,[`executor`])],8,Ka)):q(`v-if`,!0),L(` `+T(a.liveSummary(t))+` `,1),q(` 进度与看板卡片同一份数据(同一张表):两种画法一边有一边没有,
|
|
209
|
+
会让人以为是两份数据。列表这行只有一行,所以只给数字不给条 `),a.cardPercent(t)===null?q(`v-if`,!0):(H(),x(`span`,{key:1,class:`kb-table__pct`,title:a.$t(a.REPORT_PERCENT_HINT_KEY)},T(a.$t(a.REPORT_PERCENT_LABEL_KEY))+` `+T(a.cardPercent(t))+`% `,9,qa)),a.reportSilentMs(t.live.silentMs)===null?q(`v-if`,!0):(H(),x(`span`,Ja,T(a.$t(`@WORKBENCH:静默 {elapsed}`,{elapsed:a.formatDurationMs(a.reportSilentMs(t.live.silentMs))})),1))])):t.lastReply?(H(),x(O,{key:3},[q(` 跑完的任务同理给一行"最后说了什么":列表视图与看板卡片是同一批任务的
|
|
210
|
+
两种画法,一边有、一边没有会让人以为是两份数据 `),b(`span`,Ya,[a.cardAgent(t)?(H(),x(`span`,{key:0,class:`kb-table__agent`,title:a.taskExecutorName(a.cardAgent(t))},[e(a.TaskExecutorIcon,{executor:a.cardAgent(t),class:`kb-table__agent-icon`},null,8,[`executor`])],8,Xa)):q(`v-if`,!0),L(T(t.lastReply),1)])],2112)):q(`v-if`,!0)]),b(`td`,Za,[b(`span`,{class:w([`kb-table__status`,`is-`+t.column])},T(a.$t(a.COLUMNS.find(e=>e.key===t.column).labelKey)),3)]),b(`td`,Qa,[q(` 与看板卡片首行同一个口径:同一批任务的两种画法,一边有一边没有
|
|
211
|
+
会让人以为是两份数据 `),b(`span`,{class:`kb-table__time`,title:a.cardTimeTitle(t)},[a.cardDuration(t)?(H(),x(O,{key:0},[b(`span`,eo,T(a.taskSpentText(t)),1),n[12]||=b(`span`,{class:`kb-table__time-sep`,"aria-hidden":`true`},`·`,-1)],64)):q(`v-if`,!0),q(` 「AI 判定完成」在列表视图里也得有:同一批任务的两种画法,
|
|
212
|
+
一边有一边没有会让人以为是两份数据(卡片那边见 .kb-card__spent 的注释) `),t.autoCompleted?(H(),x(O,{key:1},[b(`span`,{class:`kb-table__auto-done`,title:a.autoDoneTitle(t)},T(a.$t(`@WORKBENCH:AI 判定完成`)),9,to),n[13]||=b(`span`,{class:`kb-table__time-sep`,"aria-hidden":`true`},`·`,-1)],64)):q(`v-if`,!0),b(`span`,null,T(a.relativeTimeFromIso(a.cardTime(t))),1)],8,$a)])],40,Ba))),128)),a.listRows.length===0?(H(),x(`tr`,no,[b(`td`,ro,T(a.$t(`@WORKBENCH:暂无任务`)),1)])):q(`v-if`,!0)])])])],2112)),q(`
|
|
212
213
|
看图器(点封面 / 列表里那枚「N 张图」打开)。
|
|
213
214
|
|
|
214
215
|
复用 element-plus 的 el-image-viewer,而不是自己糊一个遮罩:
|
|
@@ -224,23 +225,23 @@ import"./rolldown-runtime-C0FnF6B9.js";import{An as e,Bn as t,C as n,Cn as r,F a
|
|
|
224
225
|
默认 undefined = 关闭 —— 关掉的话遮罩会嵌在 .kb 里,被看板的滚动容器裁掉。
|
|
225
226
|
也不要再在外面套一层 <teleport to="body">:嵌套 Teleport 在 2.11.x 下会让
|
|
226
227
|
组件挂不上(AttachmentZone 那边踩过并留了注释)。
|
|
227
|
-
`),a.imageViewer?(H(),r(c,{key:2,"url-list":a.imageViewer.urls,"initial-index":a.imageViewer.index,"hide-on-click-modal":!0,teleported:!0,onClose:a.closeImages},null,8,[`url-list`,`initial-index`])):J(`v-if`,!0),J(` 右键「移动到其他项目」:全局一份,teleport 到 body(不被看板滚动容器裁掉) `),e(a.WorkbenchTaskMoveMenu,{visible:a.moveMenu.visible,x:a.moveMenu.x,y:a.moveMenu.y,task:a.moveMenu.task,projects:i.projects,onMove:a.onMoveToProject,onClose:n[10]||=e=>a.moveMenu.visible=!1},null,8,[`visible`,`x`,`y`,`task`,`projects`])])}var co=Q(qi,[[`render`,so],[`__scopeId`,`data-v-0b8fc27c`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/views/components/WorkbenchKanban.vue`]]);c(),R();var lo=`/api/workbench/orchestrator/attachments`,uo=`wb.ocInputHeight.v2`,fo=76,po=20,mo=f({__name:`OrchestratorConsole`,props:{running:{type:Array,required:!0},selectedProject:{type:[Object,null],required:!0},dispatching:{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-collapse`,`open-prompt-settings`,`generate-report`,`set-report-interval`,`locate-task`,`dispatch`],setup(e,{expose:n,emit:r}){let i=e,a=r,s=M(``),c=M(!0),l=M(!0),{active:u}=Ze(),f=M([]),p=Y(()=>({kind:`draft`,list:f.value,replace:e=>{f.value=e}})),{isUploading:h,isImageAttachment:g,humanSize:_,onAttachmentPaste:y,onAttachmentDrop:b,removeAttachment:x,pickAttachmentFile:S}=Xn(),w=Y(()=>h(`draft`)),ee=M(!1),T=M(null),E=Y(()=>u.value===`codearts`),D=Y(()=>T.value??E.value),O=Y(()=>f.value.some(e=>g(e)));function k(e){T.value=e.target.checked}function A(e){e.stopPropagation(),y(e,p.value)}function re(e){ee.value=!1,b(e,p.value)}function ie(){S(p.value)}function ae(e){x(p.value,e)}function oe(){f.value=[]}function se(){s.value=``}n({clearAttachments:oe,clearDraft:se});let ce=Y(()=>i.selectedProject?.key||``),le=Y(()=>(i.defaultPrompt||``).trim()),j=Y(()=>{let e=ce.value;return e?(i.projectPrompts?.[e]?.prompt||``).trim():``}),N=Y(()=>Object.values(i.projectPrompts||{}).some(e=>(e?.prompt||``).trim().length>0)),P=Y(()=>!!le.value||N.value),F=Y(()=>{let e=!!le.value,t=ce.value?j.value?`project`:`none`:N.value?`target`:`none`;return Z(e&&t===`project`?`@WORKBENCH:全局 + 本项目`:e&&t===`target`?`@WORKBENCH:全局 + 落点项目`:e?`@WORKBENCH:全局`:t===`project`?`@WORKBENCH:本项目`:t===`target`?`@WORKBENCH:落点项目`:`@WORKBENCH:未设置`)}),I=Y(()=>s.value.trim().length),L=Y(()=>i.maxInstructionChars||1e5),de=Y(()=>I.value>L.value),R=Y(()=>!de.value&&I.value>=L.value*.9),fe=Y(()=>s.value.trim().length>0&&!i.dispatching&&!w.value&&!de.value);function pe(){fe.value&&a(`dispatch`,{text:s.value.trim(),autoRun:c.value,attachments:f.value,projectPath:i.selectedProject?i.selectedProject.path:``,useDefaultPrompt:l.value,executor:u.value,imageText:D.value})}function B(e){e.isComposing||e.keyCode===229||e.key!==`Enter`||e.shiftKey||(e.preventDefault(),pe())}function V(){try{let e=localStorage.getItem(uo);if(!e)return null;let t=Number(e);return Number.isFinite(t)&&t>=fo?Math.round(t):null}catch{return null}}let H=M(null),U=M(V()),W=Y(()=>{let e={};return U.value&&(e.height=`${U.value}px`),e}),G=null,K=!1,q=!0;function J(e){let t=H.value;if(!t)return;let n=t.getBoundingClientRect();K=n.right-e.clientX<=po&&n.bottom-e.clientY<=po}function he(){K=!1}function X(e){let t=Math.round(e.offsetHeight);if(!(t<fo||t===U.value)){U.value=t;try{localStorage.setItem(uo,String(t))}catch{}}}o(()=>{let e=H.value;e&&(window.addEventListener(`mouseup`,he),!(typeof ResizeObserver>`u`)&&(G=new ResizeObserver(()=>{if(q){q=!1;return}let t=parseFloat(getComputedStyle(e).maxHeight),n=Number.isFinite(t)&&e.offsetHeight>=t-1;(K||!n)&&X(e)}),G.observe(e)))}),C(()=>{window.removeEventListener(`mouseup`,he),G?.disconnect(),G=null});let ge=M(null),_e=Y(()=>(i.running||[]).length),ve=Y(()=>{let e=i.running||[];return{job:new Set(e.map(e=>e.jobId).filter(Boolean)),task:new Set(e.map(e=>e.taskId).filter(Boolean))}});function ye(e){if(!e)return!1;let t=ve.value;return(e.tasks||[]).some(e=>e.jobId&&t.job.has(e.jobId)||!e.jobId&&!!e.taskId&&t.task.has(e.taskId))}let be=Y(()=>(i.reports||[]).find(ye)||null),xe=Y(()=>{let e=Q.value;if(!e)return null;let t=e.tasks||[],n=ve.value;return(t.find(e=>e.jobId&&n.job.has(e.jobId)||!e.jobId&&!!e.taskId&&n.task.has(e.taskId))||t.find(e=>!!e.taskId))?.taskId||null}),Q=Y(()=>{let e=i.reports||[];if(!e.length)return null;if(ge.value){let t=e.find(e=>e.id===ge.value);if(t)return t}return be.value}),Se=Y(()=>!!Q.value&&!ye(Q.value)),Ce=Y(()=>(i.reports||[]).length?_e.value>0?Z(`@WORKBENCH:这批任务还没有进度报告`):Z(`@WORKBENCH:当前没有正在执行的任务`):Z(`@WORKBENCH:暂无进度报告`)),we=Y(()=>(i.reports||[]).length?Z(`@WORKBENCH:最新那份报告讲的任务已经跑完了,要回看可以从历史报告里点开`):``);function Te(e){ge.value=e.id}let Ee=M(null),De=M(!0),Oe=M(!1);function ke(){let e=Ee.value;e&&!De.value&&(Oe.value=e.scrollHeight-e.clientHeight>2)}function je(){De.value=!De.value,De.value||t(ke)}let Ne=null;z(Ee,e=>{Ne?.disconnect(),Ne=null,e&&(Ne=new ResizeObserver(()=>ke()),Ne.observe(e))}),C(()=>{Ne?.disconnect(),Ne=null}),z(()=>Q.value?.id,()=>{De.value=!0,Oe.value=!1,t(ke)});function Pe(e){let t=Me(e.percent);return t===null?``:t+`%`}let ze=Y(()=>Me(Q.value?.percent));function Be(e){let t=String(e.text||``).replace(/\s+/g,` `).trim();return t?t.length>42?t.slice(0,42)+`…`:t:e.errorCode?Z(Fe(e.errorCode)):Z(`@WORKBENCH:当时没有任务在执行`)}function Ve(e){return e.errorCode?Z(Fe(e.errorCode)):e.tasks.length?Z(`@WORKBENCH:模型没有返回内容`):Z(`@WORKBENCH:生成这份报告时没有任务在执行`)}function He(e){let t=e.target,n=Number(t.value);Le.includes(n)&&a(`set-report-interval`,n)}let We=Y(()=>{let e=i.selectedProject;if(!e)return[];let t=[];if(e.exists===!1)return t.push({label:Z(`@WORKBENCH:工作区`),value:Z(`@WORKBENCH:目录不存在`),tone:`danger`}),t;let n=e.git;return!n||n.isGitRepo===null?(t.push({label:Z(`@WORKBENCH:Git 状态`),value:Z(`@WORKBENCH:未知`),tone:``}),t):n.isGitRepo?(t.push({label:Z(`@WORKBENCH:分支`),value:n.detached?Z(`@WORKBENCH:游离 HEAD`):n.branch||Z(`@WORKBENCH:未知`),tone:``}),t.push({label:Z(`@WORKBENCH:工作区`),value:n.changed>0?Z(`@WORKBENCH:未提交 {n} 项`,{n:n.changed}):Z(`@WORKBENCH:干净`),tone:n.changed>0?`warn`:``}),n.hasUpstream&&(n.ahead>0||n.behind>0)&&t.push({label:Z(`@WORKBENCH:与上游`),value:Z(`@WORKBENCH:领先 {ahead} / 落后 {behind}`,{ahead:n.ahead,behind:n.behind}),tone:n.behind>0?`warn`:``}),t):(t.push({label:Z(`@WORKBENCH:Git 状态`),value:Z(`@WORKBENCH:不是 Git 仓库`),tone:``}),t)}),$={history:`wb.ocHistoryOpen.v1`,git:`wb.ocGitOpen.v1`};function Ge(e){try{return localStorage.getItem(e)===`1`}catch{return!1}}let Ke=M(Ge($.history)),qe=M(Ge($.git));function Je(e){let t=e===`history`?Ke:qe;t.value=!t.value;try{localStorage.setItem($[e],t.value?`1`:`0`)}catch{}}function Ye(){Ke.value||Je(`history`)}let Xe={props:i,emit:a,draft:s,autoRun:c,useDefaultPrompt:l,selectedExecutor:u,draftAttachments:f,DRAFT_RAW_BASE:lo,attachTarget:p,isUploading:h,isImageAttachment:g,humanSize:_,onAttachmentPaste:y,onAttachmentDrop:b,removeAttachment:x,pickAttachmentFile:S,attachBusy:w,attachDragging:ee,imageTextChoice:T,imageTextAuto:E,imageTextOn:D,hasImageAttachment:O,onImageTextChange:k,onPaste:A,onDrop:re,onPickAttachment:ie,onRemoveAttachment:ae,clearAttachments:oe,clearDraft:se,projectKey:ce,globalPromptText:le,projectPromptText:j,anyProjectPrompt:N,anyPromptConfigured:P,promptStateLabel:F,draftChars:I,charLimit:L,overLimit:de,nearLimit:R,canSend:fe,send:pe,onInputKeydown:B,INPUT_H_KEY:uo,OC_INPUT_MIN_H:fo,readInputH:V,inputRef:H,inputH:U,inputStyle:W,get inputRO(){return G},set inputRO(e){G=e},get inputDragging(){return K},set inputDragging(e){K=e},get inputROFirst(){return q},set inputROFirst(e){q=e},INPUT_GRIP_PX:po,onInputMouseDown:J,onWindowMouseUp:he,commitInputH:X,selectedReportId:ge,runningCount:_e,runningIds:ve,reportIsLive:ye,liveReport:be,locateTaskId:xe,currentReport:Q,currentReportStale:Se,idleHint:Ce,idleHintTitle:we,pickReport:Te,textEl:Ee,textExpanded:De,textClamped:Oe,measureText:ke,toggleText:je,get textRO(){return Ne},set textRO(e){Ne=e},historyPct:Pe,currentPercent:ze,reportBrief:Be,reportNotice:Ve,onIntervalChange:He,gitSummary:We,SECT_KEY:$,readSectOpen:Ge,historyOpen:Ke,gitOpen:qe,toggleSect:Je,reviewHistory:Ye,gitBrief:Y(()=>We.value.slice(0,2).map(e=>e.value).join(` · `)),get $t(){return Z},get Promotion(){return d},get Expand(){return ue},get Fold(){return me},get Refresh(){return v},get ArrowDown(){return te},get ArrowRight(){return ne},get LocationInformation(){return m},get clockFromIso(){return rt},get relativeTimeFromIso(){return nt},get REPORT_INTERVAL_OPTIONS_MS(){return Le},get REPORT_PERCENT_HINT_KEY(){return Ue},get REPORT_PERCENT_LABEL_KEY(){return Ae},get reportIntervalLabelKey(){return Ie},get reportIntervalLabelParams(){return Re},AttachmentZone:bt,TaskExecutorPicker:et};return Object.defineProperty(Xe,"__isScriptSetup",{enumerable:!1,value:!0}),Xe}});c(),I(),B();var ho=[`title`,`aria-label`],go={class:`oc__rail-text`},_o={class:`oc__head`},vo={class:`oc__title`},yo=[`title`,`aria-label`],bo={class:`oc__report-head`},xo={class:`oc__panel-title`},So=[`value`,`title`,`aria-label`],Co=[`value`],wo=[`disabled`,`title`],To={class:`oc__report-list`},Eo={key:0,class:`rp`},Do={class:`rp__head`},Oo=[`title`],ko={class:`rp__count`},Ao={class:`rp__time`},jo=[`title`,`aria-label`],Mo=[`title`],No=[`aria-valuenow`,`aria-label`],Po={class:`rp__percent`},Fo={class:`rp__percent-tag`},Io={key:1,class:`rp__body`},Lo=[`title`],Ro=[`title`],zo={class:`oc-empty__text`},Bo=[`aria-expanded`,`title`],Vo={class:`oc__sect-title`},Ho={class:`oc__sect-meta`},Uo={class:`oc__sect-brief`},Wo={class:`oc__history-list`},Go=[`onClick`],Ko={class:`oc__history-time`},qo={class:`oc__history-pct`},Jo={class:`oc__history-sum`},Yo=[`aria-expanded`,`title`],Xo={class:`oc__sect-title`},Zo={class:`oc__sect-meta`},Qo={class:`oc__git-name`},$o={key:0,class:`oc__sect-brief`},es={class:`oc__git-list`},ts={class:`oc__git-label`},ns={class:`oc__git-label`},rs={class:`oc__git-value`},is={class:`oc__git-label`},as={class:`oc__git-value`},os=[`placeholder`],ss={key:0},cs={key:1},ls={class:`oc__compose-foot`},us=[`disabled`,`title`,`aria-label`],ds=[`title`,`aria-label`],fs=[`title`],ps=[`title`],ms=[`title`],hs=[`checked`],gs={class:`oc__foot-label`},_s=[`disabled`],vs={class:`oc__hint`};function ys(t,n,i,a,o,s){let c=l;return H(),x(`aside`,{class:w([`oc`,{"is-collapsed":i.collapsed,"is-report-empty":!i.collapsed&&!a.currentReport}])},[J(` 折叠后的收纳条:只剩一枚展开按钮 + 竖排标题,宽度收到 32px。
|
|
228
|
-
折叠不是"把宽度压成 0"—— 那样就再没有能点回来的地方了。 `),i.collapsed?(H(),x(`button`,{key:0,type:`button`,class:`oc__rail`,title:a.$t(`@WORKBENCH:展开主 Agent 控制台`),"aria-label":a.$t(`@WORKBENCH:展开主 Agent 控制台`),"aria-expanded":!1,onClick:n[0]||=e=>a.emit(`toggle-collapse`)},[e(c,{class:`oc__rail-icon`},{default:F(()=>[e(a.Fold)]),_:1}),b(`span`,
|
|
229
|
-
草稿指令和已贴的附件都还留着,展开回来能接着发 `),A(b(`header`,
|
|
228
|
+
`),a.imageViewer?(H(),r(c,{key:2,"url-list":a.imageViewer.urls,"initial-index":a.imageViewer.index,"hide-on-click-modal":!0,teleported:!0,onClose:a.closeImages},null,8,[`url-list`,`initial-index`])):q(`v-if`,!0),q(` 右键「移动到其他项目」:全局一份,teleport 到 body(不被看板滚动容器裁掉) `),e(a.WorkbenchTaskMoveMenu,{visible:a.moveMenu.visible,x:a.moveMenu.x,y:a.moveMenu.y,task:a.moveMenu.task,projects:i.projects,onMove:a.onMoveToProject,onClose:n[10]||=e=>a.moveMenu.visible=!1},null,8,[`visible`,`x`,`y`,`task`,`projects`])])}var ao=Q(Wi,[[`render`,io],[`__scopeId`,`data-v-0b8fc27c`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/views/components/WorkbenchKanban.vue`]]);c(),R();var oo=`/api/workbench/orchestrator/attachments`,so=`wb.ocInputHeight.v2`,co=76,lo=20,uo=f({__name:`OrchestratorConsole`,props:{running:{type:Array,required:!0},selectedProject:{type:[Object,null],required:!0},dispatching:{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-collapse`,`open-prompt-settings`,`generate-report`,`set-report-interval`,`locate-task`,`dispatch`],setup(e,{expose:n,emit:r}){let i=e,a=r,s=M(``),c=M(!0),l=M(!0),{active:u}=Je(),f=M([]),p=J(()=>({kind:`draft`,list:f.value,replace:e=>{f.value=e}})),{isUploading:h,isImageAttachment:g,humanSize:_,onAttachmentPaste:y,onAttachmentDrop:b,removeAttachment:x,pickAttachmentFile:S}=Zn(),w=J(()=>h(`draft`)),ee=M(!1),T=M(null),E=J(()=>u.value===`codearts`),D=J(()=>T.value??E.value),O=J(()=>f.value.some(e=>g(e)));function k(e){T.value=e.target.checked}function A(e){e.stopPropagation(),y(e,p.value)}function re(e){ee.value=!1,b(e,p.value)}function ie(){S(p.value)}function ae(e){x(p.value,e)}function oe(){f.value=[]}function se(){s.value=``}n({clearAttachments:oe,clearDraft:se});let ce=J(()=>i.selectedProject?.key||``),le=J(()=>(i.defaultPrompt||``).trim()),j=J(()=>{let e=ce.value;return e?(i.projectPrompts?.[e]?.prompt||``).trim():``}),N=J(()=>Object.values(i.projectPrompts||{}).some(e=>(e?.prompt||``).trim().length>0)),P=J(()=>!!le.value||N.value),F=J(()=>{let e=!!le.value,t=ce.value?j.value?`project`:`none`:N.value?`target`:`none`;return Z(e&&t===`project`?`@WORKBENCH:全局 + 本项目`:e&&t===`target`?`@WORKBENCH:全局 + 落点项目`:e?`@WORKBENCH:全局`:t===`project`?`@WORKBENCH:本项目`:t===`target`?`@WORKBENCH:落点项目`:`@WORKBENCH:未设置`)}),I=J(()=>s.value.trim().length),L=J(()=>i.maxInstructionChars||1e5),de=J(()=>I.value>L.value),R=J(()=>!de.value&&I.value>=L.value*.9),fe=J(()=>s.value.trim().length>0&&!i.dispatching&&!w.value&&!de.value);function pe(){fe.value&&a(`dispatch`,{text:s.value.trim(),autoRun:c.value,attachments:f.value,projectPath:i.selectedProject?i.selectedProject.path:``,useDefaultPrompt:l.value,executor:u.value,imageText:D.value})}function B(e){e.isComposing||e.keyCode===229||e.key!==`Enter`||e.shiftKey||(e.preventDefault(),pe())}function V(){try{let e=localStorage.getItem(so);if(!e)return null;let t=Number(e);return Number.isFinite(t)&&t>=co?Math.round(t):null}catch{return null}}let H=M(null),U=M(V()),me=J(()=>{let e={};return U.value&&(e.height=`${U.value}px`),e}),W=null,G=!1,K=!0;function q(e){let t=H.value;if(!t)return;let n=t.getBoundingClientRect();G=n.right-e.clientX<=lo&&n.bottom-e.clientY<=lo}function ge(){G=!1}function Y(e){let t=Math.round(e.offsetHeight);if(!(t<co||t===U.value)){U.value=t;try{localStorage.setItem(so,String(t))}catch{}}}o(()=>{let e=H.value;e&&(window.addEventListener(`mouseup`,ge),!(typeof ResizeObserver>`u`)&&(W=new ResizeObserver(()=>{if(K){K=!1;return}let t=parseFloat(getComputedStyle(e).maxHeight),n=Number.isFinite(t)&&e.offsetHeight>=t-1;(G||!n)&&Y(e)}),W.observe(e)))}),C(()=>{window.removeEventListener(`mouseup`,ge),W?.disconnect(),W=null});let X=M(null),_e=J(()=>(i.running||[]).length),ve=J(()=>{let e=i.running||[];return{job:new Set(e.map(e=>e.jobId).filter(Boolean)),task:new Set(e.map(e=>e.taskId).filter(Boolean))}});function ye(e){if(!e)return!1;let t=ve.value;return(e.tasks||[]).some(e=>e.jobId&&t.job.has(e.jobId)||!e.jobId&&!!e.taskId&&t.task.has(e.taskId))}let be=J(()=>(i.reports||[]).find(ye)||null),xe=J(()=>{let e=Q.value;if(!e)return null;let t=e.tasks||[],n=ve.value;return(t.find(e=>e.jobId&&n.job.has(e.jobId)||!e.jobId&&!!e.taskId&&n.task.has(e.taskId))||t.find(e=>!!e.taskId))?.taskId||null}),Q=J(()=>{let e=i.reports||[];if(!e.length)return null;if(X.value){let t=e.find(e=>e.id===X.value);if(t)return t}return be.value}),Se=J(()=>!!Q.value&&!ye(Q.value)),Ce=J(()=>(i.reports||[]).length?_e.value>0?Z(`@WORKBENCH:这批任务还没有进度报告`):Z(`@WORKBENCH:当前没有正在执行的任务`):Z(`@WORKBENCH:暂无进度报告`)),we=J(()=>(i.reports||[]).length?Z(`@WORKBENCH:最新那份报告讲的任务已经跑完了,要回看可以从历史报告里点开`):``);function Te(e){X.value=e.id}let Ee=M(null),De=M(!0),Oe=M(!1);function Ae(){let e=Ee.value;e&&!De.value&&(Oe.value=e.scrollHeight-e.clientHeight>2)}function je(){De.value=!De.value,De.value||t(Ae)}let Me=null;z(Ee,e=>{Me?.disconnect(),Me=null,e&&(Me=new ResizeObserver(()=>Ae()),Me.observe(e))}),C(()=>{Me?.disconnect(),Me=null}),z(()=>Q.value?.id,()=>{De.value=!0,Oe.value=!1,t(Ae)});function Le(e){let t=Ie(e.percent);return t===null?``:t+`%`}let Re=J(()=>Ie(Q.value?.percent));function ze(e){let t=String(e.text||``).replace(/\s+/g,` `).trim();return t?t.length>42?t.slice(0,42)+`…`:t:e.errorCode?Z(Be(e.errorCode)):Z(`@WORKBENCH:当时没有任务在执行`)}function He(e){return e.errorCode?Z(Be(e.errorCode)):e.tasks.length?Z(`@WORKBENCH:模型没有返回内容`):Z(`@WORKBENCH:生成这份报告时没有任务在执行`)}function Ue(e){let t=e.target,n=Number(t.value);ke.includes(n)&&a(`set-report-interval`,n)}let We=J(()=>{let e=i.selectedProject;if(!e)return[];let t=[];if(e.exists===!1)return t.push({label:Z(`@WORKBENCH:工作区`),value:Z(`@WORKBENCH:目录不存在`),tone:`danger`}),t;let n=e.git;return!n||n.isGitRepo===null?(t.push({label:Z(`@WORKBENCH:Git 状态`),value:Z(`@WORKBENCH:未知`),tone:``}),t):n.isGitRepo?(t.push({label:Z(`@WORKBENCH:分支`),value:n.detached?Z(`@WORKBENCH:游离 HEAD`):n.branch||Z(`@WORKBENCH:未知`),tone:``}),t.push({label:Z(`@WORKBENCH:工作区`),value:n.changed>0?Z(`@WORKBENCH:未提交 {n} 项`,{n:n.changed}):Z(`@WORKBENCH:干净`),tone:n.changed>0?`warn`:``}),n.hasUpstream&&(n.ahead>0||n.behind>0)&&t.push({label:Z(`@WORKBENCH:与上游`),value:Z(`@WORKBENCH:领先 {ahead} / 落后 {behind}`,{ahead:n.ahead,behind:n.behind}),tone:n.behind>0?`warn`:``}),t):(t.push({label:Z(`@WORKBENCH:Git 状态`),value:Z(`@WORKBENCH:不是 Git 仓库`),tone:``}),t)}),$={history:`wb.ocHistoryOpen.v1`,git:`wb.ocGitOpen.v1`};function Ge(e){try{return localStorage.getItem(e)===`1`}catch{return!1}}let Ke=M(Ge($.history)),qe=M(Ge($.git));function Ye(e){let t=e===`history`?Ke:qe;t.value=!t.value;try{localStorage.setItem($[e],t.value?`1`:`0`)}catch{}}function Xe(){Ke.value||Ye(`history`)}let Ze={props:i,emit:a,draft:s,autoRun:c,useDefaultPrompt:l,selectedExecutor:u,draftAttachments:f,DRAFT_RAW_BASE:oo,attachTarget:p,isUploading:h,isImageAttachment:g,humanSize:_,onAttachmentPaste:y,onAttachmentDrop:b,removeAttachment:x,pickAttachmentFile:S,attachBusy:w,attachDragging:ee,imageTextChoice:T,imageTextAuto:E,imageTextOn:D,hasImageAttachment:O,onImageTextChange:k,onPaste:A,onDrop:re,onPickAttachment:ie,onRemoveAttachment:ae,clearAttachments:oe,clearDraft:se,projectKey:ce,globalPromptText:le,projectPromptText:j,anyProjectPrompt:N,anyPromptConfigured:P,promptStateLabel:F,draftChars:I,charLimit:L,overLimit:de,nearLimit:R,canSend:fe,send:pe,onInputKeydown:B,INPUT_H_KEY:so,OC_INPUT_MIN_H:co,readInputH:V,inputRef:H,inputH:U,inputStyle:me,get inputRO(){return W},set inputRO(e){W=e},get inputDragging(){return G},set inputDragging(e){G=e},get inputROFirst(){return K},set inputROFirst(e){K=e},INPUT_GRIP_PX:lo,onInputMouseDown:q,onWindowMouseUp:ge,commitInputH:Y,selectedReportId:X,runningCount:_e,runningIds:ve,reportIsLive:ye,liveReport:be,locateTaskId:xe,currentReport:Q,currentReportStale:Se,idleHint:Ce,idleHintTitle:we,pickReport:Te,textEl:Ee,textExpanded:De,textClamped:Oe,measureText:Ae,toggleText:je,get textRO(){return Me},set textRO(e){Me=e},historyPct:Le,currentPercent:Re,reportBrief:ze,reportNotice:He,onIntervalChange:Ue,gitSummary:We,SECT_KEY:$,readSectOpen:Ge,historyOpen:Ke,gitOpen:qe,toggleSect:Ye,reviewHistory:Xe,gitBrief:J(()=>We.value.slice(0,2).map(e=>e.value).join(` · `)),get $t(){return Z},get Promotion(){return d},get Expand(){return ue},get Fold(){return he},get Refresh(){return v},get ArrowDown(){return te},get ArrowRight(){return ne},get LocationInformation(){return m},get clockFromIso(){return it},get relativeTimeFromIso(){return rt},get REPORT_INTERVAL_OPTIONS_MS(){return ke},get REPORT_PERCENT_HINT_KEY(){return Fe},get REPORT_PERCENT_LABEL_KEY(){return Ve},get reportIntervalLabelKey(){return Ne},get reportIntervalLabelParams(){return Pe},AttachmentZone:xt,TaskExecutorPicker:et};return Object.defineProperty(Ze,"__isScriptSetup",{enumerable:!1,value:!0}),Ze}});c(),I(),B();var fo=[`title`,`aria-label`],po={class:`oc__rail-text`},mo={class:`oc__head`},ho={class:`oc__title`},go=[`title`,`aria-label`],_o={class:`oc__report-head`},vo={class:`oc__panel-title`},yo=[`value`,`title`,`aria-label`],bo=[`value`],xo=[`disabled`,`title`],So={class:`oc__report-list`},Co={key:0,class:`rp`},wo={class:`rp__head`},To=[`title`],Eo={class:`rp__count`},Do={class:`rp__time`},Oo=[`title`,`aria-label`],ko=[`title`],Ao=[`aria-valuenow`,`aria-label`],jo={class:`rp__percent`},Mo={class:`rp__percent-tag`},No={key:1,class:`rp__body`},Po=[`title`],Fo=[`title`],Io={class:`oc-empty__text`},Lo=[`aria-expanded`,`title`],Ro={class:`oc__sect-title`},zo={class:`oc__sect-meta`},Bo={class:`oc__sect-brief`},Vo={class:`oc__history-list`},Ho=[`onClick`],Uo={class:`oc__history-time`},Wo={class:`oc__history-pct`},Go={class:`oc__history-sum`},Ko=[`aria-expanded`,`title`],qo={class:`oc__sect-title`},Jo={class:`oc__sect-meta`},Yo={class:`oc__git-name`},Xo={key:0,class:`oc__sect-brief`},Zo={class:`oc__git-list`},Qo={class:`oc__git-label`},$o={class:`oc__git-label`},es={class:`oc__git-value`},ts={class:`oc__git-label`},ns={class:`oc__git-value`},rs=[`placeholder`],is={key:0},as={key:1},os={class:`oc__compose-foot`},ss=[`disabled`,`title`,`aria-label`],cs=[`title`,`aria-label`],ls=[`title`],us=[`title`],ds=[`title`],fs=[`checked`],ps={class:`oc__foot-label`},ms=[`disabled`],hs={class:`oc__hint`};function gs(t,n,i,a,o,s){let c=l;return H(),x(`aside`,{class:w([`oc`,{"is-collapsed":i.collapsed,"is-report-empty":!i.collapsed&&!a.currentReport}])},[q(` 折叠后的收纳条:只剩一枚展开按钮 + 竖排标题,宽度收到 32px。
|
|
229
|
+
折叠不是"把宽度压成 0"—— 那样就再没有能点回来的地方了。 `),i.collapsed?(H(),x(`button`,{key:0,type:`button`,class:`oc__rail`,title:a.$t(`@WORKBENCH:展开主 Agent 控制台`),"aria-label":a.$t(`@WORKBENCH:展开主 Agent 控制台`),"aria-expanded":!1,onClick:n[0]||=e=>a.emit(`toggle-collapse`)},[e(c,{class:`oc__rail-icon`},{default:F(()=>[e(a.Fold)]),_:1}),b(`span`,po,T(a.$t(`@WORKBENCH:主 Agent 控制台`)),1)],8,fo)):q(`v-if`,!0),q(` 折叠时这几块整体隐藏而不是销毁(v-show 而不是 v-if):
|
|
230
|
+
草稿指令和已贴的附件都还留着,展开回来能接着发 `),A(b(`header`,mo,[b(`h3`,ho,T(a.$t(`@WORKBENCH:主 Agent 控制台`)),1),b(`button`,{type:`button`,class:`oc__collapse`,title:a.$t(`@WORKBENCH:收起主 Agent 控制台`),"aria-label":a.$t(`@WORKBENCH:收起主 Agent 控制台`),"aria-expanded":!0,onClick:n[1]||=e=>a.emit(`toggle-collapse`)},[e(c,null,{default:F(()=>[e(a.Expand)]),_:1})],8,go)],512),[[fe,!i.collapsed]]),q(` 进度报告:主 Agent 隔一会儿读一遍正在跑的 job,写一段"现在到哪一步了"。
|
|
230
231
|
报告由服务端生成(自动那份由服务端定时器产生),这里只渲染 + 两个入口:
|
|
231
|
-
改间隔、立即报告。 `),A(b(`div`,{class:w([`oc__report`,{"is-empty":!a.currentReport}])},[b(`div`,
|
|
232
|
-
自由填一个 5(分钟写成了秒)会让额度很快见底,而用户不会立刻意识到 `),b(`select`,{class:`oc__interval`,value:String(i.reportIntervalMs??0),title:a.$t(`@WORKBENCH:自动报告的间隔(关掉后仍可随时点「立即报告」)`),"aria-label":a.$t(`@WORKBENCH:自动报告间隔`),onChange:a.onIntervalChange},[(H(!0),x(O,null,E(a.REPORT_INTERVAL_OPTIONS_MS,e=>(H(),x(`option`,{key:e,value:String(e)},T(a.$t(a.reportIntervalLabelKey(e),a.reportIntervalLabelParams(e))),9,
|
|
233
|
-
是生成那一刻的事实,现在早就跑完了,不标会看着像还在跑 `),a.currentReportStale?(H(),x(`span`,{key:0,class:`rp__stale`,title:a.$t(`@WORKBENCH:这份报告讲的任务已经跑完了,内容只反映生成那一刻的情况`)},T(a.$t(`@WORKBENCH:已结束`)),9,
|
|
232
|
+
改间隔、立即报告。 `),A(b(`div`,{class:w([`oc__report`,{"is-empty":!a.currentReport}])},[b(`div`,_o,[b(`p`,vo,T(a.$t(`@WORKBENCH:进度报告`)),1),q(` 间隔设置。做成下拉而不是输入框:这个值直接决定每多久烧一次模型额度,
|
|
233
|
+
自由填一个 5(分钟写成了秒)会让额度很快见底,而用户不会立刻意识到 `),b(`select`,{class:`oc__interval`,value:String(i.reportIntervalMs??0),title:a.$t(`@WORKBENCH:自动报告的间隔(关掉后仍可随时点「立即报告」)`),"aria-label":a.$t(`@WORKBENCH:自动报告间隔`),onChange:a.onIntervalChange},[(H(!0),x(O,null,E(a.REPORT_INTERVAL_OPTIONS_MS,e=>(H(),x(`option`,{key:e,value:String(e)},T(a.$t(a.reportIntervalLabelKey(e),a.reportIntervalLabelParams(e))),9,bo))),128))],40,yo),b(`button`,{type:`button`,class:`oc__report-run`,disabled:i.generatingReport,title:a.$t(`@WORKBENCH:让主 Agent 现在汇报一次正在执行的任务进度`),onClick:n[2]||=e=>a.emit(`generate-report`)},[e(c,{class:w([`oc__report-run-icon`,{"is-spin":i.generatingReport}])},{default:F(()=>[e(a.Refresh)]),_:1},8,[`class`]),b(`span`,null,T(i.generatingReport?a.$t(`@WORKBENCH:生成中…`):a.$t(`@WORKBENCH:立即报告`)),1)],8,xo)]),b(`ul`,So,[a.currentReport?(H(),x(`li`,Co,[b(`div`,wo,[b(`span`,{class:w([`rp__trigger`,{"is-auto":a.currentReport.trigger===`auto`}])},T(a.currentReport.trigger===`auto`?a.$t(`@WORKBENCH:自动`):a.$t(`@WORKBENCH:手动`)),3),q(` 用户从历史里点开一份已经过期的报告时标一下:下面那句「N 个任务进行中」
|
|
234
|
+
是生成那一刻的事实,现在早就跑完了,不标会看着像还在跑 `),a.currentReportStale?(H(),x(`span`,{key:0,class:`rp__stale`,title:a.$t(`@WORKBENCH:这份报告讲的任务已经跑完了,内容只反映生成那一刻的情况`)},T(a.$t(`@WORKBENCH:已结束`)),9,To)):q(`v-if`,!0),b(`span`,Eo,T(a.$t(`@WORKBENCH:{n} 个任务进行中`,{n:a.currentReport.tasks.length})),1),b(`span`,Do,T(a.clockFromIso(a.currentReport.at)),1),q(` 定位:这份报告讲的任务就在看板上,但右栏看不见它在哪一列。
|
|
234
235
|
一键滚过去 + 标记,不用去三列里找(2026-10-14 评审:左右两栏
|
|
235
|
-
说同一批事,用"跳过去"消重,而不是把任务卡搬回来) `),a.locateTaskId?(H(),x(`button`,{key:1,type:`button`,class:`rp__locate`,title:a.$t(`@WORKBENCH:在面板中定位这份报告讲的任务`),"aria-label":a.$t(`@WORKBENCH:在面板中定位这份报告讲的任务`),onClick:n[3]||=e=>a.emit(`locate-task`,a.locateTaskId)},[e(c,null,{default:F(()=>[e(a.LocationInformation)]),_:1})],8,
|
|
236
|
+
说同一批事,用"跳过去"消重,而不是把任务卡搬回来) `),a.locateTaskId?(H(),x(`button`,{key:1,type:`button`,class:`rp__locate`,title:a.$t(`@WORKBENCH:在面板中定位这份报告讲的任务`),"aria-label":a.$t(`@WORKBENCH:在面板中定位这份报告讲的任务`),onClick:n[3]||=e=>a.emit(`locate-task`,a.locateTaskId)},[e(c,null,{default:F(()=>[e(a.LocationInformation)]),_:1})],8,Oo)):q(`v-if`,!0)]),q(` 进度条:主 Agent 自己给的百分比(不是我们拿时长算的 —— 跑多久跟还剩多少活
|
|
236
237
|
没有固定关系)。它没给就不画这一行,见 currentPercent。
|
|
237
238
|
形状与左栏项目列表的进度条同一套(4px / pill / --gradient-progress),
|
|
238
|
-
两处的"进度"看起来得是一个东西 `),a.currentPercent===null?
|
|
239
|
-
光甩一个 62% 会被当成实测值 `),b(`span`,
|
|
239
|
+
两处的"进度"看起来得是一个东西 `),a.currentPercent===null?q(`v-if`,!0):(H(),x(`div`,{key:0,class:`rp__progress`,title:a.$t(a.REPORT_PERCENT_HINT_KEY)},[b(`span`,{class:`rp__bar`,role:`progressbar`,"aria-valuenow":a.currentPercent,"aria-valuemin":`0`,"aria-valuemax":`100`,"aria-label":a.$t(a.REPORT_PERCENT_LABEL_KEY)},[b(`i`,{class:`rp__bar-fill`,style:u({width:a.currentPercent+`%`})},null,4)],8,Ao),q(` 「AI 估计」四个字不能省:这个数字是模型看着思考与工具调用估的,
|
|
240
|
+
光甩一个 62% 会被当成实测值 `),b(`span`,jo,[b(`span`,Mo,T(a.$t(a.REPORT_PERCENT_LABEL_KEY)),1),L(T(a.currentPercent)+`% `,1)])],8,ko)),q(` 正文:主 Agent 写的**判断**。默认只露 6 行 —— 右栏只有 ~300px 宽,
|
|
240
241
|
模型那种"任务1…任务2…任务3…"连着几段的汇报不截一下会独占整张卡。
|
|
241
242
|
折起来时底下压一层渐隐(不是硬切),配一个「展开全文」,
|
|
242
|
-
不用拖滚动条去找结尾。 `),a.currentReport.text?(H(),x(`div`,
|
|
243
|
-
三种情况的处理办法完全不同,一律写"暂无"会让人白等 `),b(`p`,{class:`rp__notice`,title:a.currentReport.errorDetail},T(a.reportNotice(a.currentReport)),9,
|
|
243
|
+
不用拖滚动条去找结尾。 `),a.currentReport.text?(H(),x(`div`,No,[b(`p`,{ref:`textEl`,class:w([`rp__text`,{"is-clamped":a.textClamped&&!a.textExpanded,"is-expanded":a.textExpanded}])},T(a.currentReport.text),3),a.textClamped||a.textExpanded?(H(),x(`button`,{key:0,type:`button`,class:`rp__more`,onClick:a.toggleText},T(a.textExpanded?a.$t(`@WORKBENCH:收起`):a.$t(`@WORKBENCH:展开全文`)),1)):q(`v-if`,!0)])):(H(),x(O,{key:2},[q(` 没有正文时给的是**实话**:没任务 / 没配模型 / 模型没返回内容,
|
|
244
|
+
三种情况的处理办法完全不同,一律写"暂无"会让人白等 `),b(`p`,{class:`rp__notice`,title:a.currentReport.errorDetail},T(a.reportNotice(a.currentReport)),9,Po)],2112)),q(`
|
|
244
245
|
这里原来还有一区「任务事实」(每个在跑的任务一张卡:标题 + 自己的进度条 +
|
|
245
246
|
工具 / 思考 / 回复三行证据)。2026-10-14 整块下掉 —— 那些字段中间看板
|
|
246
247
|
「进行中」的卡片本来就逐字有(服务端同一份 jobActivity 实现),两处并排
|
|
@@ -248,59 +249,59 @@ import"./rolldown-runtime-C0FnF6B9.js";import{An as e,Bn as t,C as n,Cn as r,F a
|
|
|
248
249
|
唯一卡片上没有的是**每个任务自己的百分比**,它跟着这次搬迁挪到了卡片上
|
|
249
250
|
(WorkbenchKanban 的 .kb-card__live-progress)。所以这一栏现在只留
|
|
250
251
|
主 Agent 的**判断**(正文 + 整体进度),依据去卡片上看。
|
|
251
|
-
`)])):(H(),x(`li`,{key:1,class:`oc-empty`,title:a.idleHintTitle},[b(`span`,
|
|
252
|
-
点开",但历史区默认折着、还在面板更下方 —— 有历史就直接给一键展开 `),(i.reports||[]).length>1?(H(),x(`button`,{key:0,type:`button`,class:`oc-empty__action`,onClick:a.reviewHistory},T(a.$t(`@WORKBENCH:回看历史报告`)),1)):
|
|
252
|
+
`)])):(H(),x(`li`,{key:1,class:`oc-empty`,title:a.idleHintTitle},[b(`span`,Io,T(a.idleHint),1),q(` 2026-10-14 评审轮:空态别做死胡同。悬停一直写着"要回看可以从历史报告里
|
|
253
|
+
点开",但历史区默认折着、还在面板更下方 —— 有历史就直接给一键展开 `),(i.reports||[]).length>1?(H(),x(`button`,{key:0,type:`button`,class:`oc-empty__action`,onClick:a.reviewHistory},T(a.$t(`@WORKBENCH:回看历史报告`)),1)):q(`v-if`,!0)],8,Fo))]),q(` 历史:一行一份,点一条就把它换到上面看。只在有两份以上时出现 ——
|
|
253
254
|
只有一份时这个列表纯粹是噪音。
|
|
254
|
-
默认折起来:它是"回看",不该跟正在看的那份抢高度(见 script 里 SECT_KEY 的注释) `),(i.reports||[]).length>1?(H(),x(`div`,{key:0,class:w([`oc__history`,{"is-collapsed":!a.historyOpen}])},[b(`button`,{type:`button`,class:`oc__sect`,"aria-expanded":a.historyOpen,title:a.historyOpen?a.$t(`@WORKBENCH:收起`):a.$t(`@WORKBENCH:展开`),onClick:n[4]||=e=>a.toggleSect(`history`)},[e(c,{class:`oc__sect-caret`},{default:F(()=>[(H(),r(g(a.historyOpen?a.ArrowDown:a.ArrowRight)))]),_:1}),b(`span`,
|
|
255
|
-
没有进度的那几条这一格是空的但**占着位**(见 historyPct) `),b(`span`,
|
|
256
|
-
不补的话,收起等于把这块唯一要扫的信息也一起收了 `),!a.gitOpen&&a.gitBrief?(H(),x(`span
|
|
257
|
-
不会冒泡经过下面的附件区 `),A(b(`textarea`,{ref:`inputRef`,class:w([`oc__input`,{"is-over":a.overLimit}]),"onUpdate:modelValue":n[6]||=e=>a.draft=e,style:u(a.inputStyle),rows:`3`,placeholder:a.$t(`@WORKBENCH:给主 Agent 下一条指令,例如:把登录模块的错误处理重构一遍`),onKeydown:a.onInputKeydown,onPaste:a.onPaste,onMousedown:a.onInputMouseDown},null,46,
|
|
255
|
+
默认折起来:它是"回看",不该跟正在看的那份抢高度(见 script 里 SECT_KEY 的注释) `),(i.reports||[]).length>1?(H(),x(`div`,{key:0,class:w([`oc__history`,{"is-collapsed":!a.historyOpen}])},[b(`button`,{type:`button`,class:`oc__sect`,"aria-expanded":a.historyOpen,title:a.historyOpen?a.$t(`@WORKBENCH:收起`):a.$t(`@WORKBENCH:展开`),onClick:n[4]||=e=>a.toggleSect(`history`)},[e(c,{class:`oc__sect-caret`},{default:F(()=>[(H(),r(g(a.historyOpen?a.ArrowDown:a.ArrowRight)))]),_:1}),b(`span`,Ro,T(a.$t(`@WORKBENCH:历史报告`)),1),q(` 折起来时这一行就是全部内容:份数是它唯一值得一眼看到的信息 `),b(`span`,zo,[b(`span`,Bo,T(a.$t(`@WORKBENCH:共 {n} 份`,{n:(i.reports||[]).length})),1)])],8,Lo),A(b(`ul`,Vo,[(H(!0),x(O,null,E(i.reports,e=>(H(),x(`li`,{key:e.id},[b(`button`,{type:`button`,class:w([`oc__history-item`,{"is-active":e.id===a.currentReport?.id}]),onClick:t=>a.pickReport(e)},[b(`span`,Uo,T(a.clockFromIso(e.at)),1),q(` 历史里也带上进度:一眼看出"这条是 20 分钟前那会儿 40%,现在 70%"。
|
|
256
|
+
没有进度的那几条这一格是空的但**占着位**(见 historyPct) `),b(`span`,Wo,T(a.historyPct(e)),1),b(`span`,Go,T(a.reportBrief(e)),1)],10,Ho)]))),128))],512),[[fe,a.historyOpen]])],2)):q(`v-if`,!0)],2),[[fe,!i.collapsed]]),A(b(`div`,{class:w([`oc__git`,{"is-collapsed":!a.gitOpen}])},[b(`button`,{type:`button`,class:`oc__sect`,"aria-expanded":a.gitOpen,title:a.gitOpen?a.$t(`@WORKBENCH:收起`):a.$t(`@WORKBENCH:展开`),onClick:n[5]||=e=>a.toggleSect(`git`)},[e(c,{class:`oc__sect-caret`},{default:F(()=>[(H(),r(g(a.gitOpen?a.ArrowDown:a.ArrowRight)))]),_:1}),b(`span`,qo,T(a.$t(`@WORKBENCH:项目概览`)),1),b(`span`,Jo,[q(` 无选中项目即「全部项目」:显式标出来,否则底下只剩「今日完成」一行,看着像数据没加载出来 `),b(`span`,Yo,T(i.selectedProject?i.selectedProject.name:a.$t(`@WORKBENCH:全部项目`)),1),q(` 折起来时再补上"这个仓库现在什么状态":分支 + 工作区。
|
|
257
|
+
不补的话,收起等于把这块唯一要扫的信息也一起收了 `),!a.gitOpen&&a.gitBrief?(H(),x(`span`,Xo,T(a.gitBrief),1)):q(`v-if`,!0)])],8,Ko),A(b(`dl`,Zo,[(H(!0),x(O,null,E(a.gitSummary,e=>(H(),x(O,{key:e.label},[b(`dt`,Qo,T(e.label),1),b(`dd`,{class:w([`oc__git-value`,{"is-warn":e.tone===`warn`,"is-danger":e.tone===`danger`}])},T(e.value),3)],64))),128)),b(`dt`,$o,T(a.$t(`@WORKBENCH:今日完成`)),1),b(`dd`,es,T(i.todayDone),1),b(`dt`,ts,T(a.$t(`@WORKBENCH:最后活跃`)),1),b(`dd`,ns,T(i.selectedProject&&a.relativeTimeFromIso(i.selectedProject.stats.lastActiveAt)||`—`),1)],512),[[fe,a.gitOpen]])],2),[[fe,!i.collapsed]]),A(b(`div`,{class:`oc__compose`,onPaste:a.onPaste,onDrop:j(a.onDrop,[`prevent`]),onDragover:n[13]||=j(e=>a.attachDragging=!0,[`prevent`]),onDragleave:n[14]||=e=>a.attachDragging=!1},[q(` 粘贴事件必须同时挂在 textarea 上:在输入框里按 Ctrl+V 时事件只到 textarea,
|
|
258
|
+
不会冒泡经过下面的附件区 `),A(b(`textarea`,{ref:`inputRef`,class:w([`oc__input`,{"is-over":a.overLimit}]),"onUpdate:modelValue":n[6]||=e=>a.draft=e,style:u(a.inputStyle),rows:`3`,placeholder:a.$t(`@WORKBENCH:给主 Agent 下一条指令,例如:把登录模块的错误处理重构一遍`),onKeydown:a.onInputKeydown,onPaste:a.onPaste,onMousedown:a.onInputMouseDown},null,46,rs),[[V,a.draft]]),a.draftAttachments.length>0||a.attachBusy?(H(),r(a.AttachmentZone,{key:0,attachments:a.draftAttachments,"is-image":a.isImageAttachment,"human-size":a.humanSize,"is-uploading":a.attachBusy,"is-paste-hover":a.attachDragging,"on-pick":a.onPickAttachment,"on-remove":a.onRemoveAttachment,"raw-base":a.DRAFT_RAW_BASE,onPaste:a.onPaste,onDrop:a.onDrop,onDragover:n[7]||=j(e=>a.attachDragging=!0,[`prevent`]),onDragenter:n[8]||=j(e=>a.attachDragging=!0,[`prevent`]),onDragleave:n[9]||=e=>a.attachDragging=!1},null,8,[`attachments`,`is-image`,`human-size`,`is-uploading`,`is-paste-hover`])):q(`v-if`,!0),q(`
|
|
258
259
|
字数:单独占输入框下方一行,不挤底部那一排按钮。
|
|
259
260
|
空草稿时不渲染("0 / 100000" 是噪音),接近上限转黄、超了转红 ——
|
|
260
261
|
目的是让"粘太长发不出去"在**点之前**看得见,而不是点完等服务端 400 才知道
|
|
261
262
|
(而超长恰恰是最容易失败的那一类,必须能改一改再发)。
|
|
262
|
-
`),a.draftChars>0?(H(),x(`p`,{key:1,class:w([`oc__count`,{"is-warn":a.nearLimit,"is-over":a.overLimit}])},[a.overLimit?(H(),x(`span`,
|
|
263
|
-
有没有设过看右侧"附加预设提示词"那个勾选(它是真实生效状态,这个只是入口) `),b(`button`,{type:`button`,class:w([`oc__attach`,{"is-on":a.anyPromptConfigured}]),title:a.$t(`@WORKBENCH:设置派发时自动附加的预设提示词(全局 / 各项目)`),"aria-label":a.$t(`@WORKBENCH:预设提示词设置`),onClick:n[10]||=e=>a.emit(`open-prompt-settings`)},[
|
|
264
|
-
干什么(用户原话:语义不清)。它勾的是"这次派发带上预设提示词" `),b(`span`,null,T(a.$t(`@WORKBENCH:附带预设提示词({state})`,{state:a.promptStateLabel})),1)],8,
|
|
263
|
+
`),a.draftChars>0?(H(),x(`p`,{key:1,class:w([`oc__count`,{"is-warn":a.nearLimit,"is-over":a.overLimit}])},[a.overLimit?(H(),x(`span`,is,T(a.$t(`@WORKBENCH:超出上限 {max} 字,请精简后再派发(超出的部分不会被发出)`,{max:a.charLimit})),1)):(H(),x(`span`,as,T(a.draftChars)+` / `+T(a.charLimit),1))],2)):q(`v-if`,!0),b(`div`,os,[b(`button`,{type:`button`,class:`oc__attach`,disabled:a.attachBusy,title:a.$t(`@WORKBENCH:添加附件(也可直接粘贴或拖入文件)`),"aria-label":a.$t(`@WORKBENCH:添加附件`),onClick:a.onPickAttachment},[q(` paperclip.svg(Tabler icons,MIT) `),e(c,null,{default:F(()=>[...n[15]||=[b(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,xmlns:`http://www.w3.org/2000/svg`},[b(`path`,{d:`M15 7l-6.5 6.5a1.5 1.5 0 0 0 3 3l6.5-6.5a3 3 0 0 0-6-6l-6.5 6.5a4.5 4.5 0 0 0 9 9l6.5-6.5`})],-1)]]),_:1})],8,ss),q(` 预设提示词设置入口:图标按钮按项目惯例不加底色,
|
|
264
|
+
有没有设过看右侧"附加预设提示词"那个勾选(它是真实生效状态,这个只是入口) `),b(`button`,{type:`button`,class:w([`oc__attach`,{"is-on":a.anyPromptConfigured}]),title:a.$t(`@WORKBENCH:设置派发时自动附加的预设提示词(全局 / 各项目)`),"aria-label":a.$t(`@WORKBENCH:预设提示词设置`),onClick:n[10]||=e=>a.emit(`open-prompt-settings`)},[q(` settings.svg(Tabler icons,MIT) `),e(c,null,{default:F(()=>[...n[16]||=[b(`svg`,{viewBox:`0 0 24 24`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,xmlns:`http://www.w3.org/2000/svg`},[b(`path`,{d:`M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 0 0-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 0 0-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 0 0-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 0 0-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 0 0 1.066-2.573c-.94-1.543.826-3.31 2.37-2.37c1 .608 2.296.07 2.572-1.065`}),b(`path`,{d:`M9 12a3 3 0 1 0 6 0a3 3 0 0 0-6 0`})],-1)]]),_:1})],10,cs),b(`label`,{class:`oc__autorn`,title:a.$t(`@WORKBENCH:取消勾选则只建任务草稿,不自动执行`)},[A(b(`input`,{type:`checkbox`,"onUpdate:modelValue":n[11]||=e=>a.autoRun=e},null,512),[[de,a.autoRun]]),b(`span`,null,T(a.$t(`@WORKBENCH:立即执行`)),1)],8,ls),q(` 一条都没设过时不出现:一个永远勾着、点了也没区别的开关只会占地方 `),a.anyPromptConfigured?(H(),x(`label`,{key:0,class:`oc__autorn`,title:a.$t(`@WORKBENCH:取消勾选则本次派发的任务不带预设提示词(设置本身不受影响)`)},[A(b(`input`,{type:`checkbox`,"onUpdate:modelValue":n[12]||=e=>a.useDefaultPrompt=e},null,512),[[de,a.useDefaultPrompt]]),q(` 2026-10-14 评审轮改名:旧文案「预设提示词(全局)」没说清这个勾选
|
|
265
|
+
干什么(用户原话:语义不清)。它勾的是"这次派发带上预设提示词" `),b(`span`,null,T(a.$t(`@WORKBENCH:附带预设提示词({state})`,{state:a.promptStateLabel})),1)],8,us)):q(`v-if`,!0),q(` 图片 → 文字:只有挂了图片才出现(没图时这个勾选没有意义)。
|
|
265
266
|
放在「立即执行 / 预设提示词」之后、「任务执行器」之前 ——
|
|
266
267
|
顺序别动:verify-workbench-dispatch-attach 用 \`.oc__autorn input\` 的
|
|
267
268
|
第一个当「立即执行」,插到它前面会让那条探针勾错框。
|
|
268
|
-
默认勾选态跟执行器走,见 imageTextOn 注释 `),a.hasImageAttachment?(H(),x(`label`,{key:1,class:`oc__autorn`,title:a.$t(`@WORKBENCH:先用 AI 把图片描述成文字再派发(codearts 读不了图时必开)`)},[b(`input`,{type:`checkbox`,checked:a.imageTextOn,onChange:a.onImageTextChange},null,40,
|
|
269
|
-
不标明身份会被当成模型选择(2026-10-14 评审) `),b(`span`,
|
|
269
|
+
默认勾选态跟执行器走,见 imageTextOn 注释 `),a.hasImageAttachment?(H(),x(`label`,{key:1,class:`oc__autorn`,title:a.$t(`@WORKBENCH:先用 AI 把图片描述成文字再派发(codearts 读不了图时必开)`)},[b(`input`,{type:`checkbox`,checked:a.imageTextOn,onChange:a.onImageTextChange},null,40,fs),b(`span`,null,T(a.$t(`@WORKBENCH:图片转文字`)),1)],8,ds)):q(`v-if`,!0),q(` 执行器标签:picker 本体只显示品牌名(「Claude Code」),
|
|
270
|
+
不标明身份会被当成模型选择(2026-10-14 评审) `),b(`span`,ps,T(a.$t(`@WORKBENCH:任务执行器`)),1),q(` 执行器:与工作台执行按钮、看板「执行」共用同一份选择。
|
|
270
271
|
下拉本体收口在 TaskExecutorPicker(对话模式底下那个也是它),
|
|
271
|
-
它自己读 composable 的共享状态,这里不用再传 v-model `),e(a.TaskExecutorPicker,{title:a.$t(`@WORKBENCH:本次派发使用的执行器(与执行按钮的临时切换共用)`)},null,8,[`title`]),b(`button`,{type:`button`,class:`oc__send`,disabled:!a.canSend,onClick:a.send},[e(c,{class:`oc__send-icon`},{default:F(()=>[e(a.Promotion)]),_:1}),b(`span`,null,T(i.dispatching?a.$t(`@WORKBENCH:派发中…`):a.$t(`@WORKBENCH:派发`)),1)],8,_s)]),b(`p`,vs,[i.selectedProject?(H(),x(O,{key:0},[L(T(a.$t(`@WORKBENCH:指令会在「{name}」下新建一个任务;Enter 派发,Shift+Enter 换行`,{name:i.selectedProject.name})),1)],64)):(H(),x(O,{key:1},[L(T(a.$t(`@WORKBENCH:指令落到哪个项目由主 Agent 判断;Enter 派发,Shift+Enter 换行`)),1)],64))])],544),[[fe,!i.collapsed]])],2)}var bs=Q(mo,[[`render`,ys],[`__scopeId`,`data-v-4c030231`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/views/components/OrchestratorConsole.vue`]]);c(),R();var xs=4e3,Ss=f({__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=M(``),o=M(``);z(()=>r.modelValue,e=>{e&&(a.value=r.defaultPrompt||``,o.value=r.projectPrompt||``)});let s=Y(()=>!!r.projectPath),c=Y(()=>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:xs,globalDraft:a,projectDraft:o,hasProject:s,dirty:c,submit:l,close:u,get $t(){return Z},CommonDialog:Oe};return Object.defineProperty(d,"__isScriptSetup",{enumerable:!1,value:!0}),d}});I(),c(),B();var Cs={class:`pd`},ws={class:`pd__intro`},Ts={class:`pd__field`},Es={class:`pd__head`},Ds={class:`pd__label`,for:`pd-global`},Os={class:`pd__count`},ks=[`placeholder`],As={class:`pd__field`},js={class:`pd__head`},Ms={class:`pd__label`,for:`pd-project`},Ns={key:0,class:`pd__count`},Ps=[`disabled`,`placeholder`],Fs={class:`pd__hint`},Is={class:`pd__foot`},Ls=[`disabled`];function Rs(e,t,n,i,a,o){return H(),r(i.CommonDialog,{"model-value":n.modelValue,title:i.$t(`@WORKBENCH:预设提示词`),width:`min(640px, 94vw)`,"close-on-click-modal":!1,"onUpdate:modelValue":t[2]||=e=>i.emit(`update:modelValue`,e)},{footer:F(()=>[b(`div`,Is,[b(`button`,{type:`button`,class:`pd__btn`,onClick:i.close},T(i.$t(`@WORKBENCH:取消`)),1),t[3]||=b(`span`,{class:`pd__foot-spacer`},null,-1),b(`button`,{type:`button`,class:`pd__btn pd__btn--primary`,disabled:n.saving||!i.dirty,onClick:i.submit},T(n.saving?i.$t(`@WORKBENCH:保存中…`):i.$t(`@WORKBENCH:保存`)),9,Ls)])]),default:F(()=>[b(`div`,Cs,[b(`p`,ws,T(i.$t(`@WORKBENCH:派发指令时自动附加在指令之前,让每个任务都带上这些约束。只影响之后派发的任务,不会改动已经建好的任务。`)),1),b(`div`,Ts,[b(`div`,Es,[b(`label`,Ds,T(i.$t(`@WORKBENCH:全局提示词`)),1),b(`span`,Os,T(i.globalDraft.length)+` / `+T(i.MAX_CHARS),1)]),A(b(`textarea`,{id:`pd-global`,"onUpdate:modelValue":t[0]||=e=>i.globalDraft=e,class:`pd__area`,rows:`5`,maxlength:i.MAX_CHARS,placeholder:i.$t(`@WORKBENCH:对所有项目生效。例如:回答用中文;改完代码必须跑一遍测试;不要动 dist 目录`)},null,8,ks),[[V,i.globalDraft]])]),b(`div`,As,[b(`div`,js,[b(`label`,Ms,T(i.hasProject?i.$t(`@WORKBENCH:「{name}」的项目提示词`,{name:n.projectName}):i.$t(`@WORKBENCH:项目提示词`)),1),i.hasProject?(H(),x(`span`,Ns,T(i.projectDraft.length)+` / `+T(i.MAX_CHARS),1)):J(`v-if`,!0)]),A(b(`textarea`,{id:`pd-project`,"onUpdate:modelValue":t[1]||=e=>i.projectDraft=e,class:`pd__area`,rows:`5`,maxlength:i.MAX_CHARS,disabled:!i.hasProject,placeholder:i.hasProject?i.$t(`@WORKBENCH:只在这个项目派发时附加。例如:包管理器用 pnpm;改动集中在 src/ui 下`):i.$t(`@WORKBENCH:先在左侧选中一个具体项目,才能设置它的提示词`)},null,8,Ps),[[V,i.projectDraft]]),b(`p`,Fs,T(i.hasProject?i.$t(`@WORKBENCH:项目提示词追加在全局提示词之后(不覆盖全局),派发到「{name}」时一起带上`,{name:n.projectName}):i.$t(`@WORKBENCH:选中的是「全部项目」,落点由主 Agent 判断 —— 想给某个项目单设提示词,先选中它`)),1)])])]),_:1},8,[`model-value`,`title`])}var zs=Q(Ss,[[`render`,Rs],[`__scopeId`,`data-v-766f470f`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/views/components/WorkbenchDefaultPromptDialog.vue`]]);c(),R();var Bs=`wb.boardProject.v1`,Vs=`wb.boardView.v1`,Hs=5e3,Us=3e4,Ws=`wb.boardLayout.v1`,Gs=180,Ks=420,qs=260,Js=900,Ys=.26,Xs=.46,Zs=f({__name:`WorkbenchBoard`,props:{openedTaskId:{type:[String,null],required:!0}},emits:[`open-task`,`create-task`,`board-tasks`,`locate-task`],setup(e,{expose:n,emit:r}){n();let i=e,a=r,{projects:s,boardTasks:c,currentProjectPath:l,loading:u,loadProjects:d,removeProject:f}=at();z(c,e=>a(`board-tasks`,e),{immediate:!0});let{activity:p,running:m,dispatching:h,maxInstructionChars:g,defaultPrompt:_,projectPrompts:v,reports:y,generatingReport:b,reportIntervalMs:x,loadOrchestrator:S,dispatch:w,saveDefaultPrompt:ee,saveProjectPrompt:T,loadReports:te,generateReport:E,setReportInterval:ne}=$e(),{active:D}=Ze(),O=(()=>{try{return localStorage.getItem(Bs)}catch{return null}})(),k=M(O||``);z(k,e=>{try{localStorage.setItem(Bs,e)}catch{}});let A=M((()=>{try{return localStorage.getItem(Vs)===`list`?`list`:`kanban`}catch{return`kanban`}})());z(A,e=>{try{localStorage.setItem(Vs,e)}catch{}});let re=M(``),ie=M(!1),ae=M(null);function oe(){ie.value=!ie.value,ie.value&&t(()=>ae.value?.focus())}function se(){ie.value=!1}function ce(){re.value.trim()||(ie.value=!1)}let le=Y(()=>k.value&&s.value.find(e=>e.key===k.value)||null),{isIconBroken:j,markIconFailed:ue}=He();z(s,e=>{k.value&&(e.some(e=>e.key===k.value)||(k.value=``))});let N=!1;function F(){if(N||(N=!0,O!==null))return;let e=l.value?$(l.value):``;e&&s.value.some(t=>t.key===e)&&(k.value=e)}let I=Y(()=>{let e=new Map(s.value.map(e=>[e.key,e.name])),t={};for(let n of c.value)n.projectPath&&(t[n.projectPath]=e.get($(n.projectPath))||``);return t}),L=Y(()=>{if(!k.value)return c.value;let e=k.value;return c.value.filter(t=>$(t.projectPath)===e)}),de=Y(()=>Pe(y.value,c.value)),R=Y(()=>{let e=new Date;e.setHours(0,0,0,0);let t=e.getTime();return{projects:s.value.length,tasks:c.value.length,running:m.value.length,todayDone:p.value.filter(e=>e.kind===`done`&&e.at&&new Date(e.at).getTime()>=t).length}});function fe(e){a(`open-task`,{taskId:e.id,projectPath:e.projectPath})}let B=null,V=!1,H=null;async function W(e=!0){if(!V){V=!0;try{await Promise.all([d(e),S(e)])}finally{V=!1}}}function G(){document.hidden||(W(!0),te(!0))}o(async()=>{window.addEventListener(`resize`,he),await W(!1),te(!0),F(),B=setInterval(()=>{document.hidden||W(!0)},Hs),H=setInterval(()=>{document.hidden||te(!0)},Us),document.addEventListener(`visibilitychange`,G)}),C(()=>{window.removeEventListener(`resize`,he),B&&=(clearInterval(B),null),H&&=(clearInterval(H),null),document.removeEventListener(`visibilitychange`,G)});let K=pe({left:null,right:null,leftCollapsed:!1,rightCollapsed:!1});function me(){try{let e=localStorage.getItem(Ws);if(!e)return;let t=JSON.parse(e);typeof t.left==`number`&&Number.isFinite(t.left)&&(K.left=t.left),typeof t.right==`number`&&Number.isFinite(t.right)&&(K.right=t.right),K.leftCollapsed=t.leftCollapsed===!0,K.rightCollapsed=t.rightCollapsed===!0}catch{}}me();function q(){try{localStorage.setItem(Ws,JSON.stringify(K))}catch{}}let J=M(typeof window>`u`?1920:window.innerWidth);function he(){J.value=window.innerWidth}let X=Y(()=>J.value<=1024),ge=Y(()=>J.value<=860);function _e(e,t){let n=e===`left`?Gs:qs,r=Math.min(e===`left`?Ks:Js,J.value*(e===`left`?Ys:Xs));return Math.round(Math.min(Math.max(t,n),Math.max(n,r)))}let ve=Y(()=>{let e={};return K.left!=null&&(e[`--wb-left-w`]=_e(`left`,K.left)+`px`),K.right!=null&&!ge.value&&(e[`--wb-right-w`]=_e(`right`,K.right)+`px`),e}),ye=M(null),be=M(null);function xe(e){return ye.value?.querySelector(e===`left`?`.board__left`:`.oc`)}function Q(e){window.removeEventListener(`mousemove`,e),document.body.style.userSelect=``,document.body.style.cursor=``,be.value=null,q()}function Se(e,t){if(e===`left`?X.value:ge.value)return;let n=xe(e);if(!n)return;t.preventDefault();let r=t.clientX,i=n.getBoundingClientRect().width;be.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);K[e]=_e(e,i+n)};window.addEventListener(`mousemove`,a),window.addEventListener(`mouseup`,()=>Q(a),{once:!0})}function Ce(e){K[e]=null,q()}let we=M(!1),Te=Y(()=>X.value?!we.value:K.leftCollapsed);function Ee(){if(X.value){we.value=!we.value;return}K.leftCollapsed=!K.leftCollapsed,q()}function De(){X.value&&(we.value=!1)}let Oe=Y(()=>K.rightCollapsed&&!ge.value);function ke(){K.rightCollapsed=!K.rightCollapsed,q()}function Ae(e){k.value=e?e.key:``,we.value=!1}function je(){a(`create-task`,{projectPath:We.value||``})}async function Me(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:D.value})}).then(e=>e.json()).catch(()=>null);if(!n?.success){P.error(n?.error||Z(`@WORKBENCH:执行失败`));return}P.success(Z(`@WORKBENCH:已开始执行`)),await W(!0)}let Ne=new Set;async function Fe(e){if(Ne.has(e.id))return;let t=e.live?.jobId;if(!t){P.error(Z(`@WORKBENCH:停止失败`));return}try{await U.confirm(Z(`@WORKBENCH:确认停止执行?已输出的内容会保留。`),Z(`@WORKBENCH:停止执行`),{confirmButtonText:Z(`@WORKBENCH:停止`),cancelButtonText:Z(`@WORKBENCH:取消`),type:`warning`})}catch{return}Ne.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){P.error(e?.error||Z(`@WORKBENCH:停止失败`));return}P.success(Z(`@WORKBENCH:已发送停止信号`)),await W(!0)}finally{Ne.delete(e.id)}}let Ie=new Set;async function Le(e){if(!Ie.has(e.id)){if(e.runningJobs>0)try{await U.confirm(Z(`@WORKBENCH:这条任务还在执行,标记完成会同时把它停掉。已输出的内容会保留。`),Z(`@WORKBENCH:标记为已完成`),{confirmButtonText:Z(`@WORKBENCH:标记完成`),cancelButtonText:Z(`@WORKBENCH:取消`),type:`warning`})}catch{return}Ie.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){P.error(t?.error||Z(`@WORKBENCH:标记失败`));return}P.success(Z(`@WORKBENCH:已标记为已完成`)),await W(!0)}finally{Ie.delete(e.id)}}}async function Re(e){if(!Ie.has(e.id)){Ie.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){P.error(t?.error||Z(`@WORKBENCH:撤销失败`));return}P.success(Z(`@WORKBENCH:已撤销完成标记`)),await W(!0)}finally{Ie.delete(e.id)}}}async function ze(e){let{ok:t,keptTasks:n}=await f(e.path);t&&(P.success(n>0?Z(`@WORKBENCH:已移除项目,{n} 条任务仍保留在「全部项目」下`,{n}):Z(`@WORKBENCH:已移除项目`)),await W(!0))}async function Be(e){let t=(e.title||``).trim()||Z(`@WORKBENCH:未命名任务`);try{await U.confirm(Z(`@WORKBENCH:删除任务「{title}」?`,{title:t}),Z(`@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){P.error(n.error||Z(`@WORKBENCH:删除失败`));return}await W(!0)}async function Ve(e,t){let n=await fetch(`/api/workbench/tasks/${encodeURIComponent(e.id)}/move`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({projectPath:t})}).then(e=>e.json()).catch(()=>null);if(!n?.success){P.error(n?.error||Z(`@WORKBENCH:移动失败`));return}let r=s.value.find(e=>$(e.path)===$(t))?.name||t;P.success(Z(`@WORKBENCH:已移动到「{name}」`,{name:r})),await W(!0)}let Ue=M(null),We=Y(()=>le.value?.path||l.value);async function Ge(e){let t=await w({text:e.text,projectPath:e.projectPath,autoRun:e.autoRun,attachments:e.attachments,useDefaultPrompt:e.useDefaultPrompt,executor:e.executor,imageText:e.imageText});t&&(Ue.value?.clearAttachments(),Ue.value?.clearDraft(),P.success(t.ran?Z(`@WORKBENCH:已派发并开始执行`):Z(`@WORKBENCH:已派发(只建任务未执行)`)),await W(!0))}let Ke=M(!1),qe=M(!1),Je=Y(()=>{let e=le.value?.key;return e&&v.value?.[e]?.prompt||``});async function Ye(e){if(qe.value)return;let t=e.globalPrompt.trim(),n=e.projectPrompt.trim(),r=le.value;qe.value=!0;try{let e=!0;t!==(_.value||``).trim()&&(e=await ee(t)),e&&r&&n!==Je.value.trim()&&(e=await T(r.path,n)),e&&(Ke.value=!1)}finally{qe.value=!1}}let Xe={props:i,emit:a,projects:s,boardTasks:c,currentProjectPath:l,loading:u,loadProjects:d,removeProject:f,activity:p,running:m,dispatching:h,maxInstructionChars:g,defaultPrompt:_,projectPrompts:v,reports:y,generatingReport:b,reportIntervalMs:x,loadOrchestrator:S,dispatch:w,saveDefaultPrompt:ee,saveProjectPrompt:T,loadReports:te,generateReport:E,setReportInterval:ne,boardExecutor:D,SELECTED_KEY:Bs,savedSelection:O,selectedKey:k,VIEW_KEY:Vs,view:A,search:re,searchOpen:ie,searchInputRef:ae,toggleSearch:oe,closeSearch:se,onSearchBlur:ce,selectedProject:le,isIconBroken:j,markIconFailed:ue,get defaultSelectionApplied(){return N},set defaultSelectionApplied(e){N=e},applyDefaultSelection:F,projectLabels:I,visibleTasks:L,taskPercents:de,headerStats:R,onOpenTask:fe,POLL_MS:Hs,get pollTimer(){return B},set pollTimer(e){B=e},get inFlight(){return V},set inFlight(e){V=e},REPORT_POLL_MS:Us,get reportPollTimer(){return H},set reportPollTimer(e){H=e},refresh:W,onVisibilityChange:G,LAYOUT_KEY:Ws,LEFT_W_MIN:Gs,LEFT_W_MAX:Ks,RIGHT_W_MIN:qs,RIGHT_W_MAX:Js,LEFT_W_SHARE:Ys,RIGHT_W_SHARE:Xs,layout:K,readLayout:me,saveLayout:q,viewportW:J,onWindowResize:he,isNarrow:X,isStacked:ge,clampWidth:_e,boardStyle:ve,colsRef:ye,dragging:be,panelEl:xe,endDrag:Q,onSplitterMouseDown:Se,onSplitterDblClick:Ce,leftDrawerOpen:we,leftHidden:Te,toggleLeft:Ee,onLeftEsc:De,rightHidden:Oe,toggleRight:ke,onSelectProject:Ae,onCreateClick:je,runTask:Me,stoppingTaskIds:Ne,stopTask:Fe,completingTaskIds:Ie,completeTask:Le,reopenTask:Re,onRemoveProject:ze,deleteTask:Be,moveTask:Ve,consoleRef:Ue,defaultProjectPath:We,onDispatch:Ge,promptDialogOpen:Ke,savingPrompt:qe,selectedProjectPrompt:Je,onSavePromptDraft:Ye,get $t(){return Z},WorkbenchProjectPanel:Mi,WorkbenchKanban:co,OrchestratorConsole:bs,WorkbenchDefaultPromptDialog:zs};return Object.defineProperty(Xe,"__isScriptSetup",{enumerable:!1,value:!0}),Xe}});c(),I(),B();var Qs=[`title`],$s={class:`board__main`},ec={class:`board__main-head`},tc=[`title`,`aria-label`],nc={class:`board__project-icon-slot`,"aria-hidden":`true`},rc=[`src`],ic={key:0,viewBox:`0 0 24 24`,width:`16`,height:`16`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,xmlns:`http://www.w3.org/2000/svg`,"aria-hidden":`true`},ac={key:1,viewBox:`0 0 24 24`,width:`16`,height:`16`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,xmlns:`http://www.w3.org/2000/svg`,"aria-hidden":`true`},oc={class:`board__main-title`},sc={class:`board__project-name`},cc=[`title`],lc={key:1,class:`board__project-path`},uc={class:`board__head-actions`},dc={class:`board__view-switch`,role:`tablist`},fc=[`aria-selected`,`aria-label`,`title`],pc=[`aria-selected`,`aria-label`,`title`],mc=[`placeholder`,`aria-label`],hc=[`aria-label`,`title`],gc=[`title`];function _c(t,n,i,a,o,s){let c=l;return H(),x(`div`,{class:`board`,style:u(a.boardStyle)},[J(` 顶栏(标题「多项目编排台」+ 项目/任务/活跃/今日四项统计)2026-10-27 整块移除:
|
|
272
|
+
它自己读 composable 的共享状态,这里不用再传 v-model `),e(a.TaskExecutorPicker,{title:a.$t(`@WORKBENCH:本次派发使用的执行器(与执行按钮的临时切换共用)`)},null,8,[`title`]),b(`button`,{type:`button`,class:`oc__send`,disabled:!a.canSend,onClick:a.send},[e(c,{class:`oc__send-icon`},{default:F(()=>[e(a.Promotion)]),_:1}),b(`span`,null,T(i.dispatching?a.$t(`@WORKBENCH:派发中…`):a.$t(`@WORKBENCH:派发`)),1)],8,ms)]),b(`p`,hs,[i.selectedProject?(H(),x(O,{key:0},[L(T(a.$t(`@WORKBENCH:指令会在「{name}」下新建一个任务;Enter 派发,Shift+Enter 换行`,{name:i.selectedProject.name})),1)],64)):(H(),x(O,{key:1},[L(T(a.$t(`@WORKBENCH:指令落到哪个项目由主 Agent 判断;Enter 派发,Shift+Enter 换行`)),1)],64))])],544),[[fe,!i.collapsed]])],2)}var _s=Q(uo,[[`render`,gs],[`__scopeId`,`data-v-4c030231`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/views/components/OrchestratorConsole.vue`]]);c(),R();var vs=4e3,ys=f({__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=M(``),o=M(``);z(()=>r.modelValue,e=>{e&&(a.value=r.defaultPrompt||``,o.value=r.projectPrompt||``)});let s=J(()=>!!r.projectPath),c=J(()=>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:vs,globalDraft:a,projectDraft:o,hasProject:s,dirty:c,submit:l,close:u,get $t(){return Z},CommonDialog:De};return Object.defineProperty(d,"__isScriptSetup",{enumerable:!1,value:!0}),d}});I(),c(),B();var bs={class:`pd`},xs={class:`pd__intro`},Ss={class:`pd__field`},Cs={class:`pd__head`},ws={class:`pd__label`,for:`pd-global`},Ts={class:`pd__count`},Es=[`placeholder`],Ds={class:`pd__field`},Os={class:`pd__head`},ks={class:`pd__label`,for:`pd-project`},As={key:0,class:`pd__count`},js=[`disabled`,`placeholder`],Ms={class:`pd__hint`},Ns={class:`pd__foot`},Ps=[`disabled`];function Fs(e,t,n,i,a,o){return H(),r(i.CommonDialog,{"model-value":n.modelValue,title:i.$t(`@WORKBENCH:预设提示词`),width:`min(640px, 94vw)`,"close-on-click-modal":!1,"onUpdate:modelValue":t[2]||=e=>i.emit(`update:modelValue`,e)},{footer:F(()=>[b(`div`,Ns,[b(`button`,{type:`button`,class:`pd__btn`,onClick:i.close},T(i.$t(`@WORKBENCH:取消`)),1),t[3]||=b(`span`,{class:`pd__foot-spacer`},null,-1),b(`button`,{type:`button`,class:`pd__btn pd__btn--primary`,disabled:n.saving||!i.dirty,onClick:i.submit},T(n.saving?i.$t(`@WORKBENCH:保存中…`):i.$t(`@WORKBENCH:保存`)),9,Ps)])]),default:F(()=>[b(`div`,bs,[b(`p`,xs,T(i.$t(`@WORKBENCH:派发指令时自动附加在指令之前,让每个任务都带上这些约束。只影响之后派发的任务,不会改动已经建好的任务。`)),1),b(`div`,Ss,[b(`div`,Cs,[b(`label`,ws,T(i.$t(`@WORKBENCH:全局提示词`)),1),b(`span`,Ts,T(i.globalDraft.length)+` / `+T(i.MAX_CHARS),1)]),A(b(`textarea`,{id:`pd-global`,"onUpdate:modelValue":t[0]||=e=>i.globalDraft=e,class:`pd__area`,rows:`5`,maxlength:i.MAX_CHARS,placeholder:i.$t(`@WORKBENCH:对所有项目生效。例如:回答用中文;改完代码必须跑一遍测试;不要动 dist 目录`)},null,8,Es),[[V,i.globalDraft]])]),b(`div`,Ds,[b(`div`,Os,[b(`label`,ks,T(i.hasProject?i.$t(`@WORKBENCH:「{name}」的项目提示词`,{name:n.projectName}):i.$t(`@WORKBENCH:项目提示词`)),1),i.hasProject?(H(),x(`span`,As,T(i.projectDraft.length)+` / `+T(i.MAX_CHARS),1)):q(`v-if`,!0)]),A(b(`textarea`,{id:`pd-project`,"onUpdate:modelValue":t[1]||=e=>i.projectDraft=e,class:`pd__area`,rows:`5`,maxlength:i.MAX_CHARS,disabled:!i.hasProject,placeholder:i.hasProject?i.$t(`@WORKBENCH:只在这个项目派发时附加。例如:包管理器用 pnpm;改动集中在 src/ui 下`):i.$t(`@WORKBENCH:先在左侧选中一个具体项目,才能设置它的提示词`)},null,8,js),[[V,i.projectDraft]]),b(`p`,Ms,T(i.hasProject?i.$t(`@WORKBENCH:项目提示词追加在全局提示词之后(不覆盖全局),派发到「{name}」时一起带上`,{name:n.projectName}):i.$t(`@WORKBENCH:选中的是「全部项目」,落点由主 Agent 判断 —— 想给某个项目单设提示词,先选中它`)),1)])])]),_:1},8,[`model-value`,`title`])}var Is=Q(ys,[[`render`,Fs],[`__scopeId`,`data-v-766f470f`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/views/components/WorkbenchDefaultPromptDialog.vue`]]);c(),R();var Ls=`wb.boardProject.v1`,Rs=`wb.boardView.v1`,zs=5e3,Bs=3e4,Vs=`wb.boardLayout.v1`,Hs=180,Us=420,Ws=260,Gs=900,Ks=.26,qs=.46,Js=f({__name:`WorkbenchBoard`,props:{openedTaskId:{type:[String,null],required:!0}},emits:[`open-task`,`create-task`,`board-tasks`,`locate-task`],setup(e,{expose:n,emit:r}){n();let i=e,a=r,{projects:s,boardTasks:c,currentProjectPath:l,loading:u,loadProjects:d,removeProject:f}=ot();z(c,e=>a(`board-tasks`,e),{immediate:!0});let{activity:p,running:m,dispatching:h,maxInstructionChars:g,defaultPrompt:_,projectPrompts:v,reports:y,generatingReport:b,reportIntervalMs:x,loadOrchestrator:S,dispatch:w,saveDefaultPrompt:ee,saveProjectPrompt:T,loadReports:te,generateReport:E,setReportInterval:ne}=Ze(),{active:D}=Je(),O=(()=>{try{return localStorage.getItem(Ls)}catch{return null}})(),k=M(O||``);z(k,e=>{try{localStorage.setItem(Ls,e)}catch{}});let A=M((()=>{try{return localStorage.getItem(Rs)===`list`?`list`:`kanban`}catch{return`kanban`}})());z(A,e=>{try{localStorage.setItem(Rs,e)}catch{}});let re=M(``),ie=M(!1),ae=M(null);function oe(){ie.value=!ie.value,ie.value&&t(()=>ae.value?.focus())}function se(){ie.value=!1}function ce(){re.value.trim()||(ie.value=!1)}let le=J(()=>k.value&&s.value.find(e=>e.key===k.value)||null),{isIconBroken:j,markIconFailed:ue}=Ue();z(s,e=>{k.value&&(e.some(e=>e.key===k.value)||(k.value=``))});let N=!1;function F(){if(N||(N=!0,O!==null))return;let e=l.value?$(l.value):``;e&&s.value.some(t=>t.key===e)&&(k.value=e)}let I=J(()=>{let e=new Map(s.value.map(e=>[e.key,e.name])),t={};for(let n of c.value)n.projectPath&&(t[n.projectPath]=e.get($(n.projectPath))||``);return t}),L=J(()=>{if(!k.value)return c.value;let e=k.value;return c.value.filter(t=>$(t.projectPath)===e)}),de=J(()=>je(y.value,c.value)),R=J(()=>{let e=new Date;e.setHours(0,0,0,0);let t=e.getTime();return{projects:s.value.length,tasks:c.value.length,running:m.value.length,todayDone:p.value.filter(e=>e.kind===`done`&&e.at&&new Date(e.at).getTime()>=t).length}});function fe(e){a(`open-task`,{taskId:e.id,projectPath:e.projectPath})}let B=null,V=!1,H=null;async function me(e=!0){if(!V){V=!0;try{await Promise.all([d(e),S(e)])}finally{V=!1}}}function W(){document.hidden||(me(!0),te(!0))}o(async()=>{window.addEventListener(`resize`,ge),await me(!1),te(!0),F(),B=setInterval(()=>{document.hidden||me(!0)},zs),H=setInterval(()=>{document.hidden||te(!0)},Bs),document.addEventListener(`visibilitychange`,W)}),C(()=>{window.removeEventListener(`resize`,ge),B&&=(clearInterval(B),null),H&&=(clearInterval(H),null),document.removeEventListener(`visibilitychange`,W)});let G=pe({left:null,right:null,leftCollapsed:!1,rightCollapsed:!1});function he(){try{let e=localStorage.getItem(Vs);if(!e)return;let t=JSON.parse(e);typeof t.left==`number`&&Number.isFinite(t.left)&&(G.left=t.left),typeof t.right==`number`&&Number.isFinite(t.right)&&(G.right=t.right),G.leftCollapsed=t.leftCollapsed===!0,G.rightCollapsed=t.rightCollapsed===!0}catch{}}he();function K(){try{localStorage.setItem(Vs,JSON.stringify(G))}catch{}}let q=M(typeof window>`u`?1920:window.innerWidth);function ge(){q.value=window.innerWidth}let Y=J(()=>q.value<=1024),X=J(()=>q.value<=860);function _e(e,t){let n=e===`left`?Hs:Ws,r=Math.min(e===`left`?Us:Gs,q.value*(e===`left`?Ks:qs));return Math.round(Math.min(Math.max(t,n),Math.max(n,r)))}let ve=J(()=>{let e={};return G.left!=null&&(e[`--wb-left-w`]=_e(`left`,G.left)+`px`),G.right!=null&&!X.value&&(e[`--wb-right-w`]=_e(`right`,G.right)+`px`),e}),ye=M(null),be=M(null);function xe(e){return ye.value?.querySelector(e===`left`?`.board__left`:`.oc`)}function Q(e){window.removeEventListener(`mousemove`,e),document.body.style.userSelect=``,document.body.style.cursor=``,be.value=null,K()}function Se(e,t){if(e===`left`?Y.value:X.value)return;let n=xe(e);if(!n)return;t.preventDefault();let r=t.clientX,i=n.getBoundingClientRect().width;be.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);G[e]=_e(e,i+n)};window.addEventListener(`mousemove`,a),window.addEventListener(`mouseup`,()=>Q(a),{once:!0})}function Ce(e){G[e]=null,K()}let we=M(!1),Te=J(()=>Y.value?!we.value:G.leftCollapsed);function Ee(){if(Y.value){we.value=!we.value;return}G.leftCollapsed=!G.leftCollapsed,K()}function De(){Y.value&&(we.value=!1)}let Oe=J(()=>G.rightCollapsed&&!X.value);function ke(){G.rightCollapsed=!G.rightCollapsed,K()}function Ae(e){k.value=e?e.key:``,we.value=!1}function Me(){a(`create-task`,{projectPath:We.value||``})}async function Ne(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:D.value})}).then(e=>e.json()).catch(()=>null);if(!n?.success){P.error(n?.error||Z(`@WORKBENCH:执行失败`));return}P.success(Z(`@WORKBENCH:已开始执行`)),await me(!0)}let Pe=new Set;async function Fe(e){if(Pe.has(e.id))return;let t=e.live?.jobId;if(!t){P.error(Z(`@WORKBENCH:停止失败`));return}try{await U.confirm(Z(`@WORKBENCH:确认停止执行?已输出的内容会保留。`),Z(`@WORKBENCH:停止执行`),{confirmButtonText:Z(`@WORKBENCH:停止`),cancelButtonText:Z(`@WORKBENCH:取消`),type:`warning`})}catch{return}Pe.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){P.error(e?.error||Z(`@WORKBENCH:停止失败`));return}P.success(Z(`@WORKBENCH:已发送停止信号`)),await me(!0)}finally{Pe.delete(e.id)}}let Ie=new Set;async function Le(e){if(!Ie.has(e.id)){if(e.runningJobs>0)try{await U.confirm(Z(`@WORKBENCH:这条任务还在执行,标记完成会同时把它停掉。已输出的内容会保留。`),Z(`@WORKBENCH:标记为已完成`),{confirmButtonText:Z(`@WORKBENCH:标记完成`),cancelButtonText:Z(`@WORKBENCH:取消`),type:`warning`})}catch{return}Ie.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){P.error(t?.error||Z(`@WORKBENCH:标记失败`));return}P.success(Z(`@WORKBENCH:已标记为已完成`)),await me(!0)}finally{Ie.delete(e.id)}}}async function Re(e){if(!Ie.has(e.id)){Ie.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){P.error(t?.error||Z(`@WORKBENCH:撤销失败`));return}P.success(Z(`@WORKBENCH:已撤销完成标记`)),await me(!0)}finally{Ie.delete(e.id)}}}async function ze(e){let{ok:t,keptTasks:n}=await f(e.path);t&&(P.success(n>0?Z(`@WORKBENCH:已移除项目,{n} 条任务仍保留在「全部项目」下`,{n}):Z(`@WORKBENCH:已移除项目`)),await me(!0))}async function Be(e){let t=(e.title||``).trim()||Z(`@WORKBENCH:未命名任务`);try{await U.confirm(Z(`@WORKBENCH:删除任务「{title}」?`,{title:t}),Z(`@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){P.error(n.error||Z(`@WORKBENCH:删除失败`));return}await me(!0)}async function Ve(e,t){let n=await fetch(`/api/workbench/tasks/${encodeURIComponent(e.id)}/move`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({projectPath:t})}).then(e=>e.json()).catch(()=>null);if(!n?.success){P.error(n?.error||Z(`@WORKBENCH:移动失败`));return}let r=s.value.find(e=>$(e.path)===$(t))?.name||t;P.success(Z(`@WORKBENCH:已移动到「{name}」`,{name:r})),await me(!0)}let He=M(null),We=J(()=>le.value?.path||l.value);async function Ge(e){let t=await w({text:e.text,projectPath:e.projectPath,autoRun:e.autoRun,attachments:e.attachments,useDefaultPrompt:e.useDefaultPrompt,executor:e.executor,imageText:e.imageText});t&&(He.value?.clearAttachments(),He.value?.clearDraft(),P.success(t.ran?Z(`@WORKBENCH:已派发并开始执行`):Z(`@WORKBENCH:已派发(只建任务未执行)`)),await me(!0))}let Ke=M(!1),qe=M(!1),Ye=J(()=>{let e=le.value?.key;return e&&v.value?.[e]?.prompt||``});async function Xe(e){if(qe.value)return;let t=e.globalPrompt.trim(),n=e.projectPrompt.trim(),r=le.value;qe.value=!0;try{let e=!0;t!==(_.value||``).trim()&&(e=await ee(t)),e&&r&&n!==Ye.value.trim()&&(e=await T(r.path,n)),e&&(Ke.value=!1)}finally{qe.value=!1}}let Qe={props:i,emit:a,projects:s,boardTasks:c,currentProjectPath:l,loading:u,loadProjects:d,removeProject:f,activity:p,running:m,dispatching:h,maxInstructionChars:g,defaultPrompt:_,projectPrompts:v,reports:y,generatingReport:b,reportIntervalMs:x,loadOrchestrator:S,dispatch:w,saveDefaultPrompt:ee,saveProjectPrompt:T,loadReports:te,generateReport:E,setReportInterval:ne,boardExecutor:D,SELECTED_KEY:Ls,savedSelection:O,selectedKey:k,VIEW_KEY:Rs,view:A,search:re,searchOpen:ie,searchInputRef:ae,toggleSearch:oe,closeSearch:se,onSearchBlur:ce,selectedProject:le,isIconBroken:j,markIconFailed:ue,get defaultSelectionApplied(){return N},set defaultSelectionApplied(e){N=e},applyDefaultSelection:F,projectLabels:I,visibleTasks:L,taskPercents:de,headerStats:R,onOpenTask:fe,POLL_MS:zs,get pollTimer(){return B},set pollTimer(e){B=e},get inFlight(){return V},set inFlight(e){V=e},REPORT_POLL_MS:Bs,get reportPollTimer(){return H},set reportPollTimer(e){H=e},refresh:me,onVisibilityChange:W,LAYOUT_KEY:Vs,LEFT_W_MIN:Hs,LEFT_W_MAX:Us,RIGHT_W_MIN:Ws,RIGHT_W_MAX:Gs,LEFT_W_SHARE:Ks,RIGHT_W_SHARE:qs,layout:G,readLayout:he,saveLayout:K,viewportW:q,onWindowResize:ge,isNarrow:Y,isStacked:X,clampWidth:_e,boardStyle:ve,colsRef:ye,dragging:be,panelEl:xe,endDrag:Q,onSplitterMouseDown:Se,onSplitterDblClick:Ce,leftDrawerOpen:we,leftHidden:Te,toggleLeft:Ee,onLeftEsc:De,rightHidden:Oe,toggleRight:ke,onSelectProject:Ae,onCreateClick:Me,runTask:Ne,stoppingTaskIds:Pe,stopTask:Fe,completingTaskIds:Ie,completeTask:Le,reopenTask:Re,onRemoveProject:ze,deleteTask:Be,moveTask:Ve,consoleRef:He,defaultProjectPath:We,onDispatch:Ge,promptDialogOpen:Ke,savingPrompt:qe,selectedProjectPrompt:Ye,onSavePromptDraft:Xe,get $t(){return Z},WorkbenchProjectPanel:ki,WorkbenchKanban:ao,OrchestratorConsole:_s,WorkbenchDefaultPromptDialog:Is};return Object.defineProperty(Qe,"__isScriptSetup",{enumerable:!1,value:!0}),Qe}});c(),I(),B();var Ys=[`title`],Xs={class:`board__main`},Zs={class:`board__main-head`},Qs=[`title`,`aria-label`],$s={class:`board__project-icon-slot`,"aria-hidden":`true`},ec=[`src`],tc={key:0,viewBox:`0 0 24 24`,width:`16`,height:`16`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,xmlns:`http://www.w3.org/2000/svg`,"aria-hidden":`true`},nc={key:1,viewBox:`0 0 24 24`,width:`16`,height:`16`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,xmlns:`http://www.w3.org/2000/svg`,"aria-hidden":`true`},rc={class:`board__main-title`},ic={class:`board__project-name`},ac=[`title`],oc={key:1,class:`board__project-path`},sc={class:`board__head-actions`},cc={class:`board__view-switch`,role:`tablist`},lc=[`aria-selected`,`aria-label`,`title`],uc=[`aria-selected`,`aria-label`,`title`],dc=[`placeholder`,`aria-label`],fc=[`aria-label`,`title`],pc=[`title`];function mc(t,n,i,a,o,s){let c=l;return H(),x(`div`,{class:`board`,style:u(a.boardStyle)},[q(` 顶栏(标题「多项目编排台」+ 项目/任务/活跃/今日四项统计)2026-10-27 整块移除:
|
|
272
273
|
用户反馈「上边这块没啥用,省得占地方」。左栏开合按钮随之搬进项目列表标题行
|
|
273
274
|
(WorkbenchProjectPanel 的 .proj__fold-btn),收起态那枚落在看板标题行左侧
|
|
274
|
-
(下面的 .board__fold-btn),保证任何状态下都能把左栏点回来。 `),b(`div`,{ref:`colsRef`,class:w([`board__cols`,{"is-resizing":a.dragging!==null}])},[
|
|
275
|
+
(下面的 .board__fold-btn),保证任何状态下都能把左栏点回来。 `),b(`div`,{ref:`colsRef`,class:w([`board__cols`,{"is-resizing":a.dragging!==null}])},[q(` 抽屉打开时的点击捕获层:点空白处收起。
|
|
275
276
|
只在窄屏 + 打开时才 display:block(见媒体查询),宽屏下是个不占位的空 div。
|
|
276
277
|
不加遮罩底色而是全透明 —— 只是为了接住点击,不是为了压暗看板;
|
|
277
|
-
真要压暗就得处理深色主题下半透明背景叠不实的老问题(见 NOTES §2)。 `),b(`div`,{class:w([`board__scrim`,{"is-on":a.leftDrawerOpen}]),"aria-hidden":`true`,onClick:n[0]||=e=>a.leftDrawerOpen=!1},null,2),b(`aside`,{class:w([`board__left`,{"is-collapsed":a.leftHidden}]),onKeydown:N(a.onLeftEsc,[`esc`])},[e(a.WorkbenchProjectPanel,{projects:a.projects,"selected-key":a.selectedKey,loading:a.loading,collapsible:!a.leftHidden,onSelect:a.onSelectProject,onRemove:a.onRemoveProject,onCollapse:a.toggleLeft},null,8,[`projects`,`selected-key`,`loading`,`collapsible`])],34),
|
|
278
|
-
窄屏把抽屉浮出来。展开态时这枚不渲染,入口在左栏标题行(.proj__fold-btn)。 `),a.leftHidden?(H(),x(`button`,{key:0,type:`button`,class:`board__icon-btn board__fold-btn`,title:a.$t(`@WORKBENCH:展开项目列表`),"aria-label":a.$t(`@WORKBENCH:展开项目列表`),"aria-expanded":!1,onClick:a.toggleLeft},[
|
|
278
|
+
真要压暗就得处理深色主题下半透明背景叠不实的老问题(见 NOTES §2)。 `),b(`div`,{class:w([`board__scrim`,{"is-on":a.leftDrawerOpen}]),"aria-hidden":`true`,onClick:n[0]||=e=>a.leftDrawerOpen=!1},null,2),b(`aside`,{class:w([`board__left`,{"is-collapsed":a.leftHidden}]),onKeydown:N(a.onLeftEsc,[`esc`])},[e(a.WorkbenchProjectPanel,{projects:a.projects,"selected-key":a.selectedKey,loading:a.loading,collapsible:!a.leftHidden,onSelect:a.onSelectProject,onRemove:a.onRemoveProject,onCollapse:a.toggleLeft},null,8,[`projects`,`selected-key`,`loading`,`collapsible`])],34),q(` 左栏分隔条:左栏收起 / 窄屏抽屉模式下不占位(不渲染 / 媒体查询里 display:none) `),a.leftHidden?q(`v-if`,!0):(H(),x(`div`,{key:0,class:`board__splitter board__splitter--left`,role:`separator`,"aria-orientation":`vertical`,title:a.$t(`@WORKBENCH:拖动调整项目列表宽度,双击恢复默认`),onMousedown:n[1]||=e=>a.onSplitterMouseDown(`left`,e),onDblclick:n[2]||=e=>a.onSplitterDblClick(`left`)},null,40,Ys)),b(`main`,Xs,[b(`div`,Zs,[q(` 左栏收起后这里是**唯一**的开合入口(顶栏已整块移除):宽屏把常驻栏拉回来,
|
|
279
|
+
窄屏把抽屉浮出来。展开态时这枚不渲染,入口在左栏标题行(.proj__fold-btn)。 `),a.leftHidden?(H(),x(`button`,{key:0,type:`button`,class:`board__icon-btn board__fold-btn`,title:a.$t(`@WORKBENCH:展开项目列表`),"aria-label":a.$t(`@WORKBENCH:展开项目列表`),"aria-expanded":!1,onClick:a.toggleLeft},[q(` chevrons-right(Tabler icons,MIT):与左栏那枚 chevrons-left 成对 `),n[15]||=b(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,xmlns:`http://www.w3.org/2000/svg`,"aria-hidden":`true`},[b(`path`,{d:`M7 7l5 5l-5 5`}),b(`path`,{d:`M13 7l5 5l-5 5`})],-1)],8,Qs)):q(`v-if`,!0),q(` 项目图标槽:和左栏项目行、顶栏目录胶囊同一个形态契约 ——
|
|
279
280
|
有 favicon 画 <img>,加载失败 / 没有就退回字形(folder / layout-grid,
|
|
280
|
-
均已 Tabler 化);「全部项目」没有单一项目可画,退回宫格字形。 `),b(`span
|
|
281
|
+
均已 Tabler 化);「全部项目」没有单一项目可画,退回宫格字形。 `),b(`span`,$s,[a.selectedProject&&a.selectedProject.iconUrl&&!a.isIconBroken(a.selectedProject.iconUrl)?(H(),x(`img`,{key:0,class:`board__project-icon-img`,src:a.selectedProject.iconUrl,alt:``,onError:n[3]||=e=>a.markIconFailed(a.selectedProject.iconUrl)},null,40,ec)):(H(),r(c,{key:1,class:`board__project-icon-glyph`},{default:F(()=>[q(` folder / layout-grid(Tabler icons,MIT)。2026-10-16 从 EP <Folder/>
|
|
281
282
|
<Grid/> 换 Tabler:这一行(槽 + 标题 + 视图切换 + 搜索)现在全部同族。
|
|
282
|
-
字形尺寸保持 16px(槽 24px,比槽小一档的"身份轻档",不跟 32px 行看齐)。 `),a.selectedProject?(H(),x(`svg`,
|
|
283
|
+
字形尺寸保持 16px(槽 24px,比槽小一档的"身份轻档",不跟 32px 行看齐)。 `),a.selectedProject?(H(),x(`svg`,tc,[...n[16]||=[b(`path`,{d:`M5 4h4l3 3h7a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2v-11a2 2 0 0 1 2 -2`},null,-1)]])):(H(),x(`svg`,nc,[...n[17]||=[b(`path`,{d:`M4 5a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -4`},null,-1),b(`path`,{d:`M14 5a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -4`},null,-1),b(`path`,{d:`M4 15a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -4`},null,-1),b(`path`,{d:`M14 15a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v4a1 1 0 0 1 -1 1h-4a1 1 0 0 1 -1 -1l0 -4`},null,-1)]]))]),_:1}))]),b(`div`,rc,[b(`h2`,ic,T(a.selectedProject?a.selectedProject.name:a.$t(`@WORKBENCH:全部项目`)),1),a.selectedProject?(H(),x(`span`,{key:0,class:`board__project-path`,title:a.selectedProject.path},T(a.selectedProject.path),9,ac)):(H(),x(`span`,oc,T(a.$t(`@WORKBENCH:共 {n} 个项目的任务`,{n:a.projects.length})),1))]),q(` 头部右侧动作区:视图切换 + 搜索。
|
|
283
284
|
2026-10-16 从看板自己的工具条(原 .kb__toolbar)搬上来的 ——
|
|
284
285
|
那一行原来只有一枚「80/82 任务完成」徽章(已去掉),
|
|
285
286
|
位置正好,视图与筛选从此贴着项目名,不再单独占一行。
|
|
286
|
-
形态收成图标:切换两枚(aria-label 说话),搜索默认只露一枚放大镜。 `),b(`div`,
|
|
287
|
-
与同排的列表/搜索/左侧漏斗同族(EP 实心 vs Tabler 描边混排有"色差感") `),n[18]||=b(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,xmlns:`http://www.w3.org/2000/svg`,"aria-hidden":`true`},[b(`path`,{d:`M4 4l6 0`}),b(`path`,{d:`M14 4l6 0`}),b(`path`,{d:`M4 10a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-2a2 2 0 0 1 -2 -2l0 -8`}),b(`path`,{d:`M14 10a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v2a2 2 0 0 1 -2 2h-2a2 2 0 0 1 -2 -2l0 -2`})],-1)]),_:1})],10,
|
|
288
|
-
否则"点开 → 再点图标想收起"会变成 blur 收起 + click 又重新展开 `),b(`button`,{type:`button`,class:`board__search-btn`,"aria-label":a.$t(`@WORKBENCH:搜索任务标题或描述`),title:a.$t(`@WORKBENCH:搜索任务标题或描述`),onMousedown:n[7]||=j(()=>{},[`prevent`]),onClick:a.toggleSearch},[e(c,null,{default:F(()=>[
|
|
289
|
-
那枚同一形状(14/描边 2)—— 用户 2026-10-16 反馈「这个也改一下」 `),n[20]||=b(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,xmlns:`http://www.w3.org/2000/svg`,"aria-hidden":`true`},[b(`path`,{d:`M3 10a7 7 0 1 0 14 0a7 7 0 1 0 -14 0`}),b(`path`,{d:`M21 21l-6 -6`})],-1)]),_:1})],40,hc)],2)])]),e(a.WorkbenchKanban,{tasks:a.visibleTasks,"project-labels":a.projectLabels,projects:a.projects,"task-percents":a.taskPercents,"show-project-label":!a.selectedProject,"opened-task-id":a.props.openedTaskId,view:a.view,"onUpdate:view":n[8]||=e=>a.view=e,search:a.search,"onUpdate:search":n[9]||=e=>a.search=e,onOpenTask:a.onOpenTask,onRunTask:a.runTask,onStopTask:a.stopTask,onCompleteTask:a.completeTask,onReopenTask:a.reopenTask,onDeleteTask:a.deleteTask,onMoveTask:a.moveTask,onCreateTask:a.onCreateClick},null,8,[`tasks`,`project-labels`,`projects`,`task-percents`,`show-project-label`,`opened-task-id`,`view`,`search`])]),J(` 右栏分隔条:右栏收起 / 竖排(≤860)时不占位 `),!a.rightHidden&&!a.isStacked?(H(),x(`div`,{key:1,class:`board__splitter board__splitter--right`,role:`separator`,"aria-orientation":`vertical`,title:a.$t(`@WORKBENCH:拖动调整主 Agent 控制台宽度,双击恢复默认`),onMousedown:n[10]||=e=>a.onSplitterMouseDown(`right`,e),onDblclick:n[11]||=e=>a.onSplitterDblClick(`right`)},null,40,gc)):J(`v-if`,!0),e(a.OrchestratorConsole,{ref:`consoleRef`,running:a.running,"selected-project":a.selectedProject,dispatching:a.dispatching,"today-done":a.headerStats.todayDone,collapsed:a.rightHidden,"default-prompt":a.defaultPrompt,"project-prompts":a.projectPrompts,reports:a.reports,"report-interval-ms":a.reportIntervalMs,"generating-report":a.generatingReport,"max-instruction-chars":a.maxInstructionChars,onToggleCollapse:a.toggleRight,onDispatch:a.onDispatch,onGenerateReport:a.generateReport,onSetReportInterval:a.setReportInterval,onOpenPromptSettings:n[12]||=e=>a.promptDialogOpen=!0,onLocateTask:n[13]||=e=>a.emit(`locate-task`,e)},null,8,[`running`,`selected-project`,`dispatching`,`today-done`,`collapsed`,`default-prompt`,`project-prompts`,`reports`,`report-interval-ms`,`generating-report`,`max-instruction-chars`,`onGenerateReport`,`onSetReportInterval`])],2),J(` 派发预设提示词:全局一条 + 选中项目一条,写完即生效于之后的派发 `),e(a.WorkbenchDefaultPromptDialog,{modelValue:a.promptDialogOpen,"onUpdate:modelValue":n[14]||=e=>a.promptDialogOpen=e,"default-prompt":a.defaultPrompt,"project-path":a.selectedProject?.path||``,"project-name":a.selectedProject?.name||``,"project-prompt":a.selectedProjectPrompt,saving:a.savingPrompt,onSave:a.onSavePromptDraft},null,8,[`modelValue`,`default-prompt`,`project-path`,`project-name`,`project-prompt`,`saving`])],4)}var vc=Q(Zs,[[`render`,_c],[`__scopeId`,`data-v-dd2dc7b4`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/views/components/WorkbenchBoard.vue`]]);c(),R();var yc=`wb.lastTaskByProject.v1`,bc=`__no_project__`,xc=`wb.sidebarWidth.v1`,Sc=200,Cc=480,wc=268,Tc=`wb.sidebarCollapsed.v1`,Ec=3e3,Dc=52,Oc=320,kc=500,Ac=f({__name:`WorkbenchView`,setup(e,{expose:n}){n();let r=Ee(),i=De(),a=M((()=>{try{let e=parseInt(localStorage.getItem(xc)||``,10);return Number.isFinite(e)?Math.min(Cc,Math.max(Sc,e)):wc}catch{return wc}})()),s=M((()=>{try{let e=localStorage.getItem(Tc);return e===null||e===`1`}catch{return!0}})());function c(){s.value=!s.value;try{localStorage.setItem(Tc,s.value?`1`:`0`)}catch{}}function l(e){e.preventDefault();let t=e.clientX,n=a.value;document.body.style.userSelect=`none`,document.body.style.cursor=`col-resize`;let r=e=>{a.value=Math.min(Cc,Math.max(Sc,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(xc,String(a.value))}catch{}},{once:!0})}function u(e){a.value=Math.min(Cc,Math.max(Sc,a.value+e));try{localStorage.setItem(xc,String(a.value))}catch{}}function d(){try{let e=localStorage.getItem(yc),t=e?JSON.parse(e):{};return t&&typeof t==`object`&&!Array.isArray(t)?t:{}}catch{return{}}}function f(e){try{localStorage.setItem(yc,JSON.stringify(e))}catch{}}function p(e,t){let n=d();n[e||bc]=t,f(n)}let m=M(!1);function h(e){ht(e.projectPath)}async function g(){let e=I.value&&X(I.value)?I.value:null;if(he(),e){m.value=!1,await ge(e);return}I.value&&J.value&&await ve(),m.value=!1}function v(){I.value&&X(I.value)&&window.setTimeout(()=>ft.value?.focus(),80)}let y=M(null);async function b(e){await re(),F.value=e.taskId,y.value=e.taskId,H(),I.value&&p($(T.value.path),e.taskId),m.value=!0}function x(e){if(!L.value.some(t=>t.id===e)){P.info(Z(`@WORKBENCH:该任务不在当前视图(可能在别的项目下)`));return}y.value=e}let{tasks:S,jobs:w,currentProject:T,connectSSE:E,disconnectSSE:D,loadCurrentProject:O,loadJobs:k,clearJobsByTask:A,loadTasks:re}=tr();function ie(){let e=$(T.value.path),t=S.value.filter(t=>!t.projectPath||$(t.projectPath)===e),n=d(),r=e&&n[e]||!e&&n[bc]||``,i=r?S.value.find(e=>e.id===r):null,a=t[0]||S.value[0]||null,o=i&&i.projectPath&&$(i.projectPath)!==e?null:i?i.id:a?a.id:null;F.value=o,H()}async function ae(){let e=F.value;if(await re(),e&&S.value.some(t=>t.id===e)){H();return}ie()}async function j(){await re(),ie()}let N=M(!1),F=M(null),I=Y(()=>S.value.find(e=>e.id===F.value)||null),L=M([]),de=Y(()=>L.value.find(e=>e.id===F.value)||null),R=Y(()=>de.value?nt(Pn(de.value)):``),fe=Y(()=>de.value?Rn(de.value):``),pe=Y(()=>de.value?zn(de.value):``),B=Y(()=>{let e=I.value?.projectPath||``;return!e||$(e)===$(T.value.path)?null:{name:e.replace(/[\\/]+$/,``).split(/[\\/]/).pop()||e,path:e}}),V=M({title:``,desc:``});function H(){I.value?V.value={title:I.value.title,desc:I.value.desc}:V.value={title:``,desc:``}}let G=M(`idle`),K=M(0),q=null,J=Y(()=>{if(!I.value)return!1;let e=I.value;return V.value.title!==e.title||V.value.desc!==e.desc});function he(){q!==null&&(clearTimeout(q),q=null)}function X(e){return!(!e||(e.title||``).trim()||(e.desc||``).trim()||(e.simpleOverride||``).trim()||Array.isArray(e.attachments)&&e.attachments.length>0)}async function ge(e){try{await fetch(`/api/workbench/tasks/${e.id}`,{method:`DELETE`})}catch{}let t=S.value.findIndex(t=>t.id===e.id);t!==-1&&S.value.splice(t,1)}async function _e(){let e=S.value.filter(e=>e.id!==F.value&&X(e));for(let t of e)await ge(t)}async function ve(){if(!I.value)return!1;if(!J.value)return!0;if(G.value=`saving`,await St(!1))return K.value=Date.now(),G.value=`saved`,setTimeout(()=>{G.value===`saved`&&Date.now()-K.value>=4e3&&(G.value=`idle`)},4e3),!0;G.value=`error`;let e=Date.now();return setTimeout(()=>{G.value===`error`&&Date.now()-e>=4e3&&(G.value=`idle`)},4e3),!1}z(()=>I.value?{id:I.value.id,title:I.value.title,desc:I.value.desc}:null,(e,t)=>{e&&t&&e.id===t.id&&(q!==null&&clearTimeout(q),q=window.setTimeout(()=>{ve()},1500))},{deep:!0}),z(F,async(e,t)=>{he(),I.value&&J.value&&await ve()}),z(T,async e=>{if(!e.path)return;let t=$(e.path),n=I.value;n&&n.projectPath&&$(n.projectPath)!==t&&await j()});function ye(e){try{let t=new Blob([JSON.stringify(e)],{type:`application/json`});navigator.sendBeacon?.(`/api/workbench/tasks`,t)}catch{}}function Q(){I.value&&J.value&&!X(I.value)&&ye(I.value)}let Se=M(!0);async function ke(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 Ae=M(null),je=M(null);async function Me(e){if(e){if(!await ke((e.title||``).trim()||Z(`@WORKBENCH:未命名任务`))){P.error(Z(`@WORKBENCH:复制失败`));return}Ae.value=e.id,P.success(Z(`@WORKBENCH:已复制任务标题`)),window.setTimeout(()=>{Ae.value===e.id&&(Ae.value=null)},1500)}}async function Ne(e){if(!e)return;let t=(e.desc||``).trim();if(!t){P.warning(Z(`@WORKBENCH:任务描述为空,无需复制`));return}if(!await ke(t)){P.error(Z(`@WORKBENCH:复制失败`));return}je.value=e.id,P.success(Z(`@WORKBENCH:已复制任务描述`)),window.setTimeout(()=>{je.value===e.id&&(je.value=null)},1500)}let{simpleConversationMessages:Pe,simpleAllJobsFor:Fe,simpleJobFor:Ie,simpleJobState:Le}=$n(w,I);function Re(e){let t=String(e?.id||``).replace(/-a$/,``),n=w.value.find(e=>e.id===t);return n?Lt(n):!1}let Be=M(null);function He(e){let t=(e?.projectPath||``).trim().replace(/[\\/]+$/,``);return t?t.split(/[\\/]/).pop()||t:T.value.name||``}async function Ue(e,t=`brief`){if(!e)return;let n=Qe(Fe(e),{title:e.title,projectName:He(e)},{scope:t});if(!n){P.warning(Z(`@WORKBENCH:暂无执行内容可复制`));return}if(!await ke(n)){P.error(Z(`@WORKBENCH:复制失败`));return}Be.value=e.id,P.success(Z(`@WORKBENCH:已复制执行内容`)),window.setTimeout(()=>{Be.value===e.id&&(Be.value=null)},1500)}function Ge(e){Ue(I.value,e===`full`?`full`:`brief`)}let Ke=[`wheel`,`touchstart`,`pointerdown`,`keydown`],qe=M(null),Je=Ve(),Ye=M(null),Xe=null,$e=null,et=null;function tt(){if(Xe&&=(Xe.disconnect(),null),$e!==null&&(clearTimeout($e),$e=null),et){for(let e of Ke)et.removeEventListener(e,tt);et=null}}function rt(){tt();let e=qe.value;if(!e)return;e.scrollToBottom?.(!1);let t=Ye.value?.querySelector(`.acu-message-list`);if(!(!t||typeof ResizeObserver>`u`)){et=t;for(let e of Ke)t.addEventListener(e,tt,{passive:!0});Xe=new ResizeObserver(()=>qe.value?.scrollToBottom?.(!1)),Xe.observe(t),t.firstElementChild&&Xe.observe(t.firstElementChild),$e=setTimeout(tt,Ec)}}let it=Y(()=>m.value&&I.value&&Fe(I.value).length>0?I.value.id:``);z(it,async e=>{tt(),e&&(await t(),rt())}),C(tt);function at(e){return e?Rt(e.id):!1}let ot=Y(()=>Fe(I.value).length>0),st=Y(()=>at(I.value)),ct=Y(()=>I.value?st.value?Z(`@WORKBENCH:正在执行中,请先「停止」再重新执行`):ot.value?Z(`@WORKBENCH:重新跑一轮:上一轮的执行记录会被清空`):``:``),lt=Y(()=>{if(!I.value)return null;let e=de.value;if(st.value||e&&e.runningJobs>0)return{key:`running`,label:Z(`@WORKBENCH:执行中`),title:Z(`@WORKBENCH:这条任务正在执行`)};if(e)return e.column===`done`?{key:`done`,label:Z(`@WORKBENCH:已完成`),title:e.autoCompleted?Z(`@WORKBENCH:静默超时后由 AI 核对,判定这条任务已经完成`):e.manualDoneAt?Z(`@WORKBENCH:已标记为已完成`):``}:e.lastJobStatus===`error`?{key:`error`,label:Z(`@WORKBENCH:执行失败`),title:Z(`@WORKBENCH:上一次执行报错,点开对话流查看原因`)}:{key:`todo`,label:Z(`@WORKBENCH:待处理`),title:``};switch(Le(Ie(I.value))){case`done`:return{key:`done`,label:Z(`@WORKBENCH:已完成`),title:``};case`error`:return{key:`error`,label:Z(`@WORKBENCH:执行失败`),title:``};case`cancelled`:return{key:`todo`,label:Z(`@WORKBENCH:已取消`),title:``};default:return{key:`todo`,label:Z(`@WORKBENCH:待处理`),title:``}}}),ut=Y(()=>{let e=I.value;if(!e)return[];let t=e.promptParts;if(t&&(t.global||t.project)){let e=[];return t.global&&e.push({key:`global`,label:Z(`@WORKBENCH:全局提示词`),text:t.global}),t.project&&e.push({key:`project`,label:Z(`@WORKBENCH:项目提示词`),text:t.project}),e}let n=(e.simpleOverride||``).trim();return n?[{key:`legacy`,label:Z(`@WORKBENCH:提示词`),text:n}]:[]}),dt=M(!1),ft=M(null),pt=M(null);function mt(e){let t=e?.currentTarget||pt.value;if(!t)return;t.style.height=`auto`;let n=document.activeElement===t?kc:Oc,r=Math.min(Math.max(t.scrollHeight,Dc),n);t.style.height=`${r}px`,t.style.overflowY=t.scrollHeight>n?`auto`:`hidden`}z(Se,async e=>{e&&(await t(),mt())}),z(()=>I.value?.id,async()=>{Se.value&&(await t(),mt())});async function ht(e){if(dt.value)return;dt.value=!0;let n={title:``,desc:``},r=(e||T.value.path||``).trim();r&&(n.projectPath=r);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){P.error(e.error||Z(`@WORKBENCH:保存失败`));return}he(),I.value&&X(I.value)?await ge(I.value):I.value&&J.value&&await ve(),await j(),e.task?.id&&(F.value=e.task.id,H(),m.value=!0,P.success(Z(`@WORKBENCH:已新建任务`)),await t(),ft.value?.focus())}finally{dt.value=!1}}async function gt(e){await U.confirm(Z(`@WORKBENCH:删除任务「{title}」?`,{title:e.title}),Z(`@WORKBENCH:确认`),{type:`warning`}),await fetch(`/api/workbench/tasks/${e.id}`,{method:`DELETE`}),F.value===e.id&&(F.value=null),j()}async function _t(e){let t=(e.title||Z(`@WORKBENCH:未命名任务`)).trim(),n={title:Z(`@WORKBENCH:{title} (副本)`,{title:t}),desc:e.desc||``,simpleOverride:e.simpleOverride||``};e.promptParts&&(e.promptParts.global||e.promptParts.project)&&(n.promptParts=e.promptParts),T.value.path&&(n.projectPath=T.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){P.error(e.error||Z(`@WORKBENCH:复制失败`));return}await j(),e.task?.id&&(F.value=e.task.id,H()),P.success(Z(`@WORKBENCH:已复制任务`))}catch(e){P.error(Z(`@WORKBENCH:网络错误: `)+(e&&e.message||e))}}async function vt(e){if(F.value===e.id)return;he();let t=I.value;t&&X(t)?await ge(t):t&&J.value&&await ve(),F.value=e.id,H(),p($(T.value.path),e.id)}async function yt(e){let{groupPath:t,orderedIds:n}=e;if(!Array.isArray(n)||n.length===0)return;let r=S.value.slice(),i=xt(S.value,t,n);if(i!==S.value){S.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:Z(`@WORKBENCH:排序保存失败`)}));e?.success||(S.value=r,P.error(e?.error||Z(`@WORKBENCH:排序保存失败`)))}catch(e){S.value=r,P.error(Z(`@WORKBENCH:排序保存失败`)+`: `+(e?.message||e))}}}function xt(e,t,n){let r=e=>$(e)||bc,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 St(e){if(!I.value)return!1;let t=await fetch(`/api/workbench/tasks`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(I.value)}).then(e=>e.json());return t.success?(e&&P.success(Z(`@WORKBENCH:已保存`)),await ae(),!0):(P.error(t.error||Z(`@WORKBENCH:保存失败`)),!1)}o(async()=>{await Promise.all([j(),O(),k()]),await _e(),E(),window.addEventListener(`beforeunload`,Q),i.fetchExecutorModels()}),C(()=>{D(),window.removeEventListener(`beforeunload`,Q),I.value&&J.value&&!X(I.value)&&ye(I.value)});let{pasteHoverId:Ct,isUploading:wt,isImageAttachment:Tt,humanSize:Et,onAttachmentPaste:Ot,onAttachmentDrop:kt,uploadAttachment:At,removeAttachment:jt,pickAttachmentFile:Mt}=Xn(),{runTask:Nt,onContinueSendFromChat:Pt,cancelJob:Ft,clearExecutionForSelectedTask:It,onReExecuteJob:Lt,isTaskRunning:Rt,queuedChatsOf:zt,removeQueuedChat:Bt,flushNextQueued:Vt}=er(w,S,I,{clearJobsByTask:A,persistTask:St,uploadAttachment:At,getExecutor:()=>Ht.value}),{active:Ht,availability:Ut,hasAnyExecutor:Wt,choose:Gt,executorModelText:Kt,executorModelTitle:qt}=Ze();function Jt(e){return Te(e)}let Yt=Y(()=>Fe(I.value).slice(-1)[0]),Xt=Y(()=>Te(Yt.value?.agent)),Zt=Y(()=>Dt(Yt.value?.agent)),Qt=Y(()=>we(Yt.value?.agent)?Yt.value.agent:`claude`),$t={configStore:r,toolsStore:i,LAST_TASK_BY_PROJECT_KEY:yc,NO_PROJECT_KEY:bc,SIDEBAR_WIDTH_KEY:xc,SIDEBAR_MIN_W:Sc,SIDEBAR_MAX_W:Cc,SIDEBAR_DEFAULT_W:wc,sidebarWidth:a,SIDEBAR_COLLAPSED_KEY:Tc,sidebarCollapsed:s,toggleSidebarCollapsed:c,onSidebarSplitterMouseDown:l,nudgeSidebarWidth:u,readLastTaskMap:d,writeLastTaskMap:f,rememberLastTask:p,editorOpen:m,createTaskFromBoard:h,closeEditor:g,onEditorOpened:v,boardOpenedTaskId:y,openTaskFromBoard:b,locateTaskFromBoard:x,tasks:S,jobs:w,currentProject:T,connectSSE:E,disconnectSSE:D,loadCurrentProject:O,loadJobs:k,clearJobsByTask:A,_loadDataTasks:re,applyRestoredSelection:ie,refreshTasks:ae,loadTasks:j,logsDialogVisible:N,selectedTaskId:F,selectedTask:I,boardTasks:L,selectedBoardTask:de,barTimeText:R,barDurationText:fe,barTimeTitle:pe,foreignRepo:B,metaSnapshot:V,captureSnapshot:H,metaSaveState:G,metaSavedAt:K,get metaSaveTimer(){return q},set metaSaveTimer(e){q=e},metaDirty:J,clearMetaSaveTimers:he,isTaskBlank:X,discardBlankTask:ge,pruneBlankTasks:_e,flushMetaSave:ve,beaconPersist:ye,onBeforeUnloadPersist:Q,taskDescExpanded:Se,copyToClipboard:ke,copyTitleFlashId:Ae,copyDescFlashId:je,copyTaskTitle:Me,copyTaskDesc:Ne,simpleConversationMessages:Pe,simpleAllJobsFor:Fe,simpleJobFor:Ie,simpleJobState:Le,onChatRetry:Re,copyExecFlashId:Be,taskRepoName:He,copyTaskExecution:Ue,onCopyExecCommand:Ge,CHAT_PIN_WINDOW_MS:Ec,CHAT_PIN_USER_EVENTS:Ke,chatRef:qe,fileChangeLabels:Je,chatWrapRef:Ye,get chatPinRO(){return Xe},set chatPinRO(e){Xe=e},get chatPinTimer(){return $e},set chatPinTimer(e){$e=e},get chatPinEl(){return et},set chatPinEl(e){et=e},stopChatPin:tt,pinChatToBottom:rt,chatRenderKey:it,isTaskRunning:at,selectedTaskHasRun:ot,selectedTaskRunning:st,runButtonTitle:ct,barStatus:lt,selectedTaskPromptParts:ut,creatingTask:dt,titleInputRef:ft,taskDescTextareaRef:pt,DESC_TEXTAREA_MIN_PX:Dc,DESC_TEXTAREA_MAX_PX:Oc,DESC_TEXTAREA_MAX_PX_FOCUS:kc,autoGrowTextarea:mt,createTaskDirect:ht,deleteTask:gt,copyTask:_t,selectTask:vt,reorderTasks:yt,applyLocalReorder:xt,persistTask:St,pasteHoverId:Ct,isUploading:wt,isImageAttachment:Tt,humanSize:Et,onAttachmentPaste:Ot,onAttachmentDrop:kt,uploadAttachment:At,removeAttachment:jt,pickAttachmentFile:Mt,runTask:Nt,onContinueSendFromChat:Pt,cancelJob:Ft,clearExecutionForSelectedTask:It,onReExecuteJob:Lt,isTaskRunningById:Rt,queuedChatsOf:zt,removeQueuedChat:Bt,flushNextQueued:Vt,selectedTaskExecutor:Ht,executorAvailability:Ut,hasAnyExecutor:Wt,pickExecutor:Gt,executorModelText:Kt,executorModelTitle:qt,executorLabel:Jt,lastSimpleJob:Yt,simpleAssistantLabel:Xt,simpleAssistantAvatar:Zt,lastJobExecutorId:Qt,lastSimpleJobRunning:Y(()=>Le(Yt.value)===`running`),lastRunExecutorTitle:Y(()=>{let e=qt(Qt.value),t=Z(`@WORKBENCH:本轮实际使用的执行器;上方按钮选的是下一次执行用谁`);return e?`${e} · ${t}`:t}),selectedTaskQueue:Y(()=>I.value?zt(I.value.id):[]),get $t(){return Z},get ArrowDown(){return te},get ArrowLeft(){return ee},get ArrowRight(){return ne},get Check(){return ce},get Document(){return le},get Delete(){return oe},get CopyDocument(){return W},get Expand(){return ue},get Fold(){return me},get VideoPlay(){return _},get Warning(){return se},AttachmentZone:bt,get ChatInput(){return xe},get ChatContainer(){return be},get MESSAGE_RAIL_CONFIG(){return We},ExecutionLogManager:Mn,get ALLOWED_EXT_HINT(){return Vn},get MAX_ATTACHMENT_BYTES(){return Hn},get TASK_EXECUTOR_OPTIONS(){return Ce},TaskExecutorIcon:ze,WorkbenchSidebar:Ar,WorkbenchBoard:vc,CommonDialog:Oe};return Object.defineProperty($t,"__isScriptSetup",{enumerable:!1,value:!0}),$t}});c(),I(),B();var jc={class:`workbench`},Mc={class:`wb-editor`},Nc={class:`wb-editor-bar`},Pc=[`title`],Fc=[`aria-pressed`,`title`,`aria-label`],Ic=[`title`],Lc=[`data-status`,`title`],Rc={class:`wb-editor-bar__status-pill`},zc={class:`wb-editor-bar__status-label`},Bc=[`title`],Vc={key:2,class:`wb-editor-bar__time`},Hc=[`title`],Uc={key:1,class:`wb-editor-bar__sep`,"aria-hidden":`true`},Wc={key:2,class:`wb-editor-bar__spent`},Gc={class:`wb-editor-bar__hint`},Kc={class:`workbench__editor-row`},qc=[`aria-label`,`aria-valuenow`,`title`],Jc={class:`wb-split`},Yc={key:0,class:`wb-placeholder`},Xc={class:`wb-split__header`},Zc={class:`wb-split__title-wrap`},Qc=[`placeholder`,`aria-label`],$c=[`title`,`aria-label`],el=[`title`],tl={key:0,class:`wb-meta-save__dot`},nl={key:1,class:`wb-meta-save__check`},rl={key:2,class:`wb-meta-save__bang`},il={key:3,class:`wb-meta-save__dot`},al=[`data-executor`,`title`],ol={class:`wb-run-executor__text`},sl=[`title`],cl={class:`sr-only`},ll={class:`sr-only`},ul={class:`wb-executor-item`},dl={class:`wb-executor-item__name`},fl=[`title`],pl={key:2,class:`wb-executor-item__missing`},ml={key:3,class:`wb-no-claude-hint`,role:`status`},hl={class:`wb-no-claude-hint__text`},gl={class:`wb-no-claude-hint__link`,href:`https://docs.claude.com/en/docs/claude-code/setup`,target:`_blank`,rel:`noopener noreferrer`},_l={class:`wb-copy-exec`},vl=[`title`,`aria-label`],yl={class:`sr-only`},bl=[`title`,`aria-label`],xl=[`title`,`aria-label`],Sl={class:`sr-only`},Cl=[`title`,`aria-label`],wl={class:`sr-only`},Tl=[`open`],El={class:`wb-task-desc__summary`},Dl={class:`wb-task-desc__label`},Ol=[`title`,`aria-label`],kl={key:0,class:`wb-task-desc__tag`},Al={key:0},jl={key:1,class:`wb-task-desc__tag-attachment`},Ml=[`placeholder`,`aria-label`],Nl={class:`wb-execution-body`},Pl={class:`wb-exec-detail`},Fl={class:`wb-form-item__label wb-task-prompt__summary`},Il={key:0,class:`wb-task-prompt__tag`},Ll={key:0,class:`wb-task-prompt__parts`},Rl={class:`wb-task-prompt__label`},zl={class:`wb-task-prompt__text`},Bl={key:1,class:`wb-task-prompt__empty`},Vl={key:0,class:`wb-simple-chat-wrap`,ref:`chatWrapRef`},Hl={class:`wb-simple-chat`},Ul={class:`wb-simple-chat__footer`},Wl={key:0,class:`wb-chat-queue`},Gl={class:`wb-chat-queue__head`},Kl={class:`wb-chat-queue__label`},ql={class:`wb-chat-queue__count`},Jl={class:`wb-chat-queue__hint`},Yl={class:`wb-chat-queue__index`},Xl=[`title`],Zl={key:0,class:`wb-chat-queue__atts`},Ql=[`title`,`aria-label`,`onClick`];function $l(t,i,a,o,s,c){let d=l,f=n,p=q,m=y;return H(),x(`div`,jc,[J(` L1:多项目编排台 —— **常驻底图**,不再与编辑器互斥 `),e(o.WorkbenchBoard,{"opened-task-id":o.boardOpenedTaskId,onOpenTask:o.openTaskFromBoard,onCreateTask:o.createTaskFromBoard,onBoardTasks:i[0]||=e=>o.boardTasks=e,onLocateTask:o.locateTaskFromBoard},null,8,[`opened-task-id`]),J(` L2:单任务编辑器 —— 默认整屏铺开(原来是 1520px 居中浮层),关掉即回到看板,全程无跳转。\r
|
|
287
|
+
形态收成图标:切换两枚(aria-label 说话),搜索默认只露一枚放大镜。 `),b(`div`,sc,[b(`div`,cc,[b(`button`,{type:`button`,role:`tab`,class:w([`board__view-btn`,{"is-active":a.view===`kanban`}]),"aria-selected":a.view===`kanban`,"aria-label":a.$t(`@WORKBENCH:看板视图`),title:a.$t(`@WORKBENCH:看板视图`),onClick:n[4]||=e=>a.view=`kanban`},[e(c,null,{default:F(()=>[q(` layout-kanban(Tabler icons,MIT)。2026-10-16 从 EP <Grid/> 换 Tabler:
|
|
288
|
+
与同排的列表/搜索/左侧漏斗同族(EP 实心 vs Tabler 描边混排有"色差感") `),n[18]||=b(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,xmlns:`http://www.w3.org/2000/svg`,"aria-hidden":`true`},[b(`path`,{d:`M4 4l6 0`}),b(`path`,{d:`M14 4l6 0`}),b(`path`,{d:`M4 10a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-2a2 2 0 0 1 -2 -2l0 -8`}),b(`path`,{d:`M14 10a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v2a2 2 0 0 1 -2 2h-2a2 2 0 0 1 -2 -2l0 -2`})],-1)]),_:1})],10,lc),b(`button`,{type:`button`,role:`tab`,class:w([`board__view-btn`,{"is-active":a.view===`list`}]),"aria-selected":a.view===`list`,"aria-label":a.$t(`@WORKBENCH:列表视图`),title:a.$t(`@WORKBENCH:列表视图`),onClick:n[5]||=e=>a.view=`list`},[e(c,null,{default:F(()=>[q(` list(Tabler icons,MIT):从 EP <Menu/> 换 Tabler `),n[19]||=b(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,xmlns:`http://www.w3.org/2000/svg`,"aria-hidden":`true`},[b(`path`,{d:`M9 6l11 0`}),b(`path`,{d:`M9 12l11 0`}),b(`path`,{d:`M9 18l11 0`}),b(`path`,{d:`M5 6l0 .01`}),b(`path`,{d:`M5 12l0 .01`}),b(`path`,{d:`M5 18l0 .01`})],-1)]),_:1})],10,uc)]),b(`div`,{class:w([`board__head-search`,{"is-open":a.searchOpen}])},[A(b(`input`,{ref:`searchInputRef`,class:`board__search-input`,type:`search`,"onUpdate:modelValue":n[6]||=e=>a.search=e,placeholder:a.$t(`@WORKBENCH:搜索任务标题或描述`),"aria-label":a.$t(`@WORKBENCH:搜索任务标题或描述`),onBlur:a.onSearchBlur,onKeydown:N(a.closeSearch,[`esc`])},null,40,dc),[[V,a.search]]),q(` mousedown.prevent:不让这一下先把输入框的焦点弄丢,
|
|
289
|
+
否则"点开 → 再点图标想收起"会变成 blur 收起 + click 又重新展开 `),b(`button`,{type:`button`,class:`board__search-btn`,"aria-label":a.$t(`@WORKBENCH:搜索任务标题或描述`),title:a.$t(`@WORKBENCH:搜索任务标题或描述`),onMousedown:n[7]||=j(()=>{},[`prevent`]),onClick:a.toggleSearch},[e(c,null,{default:F(()=>[q(` search(Tabler icons,MIT):从 EP <Search/> 换 Tabler,与左栏项目列表
|
|
290
|
+
那枚同一形状(14/描边 2)—— 用户 2026-10-16 反馈「这个也改一下」 `),n[20]||=b(`svg`,{viewBox:`0 0 24 24`,width:`14`,height:`14`,fill:`none`,stroke:`currentColor`,"stroke-width":`2`,"stroke-linecap":`round`,"stroke-linejoin":`round`,xmlns:`http://www.w3.org/2000/svg`,"aria-hidden":`true`},[b(`path`,{d:`M3 10a7 7 0 1 0 14 0a7 7 0 1 0 -14 0`}),b(`path`,{d:`M21 21l-6 -6`})],-1)]),_:1})],40,fc)],2)])]),e(a.WorkbenchKanban,{tasks:a.visibleTasks,"project-labels":a.projectLabels,projects:a.projects,"task-percents":a.taskPercents,"show-project-label":!a.selectedProject,"opened-task-id":a.props.openedTaskId,view:a.view,"onUpdate:view":n[8]||=e=>a.view=e,search:a.search,"onUpdate:search":n[9]||=e=>a.search=e,onOpenTask:a.onOpenTask,onRunTask:a.runTask,onStopTask:a.stopTask,onCompleteTask:a.completeTask,onReopenTask:a.reopenTask,onDeleteTask:a.deleteTask,onMoveTask:a.moveTask,onCreateTask:a.onCreateClick},null,8,[`tasks`,`project-labels`,`projects`,`task-percents`,`show-project-label`,`opened-task-id`,`view`,`search`])]),q(` 右栏分隔条:右栏收起 / 竖排(≤860)时不占位 `),!a.rightHidden&&!a.isStacked?(H(),x(`div`,{key:1,class:`board__splitter board__splitter--right`,role:`separator`,"aria-orientation":`vertical`,title:a.$t(`@WORKBENCH:拖动调整主 Agent 控制台宽度,双击恢复默认`),onMousedown:n[10]||=e=>a.onSplitterMouseDown(`right`,e),onDblclick:n[11]||=e=>a.onSplitterDblClick(`right`)},null,40,pc)):q(`v-if`,!0),e(a.OrchestratorConsole,{ref:`consoleRef`,running:a.running,"selected-project":a.selectedProject,dispatching:a.dispatching,"today-done":a.headerStats.todayDone,collapsed:a.rightHidden,"default-prompt":a.defaultPrompt,"project-prompts":a.projectPrompts,reports:a.reports,"report-interval-ms":a.reportIntervalMs,"generating-report":a.generatingReport,"max-instruction-chars":a.maxInstructionChars,onToggleCollapse:a.toggleRight,onDispatch:a.onDispatch,onGenerateReport:a.generateReport,onSetReportInterval:a.setReportInterval,onOpenPromptSettings:n[12]||=e=>a.promptDialogOpen=!0,onLocateTask:n[13]||=e=>a.emit(`locate-task`,e)},null,8,[`running`,`selected-project`,`dispatching`,`today-done`,`collapsed`,`default-prompt`,`project-prompts`,`reports`,`report-interval-ms`,`generating-report`,`max-instruction-chars`,`onGenerateReport`,`onSetReportInterval`])],2),q(` 派发预设提示词:全局一条 + 选中项目一条,写完即生效于之后的派发 `),e(a.WorkbenchDefaultPromptDialog,{modelValue:a.promptDialogOpen,"onUpdate:modelValue":n[14]||=e=>a.promptDialogOpen=e,"default-prompt":a.defaultPrompt,"project-path":a.selectedProject?.path||``,"project-name":a.selectedProject?.name||``,"project-prompt":a.selectedProjectPrompt,saving:a.savingPrompt,onSave:a.onSavePromptDraft},null,8,[`modelValue`,`default-prompt`,`project-path`,`project-name`,`project-prompt`,`saving`])],4)}var hc=Q(Js,[[`render`,mc],[`__scopeId`,`data-v-dd2dc7b4`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/views/components/WorkbenchBoard.vue`]]);c(),R();var gc=`wb.lastTaskByProject.v1`,_c=`__no_project__`,vc=`wb.sidebarWidth.v1`,yc=200,bc=480,xc=268,Sc=`wb.sidebarCollapsed.v1`,Cc=3e3,wc=52,Tc=320,Ec=500,Dc=f({__name:`WorkbenchView`,setup(e,{expose:n}){n();let r=Ee(),i=Ge(),a=M((()=>{try{let e=parseInt(localStorage.getItem(vc)||``,10);return Number.isFinite(e)?Math.min(bc,Math.max(yc,e)):xc}catch{return xc}})()),s=M((()=>{try{let e=localStorage.getItem(Sc);return e===null||e===`1`}catch{return!0}})());function c(){s.value=!s.value;try{localStorage.setItem(Sc,s.value?`1`:`0`)}catch{}}function l(e){e.preventDefault();let t=e.clientX,n=a.value;document.body.style.userSelect=`none`,document.body.style.cursor=`col-resize`;let r=e=>{a.value=Math.min(bc,Math.max(yc,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(vc,String(a.value))}catch{}},{once:!0})}function u(e){a.value=Math.min(bc,Math.max(yc,a.value+e));try{localStorage.setItem(vc,String(a.value))}catch{}}function d(){try{let e=localStorage.getItem(gc),t=e?JSON.parse(e):{};return t&&typeof t==`object`&&!Array.isArray(t)?t:{}}catch{return{}}}function f(e){try{localStorage.setItem(gc,JSON.stringify(e))}catch{}}function p(e,t){let n=d();n[e||_c]=t,f(n)}let m=M(!1);function h(e){ht(e.projectPath)}async function g(){let e=I.value&&Y(I.value)?I.value:null;if(ge(),e){m.value=!1,await X(e);return}I.value&&q.value&&await ve(),m.value=!1}function v(){I.value&&Y(I.value)&&window.setTimeout(()=>ft.value?.focus(),80)}let y=M(null);async function b(e){await re(),F.value=e.taskId,y.value=e.taskId,H(),I.value&&p($(T.value.path),e.taskId),m.value=!0}function x(e){if(!L.value.some(t=>t.id===e)){P.info(Z(`@WORKBENCH:该任务不在当前视图(可能在别的项目下)`));return}y.value=e}let{tasks:S,jobs:w,currentProject:T,connectSSE:E,disconnectSSE:D,loadCurrentProject:O,loadJobs:k,clearJobsByTask:A,loadTasks:re}=nr();function ie(){let e=$(T.value.path),t=S.value.filter(t=>!t.projectPath||$(t.projectPath)===e),n=d(),r=e&&n[e]||!e&&n[_c]||``,i=r?S.value.find(e=>e.id===r):null,a=t[0]||S.value[0]||null,o=i&&i.projectPath&&$(i.projectPath)!==e?null:i?i.id:a?a.id:null;F.value=o,H()}async function ae(){let e=F.value;if(await re(),e&&S.value.some(t=>t.id===e)){H();return}ie()}async function j(){await re(),ie()}let N=M(!1),F=M(null),I=J(()=>S.value.find(e=>e.id===F.value)||null),L=M([]),de=J(()=>L.value.find(e=>e.id===F.value)||null),R=J(()=>de.value?rt(Fn(de.value)):``),fe=J(()=>de.value?zn(de.value):``),pe=J(()=>de.value?Bn(de.value):``),B=J(()=>{let e=I.value?.projectPath||``;return!e||$(e)===$(T.value.path)?null:{name:e.replace(/[\\/]+$/,``).split(/[\\/]/).pop()||e,path:e}}),V=M({title:``,desc:``});function H(){I.value?V.value={title:I.value.title,desc:I.value.desc}:V.value={title:``,desc:``}}let W=M(`idle`),G=M(0),K=null,q=J(()=>{if(!I.value)return!1;let e=I.value;return V.value.title!==e.title||V.value.desc!==e.desc});function ge(){K!==null&&(clearTimeout(K),K=null)}function Y(e){return!(!e||(e.title||``).trim()||(e.desc||``).trim()||(e.simpleOverride||``).trim()||Array.isArray(e.attachments)&&e.attachments.length>0)}async function X(e){try{await fetch(`/api/workbench/tasks/${e.id}`,{method:`DELETE`})}catch{}let t=S.value.findIndex(t=>t.id===e.id);t!==-1&&S.value.splice(t,1)}async function _e(){let e=S.value.filter(e=>e.id!==F.value&&Y(e));for(let t of e)await X(t)}async function ve(){if(!I.value)return!1;if(!q.value)return!0;if(W.value=`saving`,await St(!1))return G.value=Date.now(),W.value=`saved`,setTimeout(()=>{W.value===`saved`&&Date.now()-G.value>=4e3&&(W.value=`idle`)},4e3),!0;W.value=`error`;let e=Date.now();return setTimeout(()=>{W.value===`error`&&Date.now()-e>=4e3&&(W.value=`idle`)},4e3),!1}z(()=>I.value?{id:I.value.id,title:I.value.title,desc:I.value.desc}:null,(e,t)=>{e&&t&&e.id===t.id&&(K!==null&&clearTimeout(K),K=window.setTimeout(()=>{ve()},1500))},{deep:!0}),z(F,async(e,t)=>{ge(),I.value&&q.value&&await ve()}),z(T,async e=>{if(!e.path)return;let t=$(e.path),n=I.value;n&&n.projectPath&&$(n.projectPath)!==t&&await j()});function ye(e){try{let t=new Blob([JSON.stringify(e)],{type:`application/json`});navigator.sendBeacon?.(`/api/workbench/tasks`,t)}catch{}}function Q(){I.value&&q.value&&!Y(I.value)&&ye(I.value)}let Se=M(!0);async function Oe(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 ke=M(null),Ae=M(null);async function je(e){if(e){if(!await Oe((e.title||``).trim()||Z(`@WORKBENCH:未命名任务`))){P.error(Z(`@WORKBENCH:复制失败`));return}ke.value=e.id,P.success(Z(`@WORKBENCH:已复制任务标题`)),window.setTimeout(()=>{ke.value===e.id&&(ke.value=null)},1500)}}async function Ne(e){if(!e)return;let t=(e.desc||``).trim();if(!t){P.warning(Z(`@WORKBENCH:任务描述为空,无需复制`));return}if(!await Oe(t)){P.error(Z(`@WORKBENCH:复制失败`));return}Ae.value=e.id,P.success(Z(`@WORKBENCH:已复制任务描述`)),window.setTimeout(()=>{Ae.value===e.id&&(Ae.value=null)},1500)}let{simpleConversationMessages:Pe,simpleAllJobsFor:Fe,simpleJobFor:Ie,simpleJobState:Le}=er(w,I);function Re(e){let t=I.value;if(!t)return!1;let n=Fe(t);if(!n.length)return!1;let r=String(e?.id||``).replace(/-a$/,``),i=r?n.findIndex(e=>e.id===r):n.length-1;if(i<0)return!1;if(i!==n.length-1)return P.warning(Z(`@WORKBENCH:只能重试最后一轮`)),!1;let a=n[i];return i===0?Lt(a):Rt(t,a,n[i-1])}let Be=M(null);function Ve(e){let t=(e?.projectPath||``).trim().replace(/[\\/]+$/,``);return t?t.split(/[\\/]/).pop()||t:T.value.name||``}async function Ue(e,t=`brief`){if(!e)return;let n=tt(Fe(e),{title:e.title,projectName:Ve(e)},{scope:t});if(!n){P.warning(Z(`@WORKBENCH:暂无执行内容可复制`));return}if(!await Oe(n)){P.error(Z(`@WORKBENCH:复制失败`));return}Be.value=e.id,P.success(Z(`@WORKBENCH:已复制执行内容`)),window.setTimeout(()=>{Be.value===e.id&&(Be.value=null)},1500)}function We(e){Ue(I.value,e===`full`?`full`:`brief`)}let Ke=[`wheel`,`touchstart`,`pointerdown`,`keydown`],qe=M(null),Ye=ze(),Xe=M(null),Ze=null,Qe=null,$e=null;function et(){if(Ze&&=(Ze.disconnect(),null),Qe!==null&&(clearTimeout(Qe),Qe=null),$e){for(let e of Ke)$e.removeEventListener(e,et);$e=null}}function nt(){et();let e=qe.value;if(!e)return;e.scrollToBottom?.(!1);let t=Xe.value?.querySelector(`.acu-message-list`);if(!(!t||typeof ResizeObserver>`u`)){$e=t;for(let e of Ke)t.addEventListener(e,et,{passive:!0});Ze=new ResizeObserver(()=>qe.value?.scrollToBottom?.(!1)),Ze.observe(t),t.firstElementChild&&Ze.observe(t.firstElementChild),Qe=setTimeout(et,Cc)}}let it=J(()=>m.value&&I.value&&Fe(I.value).length>0?I.value.id:``);z(it,async e=>{et(),e&&(await t(),nt())}),C(et);function at(e){return e?zt(e.id):!1}let ot=J(()=>Fe(I.value).length>0),st=J(()=>at(I.value)),ct=J(()=>I.value?st.value?Z(`@WORKBENCH:正在执行中,请先「停止」再重新执行`):ot.value?Z(`@WORKBENCH:重新跑一轮:上一轮的执行记录会被清空`):``:``),lt=J(()=>{if(!I.value)return null;let e=de.value;if(st.value||e&&e.runningJobs>0)return{key:`running`,label:Z(`@WORKBENCH:执行中`),title:Z(`@WORKBENCH:这条任务正在执行`)};if(e)return e.column===`done`?{key:`done`,label:Z(`@WORKBENCH:已完成`),title:e.autoCompleted?Z(`@WORKBENCH:静默超时后由 AI 核对,判定这条任务已经完成`):e.manualDoneAt?Z(`@WORKBENCH:已标记为已完成`):``}:e.lastJobStatus===`error`?{key:`error`,label:Z(`@WORKBENCH:执行失败`),title:Z(`@WORKBENCH:上一次执行报错,点开对话流查看原因`)}:{key:`todo`,label:Z(`@WORKBENCH:待处理`),title:``};switch(Le(Ie(I.value))){case`done`:return{key:`done`,label:Z(`@WORKBENCH:已完成`),title:``};case`error`:return{key:`error`,label:Z(`@WORKBENCH:执行失败`),title:``};case`cancelled`:return{key:`todo`,label:Z(`@WORKBENCH:已取消`),title:``};default:return{key:`todo`,label:Z(`@WORKBENCH:待处理`),title:``}}}),ut=J(()=>{let e=I.value;if(!e)return[];let t=e.promptParts;if(t&&(t.global||t.project)){let e=[];return t.global&&e.push({key:`global`,label:Z(`@WORKBENCH:全局提示词`),text:t.global}),t.project&&e.push({key:`project`,label:Z(`@WORKBENCH:项目提示词`),text:t.project}),e}let n=(e.simpleOverride||``).trim();return n?[{key:`legacy`,label:Z(`@WORKBENCH:提示词`),text:n}]:[]}),dt=M(!1),ft=M(null),pt=M(null);function mt(e){let t=e?.currentTarget||pt.value;if(!t)return;t.style.height=`auto`;let n=document.activeElement===t?Ec:Tc,r=Math.min(Math.max(t.scrollHeight,wc),n);t.style.height=`${r}px`,t.style.overflowY=t.scrollHeight>n?`auto`:`hidden`}z(Se,async e=>{e&&(await t(),mt())}),z(()=>I.value?.id,async()=>{Se.value&&(await t(),mt())});async function ht(e){if(dt.value)return;dt.value=!0;let n={title:``,desc:``},r=(e||T.value.path||``).trim();r&&(n.projectPath=r);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){P.error(e.error||Z(`@WORKBENCH:保存失败`));return}ge(),I.value&&Y(I.value)?await X(I.value):I.value&&q.value&&await ve(),await j(),e.task?.id&&(F.value=e.task.id,H(),m.value=!0,P.success(Z(`@WORKBENCH:已新建任务`)),await t(),ft.value?.focus())}finally{dt.value=!1}}async function gt(e){await U.confirm(Z(`@WORKBENCH:删除任务「{title}」?`,{title:e.title}),Z(`@WORKBENCH:确认`),{type:`warning`}),await fetch(`/api/workbench/tasks/${e.id}`,{method:`DELETE`}),F.value===e.id&&(F.value=null),j()}async function _t(e){let t=(e.title||Z(`@WORKBENCH:未命名任务`)).trim(),n={title:Z(`@WORKBENCH:{title} (副本)`,{title:t}),desc:e.desc||``,simpleOverride:e.simpleOverride||``};e.promptParts&&(e.promptParts.global||e.promptParts.project)&&(n.promptParts=e.promptParts),T.value.path&&(n.projectPath=T.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){P.error(e.error||Z(`@WORKBENCH:复制失败`));return}await j(),e.task?.id&&(F.value=e.task.id,H()),P.success(Z(`@WORKBENCH:已复制任务`))}catch(e){P.error(Z(`@WORKBENCH:网络错误: `)+(e&&e.message||e))}}async function vt(e){if(F.value===e.id)return;ge();let t=I.value;t&&Y(t)?await X(t):t&&q.value&&await ve(),F.value=e.id,H(),p($(T.value.path),e.id)}async function yt(e){let{groupPath:t,orderedIds:n}=e;if(!Array.isArray(n)||n.length===0)return;let r=S.value.slice(),i=bt(S.value,t,n);if(i!==S.value){S.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:Z(`@WORKBENCH:排序保存失败`)}));e?.success||(S.value=r,P.error(e?.error||Z(`@WORKBENCH:排序保存失败`)))}catch(e){S.value=r,P.error(Z(`@WORKBENCH:排序保存失败`)+`: `+(e?.message||e))}}}function bt(e,t,n){let r=e=>$(e)||_c,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 St(e){if(!I.value)return!1;let t=await fetch(`/api/workbench/tasks`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify(I.value)}).then(e=>e.json());return t.success?(e&&P.success(Z(`@WORKBENCH:已保存`)),await ae(),!0):(P.error(t.error||Z(`@WORKBENCH:保存失败`)),!1)}o(async()=>{await Promise.all([j(),O(),k()]),await _e(),E(),window.addEventListener(`beforeunload`,Q),i.fetchExecutorModels()}),C(()=>{D(),window.removeEventListener(`beforeunload`,Q),I.value&&q.value&&!Y(I.value)&&ye(I.value)});let{pasteHoverId:Ct,isUploading:wt,isImageAttachment:Tt,humanSize:Et,onAttachmentPaste:Dt,onAttachmentDrop:kt,uploadAttachment:At,removeAttachment:jt,pickAttachmentFile:Mt}=Zn(),{runTask:Nt,onContinueSendFromChat:Pt,cancelJob:Ft,clearExecutionForSelectedTask:It,onReExecuteJob:Lt,retryRound:Rt,isTaskRunning:zt,queuedChatsOf:Bt,removeQueuedChat:Vt,flushNextQueued:Ht}=tr(w,S,I,{clearJobsByTask:A,persistTask:St,uploadAttachment:At,getExecutor:()=>Ut.value}),{active:Ut,availability:Wt,hasAnyExecutor:Gt,choose:Kt,executorModelText:qt,executorModelTitle:Jt}=Je();function Yt(e){return Te(e)}let Xt=J(()=>Fe(I.value).slice(-1)[0]),Zt=J(()=>Te(Xt.value?.agent)),Qt=J(()=>Ot(Xt.value?.agent)),$t=J(()=>we(Xt.value?.agent)?Xt.value.agent:`claude`),en={configStore:r,toolsStore:i,LAST_TASK_BY_PROJECT_KEY:gc,NO_PROJECT_KEY:_c,SIDEBAR_WIDTH_KEY:vc,SIDEBAR_MIN_W:yc,SIDEBAR_MAX_W:bc,SIDEBAR_DEFAULT_W:xc,sidebarWidth:a,SIDEBAR_COLLAPSED_KEY:Sc,sidebarCollapsed:s,toggleSidebarCollapsed:c,onSidebarSplitterMouseDown:l,nudgeSidebarWidth:u,readLastTaskMap:d,writeLastTaskMap:f,rememberLastTask:p,editorOpen:m,createTaskFromBoard:h,closeEditor:g,onEditorOpened:v,boardOpenedTaskId:y,openTaskFromBoard:b,locateTaskFromBoard:x,tasks:S,jobs:w,currentProject:T,connectSSE:E,disconnectSSE:D,loadCurrentProject:O,loadJobs:k,clearJobsByTask:A,_loadDataTasks:re,applyRestoredSelection:ie,refreshTasks:ae,loadTasks:j,logsDialogVisible:N,selectedTaskId:F,selectedTask:I,boardTasks:L,selectedBoardTask:de,barTimeText:R,barDurationText:fe,barTimeTitle:pe,foreignRepo:B,metaSnapshot:V,captureSnapshot:H,metaSaveState:W,metaSavedAt:G,get metaSaveTimer(){return K},set metaSaveTimer(e){K=e},metaDirty:q,clearMetaSaveTimers:ge,isTaskBlank:Y,discardBlankTask:X,pruneBlankTasks:_e,flushMetaSave:ve,beaconPersist:ye,onBeforeUnloadPersist:Q,taskDescExpanded:Se,copyToClipboard:Oe,copyTitleFlashId:ke,copyDescFlashId:Ae,copyTaskTitle:je,copyTaskDesc:Ne,simpleConversationMessages:Pe,simpleAllJobsFor:Fe,simpleJobFor:Ie,simpleJobState:Le,onChatRetry:Re,copyExecFlashId:Be,taskRepoName:Ve,copyTaskExecution:Ue,onCopyExecCommand:We,CHAT_PIN_WINDOW_MS:Cc,CHAT_PIN_USER_EVENTS:Ke,chatRef:qe,fileChangeLabels:Ye,chatWrapRef:Xe,get chatPinRO(){return Ze},set chatPinRO(e){Ze=e},get chatPinTimer(){return Qe},set chatPinTimer(e){Qe=e},get chatPinEl(){return $e},set chatPinEl(e){$e=e},stopChatPin:et,pinChatToBottom:nt,chatRenderKey:it,isTaskRunning:at,selectedTaskHasRun:ot,selectedTaskRunning:st,runButtonTitle:ct,barStatus:lt,selectedTaskPromptParts:ut,creatingTask:dt,titleInputRef:ft,taskDescTextareaRef:pt,DESC_TEXTAREA_MIN_PX:wc,DESC_TEXTAREA_MAX_PX:Tc,DESC_TEXTAREA_MAX_PX_FOCUS:Ec,autoGrowTextarea:mt,createTaskDirect:ht,deleteTask:gt,copyTask:_t,selectTask:vt,reorderTasks:yt,applyLocalReorder:bt,persistTask:St,pasteHoverId:Ct,isUploading:wt,isImageAttachment:Tt,humanSize:Et,onAttachmentPaste:Dt,onAttachmentDrop:kt,uploadAttachment:At,removeAttachment:jt,pickAttachmentFile:Mt,runTask:Nt,onContinueSendFromChat:Pt,cancelJob:Ft,clearExecutionForSelectedTask:It,onReExecuteJob:Lt,retryRound:Rt,isTaskRunningById:zt,queuedChatsOf:Bt,removeQueuedChat:Vt,flushNextQueued:Ht,selectedTaskExecutor:Ut,executorAvailability:Wt,hasAnyExecutor:Gt,pickExecutor:Kt,executorModelText:qt,executorModelTitle:Jt,executorLabel:Yt,lastSimpleJob:Xt,simpleAssistantLabel:Zt,simpleAssistantAvatar:Qt,lastJobExecutorId:$t,lastSimpleJobRunning:J(()=>Le(Xt.value)===`running`),lastRunExecutorTitle:J(()=>{let e=Jt($t.value),t=Z(`@WORKBENCH:本轮实际使用的执行器;上方按钮选的是下一次执行用谁`);return e?`${e} · ${t}`:t}),selectedTaskQueue:J(()=>I.value?Bt(I.value.id):[]),get $t(){return Z},get ArrowDown(){return te},get ArrowLeft(){return ee},get ArrowRight(){return ne},get Check(){return ce},get Document(){return le},get Delete(){return oe},get CopyDocument(){return me},get Expand(){return ue},get Fold(){return he},get VideoPlay(){return _},get Warning(){return se},AttachmentZone:xt,get ChatInput(){return xe},get ChatContainer(){return be},get MESSAGE_RAIL_CONFIG(){return He},ExecutionLogManager:Nn,get ALLOWED_EXT_HINT(){return Hn},get MAX_ATTACHMENT_BYTES(){return Un},get TASK_EXECUTOR_OPTIONS(){return Ce},TaskExecutorIcon:Me,WorkbenchSidebar:Dr,WorkbenchBoard:hc,CommonDialog:De};return Object.defineProperty(en,"__isScriptSetup",{enumerable:!1,value:!0}),en}});c(),I(),B();var Oc={class:`workbench`},kc={class:`wb-editor`},Ac={class:`wb-editor-bar`},jc=[`title`],Mc=[`aria-pressed`,`title`,`aria-label`],Nc=[`title`],Pc=[`data-status`,`title`],Fc={class:`wb-editor-bar__status-pill`},Ic={class:`wb-editor-bar__status-label`},Lc=[`title`],Rc={key:2,class:`wb-editor-bar__time`},zc=[`title`],Bc={key:1,class:`wb-editor-bar__sep`,"aria-hidden":`true`},Vc={key:2,class:`wb-editor-bar__spent`},Hc={class:`wb-editor-bar__hint`},Uc={class:`workbench__editor-row`},Wc=[`aria-label`,`aria-valuenow`,`title`],Gc={class:`wb-split`},Kc={key:0,class:`wb-placeholder`},qc={class:`wb-split__header`},Jc={class:`wb-split__title-wrap`},Yc=[`placeholder`,`aria-label`],Xc=[`title`,`aria-label`],Zc=[`title`],Qc={key:0,class:`wb-meta-save__dot`},$c={key:1,class:`wb-meta-save__check`},el={key:2,class:`wb-meta-save__bang`},tl={key:3,class:`wb-meta-save__dot`},nl=[`data-executor`,`title`],rl={class:`wb-run-executor__text`},il=[`title`],al={class:`sr-only`},ol={class:`sr-only`},sl={class:`wb-executor-item`},cl={class:`wb-executor-item__name`},ll=[`title`],ul={key:2,class:`wb-executor-item__missing`},dl={key:3,class:`wb-no-claude-hint`,role:`status`},fl={class:`wb-no-claude-hint__text`},pl={class:`wb-no-claude-hint__link`,href:`https://docs.claude.com/en/docs/claude-code/setup`,target:`_blank`,rel:`noopener noreferrer`},ml={class:`wb-copy-exec`},hl=[`title`,`aria-label`],gl={class:`sr-only`},_l=[`title`,`aria-label`],vl=[`title`,`aria-label`],yl={class:`sr-only`},bl=[`title`,`aria-label`],xl={class:`sr-only`},Sl=[`open`],Cl={class:`wb-task-desc__summary`},wl={class:`wb-task-desc__label`},Tl=[`title`,`aria-label`],El={key:0,class:`wb-task-desc__tag`},Dl={key:0},Ol={key:1,class:`wb-task-desc__tag-attachment`},kl=[`placeholder`,`aria-label`],Al={class:`wb-execution-body`},jl={class:`wb-exec-detail`},Ml={class:`wb-form-item__label wb-task-prompt__summary`},Nl={key:0,class:`wb-task-prompt__tag`},Pl={key:0,class:`wb-task-prompt__parts`},Fl={class:`wb-task-prompt__label`},Il={class:`wb-task-prompt__text`},Ll={key:1,class:`wb-task-prompt__empty`},Rl={key:0,class:`wb-simple-chat-wrap`,ref:`chatWrapRef`},zl={class:`wb-simple-chat`},Bl={class:`wb-simple-chat__footer`},Vl={key:0,class:`wb-chat-queue`},Hl={class:`wb-chat-queue__head`},Ul={class:`wb-chat-queue__label`},Wl={class:`wb-chat-queue__count`},Gl={class:`wb-chat-queue__hint`},Kl={class:`wb-chat-queue__index`},ql=[`title`],Jl={key:0,class:`wb-chat-queue__atts`},Yl=[`title`,`aria-label`,`onClick`];function Xl(t,i,a,o,s,c){let d=l,f=n,p=K,m=y;return H(),x(`div`,Oc,[q(` L1:多项目编排台 —— **常驻底图**,不再与编辑器互斥 `),e(o.WorkbenchBoard,{"opened-task-id":o.boardOpenedTaskId,onOpenTask:o.openTaskFromBoard,onCreateTask:o.createTaskFromBoard,onBoardTasks:i[0]||=e=>o.boardTasks=e,onLocateTask:o.locateTaskFromBoard},null,8,[`opened-task-id`]),q(` L2:单任务编辑器 —— 默认整屏铺开(原来是 1520px 居中浮层),关掉即回到看板,全程无跳转。\r
|
|
290
291
|
新建任务也走这一层:点新建 = 建一条空白任务 + 顶起编辑器(标题输入框直接聚焦),\r
|
|
291
292
|
标题 / 描述 / 附件 / 执行都用这里已有的那套组件,不再另做一张表单。\r
|
|
292
293
|
custom-class 是给文件末尾那段非 scoped 样式用的:全屏下要抹掉圆角 / 单线边框,\r
|
|
293
|
-
并把 el-dialog__body 变成撑满剩余高度的 flex 容器。 `),e(o.CommonDialog,{modelValue:o.editorOpen,"onUpdate:modelValue":i[24]||=e=>o.editorOpen=e,title:o.$t(`@WORKBENCH:任务执行`),size:`fullscreen`,type:`flex`,"custom-class":`wb-task-dialog`,onOpened:o.onEditorOpened},{default:F(()=>[b(`div`,
|
|
294
|
-
没选中任务时(右侧是空态占位)也需要它,塞进任务头就会出现"进了编辑器却关不掉"的死角。 `),b(`div`,
|
|
294
|
+
并把 el-dialog__body 变成撑满剩余高度的 flex 容器。 `),e(o.CommonDialog,{modelValue:o.editorOpen,"onUpdate:modelValue":i[24]||=e=>o.editorOpen=e,title:o.$t(`@WORKBENCH:任务执行`),size:`fullscreen`,type:`flex`,"custom-class":`wb-task-dialog`,onOpened:o.onEditorOpened},{default:F(()=>[b(`div`,kc,[q(` 顶部细栏:关闭入口做成独立一条,而不是塞进任务头 ——\r
|
|
295
|
+
没选中任务时(右侧是空态占位)也需要它,塞进任务头就会出现"进了编辑器却关不掉"的死角。 `),b(`div`,Ac,[b(`button`,{type:`button`,class:`wb-back-btn`,title:o.$t(`@WORKBENCH:返回看板`),onClick:o.closeEditor},[e(d,{class:`wb-back-btn__icon`},{default:F(()=>[e(o.ArrowLeft)]),_:1}),b(`span`,null,T(o.$t(`@WORKBENCH:返回看板`)),1)],8,jc),q(`\r
|
|
295
296
|
任务列表栏的收起开关:细栏里唯一能"展开/收起左栏"的入口 ——\r
|
|
296
297
|
收起后左栏整块消失,没有这枚按钮就再也点不开了。\r
|
|
297
298
|
默认收起(用户要求),展开态用主色高亮,一眼看出当前左栏开着。\r
|
|
298
|
-
`),b(`button`,{type:`button`,class:w([`wb-sidebar-toggle`,{"is-active":!o.sidebarCollapsed}]),"aria-pressed":!o.sidebarCollapsed,title:o.sidebarCollapsed?o.$t(`@WORKBENCH:展开任务列表`):o.$t(`@WORKBENCH:收起任务列表`),"aria-label":o.sidebarCollapsed?o.$t(`@WORKBENCH:展开任务列表`):o.$t(`@WORKBENCH:收起任务列表`),onClick:o.toggleSidebarCollapsed},[e(d,{class:`wb-sidebar-toggle__icon`},{default:F(()=>[(H(),r(g(o.sidebarCollapsed?o.Expand:o.Fold)))]),_:1}),b(`span`,null,T(o.$t(`@WORKBENCH:任务列表`)),1)],10,
|
|
299
|
+
`),b(`button`,{type:`button`,class:w([`wb-sidebar-toggle`,{"is-active":!o.sidebarCollapsed}]),"aria-pressed":!o.sidebarCollapsed,title:o.sidebarCollapsed?o.$t(`@WORKBENCH:展开任务列表`):o.$t(`@WORKBENCH:收起任务列表`),"aria-label":o.sidebarCollapsed?o.$t(`@WORKBENCH:展开任务列表`):o.$t(`@WORKBENCH:收起任务列表`),onClick:o.toggleSidebarCollapsed},[e(d,{class:`wb-sidebar-toggle__icon`},{default:F(()=>[(H(),r(g(o.sidebarCollapsed?o.Expand:o.Fold)))]),_:1}),b(`span`,null,T(o.$t(`@WORKBENCH:任务列表`)),1)],10,Mc),b(`span`,{class:`wb-editor-bar__project`,title:o.currentProject.path},T(o.currentProject.name),9,Nc),q(`\r
|
|
299
300
|
任务状态徽标(见脚本里 barStatus 那段为什么要有它):\r
|
|
300
301
|
紧挨项目名 —— 它和"我在哪 / 打开的是谁"同属"这条任务是什么"的上下文,\r
|
|
301
302
|
比挤到右端的时间块旁边更好找。色相走角色色,在跑时圆点脉动。\r
|
|
302
303
|
data-status 给探针一个稳定钩子(值 = running / done / error / todo)。\r
|
|
303
|
-
`),o.barStatus?(H(),x(`span`,{key:0,class:w([`wb-editor-bar__status`,`is-`+o.barStatus.key]),"data-status":o.barStatus.key,title:o.barStatus.title||void 0},[b(`span`,
|
|
304
|
+
`),o.barStatus?(H(),x(`span`,{key:0,class:w([`wb-editor-bar__status`,`is-`+o.barStatus.key]),"data-status":o.barStatus.key,title:o.barStatus.title||void 0},[b(`span`,Fc,[i[26]||=b(`span`,{class:`wb-editor-bar__status-dot`,"aria-hidden":`true`},null,-1),b(`span`,Ic,T(o.barStatus.label),1)])],10,Pc)):q(`v-if`,!0),o.foreignRepo?(H(),x(`span`,{key:1,class:`wb-editor-bar__repo`,title:o.foreignRepo.path},T(o.$t(`@WORKBENCH:执行于 {name}`,{name:o.foreignRepo.name})),9,Lc)):q(`v-if`,!0),q(`\r
|
|
304
305
|
当前任务的时间 / 用时 —— 与看板卡片右上角的相对时间、卡片那行「用时 x」同一口径\r
|
|
305
306
|
(值直接取自看板轮询下来的同一条 BoardTask,所以是逐字一致,不是"两边写法对齐")。\r
|
|
306
307
|
\r
|
|
@@ -312,7 +313,7 @@ import"./rolldown-runtime-C0FnF6B9.js";import{An as e,Bn as t,C as n,Cn as r,F a
|
|
|
312
313
|
一路收到 0),「返回看板 / 项目名 / 执行于 xxx」的宽度全程不变\r
|
|
313
314
|
(±1px 是 flex 按比例分摊缺口的取整,见样式那段)。\r
|
|
314
315
|
悬停提示只挂在相对时间上:绝对值区间解释的是"什么时候",用时本身不用再解释。\r
|
|
315
|
-
`),o.barTimeText||o.barDurationText?(H(),x(`span`,
|
|
316
|
+
`),o.barTimeText||o.barDurationText?(H(),x(`span`,Rc,[o.barTimeText?(H(),x(`span`,{key:0,class:`wb-editor-bar__ago`,title:o.barTimeTitle},T(o.barTimeText),9,zc)):q(`v-if`,!0),o.barTimeText&&o.barDurationText?(H(),x(`span`,Bc,`·`)):q(`v-if`,!0),o.barDurationText?(H(),x(`span`,Vc,T(o.barDurationText),1)):q(`v-if`,!0)])):q(`v-if`,!0),b(`span`,Hc,T(o.$t(`@WORKBENCH:任务执行`)),1)]),b(`div`,Uc,[o.sidebarCollapsed?q(`v-if`,!0):(H(),r(o.WorkbenchSidebar,{key:0,style:u({width:o.sidebarWidth+`px`}),tasks:o.tasks,"selected-task-id":o.selectedTaskId,"current-project":o.currentProject,"creating-task":o.creatingTask,"is-task-running":o.isTaskRunning,onSelectTask:o.selectTask,onDeleteTask:o.deleteTask,onCopyTask:o.copyTask,onCreateTask:o.createTaskDirect,onReorderTasks:o.reorderTasks},null,8,[`style`,`tasks`,`selected-task-id`,`current-project`,`creating-task`])),o.sidebarCollapsed?q(`v-if`,!0):(H(),x(`div`,{key:1,class:`wb-splitter`,role:`separator`,tabindex:`0`,"aria-orientation":`vertical`,"aria-label":o.$t(`@WORKBENCH:拖动调整侧边栏宽度`),"aria-valuenow":o.sidebarWidth,"aria-valuemin":o.SIDEBAR_MIN_W,"aria-valuemax":o.SIDEBAR_MAX_W,title:o.$t(`@WORKBENCH:拖动调整侧边栏宽度`),onMousedown:o.onSidebarSplitterMouseDown,onKeydown:[i[1]||=N(j(e=>o.nudgeSidebarWidth(-16),[`prevent`]),[`left`]),i[2]||=N(j(e=>o.nudgeSidebarWidth(16),[`prevent`]),[`right`])]},null,40,Wc)),q(` 中:单任务编辑区 `),b(`section`,Gc,[o.selectedTask?(H(),x(O,{key:1},[b(`div`,qc,[b(`div`,Jc,[A(b(`input`,{ref:`titleInputRef`,class:`wb-input wb-input--title`,"onUpdate:modelValue":i[3]||=e=>o.selectedTask.title=e,placeholder:o.$t(`@WORKBENCH:任务标题`),"aria-label":o.$t(`@WORKBENCH:任务标题`)},null,8,Yc),[[V,o.selectedTask.title]]),b(`button`,{type:`button`,class:w([`wb-copy-btn`,{"is-flash":o.copyTitleFlashId===o.selectedTask.id}]),title:o.$t(`@WORKBENCH:复制任务标题`),"aria-label":o.$t(`@WORKBENCH:复制任务标题`),onClick:i[4]||=e=>o.copyTaskTitle(o.selectedTask)},[o.copyTitleFlashId===o.selectedTask.id?(H(),r(d,{key:1,class:`wb-copy-btn__icon wb-copy-btn__icon--check`},{default:F(()=>[...i[27]||=[L(`✓`,-1)]]),_:1})):(H(),r(d,{key:0,class:`wb-copy-btn__icon`},{default:F(()=>[e(o.CopyDocument)]),_:1}))],10,Xc)]),o.metaSaveState!==`idle`||o.metaDirty?(H(),x(`span`,{key:0,class:w([`wb-meta-save`,{"is-saving":o.metaSaveState===`saving`,"is-saved":o.metaSaveState===`saved`,"is-error":o.metaSaveState===`error`,"is-dirty":o.metaDirty&&o.metaSaveState===`idle`}]),title:o.metaSaveState===`saving`?o.$t(`@WORKBENCH:保存中…`):o.metaSaveState===`error`?o.$t(`@WORKBENCH:保存失败`):o.metaSaveState===`saved`?o.$t(`@WORKBENCH:已保存`):``},[o.metaSaveState===`saving`?(H(),x(`span`,Qc)):o.metaSaveState===`saved`?(H(),x(`span`,$c,`✓`)):o.metaSaveState===`error`?(H(),x(`span`,el,`!`)):(H(),x(`span`,tl)),L(` `+T(o.metaSaveState===`saving`?o.$t(`@WORKBENCH:保存中…`):o.metaSaveState===`saved`?o.$t(`@WORKBENCH:已保存`):o.metaSaveState===`error`?o.$t(`@WORKBENCH:保存失败`):o.$t(`@WORKBENCH:有未保存的更改`)),1)],10,Zc)):q(`v-if`,!0),q(`\r
|
|
316
317
|
「本轮实际是谁跑的」常驻徽标:对话流左侧那颗执行器头像会随滚动跑掉,而它才是\r
|
|
317
318
|
"这一轮用什么执行"的事实;旁边 split button 上挂的 hint 是**下次**用谁\r
|
|
318
319
|
(selectedTaskExecutor,用户临时选择),两者经常不一致 —— 切了执行器还没重跑、\r
|
|
@@ -322,33 +323,33 @@ import"./rolldown-runtime-C0FnF6B9.js";import{An as e,Bn as t,C as n,Cn as r,F a
|
|
|
322
323
|
(老 job 没有这个字段,按 claude 兜底,与 taskExecutorName 口径一致)。\r
|
|
323
324
|
从没跑过的任务不渲染(没有"本轮"可言)。\r
|
|
324
325
|
data-executor 给探针一个稳定钩子(值 = claude / opencode / codex / codebuddy / pi)。\r
|
|
325
|
-
`),o.lastSimpleJob?(H(),x(`span`,{key:1,class:w([`wb-run-executor`,{"is-running":o.lastSimpleJobRunning}]),"data-executor":o.lastJobExecutorId,title:o.lastRunExecutorTitle},[e(o.TaskExecutorIcon,{executor:o.lastJobExecutorId,class:`wb-run-executor__icon`},null,8,[`executor`]),b(`span`,
|
|
326
|
+
`),o.lastSimpleJob?(H(),x(`span`,{key:1,class:w([`wb-run-executor`,{"is-running":o.lastSimpleJobRunning}]),"data-executor":o.lastJobExecutorId,title:o.lastRunExecutorTitle},[e(o.TaskExecutorIcon,{executor:o.lastJobExecutorId,class:`wb-run-executor__icon`},null,8,[`executor`]),b(`span`,rl,T(o.lastSimpleJobRunning?o.$t(`@WORKBENCH:正在由 {name} 执行`,{name:o.simpleAssistantLabel}):o.$t(`@WORKBENCH:本轮由 {name} 执行`,{name:o.simpleAssistantLabel})),1)],10,nl)):q(`v-if`,!0),q(`\r
|
|
326
327
|
执行:split button —— 主体按当前选中执行器直接跑,下拉临时切换执行器。\r
|
|
327
328
|
文案随执行状态变(2026-10-01):这条任务已经有执行记录时改叫「重新执行任务」,\r
|
|
328
329
|
因为 runTask 会先清掉旧 job 再开新一轮 —— 挂着「执行任务」会让人以为是接着上一轮跑。\r
|
|
329
330
|
在跑的时候直接禁用:服务端本来就拒(400 该任务已有正在执行的 job),\r
|
|
330
331
|
点了只是白跑一趟,还想让人误以为新起了一轮。\r
|
|
331
|
-
`),o.hasAnyExecutor?(H(),r(m,{key:2,"split-button":``,type:`primary`,class:`wb-executor-split`,trigger:`click`,disabled:o.selectedTaskRunning,title:o.runButtonTitle,onClick:i[5]||=e=>o.runTask(o.selectedTask),onCommand:o.pickExecutor},{dropdown:F(()=>[e(p,null,{default:F(()=>[(H(!0),x(O,null,E(o.TASK_EXECUTOR_OPTIONS,t=>(H(),r(f,{key:t.id,command:t.id,disabled:!o.executorAvailability[t.id]},{default:F(()=>[b(`span`,
|
|
332
|
-
主按钮直接点 = 精简范围(提示词 + 模型回复);右边的箭标展开菜单选「全量」 `),b(`div`,
|
|
332
|
+
`),o.hasAnyExecutor?(H(),r(m,{key:2,"split-button":``,type:`primary`,class:`wb-executor-split`,trigger:`click`,disabled:o.selectedTaskRunning,title:o.runButtonTitle,onClick:i[5]||=e=>o.runTask(o.selectedTask),onCommand:o.pickExecutor},{dropdown:F(()=>[e(p,null,{default:F(()=>[(H(!0),x(O,null,E(o.TASK_EXECUTOR_OPTIONS,t=>(H(),r(f,{key:t.id,command:t.id,disabled:!o.executorAvailability[t.id]},{default:F(()=>[b(`span`,sl,[e(o.TaskExecutorIcon,{executor:t.id,class:`wb-executor-item__icon`},null,8,[`executor`]),b(`span`,cl,T(t.name),1),o.executorModelText(t.id)?(H(),x(`span`,{key:0,class:`wb-executor-item__model`,title:o.executorModelTitle(t.id)},T(o.executorModelText(t.id)),9,ll)):q(`v-if`,!0),o.selectedTaskExecutor===t.id?(H(),r(d,{key:1,class:`wb-executor-item__check`},{default:F(()=>[e(o.Check)]),_:1})):o.executorAvailability[t.id]?q(`v-if`,!0):(H(),x(`span`,ul,T(o.$t(`@42BB9:未安装`)),1))])]),_:2},1032,[`command`,`disabled`]))),128))]),_:1})]),default:F(()=>[e(d,{class:`wb-executor-split__play`,"aria-hidden":`true`},{default:F(()=>[e(o.VideoPlay)]),_:1}),b(`span`,{class:`wb-executor-split__hint`,title:o.executorModelTitle(o.selectedTaskExecutor)},[e(o.TaskExecutorIcon,{executor:o.selectedTaskExecutor,class:`wb-executor-split__hint-icon`},null,8,[`executor`]),b(`span`,al,T(o.executorLabel(o.selectedTaskExecutor)),1)],8,il),b(`span`,ol,T(o.selectedTaskHasRun?o.$t(`@WORKBENCH:重新执行任务`):o.$t(`@WORKBENCH:执行任务`)),1)]),_:1},8,[`disabled`,`title`,`onCommand`])):(H(),x(`div`,dl,[e(d,{class:`wb-no-claude-hint__icon`},{default:F(()=>[e(o.Warning)]),_:1}),b(`span`,fl,T(o.$t(`@WORKBENCH:未检测到本地可用的 CLI 执行器,无法执行任务`)),1),b(`a`,pl,T(o.$t(`@WORKBENCH:查看安装指引`)),1)])),q(` 一键复制执行内容:非破坏性动作,排在最前;「清空执行」这种危险动作留在后面。\r
|
|
333
|
+
主按钮直接点 = 精简范围(提示词 + 模型回复);右边的箭标展开菜单选「全量」 `),b(`div`,ml,[b(`button`,{type:`button`,class:w([`wb-logs-inline-btn wb-logs-inline-btn--copy wb-copy-exec__main`,{"is-flash":o.copyExecFlashId===o.selectedTask.id}]),title:o.$t(`@WORKBENCH:复制本任务的对话流(默认精简:仅提示词 + 模型回复)`),"aria-label":o.$t(`@WORKBENCH:复制执行内容`),onClick:i[6]||=e=>o.copyTaskExecution(o.selectedTask,`brief`)},[o.copyExecFlashId===o.selectedTask.id?(H(),r(d,{key:1,class:`wb-logs-inline-btn__icon`},{default:F(()=>[...i[28]||=[L(`✓`,-1)]]),_:1})):(H(),r(d,{key:0,class:`wb-logs-inline-btn__icon`},{default:F(()=>[e(o.CopyDocument)]),_:1})),b(`span`,gl,T(o.$t(`@WORKBENCH:复制执行内容`)),1)],10,hl),e(m,{trigger:`click`,placement:`bottom-end`,onCommand:o.onCopyExecCommand},{dropdown:F(()=>[e(p,null,{default:F(()=>[e(f,{command:`brief`},{default:F(()=>[L(T(o.$t(`@WORKBENCH:精简:提示词 + 模型回复`)),1)]),_:1}),e(f,{command:`full`},{default:F(()=>[L(T(o.$t(`@WORKBENCH:全量:提示词 / 思考 / 工具调用 / 模型回复`)),1)]),_:1})]),_:1})]),default:F(()=>[b(`button`,{type:`button`,class:`wb-logs-inline-btn wb-copy-exec__caret`,title:o.$t(`@WORKBENCH:选择复制范围`),"aria-label":o.$t(`@WORKBENCH:选择复制范围`)},[e(d,{class:`wb-logs-inline-btn__icon`},{default:F(()=>[e(o.ArrowDown)]),_:1})],8,_l)]),_:1})]),b(`button`,{type:`button`,class:`wb-logs-inline-btn wb-logs-inline-btn--danger`,title:o.$t(`@WORKBENCH:清空当前任务的所有执行内容`),"aria-label":o.$t(`@WORKBENCH:清空当前任务的所有执行内容`),onClick:i[7]||=(...e)=>o.clearExecutionForSelectedTask&&o.clearExecutionForSelectedTask(...e)},[e(d,{class:`wb-logs-inline-btn__icon`},{default:F(()=>[e(o.Delete)]),_:1}),b(`span`,yl,T(o.$t(`@WORKBENCH:清空执行`)),1)],8,vl),b(`button`,{type:`button`,class:`wb-logs-inline-btn`,title:o.$t(`@WORKBENCH:执行日志`),"aria-label":o.$t(`@WORKBENCH:执行日志`),onClick:i[8]||=e=>o.logsDialogVisible=!0},[e(d,{class:`wb-logs-inline-btn__icon`},{default:F(()=>[e(o.Document)]),_:1}),b(`span`,xl,T(o.$t(`@WORKBENCH:执行日志`)),1)],8,bl)]),q(` 任务描述区域:默认展开(执行前必看);用户可点 summary 收起 `),b(`details`,{class:`wb-task-desc`,open:o.taskDescExpanded,onToggle:i[20]||=e=>o.taskDescExpanded=e.target.open},[b(`summary`,Cl,[e(d,{class:`wb-task-desc__caret`},{default:F(()=>[(H(),r(g(o.taskDescExpanded?o.ArrowDown:o.ArrowRight)))]),_:1}),b(`span`,wl,T(o.$t(`@WORKBENCH:任务描述(可选)`)),1),b(`button`,{type:`button`,class:w([`wb-copy-btn wb-copy-btn--inline`,{"is-flash":o.copyDescFlashId===o.selectedTask.id}]),title:o.selectedTask.desc&&o.selectedTask.desc.trim()?o.$t(`@WORKBENCH:复制任务描述`):o.$t(`@WORKBENCH:任务描述为空,无需复制`),"aria-label":o.$t(`@WORKBENCH:复制任务描述`),onClick:i[9]||=j(e=>o.copyTaskDesc(o.selectedTask),[`stop`,`prevent`])},[o.copyDescFlashId===o.selectedTask.id?(H(),r(d,{key:1,class:`wb-copy-btn__icon wb-copy-btn__icon--check`},{default:F(()=>[...i[29]||=[L(`✓`,-1)]]),_:1})):(H(),r(d,{key:0,class:`wb-copy-btn__icon`},{default:F(()=>[e(o.CopyDocument)]),_:1}))],10,Tl),o.selectedTask.desc&&o.selectedTask.desc.length>0||o.selectedTask.attachments&&o.selectedTask.attachments.length>0?(H(),x(`span`,El,[o.selectedTask.desc&&o.selectedTask.desc.length>0?(H(),x(`span`,Dl,T(o.$t(`@WORKBENCH:已填写`)),1)):q(`v-if`,!0),o.selectedTask.attachments&&o.selectedTask.attachments.length>0?(H(),x(`span`,Ol,T(o.selectedTask.attachments.length),1)):q(`v-if`,!0)])):q(`v-if`,!0)]),A(b(`textarea`,{ref:`taskDescTextareaRef`,class:`wb-textarea wb-textarea--autogrow`,"onUpdate:modelValue":i[10]||=e=>o.selectedTask.desc=e,placeholder:o.$t(`@WORKBENCH:任务描述(可选)`),"aria-label":o.$t(`@WORKBENCH:任务描述(可选)`),onInput:i[11]||=e=>o.autoGrowTextarea(e),onFocus:i[12]||=e=>o.autoGrowTextarea(e),onBlur:i[13]||=e=>o.autoGrowTextarea(e),onPaste:i[14]||=e=>o.onAttachmentPaste(e,{kind:`task`,task:o.selectedTask})},null,40,kl),[[V,o.selectedTask.desc]]),e(o.AttachmentZone,{attachments:o.selectedTask.attachments||[],"is-image":o.isImageAttachment,"human-size":o.humanSize,"is-uploading":o.isUploading(`task-`+o.selectedTask.id),"is-paste-hover":o.pasteHoverId===`task-`+o.selectedTask.id,"on-pick":()=>o.pickAttachmentFile({kind:`task`,task:o.selectedTask}),"on-remove":e=>o.removeAttachment({kind:`task`,task:o.selectedTask},e),onPaste:i[15]||=e=>o.onAttachmentPaste(e,{kind:`task`,task:o.selectedTask}),onDrop:i[16]||=j(e=>o.onAttachmentDrop(e,{kind:`task`,task:o.selectedTask}),[`prevent`]),onDragover:i[17]||=j(e=>o.pasteHoverId=`task-`+o.selectedTask.id,[`prevent`]),onDragenter:i[18]||=j(e=>o.pasteHoverId=`task-`+o.selectedTask.id,[`prevent`]),onDragleave:i[19]||=e=>o.pasteHoverId=o.pasteHoverId===`task-`+o.selectedTask.id?null:o.pasteHoverId},null,8,[`attachments`,`is-image`,`human-size`,`is-uploading`,`is-paste-hover`,`on-pick`,`on-remove`])],40,Sl),q(` ── 执行主体:一条任务 = 一次会话,详情面板占满整行 ── `),b(`div`,Al,[q(` 详情面板(执行内容区) `),b(`div`,jl,[q(` ⚠️ 这一层**不要**用裸 <template> 包起来(踩过,2026-09-22):\r
|
|
333
334
|
Vue 3 只把带 v-if / v-else / v-for / v-slot 的 <template> 编译成片段,\r
|
|
334
335
|
裸 <template> 会被当成真的 <template> 元素渲染 —— 浏览器把子节点全塞进\r
|
|
335
336
|
template.content(inert DocumentFragment),不产生任何布局盒。\r
|
|
336
337
|
症状:任务在跑、看板「执行中」,但对话区一片空白,\r
|
|
337
|
-
而 innerText 里明明有内容(元素 0×0)。重构移除子任务概念时留下的空壳。 `),
|
|
338
|
-
任务级不可编辑 —— 编辑入口只有主 Agent 控制台的「预设提示词」设置。 `),b(`details`,{class:w([`wb-task-prompt`,{"has-content":o.selectedTaskPromptParts.length>0}])},[b(`summary`,
|
|
338
|
+
而 innerText 里明明有内容(元素 0×0)。重构移除子任务概念时留下的空壳。 `),q(` 提示词:派发时冻结的只读快照(全局 + 项目两段),改设置不影响历史任务。\r
|
|
339
|
+
任务级不可编辑 —— 编辑入口只有主 Agent 控制台的「预设提示词」设置。 `),b(`details`,{class:w([`wb-task-prompt`,{"has-content":o.selectedTaskPromptParts.length>0}])},[b(`summary`,Ml,[e(d,{class:`wb-task-prompt__caret`},{default:F(()=>[e(o.ArrowRight)]),_:1}),b(`span`,null,T(o.$t(`@WORKBENCH:提示词`)),1),o.selectedTaskPromptParts.length>0?(H(),x(`span`,Nl,T(o.$t(`@WORKBENCH:已填写`)),1)):q(`v-if`,!0),o.simpleJobState(o.simpleJobFor(o.selectedTask))===`running`&&o.simpleJobFor(o.selectedTask)?(H(),x(`button`,{key:1,class:`wb-simple__stop`,onClick:i[21]||=j(e=>o.cancelJob(o.simpleJobFor(o.selectedTask)),[`stop`])},T(o.$t(`@WORKBENCH:停止`)),1)):q(`v-if`,!0)]),o.selectedTaskPromptParts.length>0?(H(),x(`div`,Pl,[(H(!0),x(O,null,E(o.selectedTaskPromptParts,e=>(H(),x(`div`,{key:e.key,class:`wb-task-prompt__part`},[b(`div`,Fl,T(e.label),1),b(`pre`,Il,T(e.text),1)]))),128))])):(H(),x(`p`,Ll,T(o.$t(`@WORKBENCH:这条任务没有附加提示词`)),1))],2),q(` 任务对话流:所有轮次合并到单个 ChatContainer `),o.simpleAllJobsFor(o.selectedTask).length>0?(H(),x(`div`,Rl,[q(` ⚠️ 这层 div 不是多余的,class 也**不要**挪回 ChatContainer 上(2026-09-29 踩过):\r
|
|
339
340
|
传给 zen-ai-chat-ui 组件的 class 在**生产构建**里不会落到组件根节点上\r
|
|
340
341
|
(同一份源码 dev 会落、prod 静默丢掉,实测 class 与父级 data-v-* 双双消失),\r
|
|
341
342
|
于是 \`.wb-simple-chat :deep(.acu-*)\` 这一组样式钩子在生产 bundle 里全是死的。\r
|
|
342
343
|
症状之一就是「已完成的任务点开后有 2 个输入框」:原来靠\r
|
|
343
344
|
\`.acu-chat-footer{display:none}\` 藏 ChatContainer 自带输入框,prod 里那条规则\r
|
|
344
345
|
根本没匹配上,lib 自带输入框与下面常驻的 ChatInput 同时显示。\r
|
|
345
|
-
把 class 挂在自己的 div 上,样式钩子才在 dev / prod 都成立。 `),b(`div`,
|
|
346
|
+
把 class 挂在自己的 div 上,样式钩子才在 dev / prod 都成立。 `),b(`div`,zl,[(H(),r(o.ChatContainer,{ref:`chatRef`,key:o.selectedTask.id,messages:o.simpleConversationMessages,"assistant-name":o.simpleAssistantLabel,"assistant-avatar":o.simpleAssistantAvatar,"show-avatar":!0,theme:o.configStore.theme,"tool-calls-config":{group:!0,collapseThreshold:2},"plan-config":{labels:{title:o.$t(`@AGENT:计划`),raw:o.$t(`@AGENT:原始参数`)}},"file-changes-labels":o.fileChangeLabels,"message-rail-config":o.MESSAGE_RAIL_CONFIG,"show-input":!1,onRetry:o.onChatRetry},null,8,[`messages`,`assistant-name`,`assistant-avatar`,`theme`,`plan-config`,`file-changes-labels`,`message-rail-config`]))]),q(` 输入区:**任务在跑的时候也常驻**。\r
|
|
346
347
|
- 空闲:发送 = 立刻续接一轮\r
|
|
347
348
|
- 执行中:发送 = 排队,等这一轮 job 进终态自动接上(见 useWorkbenchExecution)\r
|
|
348
|
-
停止按钮不在这里 —— 它一直在上方「提示词」那一行的右侧。 `),b(`div`,
|
|
349
|
-
给个手动重试;其余情况点它没意义,所以只在队首出现 `),t===0&&!o.selectedTaskRunning?(H(),x(`button`,{key:1,type:`button`,class:`wb-chat-queue__btn`,onClick:i[22]||=e=>o.flushNextQueued(o.selectedTask.id)},T(o.$t(`@WORKBENCH:立即发送`)),1)):
|
|
349
|
+
停止按钮不在这里 —— 它一直在上方「提示词」那一行的右侧。 `),b(`div`,Bl,[o.selectedTaskQueue.length?(H(),x(`div`,Vl,[b(`div`,Hl,[b(`span`,Ul,T(o.$t(`@WORKBENCH:排队中`)),1),b(`span`,Wl,T(o.selectedTaskQueue.length),1),b(`span`,Gl,T(o.selectedTaskRunning?o.$t(`@WORKBENCH:等这一轮跑完自动发送`):o.$t(`@WORKBENCH:当前没有在跑的轮次`)),1)]),(H(!0),x(O,null,E(o.selectedTaskQueue,(e,t)=>(H(),x(`div`,{key:e.id,class:`wb-chat-queue__item`},[b(`span`,Kl,T(t+1),1),b(`span`,{class:`wb-chat-queue__text`,title:e.text},T(e.text),9,ql),e.files.length?(H(),x(`span`,Jl,[i[30]||=b(`span`,{"aria-hidden":`true`},`📎`,-1),L(` `+T(e.files.map(e=>e.file.name).join(`、`)),1)])):q(`v-if`,!0),q(` 队首 + 没在跑 = 上一笔发失败了(正常情况终态一到就自动发了),\r
|
|
350
|
+
给个手动重试;其余情况点它没意义,所以只在队首出现 `),t===0&&!o.selectedTaskRunning?(H(),x(`button`,{key:1,type:`button`,class:`wb-chat-queue__btn`,onClick:i[22]||=e=>o.flushNextQueued(o.selectedTask.id)},T(o.$t(`@WORKBENCH:立即发送`)),1)):q(`v-if`,!0),b(`button`,{type:`button`,class:`wb-chat-queue__btn is-remove`,title:o.$t(`@WORKBENCH:移出队列`),"aria-label":o.$t(`@WORKBENCH:移出队列`),onClick:t=>o.removeQueuedChat(o.selectedTask.id,e.id)},`✕`,8,Yl)]))),128))])):q(`v-if`,!0),(H(),r(o.ChatInput,{key:`input-`+o.selectedTask.id,placeholder:o.selectedTaskRunning?o.$t(`@WORKBENCH:执行中,发送后会排队,等这一轮跑完自动接上…`):o.$t(`@WORKBENCH:输入后续问题继续对话…(Ctrl+Enter 发送)`),"upload-config":{enabled:!0,accept:o.ALLOWED_EXT_HINT,multiple:!0,maxCount:0,maxSize:o.MAX_ATTACHMENT_BYTES},class:`wb-simple-chat__input`,onSend:i[23]||=e=>o.onContinueSendFromChat(o.selectedTask,e)},null,8,[`placeholder`,`upload-config`]))])],512)):q(`v-if`,!0)])])],64)):(H(),x(`div`,Kc,[b(`p`,null,T(o.$t(`@WORKBENCH:左侧选择任务,或新建一个任务开始`)),1)]))])])])]),_:1},8,[`modelValue`,`title`]),q(` 执行日志管理:弹窗形式承载,原本独立 tab 切换会占用首屏。\r
|
|
350
351
|
\r
|
|
351
352
|
⚠️ 必须 append-to-body。app shell 的 main.main-container 是 position:fixed + z-index:1001,\r
|
|
352
353
|
它自成一个层叠上下文:留在这里面的弹窗 z-index 再高,也只是跟"同一个上下文里的兄弟"比,\r
|
|
353
354
|
永远压不过挂在 body 下的 L2 编辑器弹窗(它 escape 了 1001 那层)。\r
|
|
354
|
-
现象就是点了「执行日志」没反应 —— 其实弹窗开了,只是被编辑器整个盖住。 `),e(o.CommonDialog,{modelValue:o.logsDialogVisible,"onUpdate:modelValue":i[25]||=e=>o.logsDialogVisible=e,title:o.$t(`@WORKBENCH:执行日志`),width:`1080px`,"close-on-click-modal":!1,top:`6vh`,type:`flex`,"custom-class":`wb-logs-dialog`,"append-to-body":``},{default:F(()=>[e(o.ExecutionLogManager)]),_:1},8,[`modelValue`,`title`])])}var
|
|
355
|
+
现象就是点了「执行日志」没反应 —— 其实弹窗开了,只是被编辑器整个盖住。 `),e(o.CommonDialog,{modelValue:o.logsDialogVisible,"onUpdate:modelValue":i[25]||=e=>o.logsDialogVisible=e,title:o.$t(`@WORKBENCH:执行日志`),width:`1080px`,"close-on-click-modal":!1,top:`6vh`,type:`flex`,"custom-class":`wb-logs-dialog`,"append-to-body":``},{default:F(()=>[e(o.ExecutionLogManager)]),_:1},8,[`modelValue`,`title`])])}var Zl=Q(Dc,[[`render`,Xl],[`__scopeId`,`data-v-28f2e82b`],[`__file`,`D:/workspace/github_workspace/zen-gitsync/src/ui/client/src/views/WorkbenchView.vue`]]);export{Zl as default};
|