nx-kv 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/package.json +1 -1
- package/src/modules/sessiontask/index.js +53 -34
- package/src/modules/sessiontask/popup.js +36 -12
- package/src/modules/sessiontask/service.js +259 -137
- package/src/modules/sessiontask/view.jsx +89 -34
- package/src/web/public/assets/{CliHints-CDKMmZbP.js → CliHints-uQDPykkl.js} +1 -1
- package/src/web/public/assets/{index-DW8t26MP.js → index-C3LDUTKW.js} +2 -2
- package/src/web/public/assets/{view-CqGxh_0X.js → view-1sDSMusO.js} +1 -1
- package/src/web/public/assets/view-BgQvKmWZ.js +1 -0
- package/src/web/public/assets/{view-CdtYjY9W.js → view-CZkcHw_6.js} +1 -1
- package/src/web/public/assets/{view-C_qjdm2x.js → view-UqnZYH9n.js} +1 -1
- package/src/web/public/index.html +1 -1
- package/src/web/public/assets/view-CLDx6X3W.js +0 -1
|
@@ -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-
|
|
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-C3LDUTKW.js";import{t as s}from"./CliHints-uQDPykkl.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};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as e,c as t,i as n,l as r,s as i}from"./index-C3LDUTKW.js";import{t as a}from"./CliHints-uQDPykkl.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 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),[_,v]=(0,o.useState)(180),[y,b]=(0,o.useState)(!1),x=(0,o.useCallback)(async()=>{try{u(await t(`/api/sessiontasks`))}catch(e){r(e.message)}},[r]);(0,o.useEffect)(()=>{x()},[x]),(0,o.useEffect)(()=>{let e=setInterval(x,1500);return()=>clearInterval(e)},[x]);let S=c?c.topics:[];(0,o.useEffect)(()=>{c&&c.settings&&v(c.settings.timeoutSec)},[c]);let C=e=>i(async()=>{v(Number(e)),b(!0);try{let n=await t(`/api/sessiontasks/setting`,{method:`PATCH`,body:{timeout:Number(e)}});v(n.timeoutSec),r(`等待超时已配置为 ${n.timeoutSec} 秒`)}finally{b(!1)}});(0,o.useEffect)(()=>{if(!S.length){f(null);return}if(d&&S.some(e=>e.key===d))return;let e=S.find(e=>e.waiting)||S[0];f(e.key)},[S,d]);let w=S.find(e=>e.key===d)||null,T=()=>i(async()=>{let e=p.trim();if(!e){r(`请输入任务内容`);return}if(!w){r(`请先选择一个主题(工作目录)`);return}g(!0);try{let n=await t(`/api/sessiontasks`,{method:`POST`,body:{cwd:w.cwd,text:e}});m(``),r(n.delivered?`已返回给等待中的 agent`:`已排入该主题队列,等待 agent 下一次 wait`),await x()}finally{g(!1)}}),E=e=>i(async()=>{await t(`/api/sessiontasks/item`,{method:`DELETE`,body:{cwd:w.cwd,id:e}}),r(`已删除`),await x()}),D=w?w.tasks.slice().reverse():[];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 sessiontask 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:_,disabled:y,onChange:e=>C(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:`colhead`,children:[(0,s.jsx)(`h3`,{children:`主题总览(按工作目录)`}),(0,s.jsx)(`span`,{className:`muted`,children:c?`${S.length} 个 · 等待中 ${c.waiting}`:``})]}),(0,s.jsx)(`div`,{style:{display:`flex`,gap:10,flexWrap:`wrap`,marginBottom:14},children:S.length?S.map(e=>{let t=e.key===d;return(0,s.jsxs)(`button`,{onClick:()=>f(e.key),className:`card`,style:{textAlign:`left`,width:270,padding:`10px 12px`,cursor:`pointer`,font:`inherit`,color:`inherit`,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.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`},children:[e.waiting?(0,s.jsx)(`span`,{className:`tag strong`,children:l(e.waitingUntil)}):(0,s.jsx)(`span`,{className:`tag`,children:`已结束`}),(0,s.jsxs)(`span`,{className:`muted`,style:{fontSize:11},children:[`待领取 `,e.pending,`/`,e.total]})]})]},e.key)}):(0,s.jsx)(`div`,{className:`card muted`,style:{padding:`20px 16px`,width:`100%`,textAlign:`center`},children:`(暂无主题;agent 调用 sessiontask wait 后会出现在这里)`})}),w&&(0,s.jsxs)(s.Fragment,{children:[(0,s.jsxs)(`div`,{className:`toolbar`,children:[(0,s.jsx)(`span`,{style:{fontWeight:700,maxWidth:240},title:w.cwd,children:w.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(),T())},placeholder:`向主题「${w.name}」的队列回填下一条任务(Enter 提交,Shift+Enter 换行)`}),(0,s.jsx)(`button`,{className:`btn`,onClick:T,disabled:h,children:h?`提交中…`:`回填新任务`})]}),(0,s.jsxs)(`div`,{className:`colhead`,children:[(0,s.jsx)(`h3`,{children:`该主题的任务队列`}),(0,s.jsxs)(`span`,{className:`muted`,children:[`待领取 `,w.pending,` · 共 `,w.total,` 条`]})]}),(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: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:76},children:`操作`})]})}),(0,s.jsx)(`tbody`,{children:D.length?D.map(e=>(0,s.jsxs)(`tr`,{children:[(0,s.jsxs)(`td`,{className:`mono`,children:[`#`,e.id]}),(0,s.jsx)(`td`,{style:{whiteSpace:`pre-wrap`},children:e.text}),(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.jsx)(`td`,{className:`ops`,children:(0,s.jsx)(`button`,{className:`btn small ghost`,onClick:()=>E(e.id),children:`删除`})})]},e.id)):(0,s.jsx)(`tr`,{children:(0,s.jsx)(`td`,{colSpan:`5`,className:`muted`,style:{textAlign:`center`,padding:`22px 0`},children:`(暂无任务,在上方回填第一条)`})})})]})})]}),(0,s.jsx)(a,{module:`sessiontask`})]})}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-
|
|
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-C3LDUTKW.js";import{t as l}from"./CliHints-uQDPykkl.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};
|
|
@@ -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-
|
|
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-C3LDUTKW.js";import{t as l}from"./CliHints-uQDPykkl.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};
|
|
@@ -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-
|
|
15
|
+
<script type="module" crossorigin src="/assets/index-C3LDUTKW.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-DW8t26MP.js";import{t as a}from"./CliHints-CDKMmZbP.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 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),_=(0,o.useCallback)(async()=>{try{u(await t(`/api/sessiontasks`))}catch(e){r(e.message)}},[r]);(0,o.useEffect)(()=>{_()},[_]),(0,o.useEffect)(()=>{let e=setInterval(_,1500);return()=>clearInterval(e)},[_]);let v=c?c.slots:[];(0,o.useEffect)(()=>{if(!v.length){f(null);return}if(d&&v.some(e=>e.key===d))return;let e=v.find(e=>e.waiting)||v[0];f(e.key)},[v,d]);let y=v.find(e=>e.key===d)||null,b=()=>i(async()=>{let e=p.trim();if(!e){r(`请输入任务内容`);return}if(!y){r(`请先选择一个等待点(现状)`);return}g(!0);try{let n=await t(`/api/sessiontasks`,{method:`POST`,body:{summary:y.summary,text:e}});m(``),r(n.delivered?`已返回给等待中的 agent`:`已排队,等待 agent 下一次 wait`),await _()}finally{g(!1)}}),x=e=>i(async()=>{await t(`/api/sessiontasks/item`,{method:`DELETE`,body:{summary:y.summary,id:e}}),r(`已删除`),await _()}),S=y?y.tasks.slice().reverse():[];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 sessiontask wait --summary "<当前现状总结>" --json `}),`作为本轮`,(0,s.jsx)(`strong`,{children:`最后一个动作`}),`调用——现状总结即等待点 key,命令阻塞并 自动打开浏览器弹窗;用户针对该现状回填后解除阻塞、返回新任务;120 秒未回填 则返回 `,(0,s.jsx)(`code`,{children:`status:"timeout"`}),`,agent 收尾结束本轮。`]})}),(0,s.jsxs)(`div`,{className:`colhead`,children:[(0,s.jsx)(`h3`,{children:`等待点总览`}),(0,s.jsx)(`span`,{className:`muted`,children:c?`${v.length} 个 · 等待中 ${c.waiting}`:``})]}),(0,s.jsx)(`div`,{style:{display:`flex`,gap:10,flexWrap:`wrap`,marginBottom:14},children:v.length?v.map(e=>{let t=e.key===d;return(0,s.jsxs)(`button`,{onClick:()=>f(e.key),className:`card`,style:{textAlign:`left`,width:250,padding:`10px 12px`,cursor:`pointer`,font:`inherit`,color:`inherit`,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.jsx)(`div`,{style:{fontWeight:700,whiteSpace:`pre-wrap`,marginBottom:6},children:e.summary}),(0,s.jsxs)(`div`,{style:{display:`flex`,gap:6,alignItems:`center`},children:[e.waiting?(0,s.jsx)(`span`,{className:`tag strong`,children:l(e.waitingUntil)}):(0,s.jsx)(`span`,{className:`tag`,children:`已结束`}),(0,s.jsxs)(`span`,{className:`muted`,style:{fontSize:11},children:[`待领取 `,e.pending,`/`,e.total]})]})]},e.key)}):(0,s.jsx)(`div`,{className:`card muted`,style:{padding:`20px 16px`,width:`100%`,textAlign:`center`},children:`(暂无等待点;agent 调用 sessiontask wait 后会出现在这里)`})}),y&&(0,s.jsxs)(s.Fragment,{children:[(0,s.jsxs)(`div`,{className:`toolbar`,children:[(0,s.jsx)(`span`,{style:{fontWeight:700,maxWidth:380,whiteSpace:`pre-wrap`},title:y.summary,children:y.summary}),(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(),b())},placeholder:`针对该现状回填下一条任务(Enter 提交,Shift+Enter 换行)`}),(0,s.jsx)(`button`,{className:`btn`,onClick:b,disabled:h,children:h?`提交中…`:`回填新任务`})]}),(0,s.jsxs)(`div`,{className:`colhead`,children:[(0,s.jsx)(`h3`,{children:`该现状的任务表`}),(0,s.jsxs)(`span`,{className:`muted`,children:[`待领取 `,y.pending,` · 共 `,y.total,` 条`]})]}),(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: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:76},children:`操作`})]})}),(0,s.jsx)(`tbody`,{children:S.length?S.map(e=>(0,s.jsxs)(`tr`,{children:[(0,s.jsxs)(`td`,{className:`mono`,children:[`#`,e.id]}),(0,s.jsx)(`td`,{style:{whiteSpace:`pre-wrap`},children:e.text}),(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.jsx)(`td`,{className:`ops`,children:(0,s.jsx)(`button`,{className:`btn small ghost`,onClick:()=>x(e.id),children:`删除`})})]},e.id)):(0,s.jsx)(`tr`,{children:(0,s.jsx)(`td`,{colSpan:`5`,className:`muted`,style:{textAlign:`center`,padding:`22px 0`},children:`(暂无任务,在上方回填第一条)`})})})]})})]}),(0,s.jsx)(a,{module:`sessiontask`})]})}export{u as default};
|