@covro/covro 0.1.0 → 0.1.1-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -80,4 +80,4 @@ Error generating stack: `+e.message+`
80
80
  `)}\n/rename 必须提供名称,其他命令无需参数。输入 // 可发送以 / 开头的普通消息。`};if(n===`status`)return i.openStatus(),{message:`已打开状态诊断;可在面板中刷新或核对提交。`};if(i.project?.id!==t.project?.id||i.selectedId!==t.selectedId)return{error:!0,message:`当前项目或会话已切换,请重新选择命令。`};let a=jC(n,i);if(a)return{error:!0,message:a};if(n===`rename`){let e=ze(r);if(e)return{error:!0,message:e}}let o=i.thread,s=`/api/threads/${encodeURIComponent(o?.id??``)}`;try{if(n===`export`){let{partial:e}=await i.exportThread(o.id);return{message:e?`已发起 Markdown 下载;存在未完成、状态待确认或截断内容,请查看文件内说明。`:`已发起已保存历史的 Markdown 下载。图片和内部记录的省略范围已在文件中说明。`}}let e;if(n===`new`)return{draftKey:i.openDraft(),message:`已打开新会话输入页,发送首条消息时创建会话。`};if(n===`fork`)e=await i.run(`fork`,o.id,`${s}/fork`,{settings:i.settings});else if(n===`review`)e=await i.run(`review`,o.id,`${s}/review`);else if(n===`rename`)e=await i.run(`rename`,o.id,`${s}/rename`,{name:r.trim()});else if(n===`resume`)i.onResumeAttempt(),e=await i.run(`resume`,o.id,`${s}/resume`),await i.refreshThread();else if(n===`compact`)e=await i.run(`compact`,o.id,`${s}/compact`);else{let t=o.turns.findLast(e=>al(e.status));e=await i.run(`interrupt`,o.id,`${s}/interrupt`,{expectedTurnId:t.id})}return MC(n,e)}catch(e){return{error:!0,message:gn(e)}}}}))}function PC(e){let[t,n]=(0,O.useState)({}),r=(0,O.useRef)(t),i=(0,O.useId)(),a=(0,O.useRef)(!1);$n(`composer`,()=>{if(a.current||Object.values(r.current).some(e=>e.images.some(e=>!e.dataUrl)))throw Error(`正在输入或读取图片,完成后会自动加载新版`);return r.current},e=>{r.current={...e,...r.current},n(r.current)});let o=(0,O.useRef)(-1/0),s=(0,O.useRef)(new Set),c=(0,O.useRef)(new Map),l=(0,O.useRef)(null),u=(0,O.useId)(),[d,f]=(0,O.useState)(!1),[p,m]=(0,O.useState)({key:``,text:``,selectedIndex:0,dismissed:!1}),[h,g]=(0,O.useState)({}),[_,v]=(0,O.useState)([]),y=e.draftKey,b=(0,O.useRef)(new WeakSet);(0,O.useEffect)(()=>{for(let t of Object.values(e.sentDrafts))b.current.has(t)||(b.current.add(t),c.current.get(t.key)?.text.replace(/^(\s*)\/\//,`$1/`)===t.text&&te(t.key))},[e.sentDrafts]),(0,O.useEffect)(()=>{a.current=!1,o.current=-1/0,m({key:``,text:``,selectedIndex:0,dismissed:!1})},[y]);let x=t[y]??sb,{text:S,images:C}=x,w=DC(S),T=OC(e.commands,S),E=p.key===y&&p.text===S?p:void 0,D=Math.min(E?.selectedIndex??0,Math.max(0,T.length-1)),k=!!(w&&d&&!E?.dismissed),A=k?T[D]:e.commands.find(e=>e.name===w?.name),j=_.includes(y);function M(e){m({key:y,text:S,selectedIndex:e,dismissed:!1})}function N(){m({key:y,text:S,selectedIndex:D,dismissed:!0})}async function ee(t){if(s.current.has(y)||a.current)return;let n=r.current[y]??sb,i=DC(n.text);if(!i)return;let o=t?`/${t.name}${i.arguments?` ${i.arguments}`:``}`:n.text,c=n.images.length?`Slash 命令不能附带图片。请先移除图片,或改为普通消息。`:kC(o,e.commands);if(c){g(e=>({...e,[y]:{message:c,error:!0}}));return}let l=e.commands.find(e=>e.name===DC(o)?.name);if(l){s.current.add(y),v(e=>[...e,y]),g(e=>({...e,[y]:{message:`正在执行 /${l.name}…`}})),N();try{let e=await l.run(DC(o)?.arguments);g(t=>({...t,[y]:e,[e.draftKey??y]:e})),e.error||F(y,e=>({...e,text:e.text===n.text?``:e.text}))}catch(e){g(t=>({...t,[y]:{error:!0,message:e instanceof Error?e.message:`命令执行失败,请重试。`}}))}finally{s.current.delete(y),v(e=>e.filter(e=>e!==y))}}}let P=C.some(e=>!e.dataUrl);function F(e,t){let i={...r.current,[e]:t(r.current[e]??sb)};r.current=i,n(i)}function te(e){let t=c.current.get(e);t&&(c.current.delete(e),F(e,e=>({text:e.text===t.text?``:e.text,images:e.images.filter(e=>!t.images.some(t=>t.id===e.id)),error:e.error===t.error?void 0:e.error})))}function I(e){if(e.defaultPrevented)return;let t=Array.from(e.clipboardData.files);if(!t.length)return;e.preventDefault();let n=cb(t,(r.current[y]??sb).images);if(n){F(y,e=>({...e,error:n}));return}let i=t.map(e=>({id:crypto.randomUUID(),name:e.name||`粘贴的图片`,size:e.size})),a=e.clipboardData.getData(`text/plain`),o=e.currentTarget.selectionStart,s=e.currentTarget.selectionEnd;F(y,e=>({text:a?(e.text.slice(0,o)+a+e.text.slice(s)).slice(0,1e5):e.text,images:[...e.images,...i]})),t.forEach((e,t)=>{let n=i[t].id;lb(e).then(e=>F(y,t=>({...t,images:t.images.map(t=>t.id===n?{...t,dataUrl:e}:t)})),()=>F(y,e=>e.images.some(e=>e.id===n)?{...e,images:e.images.filter(e=>e.id!==n),error:`图片读取失败,请重新粘贴。`}:e))})}let ne=!!(e.thread?.managed&&al(e.thread.status)),L=e.thread&&!e.thread.managed&&!e.thread.archived,R=L?e.thread?.resumeError:void 0,z=R?.code===`THREAD_IN_USE`,re=!(!e.thread&&!e.projectId||e.threadLoading||L||!S.trim()&&!C.length||P||e.disabled||e.submitting);async function ie(){if(w){await ee(k?T[D]:void 0);return}if(!re||s.current.has(y))return;let t=r.current[y]??sb;if(!t.text.trim()&&!t.images.length||t.images.some(e=>!e.dataUrl))return;s.current.add(y),c.current.set(y,t);let n=t.text,i=t.images;try{await e.onSend(n.replace(/^(\s*)\/\//,`$1/`),ne,i.length?i.map(e=>e.dataUrl):void 0)&&te(y)}finally{s.current.delete(y)}}return(0,W.jsxs)(`div`,{className:`composer-region`,children:[e.submitting&&(0,W.jsxs)(`p`,{className:`composer-resume-status`,role:`status`,children:[(0,W.jsx)(J,{name:`refresh`,size:14}),e.thread?`正在提交消息…`:`正在创建会话并发送首条消息…`]}),L&&e.resuming&&(0,W.jsxs)(`p`,{className:`composer-resume-status`,role:`status`,children:[(0,W.jsx)(J,{name:`refresh`,size:14}),`正在恢复会话…`]}),L&&e.resumeAttempted&&!e.resuming&&!R&&e.canResume&&(0,W.jsx)(q,{size:`sm`,variant:`secondary`,onClick:e.onResume,children:`重试恢复`}),R&&!e.resuming&&(0,W.jsxs)(`div`,{className:`session-resume-notice`,role:`status`,children:[(0,W.jsx)(`strong`,{children:z?`此会话正被其他进程使用`:`无法恢复会话`}),(0,W.jsx)(`p`,{children:z?`可以 Fork 已保存的历史继续对话,或在原进程释放会话后重试。新会话使用同一项目目录。`:R.message}),z&&(0,W.jsxs)(q,{size:`sm`,variant:`secondary`,disabled:!e.canFork,onClick:e.onFork,children:[(0,W.jsx)(J,{name:`fork`,size:14}),e.forking?`正在确认 Fork…`:`Fork 为新会话`]}),(0,W.jsx)(q,{size:`sm`,disabled:!e.canResume,onClick:e.onResume,children:`重试恢复`})]}),(0,W.jsxs)(`div`,{className:`composer-box`,children:[h[y]&&(0,W.jsx)(`p`,{className:`slash-feedback`,role:h[y].error?`alert`:`status`,children:h[y].message}),k&&(0,W.jsx)(EC,{id:u,commands:T,selectedIndex:D,onSelect:M,onExecute:e=>{l.current?.focus(),ee(e)}}),C.length>0&&(0,W.jsx)(`ul`,{className:`composer-images`,"aria-label":`待发送的图片`,children:C.map((e,t)=>(0,W.jsxs)(`li`,{children:[e.dataUrl?(0,W.jsx)(`img`,{src:e.dataUrl,alt:`待发送的图片 ${t+1}`}):(0,W.jsx)(`span`,{role:`status`,children:`读取中…`}),(0,W.jsx)(Ic,{asChild:!0,content:e.name,children:(0,W.jsx)(`span`,{className:`composer-image-name`,children:e.name})}),(0,W.jsx)(q,{variant:`secondary`,size:`sm`,"aria-label":`移除图片 ${t+1}`,onClick:()=>F(y,t=>({...t,error:void 0,images:t.images.filter(t=>t.id!==e.id)})),children:(0,W.jsx)(J,{name:`close`,size:13})})]},e.id))}),x.error&&(0,W.jsx)(`p`,{className:`composer-image-error`,role:`alert`,children:x.error}),(0,W.jsx)(`textarea`,{ref:l,"aria-label":ne?`追加要求`:`任务内容`,"aria-haspopup":`listbox`,"aria-controls":k?u:void 0,"aria-autocomplete":`list`,"aria-activedescendant":k&&T[D]?`${u}-${T[D].name}`:void 0,value:S,readOnly:!!e.thread?.archived,placeholder:e.thread?.archived?`取消归档后可继续对话…`:ne?`补充要求或调整方向…`:`描述任务、粘贴图片,或输入 / 查看命令…`,maxLength:1e5,onChange:e=>{F(y,t=>({...t,text:e.target.value})),m({key:y,text:e.target.value,selectedIndex:0,dismissed:!1}),g(e=>{let t={...e};return delete t[y],t})},onPaste:I,onFocus:()=>f(!0),onCompositionStart:()=>{a.current=!0},onCompositionEnd:()=>{a.current=!1,o.current=performance.now()},onBlur:()=>{f(!1),a.current=!1,o.current=-1/0},onKeyDown:e=>{if((!e.defaultPrevented||k&&e.key===`Escape`)&&!(e.nativeEvent.isComposing||e.nativeEvent.keyCode===229||a.current)){if(performance.now()-o.current<100)e.key===`Enter`&&!e.shiftKey&&e.preventDefault();else{if(k&&!e.shiftKey&&!e.altKey&&!e.metaKey&&!e.ctrlKey){if(e.key===`ArrowDown`||e.key===`ArrowUp`){e.preventDefault(),T.length&&M((D+(e.key===`ArrowDown`?1:-1)+T.length)%T.length);return}if(e.key===`Escape`){e.preventDefault(),N();return}}e.key!==`Enter`||e.shiftKey||(e.preventDefault(),!e.repeat&&ie())}}},onKeyUp:e=>{e.key===`Enter`&&(o.current=-1/0)},rows:3}),(0,W.jsxs)(TC,{settings:e.settings,projectName:e.projectName,models:e.models,onChange:e.onSettings,onSaveModelDefaults:e.onSaveModelDefaults,savingModelDefaults:e.savingModelDefaults,thread:e.thread,projectId:e.projectId,runtimeKey:e.runtimeKey,threadLoading:e.threadLoading,disabled:e.disabled||!!e.threadLoading||ne||e.submitting||e.resuming||e.forking,children:[ne&&(0,W.jsx)(Ic,{content:`中断`,children:(0,W.jsxs)(q,{"aria-label":e.interrupting?`请求中…`:`中断`,variant:`secondary`,size:`sm`,onClick:e.onInterrupt,disabled:!e.canInterrupt||e.interrupting,children:[(0,W.jsx)(J,{name:`stop`,size:13}),(0,W.jsx)(`span`,{className:`composer-action-label`,children:e.interrupting?`请求中…`:`中断`})]})}),(0,W.jsx)(Ic,{id:i,className:`composer-submit`,content:w?`Enter 执行命令 / Esc 关闭菜单`:`Enter 发送 / Shift + Enter 换行`,children:(0,W.jsxs)(q,{size:`sm`,"aria-label":w?j?`正在执行命令…`:`执行命令`:e.submitting?`正在提交…`:ne?`追加要求`:`发送任务`,"aria-describedby":i,onPointerDown:e=>{w&&e.preventDefault()},onClick:()=>{ie()},disabled:w?j||!!A?.unavailableReason:!re,children:[(0,W.jsx)(J,{name:`send`,size:14}),(0,W.jsx)(`span`,{className:`composer-action-label`,children:w?j?`正在执行…`:`执行命令`:e.submitting?`正在提交…`:ne?`追加要求`:`发送任务`})]})})]})]}),(0,W.jsx)(`p`,{className:`composer-note`,children:ne?`关闭页面不会停止任务。中断以 Codex 返回的实际状态为准。`:`Codex 使用服务器项目与权限执行,请核对操作和变更。`})]})}var FC={read:`读取`,write:`写入`,deny:`禁止访问`};function IC({request:e}){let t=e.fileSystem,n=[...t?.read.map(e=>({path:e,access:`read`}))??[],...t?.write.map(e=>({path:e,access:`write`}))??[],...t?.entries??[]];return(0,W.jsxs)(`div`,{className:`permission-details`,children:[e.network!==void 0&&(0,W.jsxs)(`div`,{className:`permission-network`,children:[(0,W.jsx)(`strong`,{children:`网络访问`}),(0,W.jsx)(`span`,{children:e.network===!0?`允许访问网络`:e.network===!1?`不开放额外网络访问`:`未指定网络访问变更`})]}),n.length>0&&(0,W.jsxs)(`div`,{children:[(0,W.jsx)(`h4`,{children:`文件与目录`}),(0,W.jsx)(`ul`,{className:`permission-paths`,children:n.map((e,t)=>(0,W.jsxs)(`li`,{children:[(0,W.jsx)(`span`,{className:`permission-access permission-access-${e.access}`,children:FC[e.access]??e.access}),(0,W.jsx)(`code`,{children:e.path})]},`${e.access}-${e.path}-${t}`))})]}),t?.globScanMaxDepth!==void 0&&(0,W.jsxs)(`p`,{children:[`目录匹配搜索深度:`,t.globScanMaxDepth]}),e.network===void 0&&n.length===0&&(0,W.jsx)(`p`,{children:`未请求额外网络或文件访问权限。`})]})}var LC=class extends Error{code;status;details;constructor(e,t,n=400,r){super(t),this.code=e,this.status=n,this.details=r,this.name=`AppError`}toJSON(e){return{code:this.code,message:this.message,...e?{clientOperationId:e}:{},...this.details===void 0?{}:{details:this.details}}}},RC=e=>{throw new LC(`VALIDATION_ERROR`,e)};function zC(e){if(!/^\d{4}-\d{2}-\d{2}$/.test(e))return!1;let t=new Date(`${e}T00:00:00.000Z`);return Number.isFinite(t.getTime())&&t.toISOString().slice(0,10)===e}function BC(e,t){switch(e){case`email`:return/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(t);case`uri`:try{return!/\s/.test(t)&&!!new URL(t).protocol}catch{return!1}case`date`:return zC(t);case`date-time`:{let e=/^(\d{4}-\d{2}-\d{2})[Tt](\d{2}):(\d{2}):(\d{2})(?:\.\d+)?(?:[Zz]|[+-](\d{2}):(\d{2}))$/.exec(t);return!!(e&&zC(e[1])&&Number(e[2])<=23&&Number(e[3])<=59&&Number(e[4])<=59&&(e[5]===void 0||Number(e[5])<=23)&&(e[6]===void 0||Number(e[6])<=59)&&Number.isFinite(Date.parse(t)))}default:return!0}}function VC(e,t){let n=()=>RC(`“${e.title}”的回答不符合字段要求`);switch(e.type){case`string`:if(typeof t!=`string`)n();else{let r=[...t].length;(e.minLength!==void 0&&r<e.minLength||e.maxLength!==void 0&&r>e.maxLength||t.length>1e4||!BC(e.format,t))&&n()}break;case`number`:case`integer`:(typeof t!=`number`||!Number.isFinite(t)||e.type===`integer`&&!Number.isSafeInteger(t)||e.minimum!==void 0&&t<e.minimum||e.maximum!==void 0&&t>e.maximum)&&n();break;case`boolean`:typeof t!=`boolean`&&n();break;case`enum`:(typeof t!=`string`||t.length>1e4||!e.options?.some(e=>e.value===t))&&n();break;case`multiEnum`:(!Array.isArray(t)||t.some(t=>typeof t!=`string`||t.length>1e4||!e.options?.some(e=>e.value===t))||t.length>500||new Set(t).size!==t.length||e.minItems!==void 0&&t.length<e.minItems||e.maxItems!==void 0&&t.length>e.maxItems)&&n()}}function HC(e){switch(e){case`pending`:return`需要你处理`;case`responding`:return`正在提交…`;case`responded`:return`已处理`;case`expired`:return`请求已失效`}}function UC(e){return Object.fromEntries(e.filter(e=>e.default!==void 0).map(e=>[e.name,typeof e.default==`number`?String(e.default):e.default]))}function WC(e){let t=[];return e.type===`integer`&&t.push(`填写整数`),e.minimum!==void 0&&t.push(`最小 ${e.minimum}`),e.maximum!==void 0&&t.push(`最大 ${e.maximum}`),e.minLength!==void 0&&t.push(`至少 ${e.minLength} 个字符`),e.maxLength!==void 0&&t.push(`最多 ${e.maxLength} 个字符`),e.minItems!==void 0&&t.push(`至少选择 ${e.minItems} 项`),e.maxItems!==void 0&&t.push(`最多选择 ${e.maxItems} 项`),e.format===`date-time`&&t.push(`日期与时间需包含时区,例如 2026-10-14T12:30:00+08:00`),t.join(` · `)}function GC(e,t){let n=Object.create(null),r=Object.create(null);for(let i of e){let e=Object.hasOwn(t,i.name)?t[i.name]:void 0;if(e===void 0||(i.type===`number`||i.type===`integer`)&&e===``){i.required&&(r[i.name]=`请填写此必填项。`);continue}let a=i.type===`number`||i.type===`integer`?Number(e):e;try{VC(i,a),n[i.name]=a}catch(e){r[i.name]=e instanceof Error?e.message:`请检查此字段的填写要求。`}}return{content:n,errors:r}}function KC(e){if(e)try{let t=new URL(e);return(t.protocol===`https:`||t.protocol===`http:`)&&!t.username&&!t.password?t.href:void 0}catch{return}}function qC({request:e,actionId:t,status:n,disabled:r,onResolve:i}){let a=e.fields??[],o=n===`pending`?e.approval?`允许本次`:e.mode===`url`?`我已完成`:a.length===0?`确认继续`:a.every(e=>[`boolean`,`enum`,`multiEnum`].includes(e.type))?`确认选择`:`提交回答`:HC(n),[s,c]=(0,O.useState)(()=>UC(a)),[l,u]=(0,O.useState)(!1),{content:d,errors:f}=GC(a,s),p=KC(e.url),m=e.schemaError||(e.mode===`url`&&!p?`此请求没有可安全打开的 HTTP 或 HTTPS 地址,无法确认完成。`:void 0),h=(e,t)=>c(n=>({...n,[e]:t}));return(0,W.jsxs)(`form`,{className:`elicitation-form`,noValidate:!0,onSubmit:t=>{t.preventDefault(),!(r||m)&&(u(!0),!(e.mode===`form`&&Object.keys(f).length>0)&&i(e.mode===`form`&&!e.approval?{decision:`accept`,content:d}:{decision:`accept`}))},children:[(0,W.jsxs)(`p`,{className:`elicitation-source`,children:[`来源:`,(0,W.jsx)(`strong`,{children:e.serverName})]}),e.approval?.allowSession&&(0,W.jsx)(`p`,{className:`elicitation-scope subtle`,children:`本会话允许仅适用于当前请求对应的工具或连接范围,并受审批策略约束;新会话需重新确认。`}),m&&(0,W.jsx)(`p`,{className:`elicitation-error`,role:`alert`,children:m}),e.mode===`url`?(0,W.jsxs)(`div`,{className:`elicitation-url`,children:[(0,W.jsx)(`span`,{children:`访问地址`}),(0,W.jsx)(`code`,{children:e.url??`未提供地址`}),p&&(0,W.jsx)(`a`,{href:p,target:`_blank`,rel:`noopener noreferrer`,referrerPolicy:`no-referrer`,children:`在新标签页打开`}),(0,W.jsx)(`p`,{children:`完成页面中的操作后,点击“我已完成”继续。`})]}):!m&&(0,W.jsx)(`div`,{className:`elicitation-fields`,children:a.map((e,n)=>{let i=`elicitation-${t}-${n}`,a=WC(e),o=l?f[e.name]:void 0,c=Object.hasOwn(s,e.name)?s[e.name]:void 0,u=[e.description&&`${i}-description`,a&&`${i}-hint`,o&&`${i}-error`].filter(Boolean).join(` `)||void 0;return(0,W.jsxs)(`div`,{className:`elicitation-field`,children:[(0,W.jsxs)(`div`,{className:`elicitation-field-heading`,children:[(0,W.jsxs)(`label`,{id:`${i}-label`,htmlFor:e.type===`multiEnum`?void 0:i,children:[e.title,(0,W.jsx)(`span`,{className:`field-necessity`,"aria-hidden":`true`,children:e.required?`必填`:`可选`})]}),!e.required&&c!==void 0&&(0,W.jsxs)(`button`,{type:`button`,className:`field-unset`,disabled:r,onClick:()=>h(e.name,void 0),children:[`不填写`,(0,W.jsx)(`span`,{className:`sr-only`,children:e.title})]})]}),e.description&&(0,W.jsx)(`p`,{id:`${i}-description`,className:`field-description`,children:e.description}),e.type===`boolean`||e.type===`enum`?(0,W.jsxs)(`select`,{id:i,className:`text-input`,value:c===void 0?``:e.type===`boolean`?c?`true`:`false`:`option:${String(c)}`,disabled:r,"aria-required":e.required,"aria-invalid":!!o,"aria-describedby":u,onChange:t=>h(e.name,t.target.value===``?void 0:e.type===`boolean`?t.target.value===`true`:t.target.value.slice(7)),children:[(0,W.jsx)(`option`,{value:``,children:`请选择`}),e.type===`boolean`?(0,W.jsxs)(W.Fragment,{children:[(0,W.jsx)(`option`,{value:`true`,children:`是`}),(0,W.jsx)(`option`,{value:`false`,children:`否`})]}):e.options?.map(e=>(0,W.jsx)(`option`,{value:`option:${e.value}`,children:e.label},e.value))]}):e.type===`multiEnum`?(0,W.jsx)(`div`,{role:`group`,"aria-labelledby":`${i}-label`,"aria-describedby":u,"aria-invalid":!!o,className:`elicitation-multi-options`,children:e.options?.map(t=>(0,W.jsxs)(`label`,{className:`question-option`,children:[(0,W.jsx)(`input`,{type:`checkbox`,disabled:r,checked:Array.isArray(c)&&c.includes(t.value),onChange:n=>{let r=Array.isArray(c)?c:[];h(e.name,n.target.checked?[...r,t.value]:r.filter(e=>e!==t.value))}}),(0,W.jsx)(`span`,{children:t.label})]},t.value))}):(0,W.jsx)(`input`,{id:i,className:`text-input`,type:e.type===`number`||e.type===`integer`?`number`:e.format===`email`?`email`:e.format===`uri`?`url`:e.format===`date`?`date`:`text`,value:typeof c==`string`?c:``,step:e.type===`integer`?1:`any`,min:e.minimum,max:e.maximum,disabled:r,"aria-required":e.required,"aria-invalid":!!o,"aria-describedby":u,placeholder:e.required?void 0:`未填写(可选)`,autoComplete:`off`,onChange:t=>h(e.name,t.target.value)}),a&&(0,W.jsx)(`p`,{id:`${i}-hint`,className:`field-hint`,children:a}),o&&(0,W.jsx)(`p`,{id:`${i}-error`,className:`elicitation-error`,role:`alert`,children:o})]},e.name)})}),l&&Object.keys(f).length>0&&!m&&(0,W.jsx)(`p`,{className:`elicitation-error`,role:`alert`,children:`请检查标出的字段后再提交。`}),(0,W.jsxs)(`div`,{className:`action-options`,children:[!m&&(0,W.jsx)(q,{type:`submit`,disabled:r,children:o}),!m&&e.approval?.allowSession&&(0,W.jsx)(q,{variant:`secondary`,disabled:r,onClick:()=>i({decision:`accept`,persist:`session`}),children:`本会话允许`}),(0,W.jsx)(q,{variant:`secondary`,disabled:r,onClick:()=>i({decision:`decline`}),children:`拒绝`}),(0,W.jsx)(q,{variant:`ghost`,disabled:r,onClick:()=>i({decision:`cancel`}),children:`取消`})]})]})}function JC({action:e,disabled:t,onResolve:n}){let[r,i]=(0,O.useState)({}),[a,o]=(0,O.useState)({}),s=e.status===`pending`,c=e.questions??[],l=e=>r[e]===`__other__`?a[e]?.trim()??``:r[e]?.trim()??``,u=c.length>0&&c.every(e=>l(e.id)),d=c.length>0&&c.every(e=>e.options.length>0&&r[e.id]!==`__other__`);return(0,W.jsxs)(`section`,{className:`action-card${e.kind===`unsupported`?` action-card-unsupported`:``}`,"aria-label":e.title,children:[(0,W.jsxs)(`div`,{className:`action-heading`,children:[(0,W.jsx)(`span`,{className:`action-icon`,children:(0,W.jsx)(J,{name:e.kind===`questions`?`chat`:`alert`,size:17})}),(0,W.jsx)(`h3`,{children:e.title}),(0,W.jsx)(`span`,{className:`action-state`,children:e.kind===`unsupported`&&e.status===`expired`?`请求未能处理`:HC(e.status)})]}),e.reason&&(0,W.jsx)(`p`,{children:e.reason}),e.cwd&&(0,W.jsxs)(`p`,{className:`mono subtle action-cwd`,children:[(0,W.jsx)(`span`,{children:`工作目录:`}),e.cwd]}),e.command&&(0,W.jsx)(`pre`,{className:`command`,children:(0,W.jsx)(`code`,{children:e.command})}),e.kind===`permissions`&&e.permissionRequest&&(0,W.jsx)(IC,{request:e.permissionRequest}),e.details!==void 0&&(0,W.jsxs)(`details`,{className:`raw-details`,open:e.kind===`network`||e.kind===`file`||void 0,children:[(0,W.jsx)(`summary`,{children:e.kind===`network`?`网络访问目标`:e.kind===`file`?`变更详情`:e.kind===`permissions`||e.kind===`elicitation`?`技术详情`:`请求详情`}),(0,W.jsx)(`pre`,{children:JSON.stringify(e.details,null,2)})]}),e.kind===`elicitation`&&e.elicitation?(0,W.jsx)(qC,{request:e.elicitation,actionId:e.actionId,status:e.status,disabled:t||!s,onResolve:n}):e.kind===`questions`?(0,W.jsxs)(`form`,{onSubmit:e=>{e.preventDefault(),!t&&s&&u&&n({answers:Object.fromEntries(c.map(e=>[e.id,[l(e.id)]]))})},children:[c.map(n=>(0,W.jsxs)(`fieldset`,{disabled:t||!s,children:[(0,W.jsx)(`legend`,{children:n.header}),(0,W.jsx)(`p`,{children:n.question}),n.options.map((t,a)=>(0,W.jsxs)(`label`,{className:`question-option`,children:[(0,W.jsx)(`input`,{type:`radio`,name:`${e.actionId}-${n.id}`,value:t.label,checked:r[n.id]===t.label,onChange:()=>i(e=>({...e,[n.id]:t.label}))}),(0,W.jsxs)(`span`,{children:[(0,W.jsx)(`strong`,{children:t.label}),(0,W.jsx)(`small`,{children:t.description})]}),(0,W.jsx)(`span`,{className:`option-number`,children:a+1})]},t.label)),n.options.length>0&&n.isOther&&(0,W.jsxs)(`label`,{className:`question-option`,children:[(0,W.jsx)(`input`,{type:`radio`,name:`${e.actionId}-${n.id}`,checked:r[n.id]===`__other__`,onChange:()=>i(e=>({...e,[n.id]:`__other__`}))}),(0,W.jsx)(`span`,{children:`其他回答`})]}),(n.options.length===0||r[n.id]===`__other__`)&&(0,W.jsx)(`input`,{className:`text-input`,type:n.isSecret?`password`:`text`,"aria-label":`${n.header}:自由回答`,value:n.options.length===0?r[n.id]??``:a[n.id]??``,maxLength:1e4,onChange:e=>n.options.length===0?i(t=>({...t,[n.id]:e.target.value})):o(t=>({...t,[n.id]:e.target.value})),placeholder:`输入你的回答`,autoComplete:`off`})]},n.id)),(0,W.jsx)(q,{type:`submit`,disabled:t||!s||!u,children:s?d?`确认选择`:`提交回答`:HC(e.status)})]}):(0,W.jsx)(`div`,{className:`action-options`,children:e.options.map(e=>(0,W.jsx)(q,{variant:/decline|cancel|reject|deny/i.test(e.id)?`secondary`:`default`,disabled:t||!s,onClick:()=>n({decision:e.id}),children:e.label},e.id))}),e.kind===`unsupported`&&(0,W.jsx)(`p`,{className:`inline-error`,children:`当前版本不支持此交互请求,未发送批准。请查看兼容性诊断。`})]})}var YC={connecting:`正在连接`,connected:`实时连接正常`,disconnected:`连接已断开`,authenticationRequired:`需要重新登录`},XC={accepted:`网关已接受`,dispatching:`等待上游确认`,acknowledged:`上游已确认提交`,failed:`提交失败`,unknown:`提交结果待核对`};function ZC({connection:e}){return(0,W.jsxs)(`span`,{className:`connection-badge connection-${e}`,children:[(0,W.jsx)(`span`,{className:`status-dot`}),YC[e]]})}function QC({entry:e,thread:t,onReconcile:n,onDiscardMissing:r,busy:i,refreshing:a}){let[o,s]=(0,O.useState)(!1),[c,l]=(0,O.useState)(!1),u=e.operation?.execution,d=e.kind===`fork`,f=!!(t&&al(t.status)&&u?.threadId===t.id),p=!!(!d&&t&&al(t.status)&&e.target===t.id);return(0,W.jsxs)(`div`,{className:`operation-card`,children:[(0,W.jsxs)(`div`,{className:`operation-title`,children:[(0,W.jsx)(`strong`,{children:XC[e.status]}),(0,W.jsx)(`span`,{children:hn(e.createdAt)})]}),(0,W.jsxs)(`dl`,{children:[(0,W.jsx)(`dt`,{children:`操作`}),(0,W.jsx)(`dd`,{children:e.kind}),(0,W.jsx)(`dt`,{children:`目标`}),(0,W.jsx)(`dd`,{children:e.target}),(0,W.jsx)(`dt`,{children:`操作 ID`}),(0,W.jsx)(`dd`,{children:e.clientOperationId}),u&&(0,W.jsxs)(W.Fragment,{children:[(0,W.jsx)(`dt`,{children:`会话`}),(0,W.jsx)(`dd`,{children:u.threadId}),(0,W.jsx)(`dt`,{children:`工作区`}),(0,W.jsx)(`dd`,{children:u.workspaceKey}),(0,W.jsx)(`dt`,{children:`运行状态`}),(0,W.jsx)(`dd`,{children:u.ended?`已经结束`:`尚未确认终结`})]})]}),(e.lookupError?.message||e.error)&&(0,W.jsx)(`p`,{className:`inline-error`,role:`alert`,children:e.lookupError?.message??e.error}),bn(e)&&(0,W.jsxs)(`div`,{className:`reconcile`,children:[(0,W.jsx)(`p`,{children:`请先检查会话历史、会话列表和原执行环境。清理仅移除此浏览器的待核对记录,不会停止任务或重新提交。`}),p?(0,W.jsx)(`p`,{children:`当前会话仍在执行,请等待结束或正常中断后再核对。`}):(0,W.jsxs)(W.Fragment,{children:[(0,W.jsxs)(`label`,{children:[(0,W.jsx)(`input`,{type:`checkbox`,checked:c,onChange:e=>l(e.target.checked)}),`我已检查历史和原执行环境,确认无需继续核对这笔提交`]}),(0,W.jsx)(q,{variant:`secondary`,size:`sm`,disabled:!c||i||a,onClick:()=>r(e.clientOperationId),children:`清除此浏览器的待核对记录`})]})]}),e.kind===`confirmCompatibility`&&e.status===`unknown`&&(0,W.jsx)(`p`,{className:`subtle`,children:`兼容性确认结果待核对,请刷新状态。此记录不代表任务执行,也不会自动重新提交。`}),e.kind!==`confirmCompatibility`&&Cn(e)&&!e.lookupError?.missing&&!e.operation?.reconciliation&&(0,W.jsxs)(`div`,{className:`reconcile`,children:[(0,W.jsx)(`p`,{children:d?`请先刷新会话列表,检查是否已生成包含原历史的新会话。核对此次 Fork 不会停止原任务或改变原任务的执行状态。`:`不会自动重发任务。先检查会话历史和原执行环境,再核对这笔提交。`}),f?(0,W.jsx)(`p`,{children:`当前任务仍在执行,请使用输入区的中断按钮。`}):(0,W.jsxs)(W.Fragment,{children:[(0,W.jsxs)(`label`,{children:[(0,W.jsx)(`input`,{type:`checkbox`,checked:o,onChange:e=>s(e.target.checked)}),d?`我已检查会话列表和历史,核实此次 Fork 的结果`:`我已核实对应旧运行已经结束`]}),(0,W.jsx)(q,{variant:`secondary`,size:`sm`,disabled:!o||i||a,onClick:()=>n(e.clientOperationId),children:i?`正在提交核对…`:d?`核对此次 Fork`:`核对并解除旧占用`})]})]}),e.operation?.reconciliation&&(0,W.jsxs)(`p`,{className:`subtle`,children:[`已于 `,hn(e.operation.reconciliation.at),` `,d?`人工核对 Fork 结果。原任务状态不变。`:`人工核对旧运行结束。`,`保留原始提交状态。`]})]})}function $C({system:e,connection:t,operations:n,thread:r,onRefresh:i,onReconcile:a,onDiscardMissing:o,busy:s,open:c,onOpenChange:l,refreshing:u}){let d=(0,O.useRef)(null);return(0,O.useEffect)(()=>{c&&d.current?.focus()},[c]),(0,W.jsxs)(`details`,{className:`diagnostics`,open:c,onToggle:e=>l(e.currentTarget.open),children:[(0,W.jsxs)(`summary`,{children:[(0,W.jsx)(J,{name:`settings`,size:16}),`状态诊断`,n.length>0&&(0,W.jsx)(`span`,{className:`count-badge`,children:n.length})]}),(0,W.jsxs)(`div`,{className:`diagnostics-panel`,id:`diagnostics-panel`,ref:d,tabIndex:-1,role:`region`,"aria-label":`状态诊断详情`,"aria-busy":u,children:[(0,W.jsxs)(`div`,{className:`diagnostics-heading`,children:[(0,W.jsx)(`h2`,{children:`运行状态`}),(0,W.jsxs)(q,{variant:`ghost`,size:`sm`,disabled:u,onClick:i,children:[(0,W.jsx)(J,{name:`refresh`,size:14}),u?`正在核对…`:`刷新状态`]})]}),(0,W.jsxs)(`section`,{className:`operation-section`,children:[(0,W.jsx)(`h3`,{children:`操作与状态核对`}),(0,W.jsx)(`p`,{className:`subtle`,role:`status`,children:u?`正在核对会话历史和提交回执…`:r?.status===`unknown`?`会话状态仍待核对。请检查操作记录和原执行环境。`:n.length>0?`请查看提交记录;核对不会自动重发任务。`:`没有待核对的提交。`}),n.map(e=>(0,W.jsx)(QC,{entry:e,thread:r,onReconcile:a,onDiscardMissing:o,busy:s.includes(`reconcile:${e.clientOperationId}`)||s.includes(`${e.kind}:${e.target}`),refreshing:u},e.clientOperationId))]}),(0,W.jsxs)(`dl`,{children:[(0,W.jsx)(`dt`,{children:`网页连接`}),(0,W.jsx)(`dd`,{children:YC[t]}),(0,W.jsx)(`dt`,{children:`Codex`}),(0,W.jsx)(`dd`,{children:e?.ready?`已就绪`:e?.connection===`starting`?`启动中`:`不可用`}),(0,W.jsx)(`dt`,{children:`账户认证`}),(0,W.jsx)(`dd`,{children:e?.authenticated===!0?`可用`:e?.authenticated===!1?`需要在本机登录 Codex`:`尚未确认`}),(0,W.jsx)(`dt`,{children:`运行版本`}),(0,W.jsx)(`dd`,{children:e?.codexVersion??`未检测到`}),(0,W.jsx)(`dt`,{children:`已验证版本`}),(0,W.jsx)(`dd`,{children:e?.verifiedVersion??`读取中`}),(0,W.jsx)(`dt`,{children:`兼容性`}),(0,W.jsx)(`dd`,{children:e?.compatibility===`verified`?`版本已验证`:e?.compatibility===`unverified`?e.compatibilityConfirmation===`confirmed`?`当前版本未经验证 · 已确认继续`:`当前版本未经验证 · 待确认`:`不可用`}),(0,W.jsx)(`dt`,{children:`入口认证`}),(0,W.jsx)(`dd`,{children:e?.authMode===`cloudflare-access`?`Cloudflare Access`:`本机模式`})]}),e?.error&&(0,W.jsx)(`p`,{className:`inline-error`,children:e.error}),e&&(0,W.jsxs)(`details`,{className:`raw-details`,children:[(0,W.jsx)(`summary`,{children:`已支持能力`}),(0,W.jsx)(`p`,{children:e.capabilities.join(` · `)||`暂无`})]})]})]})}async function ew(e){let t=await fetch(`/api/threads/${encodeURIComponent(e)}/export`,{credentials:`same-origin`,cache:`no-store`,headers:{Accept:`text/markdown`},signal:AbortSignal.timeout(35e3)}),n=t.headers.get(`content-type`)??``;if(!t.ok||!n.includes(`text/markdown`)){if(n.includes(`application/json`)){let e=await t.json();throw new Ee(t.status,e.error??{code:`EXPORT_FAILED`,message:`无法读取会话历史,未下载文件。`})}throw new Ee(t.status===200?401:t.status,{code:`AUTH_REQUIRED`,message:`登录已过期或历史接口未返回 Markdown,请重新登录后重试。`})}let r=/filename="(codex-thread-[A-Za-z0-9_-]+\.md)"/.exec(t.headers.get(`content-disposition`)??``)?.[1];if(!r)throw Error(`导出响应缺少有效文件名,未下载文件。`);let i=t.headers.get(`x-export-completeness`);if(i!==`partial`&&i!==`saved-history`)throw Error(`导出响应缺少历史完整性说明,未下载文件。`);let a=await t.blob(),o=URL.createObjectURL(a),s=document.createElement(`a`);s.href=o,s.download=r,document.body.append(s);try{s.click()}finally{s.remove(),setTimeout(()=>URL.revokeObjectURL(o),1e3)}return{partial:i===`partial`}}function tw(e){let{system:t}=e,n=(0,O.useRef)(null),[r,i]=(0,O.useState)(),[a,o]=(0,O.useState)(),s=jn(t),c=Nn(t,r,a);(0,O.useEffect)(()=>{e.onOpenChange?.(c)},[c,e.onOpenChange]),(0,O.useEffect)(()=>{let e=n.current;if(e)return c&&!e.open?e.showModal():!c&&e.open&&e.close(),()=>{e.open&&e.close()}},[c]);function l(){i(s),o(void 0)}return(0,W.jsxs)(W.Fragment,{children:[t?.compatibility===`unverified`&&(0,W.jsxs)(`div`,{className:`compatibility-banner compatibility-notice`,role:`status`,children:[(0,W.jsxs)(`span`,{children:[`当前 Codex `,t.codexVersion,` 尚未验证兼容性,部分功能可能无法正常使用。`,t.compatibilityConfirmation===`confirmed`?` 已确认继续;这不代表版本已验证。`:` 使用前需要确认。`]}),t.compatibilityConfirmation===`required`&&(0,W.jsx)(q,{variant:`ghost`,size:`sm`,onClick:()=>o(s),children:`查看兼容性提示`})]}),(0,W.jsxs)(`dialog`,{ref:n,className:`compatibility-dialog`,"aria-labelledby":`compatibility-title`,"aria-describedby":`compatibility-description`,onCancel:e=>{e.preventDefault(),l()},children:[(0,W.jsxs)(`div`,{className:`compatibility-dialog-heading`,children:[(0,W.jsx)(J,{name:`alert`,size:22}),(0,W.jsx)(`h2`,{id:`compatibility-title`,children:`Codex 版本兼容性未经验证`})]}),(0,W.jsx)(`p`,{id:`compatibility-description`,children:`当前运行的 Codex 版本尚未验证,部分功能可能无法正常使用。确认继续后仍将保留兼容性提示。`}),(0,W.jsxs)(`dl`,{children:[(0,W.jsx)(`dt`,{children:`运行版本`}),(0,W.jsx)(`dd`,{children:t?.codexVersion??`未检测到`}),(0,W.jsx)(`dt`,{children:`已验证版本`}),(0,W.jsx)(`dd`,{children:t?.verifiedVersion??`读取中`})]}),t?.ready?!e.canConfirm&&(0,W.jsx)(`p`,{className:`subtle`,role:`status`,children:`请等待连接和 Codex 认证恢复后再确认。`}):(0,W.jsx)(`p`,{className:`inline-error`,role:`status`,children:`Codex 当前不可用,无法确认继续。请关闭此提示后查看状态诊断。`}),e.error&&(0,W.jsx)(`p`,{className:`inline-error`,role:`alert`,children:e.error}),e.uncertain&&(0,W.jsxs)(`div`,{className:`compatibility-uncertain`,role:`status`,children:[(0,W.jsx)(`p`,{children:`确认请求的结果尚待核对。可刷新状态,或重新确认当前运行版本的使用许可;不会重发任务。`}),(0,W.jsx)(q,{variant:`secondary`,size:`sm`,onClick:e.onRefresh,children:`刷新确认状态`}),t?.ready&&(0,W.jsx)(q,{variant:`secondary`,size:`sm`,disabled:!e.canConfirm||e.submitting,onClick:e.onReconfirm,children:`重新确认`})]}),(0,W.jsx)(`p`,{className:`subtle`,children:`关闭提示后仍可查看诊断或中断当前任务。确认不会自动发送任务,未发送的草稿会保留。`}),(0,W.jsxs)(`div`,{className:`compatibility-dialog-actions`,children:[(0,W.jsx)(q,{variant:`secondary`,autoFocus:!0,onClick:l,children:`暂不使用`}),t?.ready&&(0,W.jsx)(q,{disabled:!e.canConfirm||e.submitting||e.uncertain,onClick:e.onConfirm,children:e.submitting?`正在确认…`:`确认继续`})]})]})]})}function nw(e){let t=(0,O.useRef)(null),n=(0,O.useRef)(!1),[r,i]=(0,O.useState)(``),[a,o]=(0,O.useState)(e.project?.name??``),[s,c]=(0,O.useState)(!1),[l,u]=(0,O.useState)(!1),[d,f]=(0,O.useState)(),p=e.disabled||l,m=s?`移除项目`:e.project?`管理项目`:`添加服务器项目`;(0,O.useEffect)(()=>{let e=t.current;return e?.showModal(),()=>e?.close()},[]);async function h(){if(!(p||n.current)){n.current=!0,u(!0),f(void 0);try{e.project?s?await e.onRemove(e.project.id):await e.onRename(e.project.id,a.trim()):await e.onAdd({path:r.trim(),...a.trim()?{name:a.trim()}:{}}),e.onClose()}catch(e){f(gn(e))}finally{n.current=!1,u(!1)}}}return(0,W.jsxs)(`dialog`,{ref:t,className:`project-dialog`,"aria-labelledby":`project-dialog-title`,"aria-describedby":`project-dialog-description`,onCancel:t=>{t.preventDefault(),l||e.onClose()},children:[(0,W.jsxs)(`div`,{className:`project-dialog-heading`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(J,{name:`folder`,size:20}),(0,W.jsx)(`h2`,{id:`project-dialog-title`,children:m})]}),(0,W.jsx)(q,{variant:`ghost`,size:`icon`,"aria-label":`关闭项目管理`,disabled:l,onClick:e.onClose,children:(0,W.jsx)(J,{name:`close`,size:17})})]}),(0,W.jsxs)(`form`,{onSubmit:e=>{e.preventDefault(),h()},children:[s?(0,W.jsxs)(W.Fragment,{children:[(0,W.jsxs)(`p`,{id:`project-dialog-description`,children:[`确定从工作空间移除「`,e.project?.name,`」?`]}),(0,W.jsxs)(`div`,{className:`project-removal-note`,children:[(0,W.jsx)(`p`,{children:`只移除项目列表中的记录,服务器上的文件和会话历史都会保留。`}),(0,W.jsx)(`p`,{children:`之后重新添加同一目录,即可继续访问原有会话。进行中的任务或未确认的操作需要先处理完成。`})]})]}):(0,W.jsxs)(W.Fragment,{children:[(0,W.jsx)(`p`,{id:`project-dialog-description`,children:e.project?`为项目设置便于识别的名称,或从工作空间移除项目。`:`添加运行 Codex Web UI 的服务器上已有的目录。添加后即可查看历史会话并开始工作。`}),e.project?(0,W.jsxs)(`div`,{className:`project-directory`,children:[(0,W.jsx)(`span`,{children:`服务器目录`}),(0,W.jsx)(`code`,{children:e.project.rootPath})]}):(0,W.jsxs)(`label`,{className:`project-field`,children:[(0,W.jsx)(`span`,{children:`服务器目录`}),(0,W.jsx)(`input`,{autoFocus:!0,required:!0,autoComplete:`off`,spellCheck:!1,placeholder:`/home/you/code/my-project`,value:r,onChange:e=>i(e.target.value),"aria-describedby":`project-path-help`,"aria-label":`服务器目录`,disabled:p}),(0,W.jsx)(`small`,{id:`project-path-help`,children:`填写服务器上的绝对路径,不是当前浏览器所在设备的目录。目录需要已存在,且服务有权访问。`})]}),(0,W.jsxs)(`label`,{className:`project-field`,children:[(0,W.jsx)(`span`,{children:e.project?`项目名称`:`项目名称(可选)`}),(0,W.jsx)(`input`,{autoFocus:!!e.project,required:!!e.project,maxLength:100,placeholder:`默认使用目录名称`,value:a,onChange:e=>o(e.target.value),disabled:p})]})]}),d&&(0,W.jsx)(`p`,{className:`inline-error project-dialog-error`,role:`alert`,children:d}),e.disabled&&(0,W.jsx)(`p`,{className:`subtle`,children:`登录已过期,请重新登录后管理项目。`}),(0,W.jsxs)(`div`,{className:`project-dialog-actions`,children:[e.project&&!s&&(0,W.jsx)(q,{className:`project-remove-button`,variant:`ghost`,disabled:p,onClick:()=>{f(void 0),c(!0)},children:`移除项目…`}),(0,W.jsx)(q,{variant:`secondary`,disabled:l,onClick:()=>{s?(f(void 0),c(!1)):e.onClose()},children:s?`返回`:`取消`}),(0,W.jsx)(q,{type:`submit`,variant:s?`destructive`:`default`,disabled:p||!s&&(e.project?!a.trim():!r.trim()),children:l?s?`正在移除…`:`正在保存…`:s?`确认移除`:e.project?`保存名称`:`添加项目`})]})]})]})}function rw({notifications:e,onClose:t}){let n=(0,O.useRef)(null);(0,O.useEffect)(()=>{let e=n.current;return e?.showModal(),()=>e?.close()},[]);let{enabled:r,access:i,requesting:a,error:o}=e,s=r&&i===`granted`,c={default:`尚未授权`,granted:`已授权`,denied:`已被浏览器阻止`,unsupported:`当前浏览器不支持`,insecure:`需要安全连接`}[i],l=![`default`,`granted`].includes(i);return(0,W.jsxs)(`dialog`,{ref:n,className:`project-dialog notification-dialog`,"aria-labelledby":`notification-dialog-title`,onCancel:e=>{e.preventDefault(),t()},children:[(0,W.jsxs)(`div`,{className:`project-dialog-heading`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(F,{size:20,"aria-hidden":`true`}),(0,W.jsx)(`h2`,{id:`notification-dialog-title`,children:`工作完成通知`})]}),(0,W.jsx)(q,{variant:`ghost`,size:`icon`,"aria-label":`关闭通知设置`,onClick:t,children:(0,W.jsx)(J,{name:`close`,size:17})})]}),(0,W.jsx)(`p`,{children:`每轮工作结束时显示项目、会话及结果,点击通知可返回对应会话。`}),(0,W.jsxs)(`div`,{className:`notification-control`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(`strong`,{children:`浏览器通知`}),(0,W.jsxs)(`span`,{role:`status`,children:[c,` · `,s?`已开启`:`未开启`]})]}),(0,W.jsx)(q,{role:`switch`,"aria-label":`浏览器通知`,"aria-checked":s,"aria-describedby":`notification-permission-help`,variant:s?`secondary`:`default`,size:`sm`,disabled:a||l,onClick:()=>void e.toggle(),children:a?`等待授权…`:s?`关闭通知`:`启用通知`})]}),(0,W.jsx)(`p`,{id:`notification-permission-help`,className:`notification-help`,children:i===`denied`?`请在浏览器的站点设置中允许通知,再回到此页面开启。`:i===`insecure`?`请使用 HTTPS 访问。localhost 或 127.0.0.1 可用于本机访问。`:i===`unsupported`?`请使用支持系统通知的桌面浏览器。页内状态与未读提示仍然可用。`:`只有点击启用后才会请求授权。此设置在当前浏览器的本站标签页间共享。`}),r&&i===`granted`&&(0,W.jsx)(q,{variant:`secondary`,size:`sm`,onClick:e.test,children:`发送测试通知`}),o&&(0,W.jsx)(`p`,{className:`inline-error`,role:`alert`,children:o}),(0,W.jsxs)(`section`,{className:`notification-background`,"aria-labelledby":`notification-background-title`,children:[(0,W.jsx)(`h3`,{id:`notification-background-title`,children:`后台通知与页面休眠`}),(0,W.jsx)(`p`,{children:`请保持页面和浏览器运行。普通后台状态可接收通知;页面被冻结或被回收期间,无法保证及时通知。恢复页面后会同步结果与未读提示。`}),(0,W.jsxs)(`details`,{children:[(0,W.jsx)(`summary`,{children:`如何让本站保持活跃`}),(0,W.jsxs)(`ul`,{children:[(0,W.jsxs)(`li`,{children:[`Chrome:设置 → 性能 → 始终保持这些网站活跃,添加本站。`,(0,W.jsx)(`a`,{href:`https://support.google.com/chrome/answer/12929150?hl=zh-Hans`,target:`_blank`,rel:`noreferrer`,children:`设置说明`})]}),(0,W.jsxs)(`li`,{children:[`Edge:设置 → 系统和性能 → 性能 → 始终保持这些网站活跃(或「从不将这些网站置于睡眠状态」),添加本站。`,(0,W.jsx)(`a`,{href:`https://support.microsoft.com/edge/learn-about-performance-features-in-microsoft-edge`,target:`_blank`,rel:`noreferrer`,children:`设置说明`})]})]}),(0,W.jsx)(`p`,{children:`需要在浏览器中手动设置,具体名称可能随版本变化。`})]})]})]})}var iw=[{key:`host`,label:`监听地址`,group:`network`,help:`本机模式使用 127.0.0.1、localhost 或 ::1。`},{key:`port`,label:`监听端口`,group:`network`,type:`number`,help:`范围 1–65535;修改后使用新端口访问。`},{key:`publicOrigin`,label:`允许访问地址`,group:`network`,multiline:!0,help:`每行一个完整的 HTTP(S) 地址,仅包含协议、主机和端口。`},{key:`issuer`,label:`Access 团队地址`,group:`network`,help:`例如 https://your-team.cloudflareaccess.com`},{key:`audience`,label:`Access 应用 AUD`,group:`network`,help:`填写 Cloudflare Access 应用的 Audience。`},{key:`binary`,label:`Codex 可执行文件`,group:`codex`,help:`可填写 codex 或服务器上的绝对路径。`},{key:`home`,label:`CODEX_HOME(可选)`,group:`codex`,help:`留空继承服务进程环境;指定时必须填写服务器上的绝对路径。`},{key:`requestTimeoutMs`,label:`请求超时(毫秒)`,group:`codex`,type:`number`,help:`范围 100–300000,默认 30000。`},{key:`maxLineBytes`,label:`Codex 单行消息上限(字节)`,group:`advanced`,type:`number`,help:`范围 1024–268435456,默认 67108864。`},{key:`eventBytes`,label:`事件缓冲上限(字节)`,group:`advanced`,type:`number`,help:`范围 1024–67108864,默认 16777216。`},{key:`wsBytes`,label:`WebSocket 缓冲上限(字节)`,group:`advanced`,type:`number`,help:`范围 1024–16777216,默认 4194304。`},{key:`itemBytes`,label:`单项内容上限(字节)`,group:`advanced`,type:`number`,help:`范围 1024–8388608,默认 2097152。`},{key:`developmentOrigins`,label:`开发环境来源`,group:`advanced`,multiline:!0,help:`每行一个本机 HTTP(S) 来源,仅在 --dev 模式使用。`}];function aw(e){return{host:e.host,port:String(e.port),publicOrigin:e.publicOrigin.join(`
81
81
  `),developmentOrigins:e.developmentOrigins.join(`
82
82
  `),mode:e.auth.mode,issuer:e.auth.mode===`cloudflare-access`?e.auth.issuer:``,audience:e.auth.mode===`cloudflare-access`?e.auth.audience:``,binary:e.codex.binary,home:e.codex.home??``,requestTimeoutMs:String(e.codex.requestTimeoutMs),maxLineBytes:String(e.codex.maxLineBytes),eventBytes:String(e.limits.eventBytes),wsBytes:String(e.limits.wsBytes),itemBytes:String(e.limits.itemBytes)}}var ow=e=>e.split(`
83
- `).map(e=>e.trim()).filter(Boolean);function sw(e,t){return{...t,host:e.host.trim(),port:Number(e.port),publicOrigin:ow(e.publicOrigin),developmentOrigins:ow(e.developmentOrigins),auth:e.mode===`local`?{mode:`local`}:{mode:e.mode,issuer:e.issuer.trim(),audience:e.audience.trim()},codex:{binary:e.binary.trim(),...e.home.trim()?{home:e.home.trim()}:{},requestTimeoutMs:Number(e.requestTimeoutMs),maxLineBytes:Number(e.maxLineBytes)},limits:{eventBytes:Number(e.eventBytes),wsBytes:Number(e.wsBytes),itemBytes:Number(e.itemBytes)}}}function cw(e,t){let n=aw(e),r=aw(t);return[...n.mode===r.mode?[]:[{label:`认证模式`,before:n.mode,after:r.mode}],...iw.filter(e=>!([`issuer`,`audience`].includes(e.key)&&r.mode===`local`)&&n[e.key]!==r[e.key]).map(e=>({label:e.label,before:n[e.key],after:r[e.key]}))]}var lw=e=>e instanceof Error?e.message:`操作失败,请重试。`;function uw({onClose:e}){let t=(0,O.useRef)(null),n=(0,O.useRef)(null),[r,i]=(0,O.useState)(),[a,o]=(0,O.useState)(),[s,c]=(0,O.useState)(),[l,u]=(0,O.useState)(),[d,f]=(0,O.useState)(!0),[p,m]=(0,O.useState)(``),[h,g]=(0,O.useState)(``),[_,v]=(0,O.useState)(!1),[y,b]=(0,O.useState)(!1),x=!!r&&!!a&&JSON.stringify(sw(a,r.saved))!==JSON.stringify(r.saved);(0,O.useEffect)(()=>{t.current?.showModal();let e=new AbortController;return Oe.gatewayConfig().then(t=>{e.signal.aborted||(i(t),o(aw(t.saved)))}).catch(t=>{e.signal.aborted||m(lw(t))}).finally(()=>{e.signal.aborted||f(!1)}),()=>{e.abort(),t.current?.close()}},[]),(0,O.useEffect)(()=>{let e=e=>{x&&e.preventDefault()};return window.addEventListener(`beforeunload`,e),()=>window.removeEventListener(`beforeunload`,e)},[x]);let S=()=>{d||(x||l?b(!0):e())};async function C(e){f(!0),m(``),g(``);try{await e()}catch(e){m(lw(e)),e instanceof Ee&&e.problem.code===`CONFIG_CONFLICT`&&v(!0)}finally{f(!1)}}async function w(){await C(async()=>{let e=await Oe.gatewayConfig();i(e),o(aw(e.saved)),c(void 0),u(void 0),v(!1)})}async function T(e){let t=e.target.files?.[0];e.target.value=``,t&&await C(async()=>{if(t.size>262144)throw Error(`配置文件不能超过 256 KiB。`);let e;try{e=JSON.parse(await t.text())}catch{throw Error(`无法解析 JSON,请检查配置文件格式。`)}u(await Oe.importGatewayConfig(e)),c(void 0)})}async function E(){await C(async()=>{let e=await Oe.exportGatewayConfig(),t=URL.createObjectURL(new Blob([`${JSON.stringify(e,null,2)}\n`],{type:`application/json`})),n=document.createElement(`a`);n.href=t,n.download=`codex-web-config.json`,document.body.append(n),n.click(),n.remove(),setTimeout(()=>URL.revokeObjectURL(t),1e3),g(`已导出配置文件中的已保存配置;未保存的编辑不包含在内。`)})}let D=r&&aw(r.running),k=l?.config??s,A=r&&k?cw(r.saved,k):[];function j(e){if(!a||!D||[`issuer`,`audience`].includes(e.key)&&a.mode!==`cloudflare-access`)return null;let t={id:`gateway-${e.key}`,"aria-labelledby":`gateway-${e.key}-label`,"aria-describedby":`gateway-${e.key}-help`,value:a[e.key],disabled:d||!r?.writable,onChange:t=>{o({...a,[e.key]:t.target.value}),g(``)}};return(0,W.jsxs)(`label`,{className:`project-field`,htmlFor:t.id,children:[(0,W.jsx)(`span`,{id:`gateway-${e.key}-label`,children:e.label}),`multiline`in e?(0,W.jsx)(`textarea`,{...t,rows:3,spellCheck:!1}):(0,W.jsx)(`input`,{...t,type:`type`in e?e.type:`text`,spellCheck:!1}),(0,W.jsx)(`small`,{id:`gateway-${e.key}-help`,children:e.help}),a[e.key]!==D[e.key]&&(0,W.jsxs)(`small`,{className:`gateway-running`,children:[`当前运行:`,D[e.key]||`未设置`]})]},e.key)}return(0,W.jsxs)(`dialog`,{ref:t,className:`project-dialog gateway-dialog`,"aria-labelledby":`gateway-title`,onCancel:e=>{e.preventDefault(),S()},children:[(0,W.jsxs)(`div`,{className:`project-dialog-heading`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(_e,{size:20,"aria-hidden":`true`}),(0,W.jsx)(`h2`,{id:`gateway-title`,children:`服务配置`})]}),(0,W.jsx)(q,{variant:`ghost`,size:`icon`,"aria-label":`关闭服务配置`,disabled:d,onClick:S,children:(0,W.jsx)(J,{name:`close`,size:17})})]}),(0,W.jsx)(`p`,{className:`gateway-intro`,children:`配置运行此网页服务的电脑。保存后需手动重启服务生效。`}),p&&(0,W.jsx)(`p`,{className:`gateway-error`,role:`alert`,children:p}),!r&&(0,W.jsx)(q,{variant:`secondary`,disabled:d,onClick:()=>void w(),children:d?`正在读取配置…`:`重新读取配置`}),r&&a&&(0,W.jsxs)(W.Fragment,{children:[(0,W.jsxs)(`div`,{className:`gateway-file`,children:[(0,W.jsx)(`span`,{children:`配置文件`}),(0,W.jsx)(`code`,{children:r.path})]}),(0,W.jsxs)(`div`,{className:`gateway-status`,role:`status`,"data-pending":r.restartRequired,children:[(0,W.jsx)(`strong`,{children:r.restartRequired?`已保存,待重启生效`:`已保存配置与当前运行配置一致`}),(0,W.jsx)(`span`,{children:`保存不会重启服务或中断当前任务。`})]}),!r.writable&&(0,W.jsx)(`p`,{className:`gateway-error`,children:r.readOnlyReason}),h&&(0,W.jsx)(`p`,{className:`gateway-notice`,role:`status`,children:h}),_&&(0,W.jsxs)(`div`,{className:`gateway-conflict`,children:[(0,W.jsx)(`p`,{children:`重新读取会丢弃当前编辑,并载入文件的最新内容。`}),(0,W.jsx)(q,{variant:`secondary`,disabled:d,onClick:()=>void w(),children:`丢弃编辑并重新读取`})]}),y?(0,W.jsxs)(`section`,{className:`gateway-review`,"aria-label":`放弃编辑确认`,children:[(0,W.jsx)(`h3`,{children:`放弃未保存的更改?`}),(0,W.jsx)(`p`,{children:`配置文件尚未修改。`}),(0,W.jsxs)(`div`,{className:`project-dialog-actions`,children:[(0,W.jsx)(q,{variant:`secondary`,onClick:()=>b(!1),children:`继续编辑`}),(0,W.jsx)(q,{variant:`destructive`,onClick:e,children:`放弃更改并关闭`})]})]}):k?(0,W.jsxs)(`section`,{className:`gateway-review`,"aria-label":l?`导入配置预览`:`保存配置预览`,children:[(0,W.jsx)(`h3`,{children:l?`预览导入配置`:`确认配置更改`}),(0,W.jsx)(`p`,{children:l?`应用到表单后仍需检查并保存,才会修改配置文件。导入将替换当前表单中的可编辑配置。`:`以下更改将在服务重启后生效。请确认新的访问地址和认证配置。`}),l&&(0,W.jsxs)(`p`,{children:[`保留当前数据目录和项目初始配置。`,l.preserved.length>0?`已忽略导入文件中的 ${l.preserved.join(`、`)}。`:``]}),A.length?(0,W.jsx)(`div`,{className:`gateway-changes`,children:A.map(e=>(0,W.jsxs)(`div`,{children:[(0,W.jsx)(`strong`,{children:e.label}),(0,W.jsxs)(`span`,{children:[`已保存:`,e.before||`未设置`]}),(0,W.jsxs)(`span`,{children:[`更改为:`,e.after||`未设置`]})]},e.label))}):(0,W.jsx)(`p`,{children:`与已保存配置没有差异。`}),(0,W.jsxs)(`details`,{className:`gateway-json`,children:[(0,W.jsx)(`summary`,{children:`查看完整 JSON`}),(0,W.jsx)(`pre`,{children:JSON.stringify(k,null,2)})]}),(0,W.jsxs)(`div`,{className:`project-dialog-actions`,children:[(0,W.jsx)(q,{variant:`secondary`,disabled:d,onClick:()=>{u(void 0),c(void 0)},children:`返回编辑`}),l?(0,W.jsx)(q,{disabled:d,onClick:()=>{o(aw(l.config)),u(void 0),g(`导入配置已应用到表单,尚未保存。`)},children:`应用到表单`}):(0,W.jsx)(q,{disabled:d||_||!A.length,onClick:()=>void C(async()=>{let e=await Oe.saveGatewayConfig(r.revision,k);i(e),o(aw(e.saved)),c(void 0),g(e.restartRequired?`配置已保存。请在方便时手动重启服务。`:`配置已保存,与当前运行配置一致。`)}),children:d?`正在保存…`:`确认保存`})]})]}):(0,W.jsxs)(W.Fragment,{children:[(0,W.jsxs)(`div`,{className:`gateway-tools`,children:[(0,W.jsxs)(q,{variant:`secondary`,size:`sm`,disabled:d||!r.writable,onClick:()=>n.current?.click(),children:[(0,W.jsx)(ye,{size:15,"aria-hidden":`true`}),`导入配置`]}),(0,W.jsxs)(q,{variant:`secondary`,size:`sm`,disabled:d,onClick:()=>void E(),children:[(0,W.jsx)(ce,{size:15,"aria-hidden":`true`}),`导出已保存配置`]}),(0,W.jsx)(`input`,{ref:n,type:`file`,accept:`.json,application/json`,"aria-label":`选择配置文件`,hidden:!0,onChange:e=>void T(e)})]}),(0,W.jsx)(`p`,{className:`gateway-help`,children:`导入仅更新服务设置;导出包含文件中的项目初始配置,不包含页面注册项目、会话、数据库或登录凭据。`}),(0,W.jsxs)(`form`,{onSubmit:e=>{e.preventDefault(),C(async()=>{c((await Oe.importGatewayConfig(sw(a,r.saved))).config)})},children:[(0,W.jsxs)(`fieldset`,{disabled:d||!r.writable,children:[(0,W.jsxs)(`section`,{className:`gateway-section`,children:[(0,W.jsx)(`h3`,{children:`网络与访问`}),(0,W.jsxs)(`div`,{className:`gateway-fields`,children:[iw.filter(e=>e.group===`network`).map(j),(0,W.jsxs)(`label`,{className:`project-field`,children:[(0,W.jsx)(`span`,{children:`认证模式`}),(0,W.jsxs)(`select`,{"aria-label":`认证模式`,value:a.mode,onChange:e=>o({...a,mode:e.target.value}),children:[(0,W.jsx)(`option`,{value:`local`,children:`本机 / Tailscale(local)`}),(0,W.jsx)(`option`,{value:`cloudflare-access`,children:`Cloudflare Access`})]}),(0,W.jsx)(`small`,{children:`本机模式仅监听回环地址;公开互联网入口使用 Cloudflare Access。`}),a.mode!==D?.mode&&(0,W.jsxs)(`small`,{className:`gateway-running`,children:[`当前运行:`,D?.mode]})]})]})]}),(0,W.jsxs)(`section`,{className:`gateway-section`,children:[(0,W.jsx)(`h3`,{children:`Codex`}),(0,W.jsx)(`div`,{className:`gateway-fields`,children:iw.filter(e=>e.group===`codex`).map(j)})]}),(0,W.jsxs)(`section`,{className:`gateway-section`,children:[(0,W.jsx)(`h3`,{children:`数据与项目`}),(0,W.jsxs)(`div`,{className:`gateway-file`,children:[(0,W.jsx)(`span`,{children:`数据目录(只读)`}),(0,W.jsx)(`code`,{children:r.saved.dataDir}),(0,W.jsx)(`span`,{children:`当前运行目录`}),(0,W.jsx)(`code`,{children:r.running.dataDir})]}),(0,W.jsx)(`p`,{className:`gateway-help`,children:`数据目录变更需要迁移数据库,请在服务停止后处理。项目请在侧栏添加、重命名或移除;此处不覆盖已保存的项目管理结果。`})]}),(0,W.jsxs)(`details`,{className:`gateway-section`,children:[(0,W.jsx)(`summary`,{children:`高级设置`}),(0,W.jsx)(`div`,{className:`gateway-fields`,children:iw.filter(e=>e.group===`advanced`).map(j)})]})]}),(0,W.jsxs)(`div`,{className:`gateway-save-bar`,children:[(0,W.jsx)(`span`,{children:x?`有未保存的更改`:`没有未保存的更改`}),(0,W.jsx)(q,{type:`submit`,disabled:d||!x||!r.writable||_,children:d?`正在校验…`:`检查更改`})]})]})]})]})]})}var dw=[`stable`,`beta`,`dev`],fw=e=>!!(e&&[`installing`,`waiting`,`stopping`,`verifying`].includes(e.phase)),pw={stable:`稳定版`,beta:`预览版`,dev:`开发版`},mw={installing:`正在安装候选版本`,waiting:`等待任务空闲`,stopping:`正在备份并重启`,verifying:`正在验证新版`,succeeded:`升级成功`,rolledBack:`已恢复上一版本`,failed:`升级失败`},hw={verified:`已验证`,unverified:`尚未验证`,unsupported:`明确不支持`,unknown:`无法确认`};function gw({title:e,value:t}){return(0,W.jsxs)(`section`,{className:`update-codex`,"aria-label":e,"data-state":t.status,children:[(0,W.jsx)(`h3`,{children:e}),(0,W.jsxs)(`div`,{children:[(0,W.jsx)(`span`,{children:`Codex CLI`}),(0,W.jsx)(`strong`,{children:t.version??`未识别`}),(0,W.jsx)(`span`,{className:`update-codex-status`,children:hw[t.status]})]}),t.manifest&&(0,W.jsxs)(`p`,{className:`subtle`,children:[`推荐:`,t.manifest.recommended,` · 已验证:`,t.manifest.verified.join(`、`)]}),t.reason&&(0,W.jsx)(`p`,{children:t.reason})]})}function _w({updates:e,onClose:t}){let n=(0,O.useRef)(null),{status:r,busy:i,error:a,reloadError:o}=e,[s,c]=(0,O.useState)(),l=s??r?.settings.channel??`stable`,[u,d]=(0,O.useState)(!1),f=r?.available?.channel===l?r.available:void 0,p=fw(r?.run),m=f?.version===r?.version,[h,g]=(0,O.useState)(),_=JSON.stringify([l,f?.version,f?.codex]),v=h===_,y=f?.codex,b=!m&&y?.status===`unverified`,x=!m&&f&&(!y||y.status===`unknown`||y.status===`unsupported`||b&&!v);return(0,O.useEffect)(()=>{g(void 0)},[_]),(0,O.useEffect)(()=>{let e=n.current;return e?.showModal(),()=>e?.close()},[]),(0,W.jsxs)(`dialog`,{ref:n,className:`project-dialog update-dialog`,"aria-labelledby":`update-title`,onCancel:e=>{e.preventDefault(),t()},children:[(0,W.jsxs)(`div`,{className:`project-dialog-heading`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(ie,{size:20,"aria-hidden":`true`}),(0,W.jsx)(`h2`,{id:`update-title`,children:`Covro 更新`})]}),(0,W.jsx)(q,{variant:`ghost`,size:`icon`,"aria-label":`关闭更新设置`,onClick:t,children:(0,W.jsx)(J,{name:`close`,size:17})})]}),(0,W.jsxs)(`div`,{className:`update-version`,children:[(0,W.jsx)(`span`,{children:`当前 Covro`}),(0,W.jsx)(`strong`,{children:r?.version??`读取中…`}),r?.commit&&(0,W.jsx)(`code`,{children:r.commit.slice(0,8)})]}),r?.codex&&(0,W.jsx)(gw,{title:`当前 Codex`,value:r.codex}),(0,W.jsxs)(`label`,{className:`update-channel`,children:[`版本渠道`,(0,W.jsx)(`select`,{"aria-label":`版本渠道`,value:l,disabled:i||p,onChange:t=>{let n=t.target.value;c(n),d(!1),g(void 0),e.check(n)},children:dw.map(e=>(0,W.jsx)(`option`,{value:e,children:pw[e]},e))})]}),(0,W.jsx)(`p`,{className:`subtle`,children:l===`stable`?`经过验证的正式版本,适合日常使用。`:l===`beta`?`提前体验准备发布的功能。`:`跟随通过检查的 main 提交,适合开发者体验和验证新功能。`}),(0,W.jsxs)(`div`,{className:`update-control`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(`strong`,{children:`空闲时自动升级`}),(0,W.jsx)(`p`,{className:`subtle`,children:`定期检查当前渠道,已验证的 Codex 组合在任务结束后安装并重启。`})]}),(0,W.jsx)(q,{role:`switch`,"aria-label":`空闲时自动升级`,"aria-checked":r?.settings.automatic??!1,variant:`secondary`,size:`sm`,disabled:i||p||!r?.supported,onClick:()=>r&&void e.configure({...r.settings,automatic:!r.settings.automatic}),children:r?.settings.automatic?`已开启`:`已关闭`})]}),r&&l!==r.settings.channel&&(0,W.jsxs)(`p`,{className:`subtle`,children:[`当前订阅:`,pw[r.settings.channel],`。成功更新后切换到`,pw[l],`。`]}),f&&(0,W.jsxs)(`div`,{className:`update-available`,children:[(0,W.jsx)(`span`,{children:m?`此渠道已是当前版本`:f.downgrade?`目标版本`:`可用版本`}),(0,W.jsx)(`strong`,{children:f.version}),f.commit&&(0,W.jsx)(`code`,{children:f.commit.slice(0,8)})]}),f?.codex&&(0,W.jsx)(gw,{title:`目标版本兼容性`,value:f.codex}),b&&(0,W.jsxs)(`label`,{className:`update-downgrade update-codex-consent`,children:[(0,W.jsx)(`input`,{type:`checkbox`,"aria-label":`允许尝试未验证的 Codex 组合`,checked:v,disabled:i||p,onChange:e=>g(e.target.checked?_:void 0)}),`我确认尝试 Codex `,y?.version,` 与 Covro `,f?.version,` `,`的未验证组合;此确认仅用于本次升级。`]}),f&&!m&&f.channel===r?.settings.channel&&r.settings.automatic&&y?.status!==`verified`&&(0,W.jsx)(`p`,{className:`update-notice`,role:`status`,children:y?.status===`unverified`?`自动升级已暂停。可以调整 Codex 版本后重新检查,或勾选确认后手动尝试。`:`自动升级已暂停。请先恢复 Codex 连接、调整版本或等待含有效兼容声明的发行版,再重新检查。`}),(0,W.jsxs)(`div`,{className:`update-buttons`,children:[(0,W.jsx)(q,{variant:`secondary`,disabled:i||p,onClick:()=>void e.check(l),children:i?`正在处理…`:`检查更新`}),(0,W.jsx)(q,{disabled:i||p||!f||!r?.supported||!!x||f.downgrade&&!u||m&&l===r.settings.channel,onClick:()=>void e.start(l,u,b&&v&&f?.codex.version?{version:f.codex.version,target:f.version}:void 0),children:m?`使用此渠道`:f?.downgrade?`切换并重启`:`升级并重启`})]}),f?.downgrade&&(0,W.jsxs)(`label`,{className:`update-downgrade`,children:[(0,W.jsx)(`input`,{type:`checkbox`,checked:u,onChange:e=>d(e.target.checked)}),`允许降级;数据库不兼容时仍会阻止切换`]}),r?.run&&(0,W.jsxs)(`section`,{className:`update-progress`,"data-phase":r.run.phase,role:`status`,children:[(0,W.jsx)(`strong`,{children:mw[r.run.phase]}),(0,W.jsxs)(`span`,{children:[r.run.from,` → `,r.run.target]}),(0,W.jsx)(`p`,{children:r.run.message}),p&&(0,W.jsx)(`progress`,{"aria-label":`升级进度`})]}),(a||r?.checkError||o)&&(0,W.jsx)(`p`,{className:`inline-error`,role:`alert`,children:o??a??r?.checkError}),!r?.supported&&r?.unsupportedReason&&(0,W.jsx)(`p`,{className:`update-notice`,children:r.unsupportedReason}),(0,W.jsxs)(`p`,{className:`update-source`,children:[`版本来源:npm 官方 registry · `,l===`stable`?`latest`:l,(0,W.jsxs)(`a`,{href:`https://github.com/yuzheng14/codex-web-ui/releases`,target:`_blank`,rel:`noreferrer`,children:[`更新记录 `,(0,W.jsx)(ue,{size:12,"aria-hidden":`true`})]})]}),(0,W.jsx)(`p`,{className:`subtle`,children:`升级保留配置、项目和会话记录。页面关闭也会继续处理,重启后自动恢复连接。`})]})}function vw(){let[e,t]=(0,O.useState)(),[n,r]=(0,O.useState)(),[i,a]=(0,O.useState)(!1),[o,s]=(0,O.useState)(),c=(0,O.useRef)(!1),l=(0,O.useRef)(!0),u=(0,O.useRef)(0),d=(0,O.useCallback)(async e=>{if(l.current&&(t(e),r(void 0),e.version!==`unknown`&&e.version!==`0.1.0`&&!c.current&&(!e.run||e.run.committed||[`rolledBack`,`failed`].includes(e.run.phase)))){c.current=!0;try{await er()}catch(e){c.current=!1,s(e instanceof Error?e.message:`草稿未能备份,暂缓重载页面`)}}},[]);(0,O.useEffect)(()=>{l.current=!0;let e=!0,t=!1,n=async()=>{if(t)return;t=!0;let n=u.current;try{let t=await De(`/api/updates`);e&&n===u.current&&await d(t)}catch{e&&r(`连接暂时中断,正在等待服务恢复…`)}finally{t=!1}};n();let i=setInterval(()=>void n(),5e3);return()=>{l.current=!1,e=!1,clearInterval(i)}},[d]);let f=(0,O.useCallback)(async(e,t)=>{u.current++,a(!0),r(void 0);try{await d(await De(e,t))}catch(e){r(e instanceof Error?e.message:`操作未能确认,请查看升级状态`)}finally{a(!1),u.current++}},[d]);return{status:e,error:n,busy:i,reloadError:o,check:e=>f(`/api/updates/check`,{channel:e}),configure:e=>f(`/api/updates/settings`,e),start:(e,t,n)=>f(`/api/updates/run`,{clientOperationId:crypto.randomUUID(),channel:e,allowDowngrade:t,codexConfirmation:n})}}var yw=encodeURIComponent;function bw({threadId:e,children:t}){return(0,W.jsx)(`div`,{className:`app-shell`,children:(0,W.jsx)(Dy,{threadId:e,children:t})})}function xw(){let e=nr(),t=vw(),[n,r]=(0,O.useState)(!1),{isUnreadCompletion:i,markCompletedRead:a}=sr(),[o,s]=(0,O.useState)(!1),[c,l]=(0,O.useState)(!1),[u,d]=(0,O.useState)(!1);(0,O.useEffect)(()=>{let e=window.matchMedia(`(min-width: 761px)`),t=()=>{e.matches&&s(!1)};return e.addEventListener(`change`,t),()=>e.removeEventListener(`change`,t)},[]);let[f,p]=(0,O.useState)(!1),[m,h]=(0,O.useState)(!1),g=(0,O.useRef)(!1),[_,v]=(0,O.useState)(),[y,b]=(0,O.useState)(!1),[x,S]=(0,O.useState)(!1),C=(0,O.useRef)(!1),w=e.projects.find(t=>t.id===e.projectId),T=_?.kind===`manage`?e.projects.find(e=>e.id===_.id):void 0;(0,O.useEffect)(()=>{_?.kind===`manage`&&!T&&v(void 0)},[_,T]);let E=()=>{s(!1),v({kind:`add`})},{thread:D,system:k}=e,A=(0,O.useRef)(void 0),j=!(!k?.ready||k.authenticated===!1||e.connection!==`connected`||e.authRequired),M=j&&!!w?.available&&!Mn(k),N=Pn(k,e.connection,e.authRequired),P=jn(k)??``,F=(t,n=D?.id??``)=>e.busy.includes(`${t}:${n}`),te=t=>e.operations.some(e=>Tn(e,t)),I=D?.turns.findLast(e=>al(e.status)),ne=D?.actions.filter(e=>e.status===`pending`||e.status===`responding`||e.kind===`unsupported`&&e.status===`expired`)??[],L=D?te(D.id)&&!F(`resume`)||D.managed&&D.status===`unknown`||D.execution&&!D.execution.ended&&D.status===`unknown`:!F(`create`,e.projectId)&&te(e.projectId),R=!!(D&&(!M||D.archived||te(D.id)||F(`resume`)||D.execution&&!D.execution.ended)),{run:z,refreshThread:re}=e,ie=(0,O.useCallback)(()=>{D&&!R&&(A.current=`${k?.codexEpoch}:${D.id}`,z(`resume`,D.id,`/api/threads/${yw(D.id)}/resume`).then(()=>re()))},[D,R,k?.codexEpoch,z,re]);(0,O.useEffect)(()=>{if((!k?.ready||D?.archived)&&(A.current=void 0),!D||D.managed||R)return;let e=`${k?.codexEpoch}:${D.id}`;A.current!==e&&ie()},[D,k?.ready,k?.codexEpoch,R,ie]);let ae=!!(D&&e.operations.some(e=>e.kind===`fork`&&Tn(e,D.id))),oe=k?.capabilities.includes(`thread/fork`)??!1,se=t=>F(`fork`,t)||e.operations.some(e=>e.kind===`fork`&&Tn(e,t)),ce=t=>{if(se(t.id))return`正在确认 Fork…请等待提交回执,暂时不能再次 Fork。`;if(!oe)return`当前 Codex 版本不支持 Fork 会话。`;if(!j)return`连接恢复且 Codex 就绪后可 Fork 会话。`;if(!e.projects.find(e=>e.id===t.projectId)?.available)return`项目目录不可用,恢复后可 Fork 会话。`;if(Mn(k))return`请先确认当前 Codex 版本的兼容性。`;if(t.historyVisible===!1||t.id===D?.id&&!D.turns.length)return`发送首条消息后可 Fork 已保存的历史。`},le=!!(D&&se(D.id)),ue=!(!D?.turns.length||ce(D)),B=async t=>{if(!ce(t))return e.run(`fork`,t.id,`/api/threads/${yw(t.id)}/fork`,t.id===D?.id?{settings:e.settings}:{})},de=()=>{D&&ue&&B(D)},fe=e.connection!==`connected`,pe=e.operations.filter(e=>e.kind===`confirmCompatibility`&&e.target===P),me=y||F(`confirmCompatibility`,P)||pe.some(e=>e.status===`accepted`||e.status===`dispatching`),ge=pe.some(e=>e.status===`unknown`&&!e.operation?.reconciliation);async function _e(){if(!g.current){g.current=!0,h(!0);try{await Promise.all([e.refreshSystem(),e.refreshThread()]),await e.refreshOperations(!0)}finally{g.current=!1,h(!1)}}}async function ve(){if(N&&!C.current){C.current=!0,b(!0);try{let t=await e.refreshSystem(),n=In(P,t,e.connection,e.authRequired);if(!n)return;await e.run(`confirmCompatibility`,P,`/api/system/compatibility/confirm`,n)}finally{C.current=!1,b(!1)}}}let ye={project:w,selectedId:e.selectedId,thread:D,system:k,connection:e.connection,authRequired:e.authRequired,settings:e.settings,openDraft:e.openDraft,busy:e.busy,operations:e.operations,run:e.run,onResumeAttempt:()=>{A.current=`${k?.codexEpoch}:${D?.id}`},refreshThread:e.refreshThread,openStatus:()=>p(!0),exportThread:ew},be=(0,O.useRef)(ye);be.current=ye;let xe=NC(()=>be.current),Se=xe.find(e=>e.name===`rename`);async function Ce(t,n,r){return!M||e.restoringSelection||e.savingModelDefaults?!1:D?n&&!I?!1:(await e.run(n?`steer`:`send`,D.id,`/api/threads/${yw(D.id)}/${n?`steer`:`turns`}`,n?{text:t,images:r,expectedTurnId:I.id}:{text:t,images:r,settings:e.settings},{kind:`send`,key:e.draftKey,text:t,images:r}))?.status===`acknowledged`:!e.selectedId&&e.sendFirstMessage(t,r)}return(0,W.jsxs)(bw,{threadId:D?.id,children:[(0,W.jsx)(dl,{onGatewaySettings:()=>{s(!1),d(!0)},onUpdates:()=>{s(!1),r(!0)},appVersion:t.status?.version,updateAvailable:!!(t.status?.available&&t.status.available.version!==t.status.version),updating:fw(t.status?.run),onNotificationSettings:()=>{s(!1),l(!0)},notificationStatus:e.notifications.error?`请检查设置`:e.notifications.enabled&&e.notifications.access===`granted`?`已开启`:`未开启`,archiveView:e.archiveView,onArchiveView:e.setArchiveView,onArchive:(t,n)=>{e.archiveThread(t,n)},onFork:e=>{B(e).then(e=>{e?.status===`acknowledged`&&s(!1)})},forkDisabledReason:ce,forking:se,archiveDisabledReason:t=>{if(F(`archive`,t.id))return`正在保存…`;if(te(t.id))return`请先核对会话操作的结果`;if(!j)return`连接恢复后可操作`;if(Mn(k))return`请先确认 Codex 版本兼容性`;if(!k?.capabilities.includes(t.archived?`thread/unarchive`:`thread/archive`))return`当前 Codex 不支持此操作`;if(!e.projects.find(e=>e.id===t.projectId)?.available)return`项目目录不可用`;if(!t.archived&&(al(t.status)||t.pendingActionCount>0))return`任务结束并处理完待办后可归档`;if(!t.archived&&t.managed&&t.status===`unknown`)return`会话状态待核对,暂时无法归档`},projects:e.projects,projectsLoaded:e.projectsLoaded,projectId:e.projectId,onProject:t=>{e.setProjectId(t),s(!1)},projectThreads:e.projectThreads,selectedId:e.selectedId,isUnreadCompletion:i,onThread:(t,n)=>{e.selectThread(t,n)},onMore:(t,n)=>{e.loadProjectThreads(t,n)},onRetry:t=>{e.loadProjectThreads(t,e.projectThreads[t]?.retryCursor)},onRefresh:()=>{e.refreshProjects().then(e.refreshProjectsThreads)},onAddProject:E,onManageProject:e=>{s(!1),v({kind:`manage`,id:e.id})},canManageProjects:!e.authRequired,onCreate:t=>{e.setProjectId(t),s(!1)},creating:t=>e.firstMessages.includes(t)||F(`create`,t)||te(t),canCreate:t=>j&&!e.savingModelDefaults&&!Mn(k)&&!!e.projects.find(e=>e.id===t)?.available,offline:fe,open:o,onClose:()=>s(!1)}),(0,W.jsxs)(`main`,{className:`main-panel`,children:[(0,W.jsxs)(`header`,{className:`topbar`,children:[(0,W.jsxs)(`div`,{className:`topbar-title`,children:[(0,W.jsx)(q,{className:`mobile-only`,variant:`ghost`,size:`icon`,"aria-label":`打开项目与会话`,onClick:()=>s(!0),children:(0,W.jsx)(J,{name:`menu`})}),(0,W.jsxs)(`div`,{children:[(0,W.jsxs)(`div`,{className:`breadcrumb`,children:[w?.name??`工作空间`,(0,W.jsx)(J,{name:`chevron`,size:12}),(0,W.jsx)(`span`,{children:D?`会话`:`新会话`})]}),D?(0,W.jsx)(ab,{title:D.title||`新会话`,rename:Se,pending:!!(D&&e.operations.some(e=>e.kind===`rename`&&Tn(e,D.id)))},`${D.projectId}:${D.id}`):(0,W.jsx)(`h1`,{children:`开始你的下一项任务`})]})]}),(0,W.jsxs)(`div`,{className:`topbar-status`,children:[D&&(0,W.jsx)(ol,{status:D.status,offline:fe}),(0,W.jsx)(ZC,{connection:e.connection}),D?.forkedFromId&&(0,W.jsx)(Ic,{id:`thread-source-hint`,content:`返回原会话`,children:(0,W.jsx)(q,{variant:`ghost`,size:`icon`,"aria-label":`返回原会话`,"aria-describedby":`thread-source-hint`,onClick:()=>{e.selectThread(D.forkedFromId)},children:(0,W.jsx)(ee,{size:16})})}),(0,W.jsx)($C,{system:k,connection:e.connection,operations:e.operations,thread:D,busy:e.busy,open:f,onOpenChange:p,refreshing:m,onDiscardMissing:e.discardMissingOperation,onRefresh:()=>{_e(),fe&&e.retryConnection()},onReconcile:t=>{e.run(`reconcile`,t,`/api/operations/${yw(t)}/reconcile`,{confirmEnded:!0}).then(e=>{if(e?.status===`acknowledged`)return _e()})}})]})]}),k?.demo&&(0,W.jsx)(`div`,{className:`demo-banner`,children:`模拟测试模式 · 当前执行结果来自显式启用的测试 app-server`}),e.authRequired?(0,W.jsxs)(`div`,{className:`error-banner persistent-banner`,role:`alert`,children:[(0,W.jsx)(J,{name:`alert`}),`登录已过期。任务不会因页面断开而被取消。`,(0,W.jsx)(`a`,{className:`button button-secondary button-small`,href:`/`,children:`重新打开登录入口`})]}):fe&&(0,W.jsxs)(`div`,{className:`connection-banner`,role:`status`,children:[(0,W.jsxs)(`span`,{children:[`实时连接`,e.connection===`connecting`?`正在建立`:`已断开,正在重连`,`。当前显示上次已知状态。`]}),(0,W.jsx)(q,{variant:`ghost`,size:`sm`,onClick:e.retryConnection,children:`立即重连`})]}),k&&!k.ready&&(0,W.jsxs)(`div`,{className:`error-banner persistent-banner`,role:`alert`,children:[`Codex 尚不可用:`,k.error??`请在私人电脑上检查 Codex 安装、认证与服务状态。`]}),(0,W.jsx)(tw,{system:k,onOpenChange:S,canConfirm:N,submitting:me,uncertain:ge,error:e.error,onRefresh:()=>{e.refreshSystem(),e.refreshOperations()},onConfirm:()=>{ve()},onReconfirm:()=>{ve()}}),e.error&&(0,W.jsxs)(`div`,{className:`error-banner dismissible`,role:`alert`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(`span`,{children:e.error}),e.errorDetails!==void 0&&(0,W.jsxs)(`details`,{className:`raw-details`,children:[(0,W.jsx)(`summary`,{children:`错误详情`}),(0,W.jsx)(`pre`,{children:JSON.stringify(e.errorDetails,null,2)})]})]}),(0,W.jsx)(q,{variant:`ghost`,size:`icon`,"aria-label":`关闭错误提示`,onClick:e.clearError,children:(0,W.jsx)(J,{name:`close`,size:15})})]}),e.operations.filter(e=>e.mutation).map(e=>(0,W.jsxs)(`div`,{className:`archive-notice mutation-notice`,role:`status`,children:[e.kind===`rename`?(0,W.jsx)(he,{size:16}):(0,W.jsx)(J,{name:`archive`,size:16}),(0,W.jsx)(`span`,{children:e.kind===`rename`?e.status===`unknown`?`重命名结果待确认`:`正在保存会话名称…`:e.mutation.archived?e.status===`unknown`?`归档结果待确认`:`正在归档会话…`:e.status===`unknown`?`取消归档结果待确认`:`正在取消归档…`}),e.status===`unknown`&&(0,W.jsx)(q,{variant:`secondary`,size:`sm`,disabled:m,onClick:()=>void _e(),children:m?`正在核对…`:`核对提交`})]},e.clientOperationId)),D?.archived&&(0,W.jsxs)(`div`,{className:`archive-notice`,role:`status`,children:[(0,W.jsx)(J,{name:`archive`,size:18}),(0,W.jsxs)(`div`,{children:[(0,W.jsx)(`strong`,{children:`此会话已归档`}),(0,W.jsx)(`p`,{children:`历史已保留。取消归档后可继续对话。`})]}),(0,W.jsx)(q,{variant:`secondary`,size:`sm`,disabled:!M||te(D.id)||F(`archive`)||!k?.capabilities.includes(`thread/unarchive`),onClick:()=>{e.archiveThread(D.id,!1)},children:F(`archive`)?`正在保存…`:`取消归档`})]}),(0,W.jsx)(rb,{thread:D,readingEnabled:!o&&!_&&!f&&!e.authRequired&&!x,onReadCompleted:a,offline:fe,projectName:w?.name,needsProject:e.projectsLoaded&&e.projects.length===0,canAddProject:!e.authRequired,onAddProject:E,questionControls:{disabled:!M||!D?.managed||!!D.archived||!!L||F(`send`)||F(`steer`)||F(`resume`),onReply:async e=>Ce(My(e),!!I)}}),(0,W.jsxs)(`div`,{className:`bottom-region`,children:[ne.length>0&&(0,W.jsx)(`div`,{className:`pending-actions`,"aria-label":`待处理请求`,children:ne.map(t=>(0,W.jsx)(JC,{action:t,disabled:!M||F(`resolve`,t.actionId)||te(t.actionId),onResolve:n=>{e.run(`resolve`,t.actionId,`/api/actions/${yw(t.actionId)}/resolve`,{resolution:n})}},t.actionId))}),L&&(0,W.jsxs)(`div`,{className:`pending-notice`,role:`status`,children:[(0,W.jsx)(J,{name:`alert`,size:15}),(0,W.jsx)(`span`,{children:D?ae?`Fork 结果尚未确认。请核对提交,暂时不能再次 Fork。`:`提交结果尚未确认。请核对提交,也可以 Fork 已保存的历史为新会话。`:`新建会话的提交结果尚未确认。请先核对提交,避免重复创建。`}),(0,W.jsx)(q,{variant:`ghost`,size:`sm`,disabled:m,"aria-expanded":f,"aria-controls":`diagnostics-panel`,onClick:()=>{p(!0),_e()},children:m?`正在核对…`:`核对提交`}),D&&!ae&&(0,W.jsx)(q,{variant:`secondary`,size:`sm`,disabled:!ue,onClick:de,children:`Fork 为新会话`})]}),(0,W.jsx)(PC,{commands:xe,thread:D,threadLoading:e.restoringSelection||!(!e.selectedId||D),draftKey:e.draftKey,sentDrafts:e.sentDrafts,projectName:w?.name,projectId:w?.available?w.id:void 0,runtimeKey:k?.ready&&e.connection===`connected`?`${k.codexEpoch}:${e.runtimeDefaultsRevision}`:void 0,settings:e.settings,models:k?.models??[],onSettings:e.setSettings,onSaveModelDefaults:e.saveModelDefaults,savingModelDefaults:e.savingModelDefaults,disabled:!M||e.restoringSelection||!!L||!!D?.archived,canInterrupt:j&&!!(D?.managed&&I),submitting:e.firstMessages.includes(e.projectId)||F(`send`)||F(`steer`),interrupting:F(`interrupt`),resuming:F(`resume`),canResume:!R,resumeAttempted:A.current===`${k?.codexEpoch}:${D?.id}`,canFork:ue,forking:le,onFork:de,onResume:ie,onInterrupt:()=>{D&&I&&e.run(`interrupt`,D.id,`/api/threads/${yw(D.id)}/interrupt`,{expectedTurnId:I.id})},onSend:Ce})]})]}),_&&(_.kind===`add`||T)&&(0,W.jsx)(nw,{project:T,disabled:e.authRequired,onAdd:e.addProject,onRename:e.renameProject,onRemove:e.removeProject,onClose:()=>v(e=>e===_?void 0:e)},_.kind===`add`?`add`:_.id),c&&(0,W.jsx)(rw,{notifications:e.notifications,onClose:()=>l(!1)}),u&&(0,W.jsx)(uw,{onClose:()=>d(!1)}),n&&(0,W.jsx)(_w,{updates:t,onClose:()=>r(!1)})]})}(0,we.createRoot)(document.getElementById(`root`)).render((0,W.jsx)(O.StrictMode,{children:(0,W.jsx)(xw,{})}));
83
+ `).map(e=>e.trim()).filter(Boolean);function sw(e,t){return{...t,host:e.host.trim(),port:Number(e.port),publicOrigin:ow(e.publicOrigin),developmentOrigins:ow(e.developmentOrigins),auth:e.mode===`local`?{mode:`local`}:{mode:e.mode,issuer:e.issuer.trim(),audience:e.audience.trim()},codex:{binary:e.binary.trim(),...e.home.trim()?{home:e.home.trim()}:{},requestTimeoutMs:Number(e.requestTimeoutMs),maxLineBytes:Number(e.maxLineBytes)},limits:{eventBytes:Number(e.eventBytes),wsBytes:Number(e.wsBytes),itemBytes:Number(e.itemBytes)}}}function cw(e,t){let n=aw(e),r=aw(t);return[...n.mode===r.mode?[]:[{label:`认证模式`,before:n.mode,after:r.mode}],...iw.filter(e=>!([`issuer`,`audience`].includes(e.key)&&r.mode===`local`)&&n[e.key]!==r[e.key]).map(e=>({label:e.label,before:n[e.key],after:r[e.key]}))]}var lw=e=>e instanceof Error?e.message:`操作失败,请重试。`;function uw({onClose:e}){let t=(0,O.useRef)(null),n=(0,O.useRef)(null),[r,i]=(0,O.useState)(),[a,o]=(0,O.useState)(),[s,c]=(0,O.useState)(),[l,u]=(0,O.useState)(),[d,f]=(0,O.useState)(!0),[p,m]=(0,O.useState)(``),[h,g]=(0,O.useState)(``),[_,v]=(0,O.useState)(!1),[y,b]=(0,O.useState)(!1),x=!!r&&!!a&&JSON.stringify(sw(a,r.saved))!==JSON.stringify(r.saved);(0,O.useEffect)(()=>{t.current?.showModal();let e=new AbortController;return Oe.gatewayConfig().then(t=>{e.signal.aborted||(i(t),o(aw(t.saved)))}).catch(t=>{e.signal.aborted||m(lw(t))}).finally(()=>{e.signal.aborted||f(!1)}),()=>{e.abort(),t.current?.close()}},[]),(0,O.useEffect)(()=>{let e=e=>{x&&e.preventDefault()};return window.addEventListener(`beforeunload`,e),()=>window.removeEventListener(`beforeunload`,e)},[x]);let S=()=>{d||(x||l?b(!0):e())};async function C(e){f(!0),m(``),g(``);try{await e()}catch(e){m(lw(e)),e instanceof Ee&&e.problem.code===`CONFIG_CONFLICT`&&v(!0)}finally{f(!1)}}async function w(){await C(async()=>{let e=await Oe.gatewayConfig();i(e),o(aw(e.saved)),c(void 0),u(void 0),v(!1)})}async function T(e){let t=e.target.files?.[0];e.target.value=``,t&&await C(async()=>{if(t.size>262144)throw Error(`配置文件不能超过 256 KiB。`);let e;try{e=JSON.parse(await t.text())}catch{throw Error(`无法解析 JSON,请检查配置文件格式。`)}u(await Oe.importGatewayConfig(e)),c(void 0)})}async function E(){await C(async()=>{let e=await Oe.exportGatewayConfig(),t=URL.createObjectURL(new Blob([`${JSON.stringify(e,null,2)}\n`],{type:`application/json`})),n=document.createElement(`a`);n.href=t,n.download=`codex-web-config.json`,document.body.append(n),n.click(),n.remove(),setTimeout(()=>URL.revokeObjectURL(t),1e3),g(`已导出配置文件中的已保存配置;未保存的编辑不包含在内。`)})}let D=r&&aw(r.running),k=l?.config??s,A=r&&k?cw(r.saved,k):[];function j(e){if(!a||!D||[`issuer`,`audience`].includes(e.key)&&a.mode!==`cloudflare-access`)return null;let t={id:`gateway-${e.key}`,"aria-labelledby":`gateway-${e.key}-label`,"aria-describedby":`gateway-${e.key}-help`,value:a[e.key],disabled:d||!r?.writable,onChange:t=>{o({...a,[e.key]:t.target.value}),g(``)}};return(0,W.jsxs)(`label`,{className:`project-field`,htmlFor:t.id,children:[(0,W.jsx)(`span`,{id:`gateway-${e.key}-label`,children:e.label}),`multiline`in e?(0,W.jsx)(`textarea`,{...t,rows:3,spellCheck:!1}):(0,W.jsx)(`input`,{...t,type:`type`in e?e.type:`text`,spellCheck:!1}),(0,W.jsx)(`small`,{id:`gateway-${e.key}-help`,children:e.help}),a[e.key]!==D[e.key]&&(0,W.jsxs)(`small`,{className:`gateway-running`,children:[`当前运行:`,D[e.key]||`未设置`]})]},e.key)}return(0,W.jsxs)(`dialog`,{ref:t,className:`project-dialog gateway-dialog`,"aria-labelledby":`gateway-title`,onCancel:e=>{e.preventDefault(),S()},children:[(0,W.jsxs)(`div`,{className:`project-dialog-heading`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(_e,{size:20,"aria-hidden":`true`}),(0,W.jsx)(`h2`,{id:`gateway-title`,children:`服务配置`})]}),(0,W.jsx)(q,{variant:`ghost`,size:`icon`,"aria-label":`关闭服务配置`,disabled:d,onClick:S,children:(0,W.jsx)(J,{name:`close`,size:17})})]}),(0,W.jsx)(`p`,{className:`gateway-intro`,children:`配置运行此网页服务的电脑。保存后需手动重启服务生效。`}),p&&(0,W.jsx)(`p`,{className:`gateway-error`,role:`alert`,children:p}),!r&&(0,W.jsx)(q,{variant:`secondary`,disabled:d,onClick:()=>void w(),children:d?`正在读取配置…`:`重新读取配置`}),r&&a&&(0,W.jsxs)(W.Fragment,{children:[(0,W.jsxs)(`div`,{className:`gateway-file`,children:[(0,W.jsx)(`span`,{children:`配置文件`}),(0,W.jsx)(`code`,{children:r.path})]}),(0,W.jsxs)(`div`,{className:`gateway-status`,role:`status`,"data-pending":r.restartRequired,children:[(0,W.jsx)(`strong`,{children:r.restartRequired?`已保存,待重启生效`:`已保存配置与当前运行配置一致`}),(0,W.jsx)(`span`,{children:`保存不会重启服务或中断当前任务。`})]}),!r.writable&&(0,W.jsx)(`p`,{className:`gateway-error`,children:r.readOnlyReason}),h&&(0,W.jsx)(`p`,{className:`gateway-notice`,role:`status`,children:h}),_&&(0,W.jsxs)(`div`,{className:`gateway-conflict`,children:[(0,W.jsx)(`p`,{children:`重新读取会丢弃当前编辑,并载入文件的最新内容。`}),(0,W.jsx)(q,{variant:`secondary`,disabled:d,onClick:()=>void w(),children:`丢弃编辑并重新读取`})]}),y?(0,W.jsxs)(`section`,{className:`gateway-review`,"aria-label":`放弃编辑确认`,children:[(0,W.jsx)(`h3`,{children:`放弃未保存的更改?`}),(0,W.jsx)(`p`,{children:`配置文件尚未修改。`}),(0,W.jsxs)(`div`,{className:`project-dialog-actions`,children:[(0,W.jsx)(q,{variant:`secondary`,onClick:()=>b(!1),children:`继续编辑`}),(0,W.jsx)(q,{variant:`destructive`,onClick:e,children:`放弃更改并关闭`})]})]}):k?(0,W.jsxs)(`section`,{className:`gateway-review`,"aria-label":l?`导入配置预览`:`保存配置预览`,children:[(0,W.jsx)(`h3`,{children:l?`预览导入配置`:`确认配置更改`}),(0,W.jsx)(`p`,{children:l?`应用到表单后仍需检查并保存,才会修改配置文件。导入将替换当前表单中的可编辑配置。`:`以下更改将在服务重启后生效。请确认新的访问地址和认证配置。`}),l&&(0,W.jsxs)(`p`,{children:[`保留当前数据目录和项目初始配置。`,l.preserved.length>0?`已忽略导入文件中的 ${l.preserved.join(`、`)}。`:``]}),A.length?(0,W.jsx)(`div`,{className:`gateway-changes`,children:A.map(e=>(0,W.jsxs)(`div`,{children:[(0,W.jsx)(`strong`,{children:e.label}),(0,W.jsxs)(`span`,{children:[`已保存:`,e.before||`未设置`]}),(0,W.jsxs)(`span`,{children:[`更改为:`,e.after||`未设置`]})]},e.label))}):(0,W.jsx)(`p`,{children:`与已保存配置没有差异。`}),(0,W.jsxs)(`details`,{className:`gateway-json`,children:[(0,W.jsx)(`summary`,{children:`查看完整 JSON`}),(0,W.jsx)(`pre`,{children:JSON.stringify(k,null,2)})]}),(0,W.jsxs)(`div`,{className:`project-dialog-actions`,children:[(0,W.jsx)(q,{variant:`secondary`,disabled:d,onClick:()=>{u(void 0),c(void 0)},children:`返回编辑`}),l?(0,W.jsx)(q,{disabled:d,onClick:()=>{o(aw(l.config)),u(void 0),g(`导入配置已应用到表单,尚未保存。`)},children:`应用到表单`}):(0,W.jsx)(q,{disabled:d||_||!A.length,onClick:()=>void C(async()=>{let e=await Oe.saveGatewayConfig(r.revision,k);i(e),o(aw(e.saved)),c(void 0),g(e.restartRequired?`配置已保存。请在方便时手动重启服务。`:`配置已保存,与当前运行配置一致。`)}),children:d?`正在保存…`:`确认保存`})]})]}):(0,W.jsxs)(W.Fragment,{children:[(0,W.jsxs)(`div`,{className:`gateway-tools`,children:[(0,W.jsxs)(q,{variant:`secondary`,size:`sm`,disabled:d||!r.writable,onClick:()=>n.current?.click(),children:[(0,W.jsx)(ye,{size:15,"aria-hidden":`true`}),`导入配置`]}),(0,W.jsxs)(q,{variant:`secondary`,size:`sm`,disabled:d,onClick:()=>void E(),children:[(0,W.jsx)(ce,{size:15,"aria-hidden":`true`}),`导出已保存配置`]}),(0,W.jsx)(`input`,{ref:n,type:`file`,accept:`.json,application/json`,"aria-label":`选择配置文件`,hidden:!0,onChange:e=>void T(e)})]}),(0,W.jsx)(`p`,{className:`gateway-help`,children:`导入仅更新服务设置;导出包含文件中的项目初始配置,不包含页面注册项目、会话、数据库或登录凭据。`}),(0,W.jsxs)(`form`,{onSubmit:e=>{e.preventDefault(),C(async()=>{c((await Oe.importGatewayConfig(sw(a,r.saved))).config)})},children:[(0,W.jsxs)(`fieldset`,{disabled:d||!r.writable,children:[(0,W.jsxs)(`section`,{className:`gateway-section`,children:[(0,W.jsx)(`h3`,{children:`网络与访问`}),(0,W.jsxs)(`div`,{className:`gateway-fields`,children:[iw.filter(e=>e.group===`network`).map(j),(0,W.jsxs)(`label`,{className:`project-field`,children:[(0,W.jsx)(`span`,{children:`认证模式`}),(0,W.jsxs)(`select`,{"aria-label":`认证模式`,value:a.mode,onChange:e=>o({...a,mode:e.target.value}),children:[(0,W.jsx)(`option`,{value:`local`,children:`本机 / Tailscale(local)`}),(0,W.jsx)(`option`,{value:`cloudflare-access`,children:`Cloudflare Access`})]}),(0,W.jsx)(`small`,{children:`本机模式仅监听回环地址;公开互联网入口使用 Cloudflare Access。`}),a.mode!==D?.mode&&(0,W.jsxs)(`small`,{className:`gateway-running`,children:[`当前运行:`,D?.mode]})]})]})]}),(0,W.jsxs)(`section`,{className:`gateway-section`,children:[(0,W.jsx)(`h3`,{children:`Codex`}),(0,W.jsx)(`div`,{className:`gateway-fields`,children:iw.filter(e=>e.group===`codex`).map(j)})]}),(0,W.jsxs)(`section`,{className:`gateway-section`,children:[(0,W.jsx)(`h3`,{children:`数据与项目`}),(0,W.jsxs)(`div`,{className:`gateway-file`,children:[(0,W.jsx)(`span`,{children:`数据目录(只读)`}),(0,W.jsx)(`code`,{children:r.saved.dataDir}),(0,W.jsx)(`span`,{children:`当前运行目录`}),(0,W.jsx)(`code`,{children:r.running.dataDir})]}),(0,W.jsx)(`p`,{className:`gateway-help`,children:`数据目录变更需要迁移数据库,请在服务停止后处理。项目请在侧栏添加、重命名或移除;此处不覆盖已保存的项目管理结果。`})]}),(0,W.jsxs)(`details`,{className:`gateway-section`,children:[(0,W.jsx)(`summary`,{children:`高级设置`}),(0,W.jsx)(`div`,{className:`gateway-fields`,children:iw.filter(e=>e.group===`advanced`).map(j)})]})]}),(0,W.jsxs)(`div`,{className:`gateway-save-bar`,children:[(0,W.jsx)(`span`,{children:x?`有未保存的更改`:`没有未保存的更改`}),(0,W.jsx)(q,{type:`submit`,disabled:d||!x||!r.writable||_,children:d?`正在校验…`:`检查更改`})]})]})]})]})]})}var dw=[`stable`,`beta`,`dev`],fw=e=>!!(e&&[`installing`,`waiting`,`stopping`,`verifying`].includes(e.phase)),pw={stable:`稳定版`,beta:`预览版`,dev:`开发版`},mw={installing:`正在安装候选版本`,waiting:`等待任务空闲`,stopping:`正在备份并重启`,verifying:`正在验证新版`,succeeded:`升级成功`,rolledBack:`已恢复上一版本`,failed:`升级失败`},hw={verified:`已验证`,unverified:`尚未验证`,unsupported:`明确不支持`,unknown:`无法确认`};function gw({title:e,value:t}){return(0,W.jsxs)(`section`,{className:`update-codex`,"aria-label":e,"data-state":t.status,children:[(0,W.jsx)(`h3`,{children:e}),(0,W.jsxs)(`div`,{children:[(0,W.jsx)(`span`,{children:`Codex CLI`}),(0,W.jsx)(`strong`,{children:t.version??`未识别`}),(0,W.jsx)(`span`,{className:`update-codex-status`,children:hw[t.status]})]}),t.manifest&&(0,W.jsxs)(`p`,{className:`subtle`,children:[`推荐:`,t.manifest.recommended,` · 已验证:`,t.manifest.verified.join(`、`)]}),t.reason&&(0,W.jsx)(`p`,{children:t.reason})]})}function _w({updates:e,onClose:t}){let n=(0,O.useRef)(null),{status:r,busy:i,error:a,reloadError:o}=e,[s,c]=(0,O.useState)(),l=s??r?.settings.channel??`stable`,[u,d]=(0,O.useState)(!1),f=r?.available?.channel===l?r.available:void 0,p=fw(r?.run),m=f?.version===r?.version,[h,g]=(0,O.useState)(),_=JSON.stringify([l,f?.version,f?.codex]),v=h===_,y=f?.codex,b=!m&&y?.status===`unverified`,x=!m&&f&&(!y||y.status===`unknown`||y.status===`unsupported`||b&&!v);return(0,O.useEffect)(()=>{g(void 0)},[_]),(0,O.useEffect)(()=>{let e=n.current;return e?.showModal(),()=>e?.close()},[]),(0,W.jsxs)(`dialog`,{ref:n,className:`project-dialog update-dialog`,"aria-labelledby":`update-title`,onCancel:e=>{e.preventDefault(),t()},children:[(0,W.jsxs)(`div`,{className:`project-dialog-heading`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(ie,{size:20,"aria-hidden":`true`}),(0,W.jsx)(`h2`,{id:`update-title`,children:`Covro 更新`})]}),(0,W.jsx)(q,{variant:`ghost`,size:`icon`,"aria-label":`关闭更新设置`,onClick:t,children:(0,W.jsx)(J,{name:`close`,size:17})})]}),(0,W.jsxs)(`div`,{className:`update-version`,children:[(0,W.jsx)(`span`,{children:`当前 Covro`}),(0,W.jsx)(`strong`,{children:r?.version??`读取中…`}),r?.commit&&(0,W.jsx)(`code`,{children:r.commit.slice(0,8)})]}),r?.codex&&(0,W.jsx)(gw,{title:`当前 Codex`,value:r.codex}),(0,W.jsxs)(`label`,{className:`update-channel`,children:[`版本渠道`,(0,W.jsx)(`select`,{"aria-label":`版本渠道`,value:l,disabled:i||p,onChange:t=>{let n=t.target.value;c(n),d(!1),g(void 0),e.check(n)},children:dw.map(e=>(0,W.jsx)(`option`,{value:e,children:pw[e]},e))})]}),(0,W.jsx)(`p`,{className:`subtle`,children:l===`stable`?`经过验证的正式版本,适合日常使用。`:l===`beta`?`提前体验准备发布的功能。`:`跟随通过检查的 main 提交,适合开发者体验和验证新功能。`}),(0,W.jsxs)(`div`,{className:`update-control`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(`strong`,{children:`空闲时自动升级`}),(0,W.jsx)(`p`,{className:`subtle`,children:`定期检查当前渠道,已验证的 Codex 组合在任务结束后安装并重启。`})]}),(0,W.jsx)(q,{role:`switch`,"aria-label":`空闲时自动升级`,"aria-checked":r?.settings.automatic??!1,variant:`secondary`,size:`sm`,disabled:i||p||!r?.supported,onClick:()=>r&&void e.configure({...r.settings,automatic:!r.settings.automatic}),children:r?.settings.automatic?`已开启`:`已关闭`})]}),r&&l!==r.settings.channel&&(0,W.jsxs)(`p`,{className:`subtle`,children:[`当前订阅:`,pw[r.settings.channel],`。成功更新后切换到`,pw[l],`。`]}),f&&(0,W.jsxs)(`div`,{className:`update-available`,children:[(0,W.jsx)(`span`,{children:m?`此渠道已是当前版本`:f.downgrade?`目标版本`:`可用版本`}),(0,W.jsx)(`strong`,{children:f.version}),f.commit&&(0,W.jsx)(`code`,{children:f.commit.slice(0,8)})]}),f?.codex&&(0,W.jsx)(gw,{title:`目标版本兼容性`,value:f.codex}),b&&(0,W.jsxs)(`label`,{className:`update-downgrade update-codex-consent`,children:[(0,W.jsx)(`input`,{type:`checkbox`,"aria-label":`允许尝试未验证的 Codex 组合`,checked:v,disabled:i||p,onChange:e=>g(e.target.checked?_:void 0)}),`我确认尝试 Codex `,y?.version,` 与 Covro `,f?.version,` `,`的未验证组合;此确认仅用于本次升级。`]}),f&&!m&&f.channel===r?.settings.channel&&r.settings.automatic&&y?.status!==`verified`&&(0,W.jsx)(`p`,{className:`update-notice`,role:`status`,children:y?.status===`unverified`?`自动升级已暂停。可以调整 Codex 版本后重新检查,或勾选确认后手动尝试。`:`自动升级已暂停。请先恢复 Codex 连接、调整版本或等待含有效兼容声明的发行版,再重新检查。`}),(0,W.jsxs)(`div`,{className:`update-buttons`,children:[(0,W.jsx)(q,{variant:`secondary`,disabled:i||p,onClick:()=>void e.check(l),children:i?`正在处理…`:`检查更新`}),(0,W.jsx)(q,{disabled:i||p||!f||!r?.supported||!!x||f.downgrade&&!u||m&&l===r.settings.channel,onClick:()=>void e.start(l,u,b&&v&&f?.codex.version?{version:f.codex.version,target:f.version}:void 0),children:m?`使用此渠道`:f?.downgrade?`切换并重启`:`升级并重启`})]}),f?.downgrade&&(0,W.jsxs)(`label`,{className:`update-downgrade`,children:[(0,W.jsx)(`input`,{type:`checkbox`,checked:u,onChange:e=>d(e.target.checked)}),`允许降级;数据库不兼容时仍会阻止切换`]}),r?.run&&(0,W.jsxs)(`section`,{className:`update-progress`,"data-phase":r.run.phase,role:`status`,children:[(0,W.jsx)(`strong`,{children:mw[r.run.phase]}),(0,W.jsxs)(`span`,{children:[r.run.from,` → `,r.run.target]}),(0,W.jsx)(`p`,{children:r.run.message}),p&&(0,W.jsx)(`progress`,{"aria-label":`升级进度`})]}),(a||r?.checkError||o)&&(0,W.jsx)(`p`,{className:`inline-error`,role:`alert`,children:o??a??r?.checkError}),!r?.supported&&r?.unsupportedReason&&(0,W.jsx)(`p`,{className:`update-notice`,children:r.unsupportedReason}),(0,W.jsxs)(`p`,{className:`update-source`,children:[`版本来源:npm 官方 registry · `,l===`stable`?`latest`:l,(0,W.jsxs)(`a`,{href:`https://github.com/yuzheng14/codex-web-ui/releases`,target:`_blank`,rel:`noreferrer`,children:[`更新记录 `,(0,W.jsx)(ue,{size:12,"aria-hidden":`true`})]})]}),(0,W.jsx)(`p`,{className:`subtle`,children:`升级保留配置、项目和会话记录。页面关闭也会继续处理,重启后自动恢复连接。`})]})}function vw(){let[e,t]=(0,O.useState)(),[n,r]=(0,O.useState)(),[i,a]=(0,O.useState)(!1),[o,s]=(0,O.useState)(),c=(0,O.useRef)(!1),l=(0,O.useRef)(!0),u=(0,O.useRef)(0),d=(0,O.useCallback)(async e=>{if(l.current&&(t(e),r(void 0),e.version!==`unknown`&&e.version!==`0.1.1-dev.1`&&!c.current&&(!e.run||e.run.committed||[`rolledBack`,`failed`].includes(e.run.phase)))){c.current=!0;try{await er()}catch(e){c.current=!1,s(e instanceof Error?e.message:`草稿未能备份,暂缓重载页面`)}}},[]);(0,O.useEffect)(()=>{l.current=!0;let e=!0,t=!1,n=async()=>{if(t)return;t=!0;let n=u.current;try{let t=await De(`/api/updates`);e&&n===u.current&&await d(t)}catch{e&&r(`连接暂时中断,正在等待服务恢复…`)}finally{t=!1}};n();let i=setInterval(()=>void n(),5e3);return()=>{l.current=!1,e=!1,clearInterval(i)}},[d]);let f=(0,O.useCallback)(async(e,t)=>{u.current++,a(!0),r(void 0);try{await d(await De(e,t))}catch(e){r(e instanceof Error?e.message:`操作未能确认,请查看升级状态`)}finally{a(!1),u.current++}},[d]);return{status:e,error:n,busy:i,reloadError:o,check:e=>f(`/api/updates/check`,{channel:e}),configure:e=>f(`/api/updates/settings`,e),start:(e,t,n)=>f(`/api/updates/run`,{clientOperationId:crypto.randomUUID(),channel:e,allowDowngrade:t,codexConfirmation:n})}}var yw=encodeURIComponent;function bw({threadId:e,children:t}){return(0,W.jsx)(`div`,{className:`app-shell`,children:(0,W.jsx)(Dy,{threadId:e,children:t})})}function xw(){let e=nr(),t=vw(),[n,r]=(0,O.useState)(!1),{isUnreadCompletion:i,markCompletedRead:a}=sr(),[o,s]=(0,O.useState)(!1),[c,l]=(0,O.useState)(!1),[u,d]=(0,O.useState)(!1);(0,O.useEffect)(()=>{let e=window.matchMedia(`(min-width: 761px)`),t=()=>{e.matches&&s(!1)};return e.addEventListener(`change`,t),()=>e.removeEventListener(`change`,t)},[]);let[f,p]=(0,O.useState)(!1),[m,h]=(0,O.useState)(!1),g=(0,O.useRef)(!1),[_,v]=(0,O.useState)(),[y,b]=(0,O.useState)(!1),[x,S]=(0,O.useState)(!1),C=(0,O.useRef)(!1),w=e.projects.find(t=>t.id===e.projectId),T=_?.kind===`manage`?e.projects.find(e=>e.id===_.id):void 0;(0,O.useEffect)(()=>{_?.kind===`manage`&&!T&&v(void 0)},[_,T]);let E=()=>{s(!1),v({kind:`add`})},{thread:D,system:k}=e,A=(0,O.useRef)(void 0),j=!(!k?.ready||k.authenticated===!1||e.connection!==`connected`||e.authRequired),M=j&&!!w?.available&&!Mn(k),N=Pn(k,e.connection,e.authRequired),P=jn(k)??``,F=(t,n=D?.id??``)=>e.busy.includes(`${t}:${n}`),te=t=>e.operations.some(e=>Tn(e,t)),I=D?.turns.findLast(e=>al(e.status)),ne=D?.actions.filter(e=>e.status===`pending`||e.status===`responding`||e.kind===`unsupported`&&e.status===`expired`)??[],L=D?te(D.id)&&!F(`resume`)||D.managed&&D.status===`unknown`||D.execution&&!D.execution.ended&&D.status===`unknown`:!F(`create`,e.projectId)&&te(e.projectId),R=!!(D&&(!M||D.archived||te(D.id)||F(`resume`)||D.execution&&!D.execution.ended)),{run:z,refreshThread:re}=e,ie=(0,O.useCallback)(()=>{D&&!R&&(A.current=`${k?.codexEpoch}:${D.id}`,z(`resume`,D.id,`/api/threads/${yw(D.id)}/resume`).then(()=>re()))},[D,R,k?.codexEpoch,z,re]);(0,O.useEffect)(()=>{if((!k?.ready||D?.archived)&&(A.current=void 0),!D||D.managed||R)return;let e=`${k?.codexEpoch}:${D.id}`;A.current!==e&&ie()},[D,k?.ready,k?.codexEpoch,R,ie]);let ae=!!(D&&e.operations.some(e=>e.kind===`fork`&&Tn(e,D.id))),oe=k?.capabilities.includes(`thread/fork`)??!1,se=t=>F(`fork`,t)||e.operations.some(e=>e.kind===`fork`&&Tn(e,t)),ce=t=>{if(se(t.id))return`正在确认 Fork…请等待提交回执,暂时不能再次 Fork。`;if(!oe)return`当前 Codex 版本不支持 Fork 会话。`;if(!j)return`连接恢复且 Codex 就绪后可 Fork 会话。`;if(!e.projects.find(e=>e.id===t.projectId)?.available)return`项目目录不可用,恢复后可 Fork 会话。`;if(Mn(k))return`请先确认当前 Codex 版本的兼容性。`;if(t.historyVisible===!1||t.id===D?.id&&!D.turns.length)return`发送首条消息后可 Fork 已保存的历史。`},le=!!(D&&se(D.id)),ue=!(!D?.turns.length||ce(D)),B=async t=>{if(!ce(t))return e.run(`fork`,t.id,`/api/threads/${yw(t.id)}/fork`,t.id===D?.id?{settings:e.settings}:{})},de=()=>{D&&ue&&B(D)},fe=e.connection!==`connected`,pe=e.operations.filter(e=>e.kind===`confirmCompatibility`&&e.target===P),me=y||F(`confirmCompatibility`,P)||pe.some(e=>e.status===`accepted`||e.status===`dispatching`),ge=pe.some(e=>e.status===`unknown`&&!e.operation?.reconciliation);async function _e(){if(!g.current){g.current=!0,h(!0);try{await Promise.all([e.refreshSystem(),e.refreshThread()]),await e.refreshOperations(!0)}finally{g.current=!1,h(!1)}}}async function ve(){if(N&&!C.current){C.current=!0,b(!0);try{let t=await e.refreshSystem(),n=In(P,t,e.connection,e.authRequired);if(!n)return;await e.run(`confirmCompatibility`,P,`/api/system/compatibility/confirm`,n)}finally{C.current=!1,b(!1)}}}let ye={project:w,selectedId:e.selectedId,thread:D,system:k,connection:e.connection,authRequired:e.authRequired,settings:e.settings,openDraft:e.openDraft,busy:e.busy,operations:e.operations,run:e.run,onResumeAttempt:()=>{A.current=`${k?.codexEpoch}:${D?.id}`},refreshThread:e.refreshThread,openStatus:()=>p(!0),exportThread:ew},be=(0,O.useRef)(ye);be.current=ye;let xe=NC(()=>be.current),Se=xe.find(e=>e.name===`rename`);async function Ce(t,n,r){return!M||e.restoringSelection||e.savingModelDefaults?!1:D?n&&!I?!1:(await e.run(n?`steer`:`send`,D.id,`/api/threads/${yw(D.id)}/${n?`steer`:`turns`}`,n?{text:t,images:r,expectedTurnId:I.id}:{text:t,images:r,settings:e.settings},{kind:`send`,key:e.draftKey,text:t,images:r}))?.status===`acknowledged`:!e.selectedId&&e.sendFirstMessage(t,r)}return(0,W.jsxs)(bw,{threadId:D?.id,children:[(0,W.jsx)(dl,{onGatewaySettings:()=>{s(!1),d(!0)},onUpdates:()=>{s(!1),r(!0)},appVersion:t.status?.version,updateAvailable:!!(t.status?.available&&t.status.available.version!==t.status.version),updating:fw(t.status?.run),onNotificationSettings:()=>{s(!1),l(!0)},notificationStatus:e.notifications.error?`请检查设置`:e.notifications.enabled&&e.notifications.access===`granted`?`已开启`:`未开启`,archiveView:e.archiveView,onArchiveView:e.setArchiveView,onArchive:(t,n)=>{e.archiveThread(t,n)},onFork:e=>{B(e).then(e=>{e?.status===`acknowledged`&&s(!1)})},forkDisabledReason:ce,forking:se,archiveDisabledReason:t=>{if(F(`archive`,t.id))return`正在保存…`;if(te(t.id))return`请先核对会话操作的结果`;if(!j)return`连接恢复后可操作`;if(Mn(k))return`请先确认 Codex 版本兼容性`;if(!k?.capabilities.includes(t.archived?`thread/unarchive`:`thread/archive`))return`当前 Codex 不支持此操作`;if(!e.projects.find(e=>e.id===t.projectId)?.available)return`项目目录不可用`;if(!t.archived&&(al(t.status)||t.pendingActionCount>0))return`任务结束并处理完待办后可归档`;if(!t.archived&&t.managed&&t.status===`unknown`)return`会话状态待核对,暂时无法归档`},projects:e.projects,projectsLoaded:e.projectsLoaded,projectId:e.projectId,onProject:t=>{e.setProjectId(t),s(!1)},projectThreads:e.projectThreads,selectedId:e.selectedId,isUnreadCompletion:i,onThread:(t,n)=>{e.selectThread(t,n)},onMore:(t,n)=>{e.loadProjectThreads(t,n)},onRetry:t=>{e.loadProjectThreads(t,e.projectThreads[t]?.retryCursor)},onRefresh:()=>{e.refreshProjects().then(e.refreshProjectsThreads)},onAddProject:E,onManageProject:e=>{s(!1),v({kind:`manage`,id:e.id})},canManageProjects:!e.authRequired,onCreate:t=>{e.setProjectId(t),s(!1)},creating:t=>e.firstMessages.includes(t)||F(`create`,t)||te(t),canCreate:t=>j&&!e.savingModelDefaults&&!Mn(k)&&!!e.projects.find(e=>e.id===t)?.available,offline:fe,open:o,onClose:()=>s(!1)}),(0,W.jsxs)(`main`,{className:`main-panel`,children:[(0,W.jsxs)(`header`,{className:`topbar`,children:[(0,W.jsxs)(`div`,{className:`topbar-title`,children:[(0,W.jsx)(q,{className:`mobile-only`,variant:`ghost`,size:`icon`,"aria-label":`打开项目与会话`,onClick:()=>s(!0),children:(0,W.jsx)(J,{name:`menu`})}),(0,W.jsxs)(`div`,{children:[(0,W.jsxs)(`div`,{className:`breadcrumb`,children:[w?.name??`工作空间`,(0,W.jsx)(J,{name:`chevron`,size:12}),(0,W.jsx)(`span`,{children:D?`会话`:`新会话`})]}),D?(0,W.jsx)(ab,{title:D.title||`新会话`,rename:Se,pending:!!(D&&e.operations.some(e=>e.kind===`rename`&&Tn(e,D.id)))},`${D.projectId}:${D.id}`):(0,W.jsx)(`h1`,{children:`开始你的下一项任务`})]})]}),(0,W.jsxs)(`div`,{className:`topbar-status`,children:[D&&(0,W.jsx)(ol,{status:D.status,offline:fe}),(0,W.jsx)(ZC,{connection:e.connection}),D?.forkedFromId&&(0,W.jsx)(Ic,{id:`thread-source-hint`,content:`返回原会话`,children:(0,W.jsx)(q,{variant:`ghost`,size:`icon`,"aria-label":`返回原会话`,"aria-describedby":`thread-source-hint`,onClick:()=>{e.selectThread(D.forkedFromId)},children:(0,W.jsx)(ee,{size:16})})}),(0,W.jsx)($C,{system:k,connection:e.connection,operations:e.operations,thread:D,busy:e.busy,open:f,onOpenChange:p,refreshing:m,onDiscardMissing:e.discardMissingOperation,onRefresh:()=>{_e(),fe&&e.retryConnection()},onReconcile:t=>{e.run(`reconcile`,t,`/api/operations/${yw(t)}/reconcile`,{confirmEnded:!0}).then(e=>{if(e?.status===`acknowledged`)return _e()})}})]})]}),k?.demo&&(0,W.jsx)(`div`,{className:`demo-banner`,children:`模拟测试模式 · 当前执行结果来自显式启用的测试 app-server`}),e.authRequired?(0,W.jsxs)(`div`,{className:`error-banner persistent-banner`,role:`alert`,children:[(0,W.jsx)(J,{name:`alert`}),`登录已过期。任务不会因页面断开而被取消。`,(0,W.jsx)(`a`,{className:`button button-secondary button-small`,href:`/`,children:`重新打开登录入口`})]}):fe&&(0,W.jsxs)(`div`,{className:`connection-banner`,role:`status`,children:[(0,W.jsxs)(`span`,{children:[`实时连接`,e.connection===`connecting`?`正在建立`:`已断开,正在重连`,`。当前显示上次已知状态。`]}),(0,W.jsx)(q,{variant:`ghost`,size:`sm`,onClick:e.retryConnection,children:`立即重连`})]}),k&&!k.ready&&(0,W.jsxs)(`div`,{className:`error-banner persistent-banner`,role:`alert`,children:[`Codex 尚不可用:`,k.error??`请在私人电脑上检查 Codex 安装、认证与服务状态。`]}),(0,W.jsx)(tw,{system:k,onOpenChange:S,canConfirm:N,submitting:me,uncertain:ge,error:e.error,onRefresh:()=>{e.refreshSystem(),e.refreshOperations()},onConfirm:()=>{ve()},onReconfirm:()=>{ve()}}),e.error&&(0,W.jsxs)(`div`,{className:`error-banner dismissible`,role:`alert`,children:[(0,W.jsxs)(`div`,{children:[(0,W.jsx)(`span`,{children:e.error}),e.errorDetails!==void 0&&(0,W.jsxs)(`details`,{className:`raw-details`,children:[(0,W.jsx)(`summary`,{children:`错误详情`}),(0,W.jsx)(`pre`,{children:JSON.stringify(e.errorDetails,null,2)})]})]}),(0,W.jsx)(q,{variant:`ghost`,size:`icon`,"aria-label":`关闭错误提示`,onClick:e.clearError,children:(0,W.jsx)(J,{name:`close`,size:15})})]}),e.operations.filter(e=>e.mutation).map(e=>(0,W.jsxs)(`div`,{className:`archive-notice mutation-notice`,role:`status`,children:[e.kind===`rename`?(0,W.jsx)(he,{size:16}):(0,W.jsx)(J,{name:`archive`,size:16}),(0,W.jsx)(`span`,{children:e.kind===`rename`?e.status===`unknown`?`重命名结果待确认`:`正在保存会话名称…`:e.mutation.archived?e.status===`unknown`?`归档结果待确认`:`正在归档会话…`:e.status===`unknown`?`取消归档结果待确认`:`正在取消归档…`}),e.status===`unknown`&&(0,W.jsx)(q,{variant:`secondary`,size:`sm`,disabled:m,onClick:()=>void _e(),children:m?`正在核对…`:`核对提交`})]},e.clientOperationId)),D?.archived&&(0,W.jsxs)(`div`,{className:`archive-notice`,role:`status`,children:[(0,W.jsx)(J,{name:`archive`,size:18}),(0,W.jsxs)(`div`,{children:[(0,W.jsx)(`strong`,{children:`此会话已归档`}),(0,W.jsx)(`p`,{children:`历史已保留。取消归档后可继续对话。`})]}),(0,W.jsx)(q,{variant:`secondary`,size:`sm`,disabled:!M||te(D.id)||F(`archive`)||!k?.capabilities.includes(`thread/unarchive`),onClick:()=>{e.archiveThread(D.id,!1)},children:F(`archive`)?`正在保存…`:`取消归档`})]}),(0,W.jsx)(rb,{thread:D,readingEnabled:!o&&!_&&!f&&!e.authRequired&&!x,onReadCompleted:a,offline:fe,projectName:w?.name,needsProject:e.projectsLoaded&&e.projects.length===0,canAddProject:!e.authRequired,onAddProject:E,questionControls:{disabled:!M||!D?.managed||!!D.archived||!!L||F(`send`)||F(`steer`)||F(`resume`),onReply:async e=>Ce(My(e),!!I)}}),(0,W.jsxs)(`div`,{className:`bottom-region`,children:[ne.length>0&&(0,W.jsx)(`div`,{className:`pending-actions`,"aria-label":`待处理请求`,children:ne.map(t=>(0,W.jsx)(JC,{action:t,disabled:!M||F(`resolve`,t.actionId)||te(t.actionId),onResolve:n=>{e.run(`resolve`,t.actionId,`/api/actions/${yw(t.actionId)}/resolve`,{resolution:n})}},t.actionId))}),L&&(0,W.jsxs)(`div`,{className:`pending-notice`,role:`status`,children:[(0,W.jsx)(J,{name:`alert`,size:15}),(0,W.jsx)(`span`,{children:D?ae?`Fork 结果尚未确认。请核对提交,暂时不能再次 Fork。`:`提交结果尚未确认。请核对提交,也可以 Fork 已保存的历史为新会话。`:`新建会话的提交结果尚未确认。请先核对提交,避免重复创建。`}),(0,W.jsx)(q,{variant:`ghost`,size:`sm`,disabled:m,"aria-expanded":f,"aria-controls":`diagnostics-panel`,onClick:()=>{p(!0),_e()},children:m?`正在核对…`:`核对提交`}),D&&!ae&&(0,W.jsx)(q,{variant:`secondary`,size:`sm`,disabled:!ue,onClick:de,children:`Fork 为新会话`})]}),(0,W.jsx)(PC,{commands:xe,thread:D,threadLoading:e.restoringSelection||!(!e.selectedId||D),draftKey:e.draftKey,sentDrafts:e.sentDrafts,projectName:w?.name,projectId:w?.available?w.id:void 0,runtimeKey:k?.ready&&e.connection===`connected`?`${k.codexEpoch}:${e.runtimeDefaultsRevision}`:void 0,settings:e.settings,models:k?.models??[],onSettings:e.setSettings,onSaveModelDefaults:e.saveModelDefaults,savingModelDefaults:e.savingModelDefaults,disabled:!M||e.restoringSelection||!!L||!!D?.archived,canInterrupt:j&&!!(D?.managed&&I),submitting:e.firstMessages.includes(e.projectId)||F(`send`)||F(`steer`),interrupting:F(`interrupt`),resuming:F(`resume`),canResume:!R,resumeAttempted:A.current===`${k?.codexEpoch}:${D?.id}`,canFork:ue,forking:le,onFork:de,onResume:ie,onInterrupt:()=>{D&&I&&e.run(`interrupt`,D.id,`/api/threads/${yw(D.id)}/interrupt`,{expectedTurnId:I.id})},onSend:Ce})]})]}),_&&(_.kind===`add`||T)&&(0,W.jsx)(nw,{project:T,disabled:e.authRequired,onAdd:e.addProject,onRename:e.renameProject,onRemove:e.removeProject,onClose:()=>v(e=>e===_?void 0:e)},_.kind===`add`?`add`:_.id),c&&(0,W.jsx)(rw,{notifications:e.notifications,onClose:()=>l(!1)}),u&&(0,W.jsx)(uw,{onClose:()=>d(!1)}),n&&(0,W.jsx)(_w,{updates:t,onClose:()=>r(!1)})]})}(0,we.createRoot)(document.getElementById(`root`)).render((0,W.jsx)(O.StrictMode,{children:(0,W.jsx)(xw,{})}));
@@ -6,7 +6,7 @@
6
6
  <meta name="theme-color" content="#f7f8fa" />
7
7
  <link rel="icon" type="image/svg+xml" href="/covro.svg" />
8
8
  <title>Covro · 工作空间</title>
9
- <script type="module" crossorigin src="/assets/index-8Pb1Fm2w.js"></script>
9
+ <script type="module" crossorigin src="/assets/index-Db6eo_Kb.js"></script>
10
10
  <link rel="stylesheet" crossorigin href="/assets/index-L3S1ZiO0.css">
11
11
  </head>
12
12
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@covro/covro",
3
- "version": "0.1.0",
3
+ "version": "0.1.1-dev.1",
4
4
  "description": "A self-hosted browser workspace for your local Codex",
5
5
  "bin": {
6
6
  "covro": "bin/covro.mjs"
@@ -86,9 +86,9 @@
86
86
  "unsupported": []
87
87
  },
88
88
  "covroCommit": "df6f834f5a19725453602996f5b189a52be4f5d9",
89
- "covroChannel": "stable",
89
+ "covroChannel": "dev",
90
90
  "covroRelease": {
91
- "runId": "39248447849",
91
+ "runId": "39248385185",
92
92
  "runAttempt": "1"
93
93
  }
94
94
  }