@teammy/server 0.1.8 → 0.1.10

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.
Binary file
@@ -6,8 +6,8 @@
6
6
  <meta name="theme-color" content="#161615" />
7
7
  <title>Teammy 工作台</title>
8
8
  <link rel="icon" type="image/png" href="./assets/teammy-favicon-BiDvlPj2.png" />
9
- <script type="module" crossorigin src="./assets/index-DQsx-e5d.js"></script>
10
- <link rel="stylesheet" crossorigin href="./assets/index-CTIAGUGG.css">
9
+ <script type="module" crossorigin src="./assets/index-BW6ule39.js"></script>
10
+ <link rel="stylesheet" crossorigin href="./assets/index-A_XSN_Cz.css">
11
11
  </head>
12
12
  <body>
13
13
  <div id="root" data-teammy-ui-version="11"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@teammy/server",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "The centralized Teammy collaboration hub server.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1 +0,0 @@
1
- import{$ as e,A as t,D as n,J as r,M as i,O as a,S as o,W as ee,a as te,b as s,et as ne,f as c,i as l,k as re,n as u,o as d,q as f,r as ie,t as ae,u as oe,v as p,y as se}from"./index-DQsx-e5d.js";import{t as m}from"./Markdown-BRPMsc7D.js";var h=e(),g=t(),_=e=>new Date(e).toLocaleTimeString([],{hour:`2-digit`,minute:`2-digit`}),v=e=>e.replace(/[#*_`>]/g,``).replace(/\s+/g,` `).trim();function y({mine:e=!1,author:t,time:n,children:r}){return(0,g.jsx)(`div`,{className:`assistant-bubble-row ${e?`mine`:``}`,children:(0,g.jsxs)(`div`,{className:`assistant-bubble`,children:[(0,g.jsxs)(`div`,{className:`assistant-bubble-meta`,children:[(0,g.jsx)(`span`,{children:t}),(0,g.jsx)(`time`,{dateTime:n,children:_(n)})]}),r]})})}function b({me:e}){let{projectId:t,request:b}=oe(),S=re(),C=a(t,e,`assistant-selection`),w=a(t,e,`assistant-drafts`),ce=(0,h.useCallback)(e=>b(`agents/outbox`,te,{signal:e}),[b]),T=n(ce,3e3,a(t,e,`outbox`)),le=(0,h.useCallback)(e=>b(`agents/chats`,ae,{signal:e}),[b]),E=n(le,3e3,a(t,e,`chats`)),[D,ue]=(0,h.useState)(()=>{let e=new URLSearchParams(location.search),t=e.get(`chat`);return t?`chat:${t}`:e.get(`message`)??S?.get(C)??``}),O=D.startsWith(`chat:`)?D.slice(5):``,k=!D||!!O,[A,j]=(0,h.useState)(()=>S?.get(a(t,e,`chat`,O))),M=A?.id===O?A:S?.get(a(t,e,`chat`,O)),de=E.data?.chats.find(e=>e.id===O),[fe,N]=(0,h.useState)(),[P,F]=(0,h.useState)(()=>S?.get(w)??{}),I=P[D]??``,L=e=>F(t=>({...t,[D]:e})),[R,z]=(0,h.useState)(!1),[B,V]=(0,h.useState)(!1),[pe,H]=(0,h.useState)(``),[U,W]=(0,h.useState)(``),G=(0,h.useRef)(new Map),K=(0,h.useRef)(null),q=(0,h.useRef)(!0),J=(0,h.useRef)(D);J.current=D,(0,h.useEffect)(()=>{A&&S?.set(a(t,e,`chat`,A.id),A)},[S,t,e,A]),(0,h.useEffect)(()=>{S?.set(w,P)},[S,w,P]);function Y(e){J.current=e,ue(e),S?.set(C,e);let t=new URL(location.href);e.startsWith(`chat:`)?t.searchParams.set(`chat`,e.slice(5)):t.searchParams.delete(`chat`),e&&!e.startsWith(`chat:`)&&e!==`debug`?t.searchParams.set(`message`,e):t.searchParams.delete(`message`),history.replaceState(history.state,``,t)}(0,h.useEffect)(()=>{!D&&E.data?.chats.length&&Y(`chat:${E.data.chats[0].id}`)},[D,E.data]);let X=(T.data?.messages??[]).filter(e=>e.box===`debug`).reverse(),Z=T.data?.messages.find(e=>e.id===(D===`debug`?fe:D));(0,h.useEffect)(()=>{D!==`debug`&&Z?.conversationId&&Y(`chat:${Z.conversationId}`)},[D,Z?.conversationId]);let Q=X.filter(e=>!e.readAt).map(e=>e.id).join(`,`);(0,h.useEffect)(()=>{Z&&!Z.readAt&&D!==`debug`&&b(`agents/outbox/${Z.id}/read`,d,{method:`POST`}).then(()=>{window.dispatchEvent(new Event(`teammy:outbox`)),T.reload()}).catch(e=>H(i(e)))},[Z?.id,Z?.readAt,D,b,T.reload]),(0,h.useEffect)(()=>{D===`debug`&&Q&&Promise.all(Q.split(`,`).map(e=>b(`agents/outbox/${e}/read`,d,{method:`POST`}))).then(()=>{window.dispatchEvent(new Event(`teammy:outbox`)),T.reload()}).catch(e=>H(i(e)))},[D,Q,b,T.reload]),(0,h.useEffect)(()=>{if(W(``),!O)return;let e=!0,n=new EventSource(ne(`/api/v1/projects/${encodeURIComponent(t)}/agents/chats/${encodeURIComponent(O)}/events`));n.addEventListener(`snapshot`,t=>{if(e)try{let e=u.parse(JSON.parse(t.data));if(e.redirect){Y(`chat:${e.redirect}`);return}j(e),W(``)}catch(e){W(i(e))}}),n.onerror=()=>{e&&W(`对话连接中断,正在重新连接…`)},n.addEventListener(`context`,t=>{if(!e)return;let n=u.pick({kind:!0,title:!0,status:!0,visibility:!0,participants:!0,pending:!0,hold:!0,redirect:!0}).parse(JSON.parse(t.data));n.redirect?Y(`chat:${n.redirect}`):j(e=>e?.id===O?{...e,...n}:e)}),n.addEventListener(`message`,t=>{if(!e)return;let n=ie.parse(JSON.parse(t.data));j(e=>e&&{...e,readCursor:Math.max(e.readCursor,n.seq),cursor:Math.max(e.cursor,Number(t.lastEventId)||0),messages:[...e.messages.filter(e=>e.id!==n.id),n].sort((e,t)=>e.seq-t.seq)})}),n.addEventListener(`message_removed`,t=>{if(!e)return;let{id:n}=f({id:r()}).parse(JSON.parse(t.data));j(e=>e?.id===O?{...e,messages:e.messages.filter(e=>e.id!==n)}:e)}),n.addEventListener(`run`,t=>{if(!e)return;let n=l.parse(JSON.parse(t.data));j(e=>e&&{...e,cursor:Math.max(e.cursor,Number(t.lastEventId)||0),runs:e.runs.some(e=>e.id===n.id)?e.runs:[...e.runs,n]})});for(let t of[`delta`,`reset`,`state`])n.addEventListener(t,n=>{if(!e)return;let r=JSON.parse(n.data);j(e=>e&&{...e,cursor:Math.max(e.cursor,Number(n.lastEventId)||0),messages:e.messages.map(e=>e.runId!==r.id||e.role!==`assistant`?e:{...e,body:t===`delta`?e.body+(r.text??``):t===`reset`?``:r.answer??e.body,state:r.state??e.state}),runs:e.runs.map(e=>e.id===r.id?{...e,answer:t===`delta`?e.answer+(r.text??``):t===`reset`?``:r.answer??e.answer,state:r.state??e.state,error:r.error===void 0?e.error:r.error}:e)})});return()=>{e=!1,n.close()}},[t,O]),(0,h.useEffect)(()=>{if(!M?.kind||M.id!==O)return;let e=()=>{document.visibilityState===`visible`&&b(`agents/chats/${O}/read`,f({ok:ee()}),{method:`POST`,body:{cursor:M.readCursor}}).then(()=>{E.reload(),window.dispatchEvent(new Event(`teammy:outbox`))}).catch(e=>H(i(e)))},t=setTimeout(e,300);return document.addEventListener(`visibilitychange`,e),()=>{clearTimeout(t),document.removeEventListener(`visibilitychange`,e)}},[O,M?.readCursor,M?.kind,b]),(0,h.useEffect)(()=>{q.current&&K.current?.scrollIntoView({block:`end`})},[D,A?.messages,Z?.recipients,X.length]);function me(){window.dispatchEvent(new Event(`teammy:outbox`)),T.reload()}async function $(e){if(q.current=!0,Y(e),H(``),N(void 0),e.startsWith(`chat:`)||e===`debug`)return;let t=T.data?.messages.find(t=>t.id===e)?.conversationId;if(t)Y(`chat:${t}`);else try{await b(`agents/outbox/${e}/read`,d,{method:`POST`}),me()}catch(e){H(i(e))}}async function he(){if(!B){V(!0),H(``);try{let e=await b(`agents/chats`,u,{method:`POST`});j(e),await $(`chat:${e.id}`),E.reload()}catch(e){H(i(e))}finally{V(!1)}}}async function ge(e){e.preventDefault();let t=I.trim();if(!t||R||B)return;z(!0),H(``);let n=G.current.get(D);n&&n.text===t||(n={text:t,id:crypto.randomUUID()},G.current.set(D,n));try{if(k){let e=n.target??O;if(!e){let r=await b(`agents/chats`,u,{method:`POST`});e=r.id,n.target=e,G.current.set(`chat:${e}`,n),F(n=>({...n,[`chat:${e}`]:t})),J.current===D&&(j(r),Y(`chat:${e}`))}let i=await b(`agents/chats/${e}`,l.extend({conversationId:r().optional()}),{method:`POST`,body:{text:t,requestId:n.id}});i.conversationId&&i.conversationId!==e&&(J.current===D||J.current===`chat:${e}`)&&Y(`chat:${i.conversationId}`),j(t=>t?.id===e?{...t,runs:t.runs.some(e=>e.id===i.id)?t.runs:[...t.runs,i]}:t),E.reload()}else{let e=await b(`agents/outbox/${Z.id}/reply`,f({conversationId:r()}),{method:`POST`,body:{body:t,requestId:n.id}});me(),J.current===D&&Y(`chat:${e.conversationId}`),E.reload(),N(void 0)}G.current.delete(D),n.target&&G.current.delete(`chat:${n.target}`),F(e=>({...e,[D]:``,...n.target?{[`chat:${n.target}`]:``}:{}}))}catch(e){H(i(e))}finally{z(!1)}}let _e=k||!!Z&&!Z.archivedAt,ve=k&&!M&&(!!O||!E.data);return(0,g.jsxs)(`div`,{className:`split-layout assistant-layout`,"data-testid":`assistant-page`,children:[(0,g.jsxs)(`aside`,{className:`assistant-list`,"aria-label":`消息列表`,children:[(0,g.jsxs)(`header`,{className:`assistant-list-heading`,children:[(0,g.jsx)(`h1`,{children:`消息`}),(0,g.jsx)(se,{className:`assistant-new-chat`,icon:`plus`,label:`新建对话`,disabled:B,onClick:()=>void he(),"data-testid":`assistant-launcher`})]}),(0,g.jsxs)(`div`,{className:`assistant-message-scroll`,children:[E.loading&&!E.data&&(0,g.jsx)(`p`,{className:`assistant-list-status`,role:`status`,children:`加载中…`}),E.data?.chats.map(e=>(0,g.jsxs)(`button`,{type:`button`,"data-testid":`assistant-chat-${e.id}`,className:`assistant-message-item assistant-chat-item ${O===e.id?`selected`:``}`,"aria-pressed":O===e.id,onClick:()=>void $(`chat:${e.id}`),children:[(0,g.jsx)(`span`,{className:`assistant-message-dot ${e.unread||e.state===`running`||e.state===`queued`?`unread`:``}`}),(0,g.jsxs)(`span`,{className:`assistant-message-copy`,children:[(0,g.jsx)(c,{selected:O===e.id,children:(0,g.jsx)(`strong`,{children:e.title})}),(0,g.jsxs)(`time`,{dateTime:e.updatedAt,children:[new Date(e.updatedAt).toLocaleDateString([],{month:`numeric`,day:`numeric`}),` `,_(e.updatedAt)]})]})]},e.id)),!!X.length&&(0,g.jsxs)(`button`,{type:`button`,"data-testid":`debug-outbox`,className:`assistant-message-item ${D===`debug`?`selected`:``}`,onClick:()=>void $(`debug`),children:[(0,g.jsx)(`span`,{className:`assistant-message-dot ${Q?`unread`:``}`}),(0,g.jsxs)(`span`,{className:`assistant-message-copy`,children:[(0,g.jsx)(c,{selected:D===`debug`,children:(0,g.jsx)(`strong`,{children:`运行提醒`})}),(0,g.jsx)(`span`,{children:v(X.at(-1).body)})]})]}),T.data?.messages.filter(e=>e.box!==`debug`&&!e.conversationId).sort((e,t)=>Number(!!e.archivedAt)-Number(!!t.archivedAt)).map(e=>(0,g.jsxs)(`button`,{type:`button`,"data-testid":`outbox-${e.id}`,className:`assistant-message-item ${e.archivedAt?`archived`:``} ${D===e.id?`selected`:``}`,onClick:()=>void $(e.id),children:[(0,g.jsx)(`span`,{className:`assistant-message-dot ${e.readAt?``:`unread`}`}),(0,g.jsxs)(`span`,{className:`assistant-message-copy`,children:[(0,g.jsx)(c,{selected:D===e.id,children:(0,g.jsx)(`strong`,{children:v(e.body)})}),(0,g.jsxs)(`time`,{dateTime:e.createdAt,children:[new Date(e.createdAt).toLocaleDateString([],{month:`numeric`,day:`numeric`}),` `,_(e.createdAt)]})]})]},e.id))]}),(0,g.jsx)(o,{error:!0,children:T.error||E.error})]}),(0,g.jsxs)(`section`,{className:`assistant-thread`,"aria-label":k?`Tim对话`:`消息内容`,children:[(0,g.jsxs)(`header`,{className:`assistant-thread-heading`,children:[(0,g.jsx)(`h2`,{children:k?de?.title??M?.title??(O?`无标题`:`Tim`):D===`debug`?`运行提醒`:`项目消息`}),M?.kind===`matter`&&(0,g.jsxs)(`span`,{className:`assistant-participants`,title:M.participants?.join(`、`),children:[M.visibility===`project`?`项目共享 · `:``,M.participants?.join(`、`)]})]}),M?.kind===`matter`&&(M.hold||M.pending||M.status===`completed`)&&(0,g.jsx)(`div`,{className:`assistant-matter-state`,role:`status`,children:M.hold?`${M.hold.scope===`all`?`已暂停`:`暂缓修改`} · ${M.hold.reason}`:M.pending?`待确认 · ${M.pending.members.join(`、`)}:${M.pending.question}`:`已完成`}),(0,g.jsxs)(`div`,{className:`assistant-transcript`,role:`log`,"aria-live":`polite`,"data-testid":`assistant-transcript`,onScroll:e=>{let t=e.currentTarget;q.current=t.scrollHeight-t.scrollTop-t.clientHeight<100},children:[k?ve?(0,g.jsxs)(`div`,{className:`assistant-empty`,"data-testid":`assistant-loading`,children:[(0,g.jsx)(s,{}),(0,g.jsx)(`p`,{role:`status`,children:U||E.error?`暂时无法加载对话`:`加载中…`})]}):M?.messages.length?M.messages.filter(e=>e.body||[`queued`,`running`,`failed`].includes(e.state)).map(t=>(0,g.jsx)(`div`,{className:`assistant-turn`,children:(0,g.jsxs)(y,{mine:t.role===`user`&&t.author===e,author:`${t.role===`assistant`?`Tim`:t.author}${t.source===`wecom`?` · 企业微信`:``}`,time:t.createdAt,children:[t.body&&(0,g.jsx)(`div`,{className:`markdown`,children:(0,g.jsx)(m,{children:t.body})}),t.role===`assistant`&&[`queued`,`running`].includes(t.state)&&(0,g.jsxs)(`span`,{className:`assistant-typing`,"aria-label":`正在回答`,children:[(0,g.jsx)(`i`,{}),(0,g.jsx)(`i`,{}),(0,g.jsx)(`i`,{})]}),t.state===`failed`&&(0,g.jsx)(o,{error:!0,children:M.runs.find(e=>e.id===t.runId)?.error||`本次回答未完成。`})]})},t.id)):(0,g.jsxs)(`div`,{className:`assistant-empty`,children:[(0,g.jsx)(s,{}),(0,g.jsx)(`p`,{children:`有什么项目问题想聊聊?`})]}):!T.data&&T.loading?(0,g.jsx)(`div`,{className:`assistant-empty`,children:(0,g.jsx)(`p`,{role:`status`,children:`加载中…`})}):D===`debug`?X.map(e=>(0,g.jsx)(x,{item:e,onReply:e.archivedAt?void 0:()=>{N(e.id),L(``),H(``)}},e.id)):Z&&(0,g.jsx)(x,{item:Z}),(0,g.jsx)(`div`,{ref:K})]}),(0,g.jsx)(o,{error:!0,children:pe||(k?U:``)}),_e?(0,g.jsxs)(`form`,{className:`assistant-composer`,onSubmit:e=>void ge(e),children:[(0,g.jsx)(`textarea`,{value:I,disabled:B,onChange:e=>L(e.target.value),"aria-label":k?`向Tim提问`:`回复消息`,placeholder:k?`问问Tim…`:`回复…`,rows:2,onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&!e.nativeEvent.isComposing&&(e.preventDefault(),e.currentTarget.form?.requestSubmit())}}),(0,g.jsx)(`button`,{className:`primary assistant-send`,type:`submit`,disabled:R||B||ve||!I.trim(),"aria-label":`发送`,children:(0,g.jsx)(p,{name:`send`})})]}):D!==`debug`&&Z&&(0,g.jsxs)(`div`,{className:`assistant-archived`,children:[(0,g.jsx)(p,{name:`archive`}),`已归档`]})]})]})}function x({item:e,onReply:t}){return(0,g.jsx)(`div`,{"data-testid":`outbox-thread-${e.id}`,children:(0,g.jsxs)(y,{author:e.box===`debug`?`运行提醒`:`Tim`,time:e.createdAt,children:[(0,g.jsx)(`div`,{className:`markdown`,children:(0,g.jsx)(m,{children:e.body})}),t&&(0,g.jsx)(`button`,{type:`button`,className:`assistant-debug-reply`,onClick:t,children:`回复`})]})})}export{b as Assistant};
@@ -1 +0,0 @@
1
- import{$ as e,A as t,D as n,F as r,L as i,O as a,S as o,c as s,et as c,g as l,j as u,l as d,s as f,u as p,v as m,w as h,y as g}from"./index-DQsx-e5d.js";import{t as _}from"./Markdown-BRPMsc7D.js";import{t as v}from"./project-links-XbF78Bal.js";import{t as y}from"./file-links-I1K8CwVK.js";import{n as b,t as x}from"./WorkspaceTree-fMDtGIFa.js";var S=e(),C=t();function w(e,t){let n=t.split(`/`).slice(0,-1);return n.map((t,r)=>b(e,n.slice(0,r+1).join(`/`))).concat(b(e,``))}function T({members:e,me:t,onRefresh:a}){let{api:m,projectId:h}=p(),[_,T]=(0,S.useState)(()=>{let t=new URLSearchParams(location.search),n=t.get(`owner`),r=i.safeParse(t.get(`path`));return n&&(n===`_project`||e.some(e=>e.id===n))&&r.success&&!s(r.data)?{owner:n,path:r.data}:void 0}),[D,O]=(0,S.useState)(()=>new Set(_?w(_.owner,_.path):[b(t,``)])),[k,A]=(0,S.useState)(()=>_?{..._,kind:`file`}:void 0),[j,M]=(0,S.useState)(0),[N,P]=(0,S.useState)(()=>{let e=new URLSearchParams(location.search);return!_&&(e.has(`owner`)||e.has(`path`))?`文件链接不完整或目标已不可用。`:``}),F=(0,S.useCallback)(async e=>{if(_)try{return{owner:_.owner,...await m.file(_.owner,_.path,void 0,e)}}catch(e){throw e instanceof u&&e.code===`FILE_NOT_FOUND`?Error(`找不到这个文件,可能已被删除或移动。`):e}},[_?.owner,_?.path,j]),I=n(F),L=I.data?.owner===_?.owner&&I.data?.file.path===_?.path?I.data:void 0;function R(e,t){let n=t.split(`/`).filter(Boolean);O(t=>{let r=new Set(t);for(let t=0;t<=n.length;t++)r.add(b(e,n.slice(0,t).join(`/`)));return r})}function z(e,t){P(``),R(e,t.split(`/`).slice(0,-1).join(`/`)),T({owner:e,path:t}),A({owner:e,path:t,kind:`file`}),history.replaceState(null,``,c(v(h,e,t)))}function B(t){if(!_)return!1;let n=y(_.owner===`_project`?_.path:`${_.owner}/${_.path}`,t);if(!n)return!/^[a-z][a-z0-9+.-]*:/i.test(t)&&!t.startsWith(`//`)&&(P(`该链接超出工作区,请在原仓库查看。`),!0);if(s(n.path))return P(`配置文件不在文件浏览中显示。`),!0;let[r,...i]=n.path.split(`/`),a=e.some(e=>e.id===r),o=a?r:f,c=a?i.join(`/`):n.path;return P(``),n.directory?(R(o,c),A({owner:o,path:c,kind:`directory`})):o===_.owner&&c===_.path?n.anchor&&[...document.querySelectorAll(`.markdown h1,.markdown h2,.markdown h3,.markdown h4`)].find(e=>e.textContent?.trim().toLowerCase().replace(/\s+/g,`-`)===n.anchor.toLowerCase())?.scrollIntoView({block:`center`}):z(o,c),!0}return(0,C.jsxs)(`div`,{className:`split-layout file-explorer`,"data-testid":`file-browser`,children:[(0,C.jsxs)(`aside`,{className:`file-tree-pane`,"aria-label":`文件资源管理器`,children:[(0,C.jsx)(d,{title:`工作区`,icon:`files`,children:(0,C.jsx)(g,{icon:`refresh`,label:`刷新文件`,"data-testid":`files-refresh`,onClick:()=>{P(``),M(e=>e+1),a()}})}),(0,C.jsx)(x,{members:e,expanded:D,selected:k,revealed:!I.loading&&!I.error&&L?{owner:L.owner,path:L.file.path,file:L.file}:void 0,onSelect:z,onToggle:(e,t)=>{A({owner:e,path:t,kind:`directory`}),O(n=>{let r=new Set(n),i=b(e,t);return r.has(i)?r.delete(i):r.add(i),r})}},j)]}),(0,C.jsx)(`section`,{className:`file-detail`,"data-testid":`file-preview`,"data-owner-id":_?.owner,"data-file-path":_?.path,"aria-label":r.filePreview,children:_?(0,C.jsxs)(C.Fragment,{children:[(0,C.jsx)(o,{error:!0,children:N||!I.loading&&I.error}),I.error&&(0,C.jsx)(`button`,{className:`file-entry-retry`,"data-testid":`files-retry`,onClick:()=>void I.reload(),children:r.retry}),I.loading?(0,C.jsx)(`p`,{className:`preview-body`,role:`status`,children:r.loading}):!I.error&&L&&(0,C.jsx)(E,{owner:L.owner,file:L.file,onLink:B},`${L.owner}:${L.file.path}:${L.file.sha256}`)]}):N?(0,C.jsx)(o,{error:!0,children:N}):(0,C.jsx)(l,{mascot:!0,title:`从一份资料开始`,description:r.pickFile})})]})}function E({owner:e,file:t,onLink:i}){let{readTextBlob:s,blobUrl:c,projectId:l}=p(),[u,d]=(0,S.useState)(!1),f=t.size>524288,v=/\.(md|markdown)$/i.test(t.path),y=(0,S.useCallback)(e=>f?Promise.resolve(void 0):s(t,e),[t.sha256,t.size,f]),b=n(y,!1,a(l,`file-body`,t.sha256));return(0,C.jsxs)(C.Fragment,{children:[(0,C.jsxs)(`header`,{className:`file-detail-header`,children:[(0,C.jsxs)(`span`,{className:`file-detail-path`,title:`${e===`_project`?`workspaces`:e}/${t.path}`,children:[(0,C.jsxs)(`span`,{children:[e===`_project`?`workspaces`:e,` / `]}),t.path]}),(0,C.jsxs)(h,{label:`文件操作`,children:[v&&(0,C.jsx)(g,{icon:u?`preview`:`code`,label:u?`切换为预览`:`切换为原文`,"data-testid":`file-toggle-raw`,"aria-pressed":u,onClick:()=>d(!u)}),(0,C.jsx)(`a`,{className:`icon-button`,"data-testid":`file-download`,"aria-label":r.download,title:r.download,href:c(t.sha256),download:t.path.split(`/`).at(-1),children:(0,C.jsx)(m,{name:`download`})})]})]}),f?(0,C.jsx)(`div`,{className:`empty`,children:(0,C.jsx)(`p`,{children:r.previewLarge})}):b.error?(0,C.jsxs)(`div`,{className:`preview-body`,children:[(0,C.jsx)(o,{error:!0,children:b.error}),(0,C.jsx)(`button`,{"data-testid":`file-preview-retry`,onClick:()=>void b.reload(),children:r.retry})]}):b.loading?(0,C.jsx)(`p`,{className:`preview-body`,role:`status`,children:r.loading}):(0,C.jsx)(`div`,{className:`preview-body`,children:v&&!u?(0,C.jsx)(`article`,{className:`markdown`,"data-testid":`file-content`,"data-format":`markdown`,children:(0,C.jsx)(_,{onLink:i,children:b.data??``})}):(0,C.jsx)(`pre`,{className:`raw`,"data-testid":`file-content`,"data-format":`text`,children:b.data})})]})}export{T as Files};
@@ -1,6 +0,0 @@
1
- import{$ as e,A as t,D as n,H as r,J as i,K as a,M as o,N as s,O as c,Q as l,R as u,S as d,U as f,V as p,X as m,Z as h,_ as g,d as _,et as v,g as y,l as b,q as x,u as S,v as C,x as w,y as T,z as E}from"./index-DQsx-e5d.js";import{n as D,r as O,t as k}from"./Markdown-BRPMsc7D.js";import{i as ee,r as A}from"./WorkspaceTree-fMDtGIFa.js";function j(e){return l(p,e)}var M=e(),N=i().regex(/^R\d{6,}$/),P=x({name:i().min(1),sha256:u,size:a().int().nonnegative()}),F=m().refine(e=>/^https?:\/\//i.test(e),`Use an HTTP or HTTPS URL.`);x({operationId:h(),title:i().trim().default(``),text:i().optional(),url:F.optional(),originals:f(P).default([])}).strict().refine(e=>!!e.text?.trim()||!!e.url||e.originals.length>0,`Provide text, a link or a file.`),x({expectedRevision:E,title:i().trim().min(1).optional(),content:i().optional(),summary:i().optional(),sourceVersion:i().optional(),contentDate:i().optional(),originals:f(P).optional()}).strict();var I=x({id:N,projectId:i(),title:i(),submittedBy:i(),createdAt:i(),revision:E,source:x({kind:r([`web`,`chat`,`group`]),url:i().nullable(),groupId:i().optional(),messageId:i().optional(),sourceVersion:i().optional(),contentDate:i().optional()}),originals:f(P),content:i().nullable(),summary:i().nullable(),state:r([`waiting`,`running`,`ready`,`failed`]),error:i().nullable(),url:i()}),L=x({materials:f(I),nextCursor:a().nullable()});x({query:i().trim().min(1),scope:r([`all`,`workspace`,`materials`]).default(`all`),materialId:N.optional(),originalHash:u.optional(),after:i().default(``),limit:j().int().min(1).max(200).default(30)}).strict();var R=x({items:f(x({key:i(),kind:r([`workspace`,`materials`]),title:i(),snippet:i(),url:i(),path:i()})),nextCursor:i().nullable()}),z=t();function te(e){let t=(e.content??``).trimStart().split(`
2
- `);return t[0]?.replace(/^#\s+/,``).trim()===e.title.trim()&&t[0].startsWith(`# `)&&t.shift(),t.join(`
3
- `).trimStart()}function B(){let e=new URLSearchParams(location.search),t=e.get(`id`);return t?{id:t,...e.get(`original`)?{original:e.get(`original`)}:{},...e.get(`revision`)?{revision:e.get(`revision`)}:{}}:void 0}function V(){let{request:e,projectId:t}=S(),[r,i]=(0,M.useState)(B),[a,s]=(0,M.useState)(r),[l,u]=(0,M.useState)(()=>new Set(r?[r.id]:[])),[f,p]=(0,M.useState)(!1),[m,h]=(0,M.useState)(``),[g,x]=(0,M.useState)(``),[w,E]=(0,M.useState)(``),[D,O]=(0,M.useState)([]),[j,N]=(0,M.useState)(),[P,F]=(0,M.useState)(!1),[R,V]=(0,M.useState)(``),U=(0,M.useRef)(null),W=(0,M.useCallback)(t=>e(`materials`,L,{signal:t}),[e]),G=n(W,5e3,c(t,`materials`)),ie=(0,M.useCallback)(t=>r?e(`materials/${encodeURIComponent(r.id)}${r.revision?`?revision=${encodeURIComponent(r.revision)}`:``}`,I,{signal:t}):Promise.resolve(null),[e,r?.id,r?.revision]),K=n(ie,5e3),q=K.data?.id===r?.id?K.data:null,J=[...new Map([...D,...G.data?.materials??[],...q?[q]:[]].map(e=>[e.id,e])).values()].sort((e,t)=>t.createdAt.localeCompare(e.createdAt)||t.id.localeCompare(e.id)),Y=j===void 0?G.data?.nextCursor:j;function X(e,n=``){i(e),s(e),x(``),E(n),p(!1),u(t=>new Set([...t,e.id])),history.replaceState(null,``,v(`/projects/${t}/materials?${new URLSearchParams({...e})}`))}(0,M.useEffect)(()=>{let e=()=>{let e=B();i(e),s(e),x(``),h(``),E(``),p(!1),e&&u(t=>new Set([...t,e.id]))};return window.addEventListener(`popstate`,e),()=>window.removeEventListener(`popstate`,e)},[]);async function ae(){if(Y&&!P){F(!0),V(``);try{let t=await e(`materials?before=${Y}`,L);O(e=>[...e,...t.materials]),N(t.nextCursor)}catch(e){V(o(e))}finally{F(!1)}}}let Z=J.find(e=>e.id===a?.id),Q=Z?.originals.find(e=>e.sha256===a?.original)?.name??Z?.title??`当前资料`;function $(){s(void 0),E(``),U.current?.focus()}return(0,z.jsxs)(`div`,{className:`split-layout file-explorer session-explorer`,"data-testid":`materials-page`,children:[(0,z.jsxs)(`aside`,{className:`file-tree-pane`,"aria-label":`资料目录`,children:[(0,z.jsx)(b,{title:`资料`,icon:`materials`,children:(0,z.jsx)(T,{icon:`plus`,label:`新增资料`,onClick:()=>{p(!0),V(``)}})}),(0,z.jsx)(d,{error:!0,children:G.error||R}),G.data?J.length===0?(0,z.jsx)(`p`,{className:`tree-status`,children:`暂无资料`}):(0,z.jsx)(`div`,{role:`tree`,"aria-label":`项目资料`,onKeyDown:A,children:J.map(e=>(0,z.jsxs)(`div`,{role:`none`,children:[(0,z.jsxs)(_,{role:`treeitem`,"aria-level":1,"aria-expanded":l.has(e.id),"aria-selected":!f&&r?.id===e.id&&!r.original,className:`tree-item tree-folder`,style:{"--tree-level":1},"data-testid":`material-folder`,title:e.title,onClick:()=>{let t=l.has(e.id);X({id:e.id}),t&&u(t=>{let n=new Set(t);return n.delete(e.id),n})},leading:(0,z.jsx)(`span`,{className:`tree-chevron ${l.has(e.id)?`expanded`:``}`,children:(0,z.jsx)(C,{name:`chevron`,size:`small`})}),children:[(0,z.jsx)(C,{name:`files`}),(0,z.jsx)(`span`,{className:`tree-name`,children:e.title})]}),l.has(e.id)&&(0,z.jsx)(`div`,{role:`group`,children:[...e.originals].sort((e,t)=>ee(e.name,t.name)).map((t,n)=>(0,z.jsxs)(_,{role:`treeitem`,"aria-level":2,"aria-selected":!f&&r?.id===e.id&&r.original===t.sha256,className:`tree-item`,style:{"--tree-level":2},"data-testid":`material-original`,title:t.name,onClick:()=>X({id:e.id,original:t.sha256,...e.id===r?.id&&r.revision?{revision:r.revision}:{}}),leading:(0,z.jsx)(`span`,{className:`tree-chevron`}),children:[(0,z.jsx)(C,{name:`file`}),(0,z.jsx)(`span`,{className:`tree-name`,children:t.name})]},`${t.sha256}:${n}`))})]},e.id))}):(0,z.jsx)(`p`,{className:`tree-status`,children:`加载中…`}),Y&&(0,z.jsx)(`button`,{className:`tree-action`,disabled:P,onClick:()=>void ae(),children:P?`加载中…`:`加载更多`})]}),(0,z.jsxs)(`section`,{className:`session-reader`,"aria-label":`资料内容与搜索`,children:[(0,z.jsx)(`div`,{className:`session-reader-content`,children:f?(0,z.jsx)(re,{onCancel:()=>p(!1),onSaved:e=>{X({id:e}),G.reload()}}):g?(0,z.jsx)(ne,{query:g,scope:a,onSelect:e=>X(e,g)},`${g}/${a?.id}/${a?.original}`):r?(0,z.jsxs)(z.Fragment,{children:[(0,z.jsx)(d,{error:!0,children:K.error}),q?r.original?(0,z.jsx)(H,{material:q,hash:r.original,highlight:w}):(0,z.jsxs)(`article`,{className:`material-body`,children:[(0,z.jsx)(`h1`,{children:q.title}),r.revision&&(0,z.jsx)(`button`,{className:`material-link`,onClick:()=>X({id:r.id}),children:`查看最新内容`}),!r.revision&&(q.state===`waiting`||q.state===`running`)?(0,z.jsx)(`p`,{className:`muted`,role:`status`,children:`正在整理…`}):null,(0,z.jsx)(d,{error:!0,children:q.error??``}),!r.revision&&q.state===`failed`&&(0,z.jsx)(`button`,{onClick:()=>void e(`materials/${r.id}/retry`,I,{method:`POST`}).then(()=>K.reload()).catch(e=>V(o(e))),children:`重试整理`}),q.content?(0,z.jsx)(`div`,{className:`markdown`,children:(0,z.jsx)(k,{highlight:w,children:te(q)})}):(0,z.jsx)(`p`,{className:`muted`,children:`正文尚未整理,可以先查看左侧原件。`})]}):(0,z.jsx)(`p`,{role:`status`,children:`加载中…`})]}):(0,z.jsx)(y,{mascot:!0,title:`选择资料开始阅读`,description:`也可以在下方搜索资料内容。`})}),!f&&(0,z.jsxs)(`form`,{className:`session-search-dock`,"data-testid":`material-search-form`,onSubmit:e=>{e.preventDefault(),x(m.trim()),E(``)},children:[a&&(0,z.jsxs)(`button`,{type:`button`,className:`search-scope-chip`,title:`清除搜索范围`,"aria-label":`清除范围:${Q}`,onClick:$,children:[(0,z.jsxs)(`span`,{className:`scope-label`,children:[`搜索:`,Q]}),(0,z.jsx)(`span`,{"aria-hidden":`true`,children:`×`})]}),(0,z.jsxs)(`div`,{className:`session-search-input-row`,children:[(0,z.jsx)(`input`,{ref:U,"aria-label":`搜索资料`,placeholder:`搜索资料内容`,value:m,onChange:e=>h(e.target.value),onKeyDown:e=>{e.key===`Backspace`&&!m&&a&&(e.preventDefault(),$())}}),(g||m||w)&&(0,z.jsx)(T,{icon:`close`,label:`清空搜索`,onClick:()=>{h(``),x(``),E(``),U.current?.focus()}}),(0,z.jsx)(T,{icon:`search`,type:`submit`,label:`搜索`,disabled:!m.trim()})]})]})]})]})}function ne({query:e,scope:t,onSelect:r}){let{request:i}=S(),[a,o]=(0,M.useState)(``),s=(0,M.useCallback)(n=>i(`resources/search?${new URLSearchParams({query:e,scope:`materials`,after:a,...t?{materialId:t.id}:{},...t?.original?{originalHash:t.original}:{}})}`,R,{signal:n}),[i,e,t?.id,t?.original,a]),c=n(s);return(0,z.jsxs)(`section`,{className:`session-results stack`,"aria-label":`搜索结果`,children:[(0,z.jsx)(d,{error:!0,children:c.error}),c.loading?(0,z.jsx)(`p`,{role:`status`,children:`正在搜索…`}):c.data?.items.length===0?(0,z.jsx)(`p`,{className:`empty`,children:`没有找到匹配的资料`}):c.data?.items.map(t=>(0,z.jsxs)(`button`,{className:`session-item`,"data-testid":`material-match`,onClick:()=>{let e=new URL(t.url,location.origin).searchParams;r({id:e.get(`id`),...e.get(`original`)?{original:e.get(`original`)}:{},...e.get(`revision`)?{revision:e.get(`revision`)}:{}})},children:[(0,z.jsx)(`strong`,{children:t.title.replace(/^R\d+ · /,``)}),(0,z.jsx)(`span`,{className:`session-excerpt`,children:(0,z.jsx)(D,{value:O(t.snippet,e),query:e})})]},t.key)),c.data?.nextCursor&&(0,z.jsx)(`button`,{disabled:c.loading,onClick:()=>o(c.data.nextCursor),children:`下一页`})]})}function H({material:e,hash:t,highlight:r}){let{projectId:i}=S(),a=e.originals.find(e=>e.sha256===t),o=v(`/api/v1/projects/${i}/materials/${e.id}/originals/${t}?revision=${e.revision}`),[s,l]=(0,M.useState)(!1),u=(0,M.useCallback)(async e=>{let t=await fetch(o,{signal:e});if(!t.ok)throw Error(`原件暂时无法读取。`);let n=await t.arrayBuffer();try{let e=new TextDecoder(`utf8`,{fatal:!0}).decode(n);return e.includes(`\0`)?null:e}catch{return null}},[o]),f=n(u,!1,c(i,`material-original`,t));if(!a)return(0,z.jsx)(d,{error:!0,children:`找不到此原件。`});let p=/\.(md|markdown)$/i.test(a.name);return(0,z.jsxs)(z.Fragment,{children:[(0,z.jsxs)(`header`,{className:`file-detail-header`,children:[(0,z.jsx)(`span`,{className:`file-detail-path`,children:a.name}),(0,z.jsxs)(`div`,{className:`toolbar-actions`,children:[p&&(0,z.jsx)(T,{icon:s?`preview`:`code`,label:s?`切换为预览`:`切换为原文`,onClick:()=>l(!s)}),(0,z.jsx)(`a`,{className:`icon-button`,"aria-label":`下载原件`,title:`下载原件`,href:o,download:a.name,children:(0,z.jsx)(C,{name:`download`})})]})]}),(0,z.jsx)(d,{error:!0,children:f.error}),f.loading?(0,z.jsx)(`p`,{role:`status`,children:`加载中…`}):f.data===null?(0,z.jsx)(`p`,{className:`muted`,children:`此格式请下载后查看。`}):f.data!==void 0&&(0,z.jsx)(`div`,{className:`preview-body`,"data-testid":`material-original-content`,children:p&&!s?(0,z.jsx)(`article`,{className:`markdown`,children:(0,z.jsx)(k,{highlight:r,children:f.data})}):(0,z.jsx)(`pre`,{className:`raw`,children:(0,z.jsx)(D,{value:f.data,query:r})})})]})}function U(e){if(e.kind===`text`){try{if([`http:`,`https:`].includes(new URL(e.text.trim()).protocol))return`link`}catch{}return`text`}let{name:t,type:n}=e.file;return n.startsWith(`image/`)||/\.(png|jpe?g|gif|webp|svg|heic|avif)$/i.test(t)?`imageFile`:/\.(csv|tsv|xlsx?|ods)$/i.test(t)?`spreadsheetFile`:/\.(json|ya?ml|xml|html?|css|[cm]?[jt]sx?|py|go|rs|sh|sql)$/i.test(t)?`codeFile`:n.startsWith(`text/`)||/\.(pdf|docx?|odt|rtf|md|txt)$/i.test(t)?`file`:`attachment`}function W(e){try{return new URL(e.trim()).hostname}catch{return e.trim().split(`
4
- `)[0]?.slice(0,80)||`文本`}}function G(e){try{return new URL(e.trim()).href}catch{return e.trim().split(`
5
- `).slice(1).join(`
6
- `)}}function re({onSaved:e,onCancel:t}){let{request:n,projectId:r}=S(),[i,a]=(0,M.useState)([]),[c,l]=(0,M.useState)(),[u,f]=(0,M.useState)(!1),[p,m]=(0,M.useState)(``),h=(0,M.useRef)(null),_=(0,M.useRef)(s()),y=(0,M.useRef)(new Map);function b(e){a(e),_.current=s(),m(``)}async function x(){f(!0),m(``);try{let t=[];for(let[e,n]of i.entries()){let i=y.current.get(n.id);if(!i){let t=n.kind===`file`?n.file.name:`${W(n.text)}.txt`,a=await fetch(v(`/api/v1/projects/${r}/materials/uploads`),{method:`POST`,headers:{"content-type":`application/octet-stream`,"x-teammy-web":`1`},body:n.kind===`file`?n.file:new Blob([n.text],{type:`text/plain`})}),o=await a.json();if(!a.ok)throw Error(o.error?.message??`第 ${e+1} 项上传失败。`);i={name:t,sha256:o.sha256,size:o.size},y.current.set(n.id,i)}t.push(i)}let a=i.length===1&&i[0]?.kind===`text`?i[0].text.trim():``,o;try{let e=new URL(a);[`http:`,`https:`].includes(e.protocol)&&(o=e.href)}catch{}e((await n(`materials`,I,{method:`POST`,body:{operationId:_.current,originals:t,...o?{url:o}:{}}})).id)}catch(e){m(o(e))}finally{f(!1)}}return(0,z.jsxs)(z.Fragment,{children:[(0,z.jsxs)(`form`,{className:`material-form`,onSubmit:e=>{e.preventDefault(),x()},children:[(0,z.jsx)(`h1`,{children:`新增资料`}),(0,z.jsx)(`p`,{className:`muted`,children:`上传附件到项目,以便于Tim进行理解`}),(0,z.jsx)(d,{error:!0,children:p}),(0,z.jsxs)(`fieldset`,{disabled:u,children:[(0,z.jsxs)(`div`,{className:`attachment-grid`,children:[i.map(e=>(0,z.jsxs)(`article`,{className:`attachment-card`,"data-testid":`attachment-card`,children:[e.kind===`text`?(0,z.jsxs)(`button`,{type:`button`,className:`attachment-content`,"aria-label":`编辑:${W(e.text)}`,onClick:()=>l({id:e.id,text:e.text}),children:[(0,z.jsx)(C,{name:U(e)}),(0,z.jsx)(`span`,{className:`attachment-name`,children:W(e.text)}),G(e.text)&&(0,z.jsx)(`span`,{className:`attachment-excerpt`,children:G(e.text)})]}):(0,z.jsxs)(`div`,{className:`attachment-content`,children:[(0,z.jsx)(C,{name:U(e)}),(0,z.jsx)(`span`,{className:`attachment-name`,children:e.file.name})]}),(0,z.jsx)(T,{className:`attachment-remove`,icon:`close`,label:`移除:${e.kind===`file`?e.file.name:W(e.text)}`,onClick:()=>{y.current.delete(e.id),b(i.filter(t=>t.id!==e.id))}})]},e.id)),(0,z.jsxs)(`button`,{type:`button`,className:`attachment-add`,onClick:()=>l({text:``}),children:[(0,z.jsx)(C,{name:`addText`}),(0,z.jsx)(`span`,{children:`添加文本/链接`})]}),(0,z.jsxs)(`button`,{type:`button`,className:`attachment-add`,onClick:()=>h.current?.click(),children:[(0,z.jsx)(C,{name:`addFile`}),(0,z.jsx)(`span`,{children:`添加文件`})]})]}),(0,z.jsx)(`input`,{ref:h,type:`file`,multiple:!0,hidden:!0,"aria-label":`原始文件`,onChange:e=>{b([...i,...[...e.target.files??[]].map(e=>({id:s(),kind:`file`,file:e}))]),e.target.value=``}}),(0,z.jsxs)(`div`,{className:`actions attachment-actions`,children:[(0,z.jsx)(`button`,{type:`button`,onClick:t,children:`取消`}),(0,z.jsx)(`button`,{type:`submit`,className:`primary`,disabled:!i.length,children:u?`上传中…`:`提交资料`})]})]})]}),c&&(0,z.jsx)(w,{id:`material-text-editor`,title:`添加文本/链接`,onClose:()=>l(void 0),children:(0,z.jsxs)(`form`,{className:`stack`,onSubmit:e=>{if(e.preventDefault(),!c.text.trim())return;let t={id:c.id??s(),kind:`text`,text:c.text};y.current.delete(t.id),b(c.id?i.map(e=>e.id===c.id?t:e):[...i,t]),l(void 0)},children:[(0,z.jsx)(g,{id:`material-attachment-text`,label:`文本或链接`,children:(0,z.jsx)(`textarea`,{autoFocus:!0,rows:8,value:c.text,onChange:e=>l({...c,text:e.target.value}),placeholder:`粘贴文本或网页链接`})}),(0,z.jsx)(`div`,{className:`actions`,children:(0,z.jsx)(`button`,{type:`submit`,className:`primary`,disabled:!c.text.trim(),children:c.id?`保存`:`添加`})})]})})]})}export{V as Materials};