nx-kv 0.8.2 → 0.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- import{a as e,c as t,i as n,l as r,n as i,o as a,r as o,s,t as c}from"./index-Iz1qH6TC.js";import{t as l}from"./CliHints-DNK3TaU5.js";var u=r(),d=s();function f(){let{boot:r,refreshBoot:s}=a(),f=e(),p=n(),{dialog:m,node:h}=o(),[g,_]=(0,u.useState)([]),[v,y]=(0,u.useState)(``),[b,x]=(0,u.useState)({name:``,description:``}),[S,C]=(0,u.useState)(null),w=(0,u.useCallback)(async()=>{if(r?.loggedIn)try{let e=await t(`/api/groups`);_(e.groups||[]),y(``)}catch(e){y(e.message)}},[r?.loggedIn]);(0,u.useEffect)(()=>{w()},[w]);let T=e=>p(async()=>{let n=await t(`/api/group`,{method:`POST`,body:{locator:e}});f(n.id===0?`已切回默认组`:`已切换到 ${n.name}`),await s(),await w()}),E=()=>p(async()=>{let e=b.name.trim();if(!e){f(`请填名称`);return}let n=await t(`/api/groups`,{method:`POST`,body:{name:e,description:b.description.trim()}});x({name:``,description:``}),f(`已新建工作空间 ${n.name}(id=${n.id})`),await s(),await w()}),D=e=>p(async()=>{let n=await m({title:`重命名「${e.name}」`,input:!0,value:e.name});n!==null&&n.trim()&&(await t(`/api/groups/${e.id}`,{method:`PATCH`,body:{name:n.trim()}}),f(`已更新名称`),await s(),await w())}),O=e=>p(async()=>{await m({message:`解散工作空间「${e.name}」(id=${e.id})?\n\n后端要求组内已无 KV 数据,否则会拒绝。此操作不可撤销。`,danger:!0})&&(await t(`/api/groups/${e.id}`,{method:`DELETE`}),f(`已解散 ${e.name}`),await s(),await w())}),k=e=>p(async()=>{let n=await t(`/api/groups/${e.id}/members`);C({title:`成员 · ${e.name}`,node:(0,d.jsx)(`div`,{className:`list`,children:n.members.length?n.members.map(e=>(0,d.jsxs)(`div`,{className:`row`,children:[(0,d.jsx)(c,{className:`name`,text:e.email,title:`点击复制邮箱`,children:e.email}),(0,d.jsx)(`span`,{className:`tag`,children:e.role||`member`}),(0,d.jsx)(`span`,{className:`muted`,children:e.nickname})]},e.userId)):(0,d.jsx)(`div`,{className:`row muted`,children:`(没有成员)`})})})});return r?.loggedIn?(0,d.jsxs)(d.Fragment,{children:[(0,d.jsxs)(`div`,{className:`toolbar`,children:[(0,d.jsx)(`input`,{placeholder:`新工作空间名称`,size:`16`,value:b.name,onChange:e=>x({...b,name:e.target.value}),onKeyDown:e=>{e.key===`Enter`&&E()}}),(0,d.jsx)(`input`,{placeholder:`描述(可选)`,size:`20`,value:b.description,onChange:e=>x({...b,description:e.target.value})}),(0,d.jsx)(`button`,{className:`btn`,onClick:E,children:`新建`}),(0,d.jsx)(`span`,{className:`sep`}),(0,d.jsx)(`button`,{className:`btn ghost`,onClick:()=>p(w),children:`刷新`})]}),(0,d.jsxs)(`div`,{className:`card`,children:[(0,d.jsxs)(`div`,{className:`colhead`,children:[(0,d.jsx)(`h3`,{children:`我的工作空间`}),(0,d.jsx)(`span`,{className:`muted`,children:`切换后清单页立即跟着变`})]}),(0,d.jsxs)(`div`,{className:`list`,children:[v?(0,d.jsx)(`div`,{className:`row muted`,children:v}):null,(0,d.jsxs)(`div`,{className:`row`,children:[(0,d.jsx)(`span`,{className:`name`,children:`默认组`}),(0,d.jsx)(`span`,{className:`desc`,children:`不传 groupId,由后端回落`}),(0,d.jsx)(`span`,{className:`acts`,children:r.groupId===0?(0,d.jsx)(`span`,{className:`tag strong`,children:`当前`}):(0,d.jsx)(`button`,{className:`btn small`,onClick:()=>T(`default`),children:`切到这里`})})]}),g.map(e=>(0,d.jsxs)(`div`,{className:`row`,children:[(0,d.jsx)(c,{className:`name`,text:e.name,title:`点击复制名称`,children:e.name}),(0,d.jsx)(`span`,{className:`tag`,children:e.myRole||`member`}),(0,d.jsx)(`span`,{className:`desc`,children:e.description||``}),(0,d.jsxs)(`span`,{className:`muted mono`,children:[`id=`,e.id]}),(0,d.jsxs)(`span`,{className:`muted`,children:[e.memberCount,` 人`]}),(0,d.jsxs)(`span`,{className:`acts`,children:[e.id===r.groupId?(0,d.jsx)(`span`,{className:`tag strong`,children:`当前`}):(0,d.jsx)(`button`,{className:`btn small`,onClick:()=>T(String(e.id)),children:`切到这里`}),(0,d.jsx)(`button`,{className:`btn small ghost`,onClick:()=>k(e),children:`成员`}),(0,d.jsx)(`button`,{className:`btn small ghost`,onClick:()=>D(e),children:`改名`}),(0,d.jsx)(`button`,{className:`btn small ghost danger`,onClick:()=>O(e),children:`解散`})]})]},e.id)),!v&&!g.length?(0,d.jsx)(`div`,{className:`row muted`,children:`(没有其他工作空间)`}):null]})]}),(0,d.jsx)(l,{module:`group`}),S?(0,d.jsx)(i,{title:S.title,onClose:()=>C(null),children:S.node}):null,h]}):(0,d.jsxs)(`div`,{className:`card`,style:{padding:16},children:[(0,d.jsx)(`div`,{className:`colhead`,children:(0,d.jsx)(`h3`,{children:`请先登录`})}),(0,d.jsx)(`div`,{className:`muted`,children:`工作空间需要登录后才能列出。`})]})}export{f as default};
1
+ import{a as e,c as t,i as n,l as r,n as i,o as a,r as o,s,t as c}from"./index-2OK9SG2y.js";import{t as l}from"./CliHints-D70_R4vQ.js";var u=r(),d=s();function f(){let{boot:r,refreshBoot:s}=a(),f=e(),p=n(),{dialog:m,node:h}=o(),[g,_]=(0,u.useState)([]),[v,y]=(0,u.useState)(``),[b,x]=(0,u.useState)({name:``,description:``}),[S,C]=(0,u.useState)(null),w=(0,u.useCallback)(async()=>{if(r?.loggedIn)try{let e=await t(`/api/groups`);_(e.groups||[]),y(``)}catch(e){y(e.message)}},[r?.loggedIn]);(0,u.useEffect)(()=>{w()},[w]);let T=e=>p(async()=>{let n=await t(`/api/group`,{method:`POST`,body:{locator:e}});f(n.id===0?`已切回默认组`:`已切换到 ${n.name}`),await s(),await w()}),E=()=>p(async()=>{let e=b.name.trim();if(!e){f(`请填名称`);return}let n=await t(`/api/groups`,{method:`POST`,body:{name:e,description:b.description.trim()}});x({name:``,description:``}),f(`已新建工作空间 ${n.name}(id=${n.id})`),await s(),await w()}),D=e=>p(async()=>{let n=await m({title:`重命名「${e.name}」`,input:!0,value:e.name});n!==null&&n.trim()&&(await t(`/api/groups/${e.id}`,{method:`PATCH`,body:{name:n.trim()}}),f(`已更新名称`),await s(),await w())}),O=e=>p(async()=>{await m({message:`解散工作空间「${e.name}」(id=${e.id})?\n\n后端要求组内已无 KV 数据,否则会拒绝。此操作不可撤销。`,danger:!0})&&(await t(`/api/groups/${e.id}`,{method:`DELETE`}),f(`已解散 ${e.name}`),await s(),await w())}),k=e=>p(async()=>{let n=await t(`/api/groups/${e.id}/members`);C({title:`成员 · ${e.name}`,node:(0,d.jsx)(`div`,{className:`list`,children:n.members.length?n.members.map(e=>(0,d.jsxs)(`div`,{className:`row`,children:[(0,d.jsx)(c,{className:`name`,text:e.email,title:`点击复制邮箱`,children:e.email}),(0,d.jsx)(`span`,{className:`tag`,children:e.role||`member`}),(0,d.jsx)(`span`,{className:`muted`,children:e.nickname})]},e.userId)):(0,d.jsx)(`div`,{className:`row muted`,children:`(没有成员)`})})})});return r?.loggedIn?(0,d.jsxs)(d.Fragment,{children:[(0,d.jsxs)(`div`,{className:`toolbar`,children:[(0,d.jsx)(`input`,{placeholder:`新工作空间名称`,size:`16`,value:b.name,onChange:e=>x({...b,name:e.target.value}),onKeyDown:e=>{e.key===`Enter`&&E()}}),(0,d.jsx)(`input`,{placeholder:`描述(可选)`,size:`20`,value:b.description,onChange:e=>x({...b,description:e.target.value})}),(0,d.jsx)(`button`,{className:`btn`,onClick:E,children:`新建`}),(0,d.jsx)(`span`,{className:`sep`}),(0,d.jsx)(`button`,{className:`btn ghost`,onClick:()=>p(w),children:`刷新`})]}),(0,d.jsxs)(`div`,{className:`card`,children:[(0,d.jsxs)(`div`,{className:`colhead`,children:[(0,d.jsx)(`h3`,{children:`我的工作空间`}),(0,d.jsx)(`span`,{className:`muted`,children:`切换后清单页立即跟着变`})]}),(0,d.jsxs)(`div`,{className:`list`,children:[v?(0,d.jsx)(`div`,{className:`row muted`,children:v}):null,(0,d.jsxs)(`div`,{className:`row`,children:[(0,d.jsx)(`span`,{className:`name`,children:`默认组`}),(0,d.jsx)(`span`,{className:`desc`,children:`不传 groupId,由后端回落`}),(0,d.jsx)(`span`,{className:`acts`,children:r.groupId===0?(0,d.jsx)(`span`,{className:`tag strong`,children:`当前`}):(0,d.jsx)(`button`,{className:`btn small`,onClick:()=>T(`default`),children:`切到这里`})})]}),g.map(e=>(0,d.jsxs)(`div`,{className:`row`,children:[(0,d.jsx)(c,{className:`name`,text:e.name,title:`点击复制名称`,children:e.name}),(0,d.jsx)(`span`,{className:`tag`,children:e.myRole||`member`}),(0,d.jsx)(`span`,{className:`desc`,children:e.description||``}),(0,d.jsxs)(`span`,{className:`muted mono`,children:[`id=`,e.id]}),(0,d.jsxs)(`span`,{className:`muted`,children:[e.memberCount,` 人`]}),(0,d.jsxs)(`span`,{className:`acts`,children:[e.id===r.groupId?(0,d.jsx)(`span`,{className:`tag strong`,children:`当前`}):(0,d.jsx)(`button`,{className:`btn small`,onClick:()=>T(String(e.id)),children:`切到这里`}),(0,d.jsx)(`button`,{className:`btn small ghost`,onClick:()=>k(e),children:`成员`}),(0,d.jsx)(`button`,{className:`btn small ghost`,onClick:()=>D(e),children:`改名`}),(0,d.jsx)(`button`,{className:`btn small ghost danger`,onClick:()=>O(e),children:`解散`})]})]},e.id)),!v&&!g.length?(0,d.jsx)(`div`,{className:`row muted`,children:`(没有其他工作空间)`}):null]})]}),(0,d.jsx)(l,{module:`group`}),S?(0,d.jsx)(i,{title:S.title,onClose:()=>C(null),children:S.node}):null,h]}):(0,d.jsxs)(`div`,{className:`card`,style:{padding:16},children:[(0,d.jsx)(`div`,{className:`colhead`,children:(0,d.jsx)(`h3`,{children:`请先登录`})}),(0,d.jsx)(`div`,{className:`muted`,children:`工作空间需要登录后才能列出。`})]})}export{f as default};
@@ -0,0 +1 @@
1
+ import{a as e,c as t,i as n,l as r,s as i}from"./index-2OK9SG2y.js";import{t as a}from"./CliHints-D70_R4vQ.js";var o=r(),s=i();function c(e){let t=/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/.exec(e||``);return t?new Date(+t[1],t[2]-1,+t[3],+t[4],+t[5],+t[6]):null}function l(e){let t=c(e);if(!t)return``;let n=t.getTime()-Date.now();if(n<=0)return`等待中 0:00`;let r=Math.floor(n/6e4),i=Math.floor(n%6e4/1e3);return`等待中 ${r}:${String(i).padStart(2,`0`)}`}function ee(e){if(!e||!e.waiting)return null;let t=l(e.waitingUntil);if(!e.waitingSince)return t;let n=c(e.waitingSince);if(!n)return t;let r=Date.now()-n.getTime();if(r<0)return t;let i=Math.floor(r/6e4),a=Math.floor(r%6e4/1e3);return`等待中 已等 ${i}:${String(a).padStart(2,`0`)} · 剩 ${t.replace(/^等待中\s*/,``)}`}function te(){let r=e(),i=n(),[c,te]=(0,o.useState)(null),[u,d]=(0,o.useState)(null),[f,p]=(0,o.useState)(``),[m,h]=(0,o.useState)(!1),[ne,g]=(0,o.useState)(180),[re,ie]=(0,o.useState)(!1),[_,ae]=(0,o.useState)(!1),[v,y]=(0,o.useState)(``),[oe,se]=(0,o.useState)(``),[b,ce]=(0,o.useState)(!1),[x,S]=(0,o.useState)(!1),[C,w]=(0,o.useState)(``),[T,E]=(0,o.useState)(!1),[D,O]=(0,o.useState)(`connecting`),[k,A]=(0,o.useState)(null),[j,M]=(0,o.useState)(null),[N,P]=(0,o.useState)(``),[F,I]=(0,o.useState)(!1),[L,R]=(0,o.useState)(null),[z,B]=(0,o.useState)(null),[V,H]=(0,o.useState)(!1),[U,W]=(0,o.useState)(()=>new Set),[G,K]=(0,o.useState)(!1),q=(0,o.useCallback)(async()=>{try{let e=await t(`/api/localtasks`);te(e),O(`ok`)}catch{O(`reconnecting`)}},[]);(0,o.useEffect)(()=>{q()},[q]),(0,o.useEffect)(()=>{let e=setInterval(q,1500);return()=>clearInterval(e)},[q]),(0,o.useEffect)(()=>{if(!k)return;let e=e=>{e.key===`Escape`&&A(null)};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[k]);let J=c?c.topics:[];(0,o.useEffect)(()=>{c&&c.settings&&(g(c.settings.timeoutSec),y(c.settings.taskSuffix||``),se(c.settings.defaultTaskSuffix||``),ce(!!c.settings.suffixEnabled))},[c]);let le=e=>i(async()=>{g(Number(e)),ie(!0);try{let n=await t(`/api/localtasks/setting`,{method:`PATCH`,body:{timeout:Number(e)}});g(n.timeoutSec),r(`等待超时已配置为 ${n.timeoutSec} 秒`)}finally{ie(!1)}}),Y=e=>i(async()=>{E(!0);try{let n=await t(`/api/localtasks/setting`,{method:`PATCH`,body:{suffix:e}});y(n.taskSuffix),ce(!!n.suffixEnabled),S(!1),w(``),r(n.suffixEnabled?`收尾追加语已更新`:`收尾追加语已关闭`),await q()}finally{E(!1)}}),ue=()=>Y(``),de=()=>i(async()=>{ae(!0);try{let e=await t(`/api/localtasks/prune`,{method:`POST`,body:{}});r(e.count?`已清理 ${e.count} 个旧主题`:`没有需要清理的旧数据`),await q()}finally{ae(!1)}});(0,o.useEffect)(()=>{if(!J.length){d(null);return}if(u&&J.some(e=>e.key===u))return;let e=J.find(e=>e.waiting)||J[0];d(e.key)},[J,u]),(0,o.useEffect)(()=>{W(e=>{let t=new Set([...e].filter(e=>J.some(t=>t.key===e)));return t.size===e.size?e:t})},[J]);let X=J.find(e=>e.key===u)||null,fe=e=>W(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n}),pe=J.length>0&&U.size===J.length,me=()=>W(pe?new Set:new Set(J.map(e=>e.key))),he=()=>i(async()=>{let e=f.trim();if(!e){r(`请输入任务内容`);return}if(!X){r(`请先选择一个主题(工作目录)`);return}h(!0);try{let n=await t(`/api/localtasks`,{method:`POST`,body:{cwd:X.cwd,text:e}});p(``),r(n.delivered?`已返回给等待中的 agent`:`已排入该主题队列,等待 agent 下一次 wait`),await q()}finally{h(!1)}}),ge=e=>i(async()=>{await t(`/api/localtasks/item`,{method:`DELETE`,body:{cwd:X.cwd,id:e}}),r(`已删除`),await q()}),_e=e=>i(async()=>{let n=e.waiting?`主题「${e.name}」正在等待中,删除后其 agent 将超时收尾,确认删除?`:`删除主题「${e.name}」及其全部 ${e.total} 条任务?`;if(window.confirm(n)){K(!0);try{await t(`/api/localtasks/topic`,{method:`DELETE`,body:e.waiting?{key:e.key,force:!0}:{key:e.key}}),W(t=>{let n=new Set(t);return n.delete(e.key),n}),r(`已删除主题`),await q()}finally{K(!1)}}}),ve=e=>i(async()=>{if(!e||!e.waiting)return;let n=`关闭主题「${e.name}」的等待?\n\n阻塞中的 wait 立即收尾(走与超时同一条出口,agent 照常结束本轮),主题与任务都保留。`;if(!window.confirm(n))return;let i=await t(`/api/localtasks/cancel`,{method:`POST`,body:{key:e.key}});i&&i.cancelled?r(`已关闭等待`):r(`该主题不在等待中`),await q()}),ye=()=>i(async()=>{if(!U.size)return;let e=J.filter(e=>U.has(e.key)),n=e.filter(e=>e.waiting).length,i=`确认删除选中的 ${e.length} 个主题?`;if(n&&(i+=`(其中 ${n} 个等待中,删除后其 agent 将超时收尾)`),window.confirm(i)){K(!0);try{let e=await t(`/api/localtasks/topics/remove`,{method:`POST`,body:{keys:[...U],force:n>0}});r(`已删除 ${e.count} 个主题`+(e.skipped.length?`,跳过 ${e.skipped.length} 个`:``)),W(new Set),await q()}finally{K(!1)}}}),be=e=>{M(e.id),P(e.text)},xe=()=>{M(null),P(``)},Se=()=>i(async()=>{let e=N.trim();if(!e){r(`任务内容不能为空`);return}I(!0);try{await t(`/api/localtasks/item`,{method:`PATCH`,body:{cwd:X.cwd,id:j,text:e}}),r(`已保存修改`),M(null),await q()}finally{I(!1)}}),Ce=X?X.tasks.slice().reverse():[],Z=X?X.tasks.filter(e=>e.status!==`consumed`):[],Q=(e,{beforeId:n,afterId:a})=>i(async()=>{H(!0);try{await t(`/api/localtasks/reorder`,{method:`PATCH`,body:{cwd:X.cwd,id:e,beforeId:n,afterId:a}}),r(`已调整领取优先级`),await q()}finally{H(!1),R(null),B(null)}}),$=(e,t)=>{let n=Z.findIndex(t=>t.id===e.id);t===`up`&&n>0&&Q(e.id,{beforeId:Z[n-1].id}),t===`down`&&n<Z.length-1&&Q(e.id,{afterId:Z[n+1].id})},we=(e,t)=>{if(L===null||t.status===`consumed`||L===t.id)return;e.preventDefault(),e.dataTransfer.dropEffect=`move`;let n=e.currentTarget.getBoundingClientRect(),r=e.clientY<n.top+n.height/2?`top`:`bottom`;B(e=>e&&e.id===t.id&&e.pos===r?e:{id:t.id,pos:r})},Te=(e,t)=>{if(L===null||t.status===`consumed`||L===t.id)return;e.preventDefault();let n=e.currentTarget.getBoundingClientRect(),r=e.clientY<n.top+n.height/2,i=L;R(null),B(null),Q(i,r?{afterId:t.id}:{beforeId:t.id})};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(`div`,{className:`card`,style:{padding:`10px 14px`},children:(0,s.jsxs)(`div`,{className:`muted`,style:{fontSize:12},children:[`agent 用法:完成当前任务后,把`,(0,s.jsx)(`code`,{children:` nx-kv localtask wait --cwd "<工作目录>" --summary "<当前现状>" --json `}),`作为本轮`,(0,s.jsx)(`strong`,{children:`最后一个动作`}),`调用——工作目录即`,(0,s.jsx)(`strong`,{children:`主题`}),`、主题拥有任务队列, 同目录共用队列、不同目录互不串,任务可在队列里堆积;命令阻塞并自动打开浏览器弹窗, 用户回填后解除阻塞、返回新任务;超时未回填则返回 `,(0,s.jsx)(`code`,{children:`status:"timeout"`}),`,agent 收尾结束本轮。`]})}),(0,s.jsxs)(`div`,{className:`card`,style:{padding:`10px 14px`,display:`flex`,alignItems:`center`,gap:12,flexWrap:`wrap`},children:[(0,s.jsx)(`span`,{style:{fontWeight:700},children:`等待超时`}),(0,s.jsxs)(`select`,{value:ne,disabled:re,onChange:e=>le(e.target.value),style:{font:`inherit`,padding:`5px 8px`},children:[(0,s.jsx)(`option`,{value:60,children:`1 分钟`}),(0,s.jsx)(`option`,{value:120,children:`2 分钟`}),(0,s.jsx)(`option`,{value:180,children:`3 分钟(推荐)`}),(0,s.jsx)(`option`,{value:240,children:`4 分钟`}),(0,s.jsx)(`option`,{value:300,children:`5 分钟`}),(0,s.jsx)(`option`,{value:600,children:`10 分钟(最大)`})]}),(0,s.jsx)(`span`,{className:`muted`,style:{fontSize:12},children:`agent wait 未带 --timeout 时使用此值;推荐 3 分钟、最大 10 分钟。`})]}),(0,s.jsxs)(`div`,{className:`card`,style:{padding:`10px 14px`},children:[(0,s.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:12,flexWrap:`wrap`,marginBottom:x?10:0},children:[(0,s.jsx)(`span`,{style:{fontWeight:700},children:`收尾追加语`}),(0,s.jsx)(`span`,{className:`muted`,style:{fontSize:12},children:`每次 wait 返回任务时,自动拼到 task.text 末尾。强制 agent 计划最后再 wait 一次,避免长对话漂移漏调。`}),(0,s.jsxs)(`span`,{style:{marginLeft:`auto`,display:`flex`,gap:8,alignItems:`center`},children:[(0,s.jsx)(`span`,{className:`tag`+(b?``:` muted`),style:{fontSize:11},children:b?`已开启`:`已关闭`}),!x&&(0,s.jsxs)(s.Fragment,{children:[b&&(0,s.jsx)(`button`,{className:`btn small ghost`,onClick:()=>{w(v),S(!0)},children:`编辑`}),b?(0,s.jsx)(`button`,{className:`btn small ghost`,onClick:()=>ue(),disabled:T,title:`关闭后,wait 返回的任务不再追加提示词`,children:`关闭`}):(0,s.jsx)(`button`,{className:`btn small`,onClick:()=>{w(oe),S(!0)},title:`恢复默认收尾追加语并开启`,children:`开启`})]})]})]}),!x&&v&&(0,s.jsx)(`div`,{className:`muted`,style:{fontSize:12,whiteSpace:`pre-wrap`,borderLeft:`2px solid #eee`,padding:`4px 0 4px 10px`},children:v}),x&&(0,s.jsxs)(`div`,{children:[(0,s.jsx)(`textarea`,{value:C,onChange:e=>w(e.target.value),rows:5,style:{width:`100%`,font:`inherit`,padding:8,boxSizing:`border-box`},placeholder:`(留空 = 关闭;非空 = 启用并以这段文本作为追加语)`}),(0,s.jsxs)(`div`,{style:{display:`flex`,gap:8,marginTop:8,alignItems:`center`,flexWrap:`wrap`},children:[(0,s.jsx)(`button`,{className:`btn small`,onClick:()=>Y(C),disabled:T,children:`保存`}),(0,s.jsx)(`button`,{className:`btn small ghost`,onClick:()=>{S(!1),w(``)},disabled:T,children:`取消`}),(0,s.jsx)(`button`,{className:`btn small ghost`,onClick:()=>Y(oe),disabled:T,title:`覆盖为默认文案并开启`,children:`恢复默认`}),(0,s.jsx)(`span`,{className:`muted`,style:{fontSize:11,marginLeft:`auto`},children:`留空保存 = 关闭`})]})]})]}),(0,s.jsxs)(`div`,{className:`colhead`,children:[(0,s.jsx)(`input`,{type:`checkbox`,checked:pe,onChange:me,disabled:!J.length,title:`全选 / 取消全选`,style:{margin:0}}),(0,s.jsx)(`h3`,{children:`主题总览(按工作目录)`}),(0,s.jsxs)(`span`,{className:`muted`,style:{fontSize:11,display:`inline-flex`,alignItems:`center`,gap:4,color:D===`ok`?`#2a9d5c`:D===`reconnecting`?`#c0392b`:`#888`},title:D===`ok`?`实时连接正常(数据轮询可达后端)`:D===`reconnecting`?`连接断开,正在重连…`:`正在连接…`,children:[(0,s.jsx)(`span`,{style:{display:`inline-block`,width:8,height:8,borderRadius:`50%`,background:D===`ok`?`#2a9d5c`:D===`reconnecting`?`#c0392b`:`#aaa`}}),D===`ok`?`实时连接正常`:D===`reconnecting`?`连接断开,正在重连…`:`正在连接…`]}),(0,s.jsx)(`span`,{className:`muted`,children:c?` · ${J.length} 个 · 等待中 ${c.waiting}`:``}),(0,s.jsxs)(`span`,{style:{marginLeft:`auto`,display:`flex`,gap:8},children:[(0,s.jsx)(`button`,{className:`btn small ghost`,onClick:ye,disabled:!U.size||G,title:`删除勾选的主题(含其全部任务)`,children:G?`删除中…`:`批量删除${U.size?` (${U.size})`:``}`}),(0,s.jsx)(`button`,{className:`btn small ghost`,onClick:de,disabled:_,title:`清理旧模型无目录主题与空主题(等待中一律保留)`,children:_?`清理中…`:`清理旧数据`})]})]}),(0,s.jsx)(`div`,{style:{display:`flex`,gap:10,flexWrap:`wrap`,marginBottom:14},children:J.length?J.map(e=>{let t=e.key===u;return(0,s.jsxs)(`div`,{onClick:()=>d(e.key),className:`card`,style:{textAlign:`left`,width:270,padding:`10px 12px`,cursor:`pointer`,border:t?`1px solid var(--ink,#14161a)`:`1px solid transparent`,boxShadow:t?`0 0 0 2px rgba(20,22,26,.12)`:`0 1px 2px rgba(20,22,26,.06), 0 6px 16px rgba(20,22,26,.05)`},children:[(0,s.jsxs)(`div`,{style:{display:`flex`,gap:8,alignItems:`flex-start`},children:[(0,s.jsx)(`input`,{type:`checkbox`,checked:U.has(e.key),onChange:()=>fe(e.key),onClick:e=>e.stopPropagation(),title:`选择以批量删除`,style:{margin:`3px 0 0`}}),(0,s.jsxs)(`div`,{style:{flex:1,minWidth:0},children:[(0,s.jsx)(`div`,{style:{fontWeight:700,marginBottom:2},children:e.name||`(未命名)`}),(0,s.jsx)(`div`,{className:`mono muted`,title:e.cwd,style:{fontSize:11,wordBreak:`break-all`,marginBottom:6,minHeight:15},children:e.cwd||`(旧数据,无目录)`})]})]}),e.summary&&(0,s.jsxs)(`div`,{className:`muted`,style:{fontSize:11,whiteSpace:`pre-wrap`,marginBottom:6,cursor:`zoom-in`},title:`点击查看完整现状`,onClick:t=>{t.stopPropagation(),A({title:`主题「${e.name}」现状`,body:e.summary})},children:[`现状:`,e.summary]}),(0,s.jsxs)(`div`,{style:{display:`flex`,gap:6,alignItems:`center`,flexWrap:`wrap`},children:[e.waiting?(0,s.jsx)(`span`,{className:`tag strong`,children:ee(e)||l(e.waitingUntil)}):(0,s.jsx)(`span`,{className:`tag`,children:`已结束`}),(0,s.jsxs)(`span`,{className:`muted`,style:{fontSize:11},children:[`待领取 `,e.pending,`/`,e.total]})]}),(0,s.jsxs)(`div`,{style:{display:`flex`,justifyContent:`flex-end`,gap:6,marginTop:8},onClick:e=>e.stopPropagation(),children:[e.waiting&&(0,s.jsx)(`button`,{className:`btn small ghost`,onClick:()=>ve(e),title:`关闭本次等待(阻塞中的 wait 立即收尾,主题与任务保留)`,children:`关闭`}),(0,s.jsx)(`button`,{className:`btn small ghost`,onClick:()=>_e(e),disabled:G,title:`删除整个主题(含全部任务)`,children:`删除主题`})]})]},e.key)}):(0,s.jsx)(`div`,{className:`card muted`,style:{padding:`20px 16px`,width:`100%`,textAlign:`center`},children:`(暂无主题;agent 调用 localtask wait 后会出现在这里)`})}),X&&(0,s.jsxs)(s.Fragment,{children:[(0,s.jsxs)(`div`,{className:`toolbar`,children:[(0,s.jsx)(`span`,{style:{fontWeight:700,maxWidth:240},title:X.cwd,children:X.name}),(0,s.jsx)(`span`,{className:`sep`}),(0,s.jsx)(`textarea`,{style:{flex:1,minWidth:240,minHeight:40,resize:`vertical`},spellCheck:`false`,value:f,onChange:e=>p(e.target.value),onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),he())},placeholder:`向主题「${X.name}」的队列回填下一条任务(Enter 提交,Shift+Enter 换行)`}),(0,s.jsx)(`button`,{className:`btn`,onClick:he,disabled:m,children:m?`提交中…`:`回填新任务`})]}),(0,s.jsxs)(`div`,{className:`colhead`,children:[(0,s.jsx)(`h3`,{children:`该主题的任务队列`}),(0,s.jsxs)(`span`,{className:`muted`,children:[`待领取 `,X.pending,` · 共 `,X.total,` 条`]}),(0,s.jsx)(`span`,{className:`muted`,style:{fontSize:12,marginLeft:`auto`},children:`拖拽待领取行(或用「提前/置后」)调整领取优先级`})]}),(0,s.jsx)(`div`,{className:`card`,style:{padding:4},children:(0,s.jsxs)(`table`,{children:[(0,s.jsx)(`thead`,{children:(0,s.jsxs)(`tr`,{children:[(0,s.jsx)(`th`,{style:{width:34}}),(0,s.jsx)(`th`,{style:{width:56},children:`#`}),(0,s.jsx)(`th`,{children:`任务`}),(0,s.jsx)(`th`,{style:{width:80},children:`状态`}),(0,s.jsx)(`th`,{style:{width:160},children:`时间`}),(0,s.jsx)(`th`,{style:{width:150},children:`操作`})]})}),(0,s.jsx)(`tbody`,{children:Ce.length?Ce.map(e=>{let t=e.status!==`consumed`,n=L===e.id,r=z&&z.id===e.id;return(0,s.jsxs)(`tr`,{draggable:t&&j!==e.id,onDragStart:t=>{R(e.id),t.dataTransfer.effectAllowed=`move`;try{t.dataTransfer.setData(`text/plain`,String(e.id))}catch{}},onDragOver:t=>we(t,e),onDrop:t=>Te(t,e),onDragEnd:()=>{R(null),B(null)},style:{cursor:t&&j!==e.id?`grab`:`default`,opacity:n?.4:1,boxShadow:r?z.pos===`top`?`inset 0 2px 0 var(--ink,#14161a)`:`inset 0 -2px 0 var(--ink,#14161a)`:`none`,background:r?`rgba(20,22,26,.04)`:void 0},children:[(0,s.jsx)(`td`,{className:`mono muted`,title:`按住拖拽调整优先级`,style:{textAlign:`center`,userSelect:`none`},children:t?`⠿`:``}),(0,s.jsxs)(`td`,{className:`mono`,children:[`#`,e.id]}),(0,s.jsx)(`td`,{style:{whiteSpace:`pre-wrap`},children:j===e.id?(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(`textarea`,{value:N,onChange:e=>P(e.target.value),onKeyDown:e=>{e.key===`Enter`&&(e.ctrlKey||e.metaKey)&&(e.preventDefault(),Se()),e.key===`Escape`&&xe()},spellCheck:`false`,autoFocus:!0,style:{width:`100%`,minHeight:60,resize:`vertical`}}),(0,s.jsxs)(`div`,{style:{display:`flex`,gap:8,marginTop:6},children:[(0,s.jsx)(`button`,{className:`btn small`,onClick:Se,disabled:F,children:F?`保存中…`:`保存`}),(0,s.jsx)(`button`,{className:`btn small ghost`,onClick:xe,disabled:F,children:`取消`}),(0,s.jsx)(`span`,{className:`muted`,style:{fontSize:11,alignSelf:`center`},children:`Ctrl+Enter 保存 · Esc 取消`})]})]}):(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(`span`,{style:{cursor:e.text.length>50?`zoom-in`:`default`},onClick:t=>{t.stopPropagation(),e.text.length>50&&A({title:`任务 #${e.id} 全文`,body:e.text})},title:e.text.length>50?`点击查看完整任务文本`:void 0,children:e.text}),e.roundSummary&&(0,s.jsxs)(`div`,{className:`muted`,style:{fontSize:11,marginTop:4,paddingTop:4,borderTop:`1px dashed var(--line,#e6e8eb)`,whiteSpace:`pre-wrap`,cursor:`zoom-in`},title:`点击查看完整上一轮总结`,onClick:t=>{t.stopPropagation(),A({title:`上一轮完成总结`,body:e.roundSummary})},children:[`上一轮完成:`,e.roundSummary]})]})}),(0,s.jsx)(`td`,{children:e.status===`consumed`?(0,s.jsx)(`span`,{className:`tag strong`,children:`已领取`}):(0,s.jsx)(`span`,{className:`tag`,children:`待领取`})}),(0,s.jsx)(`td`,{className:`mono`,children:e.consumedAt||e.createdAt}),(0,s.jsxs)(`td`,{className:`ops`,children:[t&&j!==e.id&&(()=>{let t=Z.findIndex(t=>t.id===e.id);return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(`button`,{className:`btn small ghost`,onClick:()=>be(e),children:`编辑`}),(0,s.jsx)(`button`,{className:`btn small ghost`,title:`提高优先级(更早被领取)`,disabled:V||t<=0,onClick:()=>$(e,`up`),children:`提前`}),(0,s.jsx)(`button`,{className:`btn small ghost`,title:`降低优先级(更晚被领取)`,disabled:V||t>=Z.length-1,onClick:()=>$(e,`down`),children:`置后`})]})})(),(0,s.jsx)(`button`,{className:`btn small ghost`,onClick:()=>ge(e.id),children:`删除`})]})]},e.id)}):(0,s.jsx)(`tr`,{children:(0,s.jsx)(`td`,{colSpan:`6`,className:`muted`,style:{textAlign:`center`,padding:`22px 0`},children:`(暂无任务,在上方回填第一条)`})})})]})})]}),(0,s.jsx)(a,{module:`localtask`}),k&&(0,s.jsx)(`div`,{onClick:()=>A(null),style:{position:`fixed`,inset:0,background:`rgba(0,0,0,0.4)`,display:`flex`,alignItems:`center`,justifyContent:`center`,zIndex:1e3},children:(0,s.jsxs)(`div`,{onClick:e=>e.stopPropagation(),style:{background:`#fff`,borderRadius:8,padding:20,maxWidth:`min(720px, 90vw)`,maxHeight:`80vh`,overflow:`auto`,boxShadow:`0 12px 40px rgba(0,0,0,0.25)`},children:[(0,s.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,marginBottom:12},children:[(0,s.jsx)(`strong`,{style:{fontSize:14},children:k.title}),(0,s.jsx)(`button`,{className:`btn small ghost`,onClick:()=>A(null),style:{marginLeft:`auto`},children:`关闭`})]}),(0,s.jsx)(`div`,{style:{fontSize:13,lineHeight:1.6,whiteSpace:`pre-wrap`,wordBreak:`break-word`},children:k.body})]})})]})}export{te as default};
@@ -1 +1 @@
1
- import{a as e,c as t,i as n,l as r,o as i,s as a,t as o}from"./index-Iz1qH6TC.js";import{t as s}from"./CliHints-DNK3TaU5.js";var c=r(),l=a();function u(){let{boot:r,refreshBoot:a}=i(),u=e(),d=n(),[f,p]=(0,c.useState)(r?.email||``),[m,h]=(0,c.useState)(``),[g,_]=(0,c.useState)(!1),v=()=>d(async()=>{if(!f.trim()){u(`请填邮箱`);return}if(!m){u(`请填密码`);return}_(!0);try{let e=await t(`/api/auth/login`,{method:`POST`,body:{email:f.trim(),password:m}});h(``),u(`已登录: ${e.email}`),await a()}finally{_(!1)}});return(0,l.jsxs)(l.Fragment,{children:[(0,l.jsxs)(`div`,{className:`card`,children:[(0,l.jsxs)(`div`,{className:`colhead`,children:[(0,l.jsx)(`h3`,{children:`登录态`}),(0,l.jsx)(`span`,{className:r?.loggedIn?`tag strong`:`tag bad`,children:r?.loggedIn?`已登录`:`未登录`})]}),(0,l.jsxs)(`div`,{className:`settings`,children:[(0,l.jsx)(`dt`,{children:`账号`}),(0,l.jsx)(`dd`,{children:r?.email||(0,l.jsx)(`span`,{className:`muted`,children:`(未登录)`})}),(0,l.jsx)(`dt`,{children:`userId`}),(0,l.jsx)(`dd`,{children:r?.userId||`-`}),(0,l.jsx)(`dt`,{children:`后端`}),(0,l.jsx)(`dd`,{className:`mono`,children:(0,l.jsx)(o,{text:r?.baseUrl,children:r?.baseUrl})}),(0,l.jsx)(`dt`,{children:`本机配置`}),(0,l.jsx)(`dd`,{className:`mono`,children:(0,l.jsx)(o,{text:r?.configPath,children:r?.configPath})})]})]}),(0,l.jsxs)(`div`,{className:`card`,children:[(0,l.jsx)(`div`,{className:`colhead`,children:(0,l.jsx)(`h3`,{children:r?.loggedIn?`切换账号`:`登录`})}),(0,l.jsxs)(`div`,{className:`row-inline`,style:{padding:12},children:[(0,l.jsx)(`input`,{placeholder:`邮箱`,size:`24`,spellCheck:`false`,value:f,onChange:e=>p(e.target.value)}),(0,l.jsx)(`input`,{placeholder:`密码`,type:`password`,size:`18`,value:m,onChange:e=>h(e.target.value),onKeyDown:e=>{e.key===`Enter`&&v()}}),(0,l.jsx)(`button`,{className:`btn`,onClick:v,disabled:g,children:g?`登录中…`:`登录`}),r?.loggedIn?(0,l.jsx)(`button`,{className:`btn ghost danger`,onClick:()=>d(async()=>{await t(`/api/auth/logout`,{method:`POST`}),u(`已登出`),await a()}),children:`登出`}):null]}),(0,l.jsxs)(`div`,{className:`muted`,style:{padding:`0 12px 12px`,fontSize:12},children:[`密码只用于本次请求,不写入本机配置;配置里只保存 token。 也可以用 CLI:`,(0,l.jsx)(`code`,{children:`nx-kv auth login <email>`}),`(会交互式隐藏输入密码)。`]})]}),(0,l.jsx)(s,{module:`auth`})]})}export{u as default};
1
+ import{a as e,c as t,i as n,l as r,o as i,s as a,t as o}from"./index-2OK9SG2y.js";import{t as s}from"./CliHints-D70_R4vQ.js";var c=r(),l=a();function u(){let{boot:r,refreshBoot:a}=i(),u=e(),d=n(),[f,p]=(0,c.useState)(r?.email||``),[m,h]=(0,c.useState)(``),[g,_]=(0,c.useState)(!1),v=()=>d(async()=>{if(!f.trim()){u(`请填邮箱`);return}if(!m){u(`请填密码`);return}_(!0);try{let e=await t(`/api/auth/login`,{method:`POST`,body:{email:f.trim(),password:m}});h(``),u(`已登录: ${e.email}`),await a()}finally{_(!1)}});return(0,l.jsxs)(l.Fragment,{children:[(0,l.jsxs)(`div`,{className:`card`,children:[(0,l.jsxs)(`div`,{className:`colhead`,children:[(0,l.jsx)(`h3`,{children:`登录态`}),(0,l.jsx)(`span`,{className:r?.loggedIn?`tag strong`:`tag bad`,children:r?.loggedIn?`已登录`:`未登录`})]}),(0,l.jsxs)(`div`,{className:`settings`,children:[(0,l.jsx)(`dt`,{children:`账号`}),(0,l.jsx)(`dd`,{children:r?.email||(0,l.jsx)(`span`,{className:`muted`,children:`(未登录)`})}),(0,l.jsx)(`dt`,{children:`userId`}),(0,l.jsx)(`dd`,{children:r?.userId||`-`}),(0,l.jsx)(`dt`,{children:`后端`}),(0,l.jsx)(`dd`,{className:`mono`,children:(0,l.jsx)(o,{text:r?.baseUrl,children:r?.baseUrl})}),(0,l.jsx)(`dt`,{children:`本机配置`}),(0,l.jsx)(`dd`,{className:`mono`,children:(0,l.jsx)(o,{text:r?.configPath,children:r?.configPath})})]})]}),(0,l.jsxs)(`div`,{className:`card`,children:[(0,l.jsx)(`div`,{className:`colhead`,children:(0,l.jsx)(`h3`,{children:r?.loggedIn?`切换账号`:`登录`})}),(0,l.jsxs)(`div`,{className:`row-inline`,style:{padding:12},children:[(0,l.jsx)(`input`,{placeholder:`邮箱`,size:`24`,spellCheck:`false`,value:f,onChange:e=>p(e.target.value)}),(0,l.jsx)(`input`,{placeholder:`密码`,type:`password`,size:`18`,value:m,onChange:e=>h(e.target.value),onKeyDown:e=>{e.key===`Enter`&&v()}}),(0,l.jsx)(`button`,{className:`btn`,onClick:v,disabled:g,children:g?`登录中…`:`登录`}),r?.loggedIn?(0,l.jsx)(`button`,{className:`btn ghost danger`,onClick:()=>d(async()=>{await t(`/api/auth/logout`,{method:`POST`}),u(`已登出`),await a()}),children:`登出`}):null]}),(0,l.jsxs)(`div`,{className:`muted`,style:{padding:`0 12px 12px`,fontSize:12},children:[`密码只用于本次请求,不写入本机配置;配置里只保存 token。 也可以用 CLI:`,(0,l.jsx)(`code`,{children:`nx-kv auth login <email>`}),`(会交互式隐藏输入密码)。`]})]}),(0,l.jsx)(s,{module:`auth`})]})}export{u as default};
@@ -1,2 +1,2 @@
1
- import{a as e,c as t,i as n,l as r,n as i,o as a,r as o,s,t as c}from"./index-Iz1qH6TC.js";import{t as l}from"./CliHints-DNK3TaU5.js";var u=r(),d=s(),f=[[`open`,`待办`],[`done`,`已完成`],[`freeze`,`冻结`]],p=e=>e?String(e).slice(0,16).replace(`T`,` `):``,m=15,h=(e,t)=>`${e}:${t.id}:${t.text}`;function g({bucket:e,task:t,dupCount:n,onAct:r}){let i=e===`done`,a=e===`freeze`,o=i?t.doneAt:a?t.frozenAt:t.createdAt;return(0,d.jsxs)(`div`,{className:`row`,children:[(0,d.jsxs)(`span`,{className:`tid`,children:[`#`,t.id]}),(0,d.jsx)(c,{className:`topic`,text:t.topic,title:`点击复制主题`,children:t.topic}),(0,d.jsx)(`span`,{className:`text`,title:t.text,children:t.text}),n>1?(0,d.jsxs)(`span`,{className:`tag`,title:`同内容有 ${n} 条,操作时需要消歧`,children:[`同内容×`,n]}):null,(0,d.jsx)(`span`,{className:`muted time`,children:p(o)}),(0,d.jsxs)(`span`,{className:`acts`,children:[e===`open`?(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(`button`,{className:`btn small`,onClick:()=>r(`done`,t),children:`完成`}),(0,d.jsx)(`button`,{className:`btn small ghost`,onClick:()=>r(`freeze`,t),children:`冻结`})]}):null,a?(0,d.jsx)(`button`,{className:`btn small`,onClick:()=>r(`unfreeze`,t),children:`解冻`}):null,(0,d.jsx)(`button`,{className:`btn small ghost`,onClick:()=>r(`edit`,t,e),children:`编辑`}),(0,d.jsx)(`button`,{className:`btn small ghost danger`,onClick:()=>r(`remove`,t,e),children:`删除`})]}),t.note?(0,d.jsx)(`div`,{className:`note`,children:t.note}):null]})}function _(){let{boot:r,ui:s,patchUi:c,refreshBoot:_}=a(),v=e(),y=n(),{dialog:b,node:x}=o(),[S,C]=(0,u.useState)(null),[w,T]=(0,u.useState)(!1),[E,D]=(0,u.useState)({topic:``,text:``}),[O,k]=(0,u.useState)(null),[A,j]=(0,u.useState)({}),M=r?.groupId??0,N=(r?.groups||[]).find(e=>e.id===M)?.name||(M?`#${M}`:`默认组`),P=(0,u.useCallback)(async()=>{if(r?.loggedIn)try{C(await t(`/api/todo`))}catch(e){v(e.message)}},[r?.loggedIn,v]);(0,u.useEffect)(()=>{P()},[P,M]);let F=(0,u.useCallback)(async()=>{T(!0);try{await P()}finally{T(!1)}},[P]),I=(0,u.useMemo)(()=>{let e=new Map;if(!S)return e;for(let[t]of f)for(let n of S[t]||[])e.set(n.text,(e.get(n.text)||0)+1);return e},[S]),L=(0,u.useMemo)(()=>{if(!S)return null;let e=s.topic,t=t=>t?e?t.filter(t=>t.topic===e):t:null;return{open:t(S.open),done:t(S.done),freeze:t(S.freeze)}},[S,s.topic]);if(!r?.loggedIn)return(0,d.jsxs)(`div`,{className:`card`,style:{padding:16},children:[(0,d.jsx)(`div`,{className:`colhead`,children:(0,d.jsx)(`h3`,{children:`请先登录`})}),(0,d.jsxs)(`div`,{className:`muted`,children:[`在「登录」页填写邮箱与密码,或执行 `,(0,d.jsx)(`code`,{children:`nx-kv auth login <email>`}),`。`]})]});let R=async(e,t)=>{let n=[];for(let[t]of f)for(let r of S[t]||[])r.text===e.text&&n.push({bucket:t,task:r});if(n.length<=1)return{bucket:t,task:e,pick:void 0};let r=n.findIndex(n=>n.bucket===t&&n.task.createdAt===e.createdAt),i=await b({title:`「${e.text.slice(0,30)}」有 ${n.length} 条,选哪一条?`,message:n.map((e,t)=>`[${t}] ${e.bucket} ${p(e.task.createdAt)} #${e.task.id}`).join(`
1
+ import{a as e,c as t,i as n,l as r,n as i,o as a,r as o,s,t as c}from"./index-2OK9SG2y.js";import{t as l}from"./CliHints-D70_R4vQ.js";var u=r(),d=s(),f=[[`open`,`待办`],[`done`,`已完成`],[`freeze`,`冻结`]],p=e=>e?String(e).slice(0,16).replace(`T`,` `):``,m=15,h=(e,t)=>`${e}:${t.id}:${t.text}`;function g({bucket:e,task:t,dupCount:n,onAct:r}){let i=e===`done`,a=e===`freeze`,o=i?t.doneAt:a?t.frozenAt:t.createdAt;return(0,d.jsxs)(`div`,{className:`row`,children:[(0,d.jsxs)(`span`,{className:`tid`,children:[`#`,t.id]}),(0,d.jsx)(c,{className:`topic`,text:t.topic,title:`点击复制主题`,children:t.topic}),(0,d.jsx)(`span`,{className:`text`,title:t.text,children:t.text}),n>1?(0,d.jsxs)(`span`,{className:`tag`,title:`同内容有 ${n} 条,操作时需要消歧`,children:[`同内容×`,n]}):null,(0,d.jsx)(`span`,{className:`muted time`,children:p(o)}),(0,d.jsxs)(`span`,{className:`acts`,children:[e===`open`?(0,d.jsxs)(d.Fragment,{children:[(0,d.jsx)(`button`,{className:`btn small`,onClick:()=>r(`done`,t),children:`完成`}),(0,d.jsx)(`button`,{className:`btn small ghost`,onClick:()=>r(`freeze`,t),children:`冻结`})]}):null,a?(0,d.jsx)(`button`,{className:`btn small`,onClick:()=>r(`unfreeze`,t),children:`解冻`}):null,(0,d.jsx)(`button`,{className:`btn small ghost`,onClick:()=>r(`edit`,t,e),children:`编辑`}),(0,d.jsx)(`button`,{className:`btn small ghost danger`,onClick:()=>r(`remove`,t,e),children:`删除`})]}),t.note?(0,d.jsx)(`div`,{className:`note`,children:t.note}):null]})}function _(){let{boot:r,ui:s,patchUi:c,refreshBoot:_}=a(),v=e(),y=n(),{dialog:b,node:x}=o(),[S,C]=(0,u.useState)(null),[w,T]=(0,u.useState)(!1),[E,D]=(0,u.useState)({topic:``,text:``}),[O,k]=(0,u.useState)(null),[A,j]=(0,u.useState)({}),M=r?.groupId??0,N=(r?.groups||[]).find(e=>e.id===M)?.name||(M?`#${M}`:`默认组`),P=(0,u.useCallback)(async()=>{if(r?.loggedIn)try{C(await t(`/api/todo`))}catch(e){v(e.message)}},[r?.loggedIn,v]);(0,u.useEffect)(()=>{P()},[P,M]);let F=(0,u.useCallback)(async()=>{T(!0);try{await P()}finally{T(!1)}},[P]),I=(0,u.useMemo)(()=>{let e=new Map;if(!S)return e;for(let[t]of f)for(let n of S[t]||[])e.set(n.text,(e.get(n.text)||0)+1);return e},[S]),L=(0,u.useMemo)(()=>{if(!S)return null;let e=s.topic,t=t=>t?e?t.filter(t=>t.topic===e):t:null;return{open:t(S.open),done:t(S.done),freeze:t(S.freeze)}},[S,s.topic]);if(!r?.loggedIn)return(0,d.jsxs)(`div`,{className:`card`,style:{padding:16},children:[(0,d.jsx)(`div`,{className:`colhead`,children:(0,d.jsx)(`h3`,{children:`请先登录`})}),(0,d.jsxs)(`div`,{className:`muted`,children:[`在「登录」页填写邮箱与密码,或执行 `,(0,d.jsx)(`code`,{children:`nx-kv auth login <email>`}),`。`]})]});let R=async(e,t)=>{let n=[];for(let[t]of f)for(let r of S[t]||[])r.text===e.text&&n.push({bucket:t,task:r});if(n.length<=1)return{bucket:t,task:e,pick:void 0};let r=n.findIndex(n=>n.bucket===t&&n.task.createdAt===e.createdAt),i=await b({title:`「${e.text.slice(0,30)}」有 ${n.length} 条,选哪一条?`,message:n.map((e,t)=>`[${t}] ${e.bucket} ${p(e.task.createdAt)} #${e.task.id}`).join(`
2
2
  `),input:!0,placeholder:`输入 0..${n.length-1}`,value:String(r>=0?r:0)});if(i===null)return null;let a=Number(i);return!Number.isInteger(a)||!n[a]?(v(`请输入 0..${n.length-1}`),null):{...n[a],pick:a}},z=(e,n,r)=>y(async()=>{let i=e===`remove`||e===`edit`?await R(n,r):{bucket:r,task:n,pick:void 0};if(!i)return;let a={group:M,ref:i.task.text,pick:i.pick};if(e===`done`){let e=await b({title:`完成结果`,message:`完成「${n.text.slice(0,40)}」`,input:!0,placeholder:`可选:写一句完成结果`});if(e===null)return;await t(`/api/todo/done`,{method:`POST`,body:{...a,result:e||void 0}}),v(`已完成`)}else if(e===`freeze`)await t(`/api/todo/freeze`,{method:`POST`,body:a}),v(`已冻结`);else if(e===`unfreeze`)await t(`/api/todo/unfreeze`,{method:`POST`,body:a}),v(`已解冻`);else if(e===`remove`){if(!await b({message:`删除「${n.text.slice(0,40)}」?`,danger:!0}))return;await t(`/api/todo/item`,{method:`DELETE`,body:a}),v(`已删除`)}else if(e===`edit`){let e=await b({title:`编辑内容`,input:!0,value:i.task.text});if(e===null||!e)return;await t(`/api/todo/item`,{method:`PATCH`,body:{...a,text:e,matchTopic:i.task.topic}}),v(`已更新`)}await F(),await _()}),B=()=>y(async()=>{let e=await b({title:`归档已完成的旧记录`,message:`把「完成时间早于该日期」的记录移到冷 key(默认 30 天前)。留空用默认值。`,input:!0,placeholder:`YYYY-MM-DD,留空 = 30 天前`});if(e===null)return;let n=await t(`/api/todo/archive`,{method:`POST`,body:{before:e.trim()||void 0,group:M}});v(n.moved?`已归档 ${n.moved} 条 → ${n.coldKey}`:`没有需要归档的记录`),await F()}),V=()=>y(async()=>{let e=E.topic.trim(),n=E.text.trim();if(!e){v(`请填主题`);return}if(!n){v(`请填内容`);return}let r=await t(`/api/todo`,{method:`POST`,body:{topic:e,text:n,group:M}});D({topic:e,text:``}),v(`已加入待办${r.topicAdded?`(新主题 ${e})`:``}`),await F()}),H=(e,t)=>A[e]?t:t.slice(0,m),U=S?.topics||[],W=L?f.map(([e,t])=>`${t} ${(L[e]||[]).length}`).join(` · `):``;return(0,d.jsxs)(d.Fragment,{children:[(0,d.jsxs)(`div`,{className:`toolbar`,children:[(0,d.jsx)(`label`,{children:`工作空间`}),(0,d.jsx)(`span`,{className:`pill on`,children:N}),(0,d.jsx)(`span`,{className:`sep`}),(0,d.jsx)(`label`,{children:`主题`}),(0,d.jsxs)(`select`,{value:s.topic,onChange:e=>c({topic:e.target.value}),children:[(0,d.jsx)(`option`,{value:``,children:`全部`}),U.map(e=>(0,d.jsx)(`option`,{value:e,children:e},e))]}),(0,d.jsx)(`span`,{className:`sep`}),(0,d.jsx)(`input`,{placeholder:`主题`,size:`8`,value:E.topic,onChange:e=>D({...E,topic:e.target.value})}),(0,d.jsx)(`input`,{placeholder:`要做什么…`,size:`30`,value:E.text,onChange:e=>D({...E,text:e.target.value}),onKeyDown:e=>{e.key===`Enter`&&V()}}),(0,d.jsx)(`button`,{className:`btn`,onClick:V,children:`加入待办`}),(0,d.jsx)(`button`,{className:`btn ghost`,onClick:F,disabled:w,children:w?`刷新中…`:`刷新`})]}),(0,d.jsx)(`div`,{className:`muted`,style:{margin:`0 0 8px 2px`,fontSize:12},children:W}),(0,d.jsx)(`div`,{className:`cols`,children:f.map(([e,t])=>(0,d.jsxs)(`div`,{className:`col`,children:[(0,d.jsxs)(`div`,{className:`colhead`,children:[(0,d.jsx)(`h3`,{children:t}),(0,d.jsx)(`span`,{className:`muted`,children:(L?.[e]||[]).length}),e===`done`&&(L?.done||[]).length?(0,d.jsx)(`button`,{className:`btn small ghost`,style:{marginLeft:`auto`},onClick:B,title:`把较旧的完成记录移到冷 key`,children:`归档旧记录`}):null]}),(0,d.jsxs)(`div`,{className:`card list`,children:[(L?.[e]||[]).length?H(e,L[e]).map(t=>(0,d.jsx)(g,{bucket:e,task:t,dupCount:I.get(t.text)||1,onAct:z},h(e,t))):(0,d.jsx)(`div`,{className:`row muted`,children:`(空)`}),(L?.[e]||[]).length>m?(0,d.jsx)(`div`,{className:`row muted`,style:{cursor:`pointer`,justifyContent:`center`},onClick:()=>j(t=>({...t,[e]:!t[e]})),children:A[e]?`收起`:`还有 ${L[e].length-m} 条,点击展开`}):null]})]},e))}),(0,d.jsx)(l,{module:`todo`}),O?(0,d.jsx)(i,{title:O.title,onClose:()=>k(null),children:O.node}):null,x]})}export{_ as default};
@@ -12,7 +12,7 @@
12
12
  <!-- .ico 兜底:浏览器不认上面的 <link> 时会自己请求 /favicon.ico -->
13
13
  <link rel="icon" type="image/x-icon" href="/favicon.ico">
14
14
  <link rel="apple-touch-icon" sizes="512x512" href="/logo-rounded.png">
15
- <script type="module" crossorigin src="/assets/index-Iz1qH6TC.js"></script>
15
+ <script type="module" crossorigin src="/assets/index-2OK9SG2y.js"></script>
16
16
  <link rel="stylesheet" crossorigin href="/assets/index-CmCYxz0e.css">
17
17
  </head>
18
18
  <body>
@@ -1 +0,0 @@
1
- import{a as e,c as t,i as n,l as r,s as i}from"./index-Iz1qH6TC.js";import{t as a}from"./CliHints-DNK3TaU5.js";var o=r(),s=i();function c(e){let t=/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/.exec(e||``);return t?new Date(+t[1],t[2]-1,+t[3],+t[4],+t[5],+t[6]):null}function l(e){let t=c(e);if(!t)return``;let n=t.getTime()-Date.now();if(n<=0)return`等待中 0:00`;let r=Math.floor(n/6e4),i=Math.floor(n%6e4/1e3);return`等待中 ${r}:${String(i).padStart(2,`0`)}`}function ee(e){if(!e||!e.waiting)return null;let t=l(e.waitingUntil);if(!e.waitingSince)return t;let n=c(e.waitingSince);if(!n)return t;let r=Date.now()-n.getTime();if(r<0)return t;let i=Math.floor(r/6e4),a=Math.floor(r%6e4/1e3);return`等待中 已等 ${i}:${String(a).padStart(2,`0`)} · 剩 ${t.replace(/^等待中\s*/,``)}`}function u(){let r=e(),i=n(),[c,u]=(0,o.useState)(null),[d,f]=(0,o.useState)(null),[p,m]=(0,o.useState)(``),[h,g]=(0,o.useState)(!1),[te,_]=(0,o.useState)(180),[ne,v]=(0,o.useState)(!1),[y,b]=(0,o.useState)(!1),[x,S]=(0,o.useState)(``),[re,ie]=(0,o.useState)(``),[C,w]=(0,o.useState)(!1),[T,E]=(0,o.useState)(!1),[D,O]=(0,o.useState)(``),[k,A]=(0,o.useState)(!1),[j,M]=(0,o.useState)(null),[N,P]=(0,o.useState)(``),[F,I]=(0,o.useState)(!1),[L,R]=(0,o.useState)(null),[z,B]=(0,o.useState)(null),[V,H]=(0,o.useState)(!1),[U,W]=(0,o.useState)(()=>new Set),[G,K]=(0,o.useState)(!1),q=(0,o.useCallback)(async()=>{try{u(await t(`/api/localtasks`))}catch(e){r(e.message)}},[r]);(0,o.useEffect)(()=>{q()},[q]),(0,o.useEffect)(()=>{let e=setInterval(q,1500);return()=>clearInterval(e)},[q]);let J=c?c.topics:[];(0,o.useEffect)(()=>{c&&c.settings&&(_(c.settings.timeoutSec),S(c.settings.taskSuffix||``),ie(c.settings.defaultTaskSuffix||``),w(!!c.settings.suffixEnabled))},[c]);let ae=e=>i(async()=>{_(Number(e)),v(!0);try{let n=await t(`/api/localtasks/setting`,{method:`PATCH`,body:{timeout:Number(e)}});_(n.timeoutSec),r(`等待超时已配置为 ${n.timeoutSec} 秒`)}finally{v(!1)}}),Y=e=>i(async()=>{A(!0);try{let n=await t(`/api/localtasks/setting`,{method:`PATCH`,body:{suffix:e}});S(n.taskSuffix),w(!!n.suffixEnabled),E(!1),O(``),r(n.suffixEnabled?`收尾追加语已更新`:`收尾追加语已关闭`),await q()}finally{A(!1)}}),oe=()=>Y(``),se=()=>i(async()=>{b(!0);try{let e=await t(`/api/localtasks/prune`,{method:`POST`,body:{}});r(e.count?`已清理 ${e.count} 个旧主题`:`没有需要清理的旧数据`),await q()}finally{b(!1)}});(0,o.useEffect)(()=>{if(!J.length){f(null);return}if(d&&J.some(e=>e.key===d))return;let e=J.find(e=>e.waiting)||J[0];f(e.key)},[J,d]),(0,o.useEffect)(()=>{W(e=>{let t=new Set([...e].filter(e=>J.some(t=>t.key===e)));return t.size===e.size?e:t})},[J]);let X=J.find(e=>e.key===d)||null,ce=e=>W(t=>{let n=new Set(t);return n.has(e)?n.delete(e):n.add(e),n}),le=J.length>0&&U.size===J.length,ue=()=>W(le?new Set:new Set(J.map(e=>e.key))),de=()=>i(async()=>{let e=p.trim();if(!e){r(`请输入任务内容`);return}if(!X){r(`请先选择一个主题(工作目录)`);return}g(!0);try{let n=await t(`/api/localtasks`,{method:`POST`,body:{cwd:X.cwd,text:e}});m(``),r(n.delivered?`已返回给等待中的 agent`:`已排入该主题队列,等待 agent 下一次 wait`),await q()}finally{g(!1)}}),fe=e=>i(async()=>{await t(`/api/localtasks/item`,{method:`DELETE`,body:{cwd:X.cwd,id:e}}),r(`已删除`),await q()}),pe=e=>i(async()=>{let n=e.waiting?`主题「${e.name}」正在等待中,删除后其 agent 将超时收尾,确认删除?`:`删除主题「${e.name}」及其全部 ${e.total} 条任务?`;if(window.confirm(n)){K(!0);try{await t(`/api/localtasks/topic`,{method:`DELETE`,body:e.waiting?{key:e.key,force:!0}:{key:e.key}}),W(t=>{let n=new Set(t);return n.delete(e.key),n}),r(`已删除主题`),await q()}finally{K(!1)}}}),me=e=>i(async()=>{if(!e||!e.waiting)return;let n=`关闭主题「${e.name}」的等待?\n\n阻塞中的 wait 立即收尾(走与超时同一条出口,agent 照常结束本轮),主题与任务都保留。`;if(!window.confirm(n))return;let i=await t(`/api/localtasks/cancel`,{method:`POST`,body:{key:e.key}});i&&i.cancelled?r(`已关闭等待`):r(`该主题不在等待中`),await q()}),he=()=>i(async()=>{if(!U.size)return;let e=J.filter(e=>U.has(e.key)),n=e.filter(e=>e.waiting).length,i=`确认删除选中的 ${e.length} 个主题?`;if(n&&(i+=`(其中 ${n} 个等待中,删除后其 agent 将超时收尾)`),window.confirm(i)){K(!0);try{let e=await t(`/api/localtasks/topics/remove`,{method:`POST`,body:{keys:[...U],force:n>0}});r(`已删除 ${e.count} 个主题`+(e.skipped.length?`,跳过 ${e.skipped.length} 个`:``)),W(new Set),await q()}finally{K(!1)}}}),ge=e=>{M(e.id),P(e.text)},Z=()=>{M(null),P(``)},_e=()=>i(async()=>{let e=N.trim();if(!e){r(`任务内容不能为空`);return}I(!0);try{await t(`/api/localtasks/item`,{method:`PATCH`,body:{cwd:X.cwd,id:j,text:e}}),r(`已保存修改`),M(null),await q()}finally{I(!1)}}),ve=X?X.tasks.slice().reverse():[],Q=X?X.tasks.filter(e=>e.status!==`consumed`):[],$=(e,{beforeId:n,afterId:a})=>i(async()=>{H(!0);try{await t(`/api/localtasks/reorder`,{method:`PATCH`,body:{cwd:X.cwd,id:e,beforeId:n,afterId:a}}),r(`已调整领取优先级`),await q()}finally{H(!1),R(null),B(null)}}),ye=(e,t)=>{let n=Q.findIndex(t=>t.id===e.id);t===`up`&&n>0&&$(e.id,{beforeId:Q[n-1].id}),t===`down`&&n<Q.length-1&&$(e.id,{afterId:Q[n+1].id})},be=(e,t)=>{if(L===null||t.status===`consumed`||L===t.id)return;e.preventDefault(),e.dataTransfer.dropEffect=`move`;let n=e.currentTarget.getBoundingClientRect(),r=e.clientY<n.top+n.height/2?`top`:`bottom`;B(e=>e&&e.id===t.id&&e.pos===r?e:{id:t.id,pos:r})},xe=(e,t)=>{if(L===null||t.status===`consumed`||L===t.id)return;e.preventDefault();let n=e.currentTarget.getBoundingClientRect(),r=e.clientY<n.top+n.height/2,i=L;R(null),B(null),$(i,r?{afterId:t.id}:{beforeId:t.id})};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(`div`,{className:`card`,style:{padding:`10px 14px`},children:(0,s.jsxs)(`div`,{className:`muted`,style:{fontSize:12},children:[`agent 用法:完成当前任务后,把`,(0,s.jsx)(`code`,{children:` nx-kv localtask wait --cwd "<工作目录>" --summary "<当前现状>" --json `}),`作为本轮`,(0,s.jsx)(`strong`,{children:`最后一个动作`}),`调用——工作目录即`,(0,s.jsx)(`strong`,{children:`主题`}),`、主题拥有任务队列, 同目录共用队列、不同目录互不串,任务可在队列里堆积;命令阻塞并自动打开浏览器弹窗, 用户回填后解除阻塞、返回新任务;超时未回填则返回 `,(0,s.jsx)(`code`,{children:`status:"timeout"`}),`,agent 收尾结束本轮。`]})}),(0,s.jsxs)(`div`,{className:`card`,style:{padding:`10px 14px`,display:`flex`,alignItems:`center`,gap:12,flexWrap:`wrap`},children:[(0,s.jsx)(`span`,{style:{fontWeight:700},children:`等待超时`}),(0,s.jsxs)(`select`,{value:te,disabled:ne,onChange:e=>ae(e.target.value),style:{font:`inherit`,padding:`5px 8px`},children:[(0,s.jsx)(`option`,{value:60,children:`1 分钟`}),(0,s.jsx)(`option`,{value:120,children:`2 分钟`}),(0,s.jsx)(`option`,{value:180,children:`3 分钟(推荐)`}),(0,s.jsx)(`option`,{value:240,children:`4 分钟`}),(0,s.jsx)(`option`,{value:300,children:`5 分钟`}),(0,s.jsx)(`option`,{value:600,children:`10 分钟(最大)`})]}),(0,s.jsx)(`span`,{className:`muted`,style:{fontSize:12},children:`agent wait 未带 --timeout 时使用此值;推荐 3 分钟、最大 10 分钟。`})]}),(0,s.jsxs)(`div`,{className:`card`,style:{padding:`10px 14px`},children:[(0,s.jsxs)(`div`,{style:{display:`flex`,alignItems:`center`,gap:12,flexWrap:`wrap`,marginBottom:T?10:0},children:[(0,s.jsx)(`span`,{style:{fontWeight:700},children:`收尾追加语`}),(0,s.jsx)(`span`,{className:`muted`,style:{fontSize:12},children:`每次 wait 返回任务时,自动拼到 task.text 末尾。强制 agent 计划最后再 wait 一次,避免长对话漂移漏调。`}),(0,s.jsxs)(`span`,{style:{marginLeft:`auto`,display:`flex`,gap:8,alignItems:`center`},children:[(0,s.jsx)(`span`,{className:`tag`+(C?``:` muted`),style:{fontSize:11},children:C?`已开启`:`已关闭`}),!T&&(0,s.jsxs)(s.Fragment,{children:[C&&(0,s.jsx)(`button`,{className:`btn small ghost`,onClick:()=>{O(x),E(!0)},children:`编辑`}),C?(0,s.jsx)(`button`,{className:`btn small ghost`,onClick:()=>oe(),disabled:k,title:`关闭后,wait 返回的任务不再追加提示词`,children:`关闭`}):(0,s.jsx)(`button`,{className:`btn small`,onClick:()=>{O(re),E(!0)},title:`恢复默认收尾追加语并开启`,children:`开启`})]})]})]}),!T&&x&&(0,s.jsx)(`div`,{className:`muted`,style:{fontSize:12,whiteSpace:`pre-wrap`,borderLeft:`2px solid #eee`,padding:`4px 0 4px 10px`},children:x}),T&&(0,s.jsxs)(`div`,{children:[(0,s.jsx)(`textarea`,{value:D,onChange:e=>O(e.target.value),rows:5,style:{width:`100%`,font:`inherit`,padding:8,boxSizing:`border-box`},placeholder:`(留空 = 关闭;非空 = 启用并以这段文本作为追加语)`}),(0,s.jsxs)(`div`,{style:{display:`flex`,gap:8,marginTop:8,alignItems:`center`,flexWrap:`wrap`},children:[(0,s.jsx)(`button`,{className:`btn small`,onClick:()=>Y(D),disabled:k,children:`保存`}),(0,s.jsx)(`button`,{className:`btn small ghost`,onClick:()=>{E(!1),O(``)},disabled:k,children:`取消`}),(0,s.jsx)(`button`,{className:`btn small ghost`,onClick:()=>Y(re),disabled:k,title:`覆盖为默认文案并开启`,children:`恢复默认`}),(0,s.jsx)(`span`,{className:`muted`,style:{fontSize:11,marginLeft:`auto`},children:`留空保存 = 关闭`})]})]})]}),(0,s.jsxs)(`div`,{className:`colhead`,children:[(0,s.jsx)(`input`,{type:`checkbox`,checked:le,onChange:ue,disabled:!J.length,title:`全选 / 取消全选`,style:{margin:0}}),(0,s.jsx)(`h3`,{children:`主题总览(按工作目录)`}),(0,s.jsx)(`span`,{className:`muted`,children:c?`${J.length} 个 · 等待中 ${c.waiting}`:``}),(0,s.jsxs)(`span`,{style:{marginLeft:`auto`,display:`flex`,gap:8},children:[(0,s.jsx)(`button`,{className:`btn small ghost`,onClick:he,disabled:!U.size||G,title:`删除勾选的主题(含其全部任务)`,children:G?`删除中…`:`批量删除${U.size?` (${U.size})`:``}`}),(0,s.jsx)(`button`,{className:`btn small ghost`,onClick:se,disabled:y,title:`清理旧模型无目录主题与空主题(等待中一律保留)`,children:y?`清理中…`:`清理旧数据`})]})]}),(0,s.jsx)(`div`,{style:{display:`flex`,gap:10,flexWrap:`wrap`,marginBottom:14},children:J.length?J.map(e=>{let t=e.key===d;return(0,s.jsxs)(`div`,{onClick:()=>f(e.key),className:`card`,style:{textAlign:`left`,width:270,padding:`10px 12px`,cursor:`pointer`,border:t?`1px solid var(--ink,#14161a)`:`1px solid transparent`,boxShadow:t?`0 0 0 2px rgba(20,22,26,.12)`:`0 1px 2px rgba(20,22,26,.06), 0 6px 16px rgba(20,22,26,.05)`},children:[(0,s.jsxs)(`div`,{style:{display:`flex`,gap:8,alignItems:`flex-start`},children:[(0,s.jsx)(`input`,{type:`checkbox`,checked:U.has(e.key),onChange:()=>ce(e.key),onClick:e=>e.stopPropagation(),title:`选择以批量删除`,style:{margin:`3px 0 0`}}),(0,s.jsxs)(`div`,{style:{flex:1,minWidth:0},children:[(0,s.jsx)(`div`,{style:{fontWeight:700,marginBottom:2},children:e.name||`(未命名)`}),(0,s.jsx)(`div`,{className:`mono muted`,title:e.cwd,style:{fontSize:11,wordBreak:`break-all`,marginBottom:6,minHeight:15},children:e.cwd||`(旧数据,无目录)`})]})]}),e.summary&&(0,s.jsxs)(`div`,{className:`muted`,style:{fontSize:11,whiteSpace:`pre-wrap`,marginBottom:6},children:[`现状:`,e.summary]}),(0,s.jsxs)(`div`,{style:{display:`flex`,gap:6,alignItems:`center`,flexWrap:`wrap`},children:[e.waiting?(0,s.jsx)(`span`,{className:`tag strong`,children:ee(e)||l(e.waitingUntil)}):(0,s.jsx)(`span`,{className:`tag`,children:`已结束`}),(0,s.jsxs)(`span`,{className:`muted`,style:{fontSize:11},children:[`待领取 `,e.pending,`/`,e.total]})]}),(0,s.jsxs)(`div`,{style:{display:`flex`,justifyContent:`flex-end`,gap:6,marginTop:8},onClick:e=>e.stopPropagation(),children:[e.waiting&&(0,s.jsx)(`button`,{className:`btn small ghost`,onClick:()=>me(e),title:`关闭本次等待(阻塞中的 wait 立即收尾,主题与任务保留)`,children:`关闭`}),(0,s.jsx)(`button`,{className:`btn small ghost`,onClick:()=>pe(e),disabled:G,title:`删除整个主题(含全部任务)`,children:`删除主题`})]})]},e.key)}):(0,s.jsx)(`div`,{className:`card muted`,style:{padding:`20px 16px`,width:`100%`,textAlign:`center`},children:`(暂无主题;agent 调用 localtask wait 后会出现在这里)`})}),X&&(0,s.jsxs)(s.Fragment,{children:[(0,s.jsxs)(`div`,{className:`toolbar`,children:[(0,s.jsx)(`span`,{style:{fontWeight:700,maxWidth:240},title:X.cwd,children:X.name}),(0,s.jsx)(`span`,{className:`sep`}),(0,s.jsx)(`textarea`,{style:{flex:1,minWidth:240,minHeight:40,resize:`vertical`},spellCheck:`false`,value:p,onChange:e=>m(e.target.value),onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),de())},placeholder:`向主题「${X.name}」的队列回填下一条任务(Enter 提交,Shift+Enter 换行)`}),(0,s.jsx)(`button`,{className:`btn`,onClick:de,disabled:h,children:h?`提交中…`:`回填新任务`})]}),(0,s.jsxs)(`div`,{className:`colhead`,children:[(0,s.jsx)(`h3`,{children:`该主题的任务队列`}),(0,s.jsxs)(`span`,{className:`muted`,children:[`待领取 `,X.pending,` · 共 `,X.total,` 条`]}),(0,s.jsx)(`span`,{className:`muted`,style:{fontSize:12,marginLeft:`auto`},children:`拖拽待领取行(或用「提前/置后」)调整领取优先级`})]}),(0,s.jsx)(`div`,{className:`card`,style:{padding:4},children:(0,s.jsxs)(`table`,{children:[(0,s.jsx)(`thead`,{children:(0,s.jsxs)(`tr`,{children:[(0,s.jsx)(`th`,{style:{width:34}}),(0,s.jsx)(`th`,{style:{width:56},children:`#`}),(0,s.jsx)(`th`,{children:`任务`}),(0,s.jsx)(`th`,{style:{width:80},children:`状态`}),(0,s.jsx)(`th`,{style:{width:160},children:`时间`}),(0,s.jsx)(`th`,{style:{width:150},children:`操作`})]})}),(0,s.jsx)(`tbody`,{children:ve.length?ve.map(e=>{let t=e.status!==`consumed`,n=L===e.id,r=z&&z.id===e.id;return(0,s.jsxs)(`tr`,{draggable:t&&j!==e.id,onDragStart:t=>{R(e.id),t.dataTransfer.effectAllowed=`move`;try{t.dataTransfer.setData(`text/plain`,String(e.id))}catch{}},onDragOver:t=>be(t,e),onDrop:t=>xe(t,e),onDragEnd:()=>{R(null),B(null)},style:{cursor:t&&j!==e.id?`grab`:`default`,opacity:n?.4:1,boxShadow:r?z.pos===`top`?`inset 0 2px 0 var(--ink,#14161a)`:`inset 0 -2px 0 var(--ink,#14161a)`:`none`,background:r?`rgba(20,22,26,.04)`:void 0},children:[(0,s.jsx)(`td`,{className:`mono muted`,title:`按住拖拽调整优先级`,style:{textAlign:`center`,userSelect:`none`},children:t?`⠿`:``}),(0,s.jsxs)(`td`,{className:`mono`,children:[`#`,e.id]}),(0,s.jsx)(`td`,{style:{whiteSpace:`pre-wrap`},children:j===e.id?(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(`textarea`,{value:N,onChange:e=>P(e.target.value),onKeyDown:e=>{e.key===`Enter`&&(e.ctrlKey||e.metaKey)&&(e.preventDefault(),_e()),e.key===`Escape`&&Z()},spellCheck:`false`,autoFocus:!0,style:{width:`100%`,minHeight:60,resize:`vertical`}}),(0,s.jsxs)(`div`,{style:{display:`flex`,gap:8,marginTop:6},children:[(0,s.jsx)(`button`,{className:`btn small`,onClick:_e,disabled:F,children:F?`保存中…`:`保存`}),(0,s.jsx)(`button`,{className:`btn small ghost`,onClick:Z,disabled:F,children:`取消`}),(0,s.jsx)(`span`,{className:`muted`,style:{fontSize:11,alignSelf:`center`},children:`Ctrl+Enter 保存 · Esc 取消`})]})]}):(0,s.jsxs)(s.Fragment,{children:[e.text,e.roundSummary&&(0,s.jsxs)(`div`,{className:`muted`,style:{fontSize:11,marginTop:4,paddingTop:4,borderTop:`1px dashed var(--line,#e6e8eb)`,whiteSpace:`pre-wrap`},title:`该任务所回应的 agent 上一轮完成总结`,children:[`上一轮完成:`,e.roundSummary]})]})}),(0,s.jsx)(`td`,{children:e.status===`consumed`?(0,s.jsx)(`span`,{className:`tag strong`,children:`已领取`}):(0,s.jsx)(`span`,{className:`tag`,children:`待领取`})}),(0,s.jsx)(`td`,{className:`mono`,children:e.consumedAt||e.createdAt}),(0,s.jsxs)(`td`,{className:`ops`,children:[t&&j!==e.id&&(()=>{let t=Q.findIndex(t=>t.id===e.id);return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(`button`,{className:`btn small ghost`,onClick:()=>ge(e),children:`编辑`}),(0,s.jsx)(`button`,{className:`btn small ghost`,title:`提高优先级(更早被领取)`,disabled:V||t<=0,onClick:()=>ye(e,`up`),children:`提前`}),(0,s.jsx)(`button`,{className:`btn small ghost`,title:`降低优先级(更晚被领取)`,disabled:V||t>=Q.length-1,onClick:()=>ye(e,`down`),children:`置后`})]})})(),(0,s.jsx)(`button`,{className:`btn small ghost`,onClick:()=>fe(e.id),children:`删除`})]})]},e.id)}):(0,s.jsx)(`tr`,{children:(0,s.jsx)(`td`,{colSpan:`6`,className:`muted`,style:{textAlign:`center`,padding:`22px 0`},children:`(暂无任务,在上方回填第一条)`})})})]})})]}),(0,s.jsx)(a,{module:`localtask`})]})}export{u as default};