zen-gitsync 2.17.42 → 2.17.44

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