@openchambery/web 2.0.5-beta.3 → 2.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/assets/{AssistantView-BeQjlQi5.js → AssistantView-kXN4mz6j.js} +3 -3
  2. package/dist/assets/{DiagramView-BPFVXhly.js → DiagramView-CGLAl3iS.js} +1 -1
  3. package/dist/assets/MarkdownRenderer-DA08bZsM.js +2 -0
  4. package/dist/assets/{MarkdownRendererImpl-DCim2MBS.js → MarkdownRendererImpl-qaVTVCHe.js} +1 -1
  5. package/dist/assets/{MarkstreamRendererImpl-DLI17gOM.js → MarkstreamRendererImpl-CQdVI8Vx.js} +1 -1
  6. package/dist/assets/{MobileDetailNavigation-C9097prS.js → MobileDetailNavigation-xaAVkxD-.js} +1 -1
  7. package/dist/assets/{MobileShareBridge-BVRtivg8.js → MobileShareBridge-z2TFroKY.js} +1 -1
  8. package/dist/assets/MobileTabPageHeader-DPlvhJFe.js +2 -0
  9. package/dist/assets/{MultiRunWindow-VdUAIkKj.js → MultiRunWindow-vJc2NLzu.js} +1 -1
  10. package/dist/assets/{SettingsView-BcQCG9q0.js → SettingsView-BG7DgHmP.js} +6 -6
  11. package/dist/assets/{SettingsWindow-BSap8D3j.js → SettingsWindow-3QrhPfuk.js} +1 -1
  12. package/dist/assets/{TerminalView-CQEmfuGt.js → TerminalView-Ciw0BIiz.js} +1 -1
  13. package/dist/assets/{ToolOutputDialog-3cIIsSBA.js → ToolOutputDialog-D_23USz-.js} +1 -1
  14. package/dist/assets/{appThemeRegistry-Dl2OjM9t.js → appThemeRegistry-lhAKuFFB.js} +1 -1
  15. package/dist/assets/{fileMentionTouchSelection-BJOHH2CX.js → fileMentionTouchSelection-DPSC4Fx2.js} +1 -1
  16. package/dist/assets/{gitApi-C-zOJTEi.js → gitApi-DeWWyR94.js} +3 -3
  17. package/dist/assets/insertionBoundaries-aV1Cm6zA.js +1 -0
  18. package/dist/assets/{main-ctL2Nr48.js → main-0XIuL0dd.js} +11 -11
  19. package/dist/assets/{main-Fbjmo73O.js → main-DZGXa6wk.js} +2 -2
  20. package/dist/assets/{mcpQueries-B1I3urB4.js → mcpQueries-pTPWjOQO.js} +1 -1
  21. package/dist/assets/{miniChat-BFctomLE.js → miniChat-C8K4fwOO.js} +2 -2
  22. package/dist/assets/{mobile-CgrEAs5U.js → mobile-Brtl2UnC.js} +2 -2
  23. package/dist/assets/multirun-B7FPVrQ-.js +3 -0
  24. package/dist/assets/{projectMeta-iGmHOQNp.js → projectMeta-D_jCNzjw.js} +1 -1
  25. package/dist/assets/{renderElectronMiniChatApp-B82q9wxX.js → renderElectronMiniChatApp-e6XqcsYi.js} +2 -2
  26. package/dist/assets/renderMobileApp-BQenfg50.js +28 -0
  27. package/dist/assets/{runtimeConfig-CCw0l6aJ.js → runtimeConfig-CJE7T1Sr.js} +1 -1
  28. package/dist/assets/{runtimeEndpointReset-CvWlsn11.js → runtimeEndpointReset-DULSaOrI.js} +6 -6
  29. package/dist/assets/{sessionChangeSummary-BCz7YMwL.js → sessionChangeSummary-CVZBClsA.js} +1 -1
  30. package/dist/assets/{sessionLookup-BpO4cCmV.js → sessionLookup--qnazVNO.js} +1 -1
  31. package/dist/assets/{useAppFontEffects-KlbtUhYE.js → useAppFontEffects-BHenW5Q2.js} +53 -53
  32. package/dist/assets/{useDesktopWindowControlsLayout-BflHVu5S.js → useDesktopWindowControlsLayout-BGgoqF_n.js} +1 -1
  33. package/dist/assets/{useEffectiveDirectory-BbQKZPcu.js → useEffectiveDirectory-CF16bcpx.js} +1 -1
  34. package/dist/assets/useMobileNavigationStore-DBML5LIl.js +415 -0
  35. package/dist/assets/{useSessionAutoCleanup-Dho6q-O2.js → useSessionAutoCleanup-moxr9XbA.js} +1 -1
  36. package/dist/assets/{useWorkerHighlightedLines-CbvulSje.js → useWorkerHighlightedLines-DYVg-cuB.js} +1 -1
  37. package/dist/index.html +2 -2
  38. package/dist/mini-chat.html +2 -2
  39. package/dist/mobile.html +2 -2
  40. package/package.json +1 -1
  41. package/server/lib/question-auto-delegate/DOCUMENTATION.md +4 -0
  42. package/server/lib/question-auto-delegate/core.d.ts +5 -0
  43. package/server/lib/question-auto-delegate/core.js +62 -13
  44. package/server/lib/question-auto-delegate/form-io.js +4 -1
  45. package/server/lib/question-auto-delegate/pause-store.d.ts +7 -0
  46. package/server/lib/question-auto-delegate/pause-store.js +39 -0
  47. package/server/lib/question-auto-delegate/runtime.js +3 -0
  48. package/server/lib/question-auto-delegate/runtime.test.js +128 -1
  49. package/dist/assets/MarkdownRenderer-D1fVOsHS.js +0 -2
  50. package/dist/assets/MobileTabPageHeader-tKa6r_KP.js +0 -2
  51. package/dist/assets/insertionBoundaries-DduQc2QR.js +0 -1
  52. package/dist/assets/multirun-BuVN-s4M.js +0 -3
  53. package/dist/assets/renderMobileApp-CM_El_gZ.js +0 -28
  54. package/dist/assets/useMobileNavigationStore-BjIptzTV.js +0 -415
@@ -1,4 +1,4 @@
1
- import{o as e}from"./rolldown-runtime-C0FnF6B9.js";import{n as t}from"./runtime-fetch-CiqQd__Y.js";import{On as n,on as r}from"./persistence-Dnj1QOdX.js";import{nt as i,rt as a}from"./vendor-base-ui-CnHfUmDN.js";import{n as o}from"./platform-wu6wSDfg.js";import{v as s}from"./useUIStore-Dfx6TKvi.js";import{n as c}from"./vendor-react-DLPElpoQ.js";import{a as l,n as u}from"./vendor-aparajita-capacitor-secure-storage-CjQdwfjS.js";import{f as d,r as f,t as p}from"./button-CUwjpv-i.js";import{n as m}from"./Icon-BdzPRCSy.js";import{i as h,n as g,t as _}from"./tooltip-DDNnmcXI.js";import{n as v}from"./useThemeSystem-DMzWVJaW.js";import{n as y}from"./markdownTheme-DM5h1i18.js";import{n as b}from"./MarkdownRenderer-D1fVOsHS.js";import{n as x,o as S,s as C,t as w}from"./markdown-worker-bS5OgGO3.js";import{a as T,i as E,o as D,t as ee}from"./imageSource-BpUsiwFd.js";import{t as te}from"./vendor-tanstack-react-virtual-tlDgH6PG.js";var O=e(a(),1),k=c(),A=i(),ne=`w-[min(30rem,calc(100cqw-1rem))] min-w-[280px] max-w-full overflow-hidden rounded-xl shadow-[inset_0_1px_0_0_rgba(255,255,255,0.8),inset_0_0_0_1px_rgba(0,0,0,0.04),0_0_0_1px_rgba(0,0,0,0.10),0_1px_2px_-0.5px_rgba(0,0,0,0.08),0_4px_8px_-2px_rgba(0,0,0,0.08),0_12px_20px_-4px_rgba(0,0,0,0.08)] dark:shadow-[inset_0_1px_0_0_rgba(255,255,255,0.12),inset_0_0_0_1px_rgba(255,255,255,0.08),0_0_0_1px_rgba(0,0,0,0.36),0_1px_1px_-0.5px_rgba(0,0,0,0.22),0_3px_3px_-1.5px_rgba(0,0,0,0.20),0_6px_6px_-3px_rgba(0,0,0,0.16)]`,j={maxWidth:`min(28rem, calc(100cqw - 4ch))`,backgroundColor:`var(--surface-elevated)`,color:`var(--surface-elevated-foreground)`},M=`flex items-center justify-between gap-3 border-b border-[var(--surface-subtle)] px-3 py-2.5`,N=`text-xs font-medium leading-4 text-foreground md:text-[0.8125rem] md:leading-5`,re=`text-xs tabular-nums leading-4 text-muted-foreground md:text-[0.8125rem] md:leading-5`,P=`m-0 list-none divide-y divide-[var(--surface-subtle)] p-0`,F=`${P} max-h-[min(22rem,50vh)] overflow-y-auto`,ie=`${P} w-full`,ae={className:`p-0 rounded-none`,maxHeightClass:`max-h-[46vh]`,disableHorizontal:!0},I=`px-2.5 py-1.5 text-xs leading-4 md:py-2 md:text-[0.8125rem] md:leading-5`,oe=`flex min-w-0 items-center gap-1 text-xs leading-4 text-muted-foreground md:gap-1.5 md:text-[0.8125rem] md:leading-5`,se=`min-w-0 truncate text-xs leading-4 text-foreground md:text-[0.8125rem] md:leading-5`,ce=`inline-flex shrink-0 items-center gap-1 text-xs leading-4 tabular-nums text-muted-foreground md:text-[0.8125rem] md:leading-5`,le=`h-3 w-3 shrink-0 md:h-3.5 md:w-3.5`,ue={in_progress:`text-foreground`,pending:`text-foreground`,completed:`text-muted-foreground line-through`,cancelled:`text-muted-foreground line-through`},L={in_progress:`chat.statusRow.todo.status.inProgress`,pending:`chat.statusRow.todo.status.pending`,completed:`chat.statusRow.todo.status.completed`,cancelled:`chat.statusRow.todo.status.cancelled`},R=e=>{let t=(0,k.c)(26),{todo:n,isActive:r,activeRef:i}=e,{t:a}=d(),o=z.has(n.status)?n.status:`pending`,s=L[o],c;t[0]!==a||t[1]!==s?(c=a(s),t[0]=a,t[1]=s,t[2]=c):c=t[2];let l=c,u;t[3]===o?u=t[4]:(u=o===`in_progress`?(0,A.jsx)(m,{name:`record-circle`,className:`h-3.5 w-3.5 text-[var(--status-info)]`,"aria-hidden":`true`}):o===`completed`?(0,A.jsx)(m,{name:`checkbox-circle`,className:`h-3.5 w-3.5 text-[var(--status-success)]`,"aria-hidden":`true`}):(0,A.jsx)(m,{name:`time`,className:`h-3.5 w-3.5 text-muted-foreground`,"aria-hidden":`true`}),t[3]=o,t[4]=u);let p=u,v=r?`step`:void 0,y=r&&`bg-[var(--surface-muted)] before:absolute before:inset-y-2 before:left-0 before:w-0.5 before:rounded-full before:bg-[var(--status-info)]`,b;t[5]===y?b=t[6]:(b=f(`group relative grid min-w-0 grid-cols-[1rem_minmax(0,1fr)] items-start gap-2.5`,I,y),t[5]=y,t[6]=b);let x;t[7]!==p||t[8]!==l?(x=(0,A.jsx)(h,{asChild:!0,children:(0,A.jsx)(`span`,{className:`flex size-4 items-center justify-center`,"aria-label":l,children:p})}),t[7]=p,t[8]=l,t[9]=x):x=t[9];let S;t[10]===l?S=t[11]:(S=(0,A.jsx)(g,{side:`left`,sideOffset:6,children:l}),t[10]=l,t[11]=S);let C;t[12]!==x||t[13]!==S?(C=(0,A.jsxs)(_,{children:[x,S]}),t[12]=x,t[13]=S,t[14]=C):C=t[14];let w=ue[o],T;t[15]===w?T=t[16]:(T=f(`block whitespace-normal break-words`,w),t[15]=w,t[16]=T);let E;t[17]!==T||t[18]!==n.content?(E=(0,A.jsx)(`span`,{className:`min-w-0 flex-1`,children:(0,A.jsx)(`span`,{className:T,children:n.content})}),t[17]=T,t[18]=n.content,t[19]=E):E=t[19];let D;return t[20]!==i||t[21]!==E||t[22]!==v||t[23]!==b||t[24]!==C?(D=(0,A.jsxs)(`li`,{ref:i,"aria-current":v,className:b,children:[C,E]}),t[20]=i,t[21]=E,t[22]=v,t[23]=b,t[24]=C,t[25]=D):D=t[25],D},z=new Set([`in_progress`,`pending`,`completed`,`cancelled`]),B=`image/png`,V=l(`OpenChamberMedia`),H=e=>{let t=e.toLowerCase().split(`;`)[0]?.trim()||B;if(t===`image/jpeg`||t===`image/jpg`)return`jpg`;if(t===`image/webp`)return`webp`;if(t===`image/gif`)return`gif`;if(t===`image/svg+xml`)return`svg`;if(t===`image/png`)return`png`;let n=t.split(`/`)[1];return n&&/^[a-z0-9.+-]+$/i.test(n)?n:`png`},U=(e,t)=>{let n=`image.${H(t)}`,r=(((e||``).trim()||n).split(/[\\/]/).pop()||n).replace(/[^\w.\- ()[\]]+/g,`_`).replace(/^\.+/,``);return r?/\.[a-z0-9]{1,8}$/i.test(r)?r:`${r}.${H(t)}`:n},W=e=>new Promise((t,n)=>{let r=new FileReader;r.onload=()=>{if(typeof r.result==`string`){t(r.result);return}n(Error(`Failed to encode image`))},r.onerror=()=>n(r.error??Error(`Failed to encode image`)),r.readAsDataURL(e)}),de=async e=>{let t=await W(e),n=t.indexOf(`,`);return n>=0?t.slice(n+1):t},fe=(e,t)=>{let n=URL.createObjectURL(e),r=document.createElement(`a`);r.href=n,r.download=t,document.body.appendChild(r),r.click(),document.body.removeChild(r),window.setTimeout(()=>URL.revokeObjectURL(n),1e3)},G=async(e,t)=>{let n=await fetch(e,{signal:t,cache:`no-store`});if(!n.ok)throw Error(`Image fetch failed (${n.status})`);return n.blob()},pe=async(e,t=B)=>{if(!e.naturalWidth||!e.naturalHeight)return null;let n=e.currentSrc||e.src;if(n&&(/^(?:blob:|data:|openchamber-asset:)/i.test(n)||/^https?:/i.test(n)||/^\/api(?=\/|[?#]|$)/.test(n)))try{let e=await G(n);if(e.size>0)return e}catch{}try{let n=document.createElement(`canvas`);n.width=e.naturalWidth,n.height=e.naturalHeight;let r=n.getContext(`2d`);if(!r)return null;r.drawImage(e,0,0);let i=t.startsWith(`image/`)?t:B,a=await new Promise(e=>{n.toBlob(t=>e(t),i===`image/jpg`?`image/jpeg`:i)});return a&&a.size>0?a:null}catch{return null}},me=async(e,t)=>{let n=``;try{return n=await ee(e,t??new AbortController().signal),await G(n,t)}finally{n&&T(n)}},he=async(e,n)=>{let r=e.effectiveDirectory??``,i=null;e.prefetchedBlob&&e.prefetchedBlob.size>0&&(i=e.prefetchedBlob);let a=e.displayUrl?.trim();if(!i&&a)try{i=await G(a,n)}catch{i=null}if(!i){let a=e.sourceUrl.trim();if(!a)throw Error(`Image source is empty`);if(/^(?:data|blob):/i.test(a)||/^https?:/i.test(a)||/^\/api(?=\/|[?#]|$)/.test(a))i=await G(a,n);else{let e=D(a,r);if(E(e))try{i=await me(e.path,n)}catch{let r=await t(`/api/fs/raw`,{method:`GET`,cache:`no-store`,query:{path:e.path},signal:n});if(!r.ok)throw Error(`Image source request failed with status ${r.status}`);i=await r.blob()}else i=await G(e.source,n)}}if(!i||i.size<=0)throw Error(`Image is empty`);let o=(e.mimeType||(i.type&&i.type.startsWith(`image/`)?i.type:``)||B).split(`;`)[0].trim()||B;return{blob:i,filename:U(e.filename,o),mimeType:o}},ge=()=>!o()||u===void 0?!1:u.isPluginAvailable(`OpenChamberMedia`),_e=async(e,t)=>{let{blob:i,filename:a,mimeType:o}=await he(e,t);if(ge()){let e=await de(i);return await V.saveImage({dataBase64:e,mimeType:o,filename:a}),`saved`}if(r()){let e=n()?.vscode;if(e?.saveImage){let t=await W(i);return await e.saveImage({fileName:a,dataUrl:t}),`saved`}}return fe(i,a),`downloaded`},ve=e=>e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`).replace(/'/g,`&#39;`),ye=e=>e?Object.entries(e).map(([e,t])=>t==null?``:`${e.startsWith(`--`)?e:e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`)}:${typeof t==`number`?`${t}px`:t};`).join(``):``,K=(e,t,n)=>{let r=e.querySelector(`pre`);r&&(r.style.margin=`0`,r.style.background=`transparent`,r.style.whiteSpace=t?`pre-wrap`:`pre`,t&&(r.style.wordBreak=`break-word`,r.style.overflowWrap=`break-word`));let i=e.querySelector(`code`);if(i){let e=ye(n);e&&i.setAttribute(`style`,`${i.getAttribute(`style`)??``}${e}`)}},be=e=>`<pre><code>${ve(e)}</code></pre>`,xe=e=>{let t=(0,k.c)(21),{code:n,language:r,className:i,style:a,codeStyle:o,wrap:s}=e,c=s!==void 0&&s,{currentTheme:l}=v(),u=O.useRef(null),d;t[0]===l?d=t[1]:(d=y(l),t[0]=l,t[1]=d);let p=d,m,h;t[2]!==n||t[3]!==o||t[4]!==c?(m=()=>{let e=u.current;e&&(e.innerHTML=be(n),K(e,c,o))},h=[n,c,o],t[2]=n,t[3]=o,t[4]=c,t[5]=m,t[6]=h):(m=t[5],h=t[6]),O.useLayoutEffect(m,h);let g,_;t[7]!==n||t[8]!==o||t[9]!==r||t[10]!==c?(g=()=>{let e=u.current;if(!e)return;let t=!0,i=new AbortController;return w(n,(r||`text`).toLowerCase(),{signal:i.signal,priority:`visible`}).then(n=>{!t||!e||!n||(e.innerHTML=n,K(e,c,o))}),()=>{t=!1,i.abort()}},_=[n,r,c,o],t[7]=n,t[8]=o,t[9]=r,t[10]=c,t[11]=g,t[12]=_):(g=t[11],_=t[12]),O.useEffect(g,_);let b;t[13]===i?b=t[14]:(b=f(`typography-code`,i),t[13]=i,t[14]=b);let x=p,S;t[15]!==a||t[16]!==x?(S={...x,...a},t[15]=a,t[16]=x,t[17]=S):S=t[17];let C;return t[18]!==b||t[19]!==S?(C=(0,A.jsx)(`div`,{ref:u,className:b,style:S}),t[18]=b,t[19]=S,t[20]=C):C=t[20],C},Se=e=>{let t=e.replace(/^<file>\s*\n?/,``).replace(/\n?<\/file>\s*$/,``);return t=t.replace(/^\s*\d{5}\|\s?/gm,``),t.trim()},Ce=(e,t=``)=>{if(typeof e==`string`)return e;if(e==null)return t;if(typeof e==`number`||typeof e==`boolean`||typeof e==`bigint`)return String(e);try{return JSON.stringify(e)}catch{return t}},we=e=>e?e.includes(`<diagnostics`)||e.includes(`<file_diagnostics>`)||e.includes(`LSP errors detected`)||e.includes(`This file has errors`):!1,Te=e=>e?e.replace(/\n{0,2}LSP errors detected[\s\S]*?<diagnostics[^>]*>[\s\S]*?<\/diagnostics>/g,``).replace(/\n{0,2}This file has errors[\s\S]*?<\/file_diagnostics>/g,``).replace(/<diagnostics[^>]*>[\s\S]*?<\/diagnostics>/g,``).replace(/<file_diagnostics>[\s\S]*?<\/file_diagnostics>/g,``).trim():``,Ee=(e,t)=>!e||typeof e!=`object`?String(e):C(e,t||``),q=e=>{if(typeof e==`string`){let t=e.trim();return t.length>0?t:void 0}if(e&&typeof e==`object`){let t=e.patch;if(typeof t==`string`){let e=t.trim();return e.length>0?e:void 0}}},De=e=>{if(!e||typeof e!=`object`)return;let t=q(e.patch)??q(e.diff);if(t)return t;let n=Array.isArray(e.files)?e.files:[];for(let e of n){if(!e||typeof e!=`object`)continue;let t=q(e.patch)??q(e.diff);if(t)return t}},Oe=e=>{if(!e||typeof e!=`string`)return{data:null,isJson:!1};let t=e.trim();if(!t.startsWith(`{`)&&!t.startsWith(`[`)||!t.endsWith(`}`)&&!t.endsWith(`]`)||t.length<2)return{data:null,isJson:!1};try{let e=JSON.parse(t);return typeof e==`object`&&e?{data:e,isJson:!0}:{data:null,isJson:!1}}catch{return{data:null,isJson:!1}}},ke=(e,t,n)=>{let r=Se(e);if((t===`edit`||t===`multiedit`||t===`write`||t===`apply_patch`)&&we(r)&&(r=Te(r)),(t===`edit`||t===`multiedit`||t===`apply_patch`)&&r.trim().length===0){let e=De(n);if(e)return e}return r},Ae=e=>{let t=e.match(/<type>(file|directory)<\/type>/i)?.[1]?.toLowerCase()??`unknown`,n=(e.match(/<content>([\s\S]*?)<\/content>/i)?.[1]??e).replace(/\r\n/g,`
1
+ import{o as e}from"./rolldown-runtime-C0FnF6B9.js";import{n as t}from"./runtime-fetch-CiqQd__Y.js";import{On as n,on as r}from"./persistence-Dnj1QOdX.js";import{nt as i,rt as a}from"./vendor-base-ui-CnHfUmDN.js";import{n as o}from"./platform-wu6wSDfg.js";import{v as s}from"./useUIStore-Dfx6TKvi.js";import{n as c}from"./vendor-react-DLPElpoQ.js";import{a as l,n as u}from"./vendor-aparajita-capacitor-secure-storage-CjQdwfjS.js";import{f as d,r as f,t as p}from"./button-CUwjpv-i.js";import{n as m}from"./Icon-BdzPRCSy.js";import{i as h,n as g,t as _}from"./tooltip-DDNnmcXI.js";import{n as v}from"./useThemeSystem-DMzWVJaW.js";import{n as y}from"./markdownTheme-DM5h1i18.js";import{n as b}from"./MarkdownRenderer-DA08bZsM.js";import{n as x,o as S,s as C,t as w}from"./markdown-worker-bS5OgGO3.js";import{a as T,i as E,o as D,t as ee}from"./imageSource-BpUsiwFd.js";import{t as te}from"./vendor-tanstack-react-virtual-tlDgH6PG.js";var O=e(a(),1),k=c(),A=i(),ne=`w-[min(30rem,calc(100cqw-1rem))] min-w-[280px] max-w-full overflow-hidden rounded-xl shadow-[inset_0_1px_0_0_rgba(255,255,255,0.8),inset_0_0_0_1px_rgba(0,0,0,0.04),0_0_0_1px_rgba(0,0,0,0.10),0_1px_2px_-0.5px_rgba(0,0,0,0.08),0_4px_8px_-2px_rgba(0,0,0,0.08),0_12px_20px_-4px_rgba(0,0,0,0.08)] dark:shadow-[inset_0_1px_0_0_rgba(255,255,255,0.12),inset_0_0_0_1px_rgba(255,255,255,0.08),0_0_0_1px_rgba(0,0,0,0.36),0_1px_1px_-0.5px_rgba(0,0,0,0.22),0_3px_3px_-1.5px_rgba(0,0,0,0.20),0_6px_6px_-3px_rgba(0,0,0,0.16)]`,j={maxWidth:`min(28rem, calc(100cqw - 4ch))`,backgroundColor:`var(--surface-elevated)`,color:`var(--surface-elevated-foreground)`},M=`flex items-center justify-between gap-3 border-b border-[var(--surface-subtle)] px-3 py-2.5`,N=`text-xs font-medium leading-4 text-foreground md:text-[0.8125rem] md:leading-5`,re=`text-xs tabular-nums leading-4 text-muted-foreground md:text-[0.8125rem] md:leading-5`,P=`m-0 list-none divide-y divide-[var(--surface-subtle)] p-0`,F=`${P} max-h-[min(22rem,50vh)] overflow-y-auto`,ie=`${P} w-full`,ae={className:`p-0 rounded-none`,maxHeightClass:`max-h-[46vh]`,disableHorizontal:!0},I=`px-2.5 py-1.5 text-xs leading-4 md:py-2 md:text-[0.8125rem] md:leading-5`,oe=`flex min-w-0 items-center gap-1 text-xs leading-4 text-muted-foreground md:gap-1.5 md:text-[0.8125rem] md:leading-5`,se=`min-w-0 truncate text-xs leading-4 text-foreground md:text-[0.8125rem] md:leading-5`,ce=`inline-flex shrink-0 items-center gap-1 text-xs leading-4 tabular-nums text-muted-foreground md:text-[0.8125rem] md:leading-5`,le=`h-3 w-3 shrink-0 md:h-3.5 md:w-3.5`,ue={in_progress:`text-foreground`,pending:`text-foreground`,completed:`text-muted-foreground line-through`,cancelled:`text-muted-foreground line-through`},L={in_progress:`chat.statusRow.todo.status.inProgress`,pending:`chat.statusRow.todo.status.pending`,completed:`chat.statusRow.todo.status.completed`,cancelled:`chat.statusRow.todo.status.cancelled`},R=e=>{let t=(0,k.c)(26),{todo:n,isActive:r,activeRef:i}=e,{t:a}=d(),o=z.has(n.status)?n.status:`pending`,s=L[o],c;t[0]!==a||t[1]!==s?(c=a(s),t[0]=a,t[1]=s,t[2]=c):c=t[2];let l=c,u;t[3]===o?u=t[4]:(u=o===`in_progress`?(0,A.jsx)(m,{name:`record-circle`,className:`h-3.5 w-3.5 text-[var(--status-info)]`,"aria-hidden":`true`}):o===`completed`?(0,A.jsx)(m,{name:`checkbox-circle`,className:`h-3.5 w-3.5 text-[var(--status-success)]`,"aria-hidden":`true`}):(0,A.jsx)(m,{name:`time`,className:`h-3.5 w-3.5 text-muted-foreground`,"aria-hidden":`true`}),t[3]=o,t[4]=u);let p=u,v=r?`step`:void 0,y=r&&`bg-[var(--surface-muted)] before:absolute before:inset-y-2 before:left-0 before:w-0.5 before:rounded-full before:bg-[var(--status-info)]`,b;t[5]===y?b=t[6]:(b=f(`group relative grid min-w-0 grid-cols-[1rem_minmax(0,1fr)] items-start gap-2.5`,I,y),t[5]=y,t[6]=b);let x;t[7]!==p||t[8]!==l?(x=(0,A.jsx)(h,{asChild:!0,children:(0,A.jsx)(`span`,{className:`flex size-4 items-center justify-center`,"aria-label":l,children:p})}),t[7]=p,t[8]=l,t[9]=x):x=t[9];let S;t[10]===l?S=t[11]:(S=(0,A.jsx)(g,{side:`left`,sideOffset:6,children:l}),t[10]=l,t[11]=S);let C;t[12]!==x||t[13]!==S?(C=(0,A.jsxs)(_,{children:[x,S]}),t[12]=x,t[13]=S,t[14]=C):C=t[14];let w=ue[o],T;t[15]===w?T=t[16]:(T=f(`block whitespace-normal break-words`,w),t[15]=w,t[16]=T);let E;t[17]!==T||t[18]!==n.content?(E=(0,A.jsx)(`span`,{className:`min-w-0 flex-1`,children:(0,A.jsx)(`span`,{className:T,children:n.content})}),t[17]=T,t[18]=n.content,t[19]=E):E=t[19];let D;return t[20]!==i||t[21]!==E||t[22]!==v||t[23]!==b||t[24]!==C?(D=(0,A.jsxs)(`li`,{ref:i,"aria-current":v,className:b,children:[C,E]}),t[20]=i,t[21]=E,t[22]=v,t[23]=b,t[24]=C,t[25]=D):D=t[25],D},z=new Set([`in_progress`,`pending`,`completed`,`cancelled`]),B=`image/png`,V=l(`OpenChamberMedia`),H=e=>{let t=e.toLowerCase().split(`;`)[0]?.trim()||B;if(t===`image/jpeg`||t===`image/jpg`)return`jpg`;if(t===`image/webp`)return`webp`;if(t===`image/gif`)return`gif`;if(t===`image/svg+xml`)return`svg`;if(t===`image/png`)return`png`;let n=t.split(`/`)[1];return n&&/^[a-z0-9.+-]+$/i.test(n)?n:`png`},U=(e,t)=>{let n=`image.${H(t)}`,r=(((e||``).trim()||n).split(/[\\/]/).pop()||n).replace(/[^\w.\- ()[\]]+/g,`_`).replace(/^\.+/,``);return r?/\.[a-z0-9]{1,8}$/i.test(r)?r:`${r}.${H(t)}`:n},W=e=>new Promise((t,n)=>{let r=new FileReader;r.onload=()=>{if(typeof r.result==`string`){t(r.result);return}n(Error(`Failed to encode image`))},r.onerror=()=>n(r.error??Error(`Failed to encode image`)),r.readAsDataURL(e)}),de=async e=>{let t=await W(e),n=t.indexOf(`,`);return n>=0?t.slice(n+1):t},fe=(e,t)=>{let n=URL.createObjectURL(e),r=document.createElement(`a`);r.href=n,r.download=t,document.body.appendChild(r),r.click(),document.body.removeChild(r),window.setTimeout(()=>URL.revokeObjectURL(n),1e3)},G=async(e,t)=>{let n=await fetch(e,{signal:t,cache:`no-store`});if(!n.ok)throw Error(`Image fetch failed (${n.status})`);return n.blob()},pe=async(e,t=B)=>{if(!e.naturalWidth||!e.naturalHeight)return null;let n=e.currentSrc||e.src;if(n&&(/^(?:blob:|data:|openchamber-asset:)/i.test(n)||/^https?:/i.test(n)||/^\/api(?=\/|[?#]|$)/.test(n)))try{let e=await G(n);if(e.size>0)return e}catch{}try{let n=document.createElement(`canvas`);n.width=e.naturalWidth,n.height=e.naturalHeight;let r=n.getContext(`2d`);if(!r)return null;r.drawImage(e,0,0);let i=t.startsWith(`image/`)?t:B,a=await new Promise(e=>{n.toBlob(t=>e(t),i===`image/jpg`?`image/jpeg`:i)});return a&&a.size>0?a:null}catch{return null}},me=async(e,t)=>{let n=``;try{return n=await ee(e,t??new AbortController().signal),await G(n,t)}finally{n&&T(n)}},he=async(e,n)=>{let r=e.effectiveDirectory??``,i=null;e.prefetchedBlob&&e.prefetchedBlob.size>0&&(i=e.prefetchedBlob);let a=e.displayUrl?.trim();if(!i&&a)try{i=await G(a,n)}catch{i=null}if(!i){let a=e.sourceUrl.trim();if(!a)throw Error(`Image source is empty`);if(/^(?:data|blob):/i.test(a)||/^https?:/i.test(a)||/^\/api(?=\/|[?#]|$)/.test(a))i=await G(a,n);else{let e=D(a,r);if(E(e))try{i=await me(e.path,n)}catch{let r=await t(`/api/fs/raw`,{method:`GET`,cache:`no-store`,query:{path:e.path},signal:n});if(!r.ok)throw Error(`Image source request failed with status ${r.status}`);i=await r.blob()}else i=await G(e.source,n)}}if(!i||i.size<=0)throw Error(`Image is empty`);let o=(e.mimeType||(i.type&&i.type.startsWith(`image/`)?i.type:``)||B).split(`;`)[0].trim()||B;return{blob:i,filename:U(e.filename,o),mimeType:o}},ge=()=>!o()||u===void 0?!1:u.isPluginAvailable(`OpenChamberMedia`),_e=async(e,t)=>{let{blob:i,filename:a,mimeType:o}=await he(e,t);if(ge()){let e=await de(i);return await V.saveImage({dataBase64:e,mimeType:o,filename:a}),`saved`}if(r()){let e=n()?.vscode;if(e?.saveImage){let t=await W(i);return await e.saveImage({fileName:a,dataUrl:t}),`saved`}}return fe(i,a),`downloaded`},ve=e=>e.replace(/&/g,`&amp;`).replace(/</g,`&lt;`).replace(/>/g,`&gt;`).replace(/"/g,`&quot;`).replace(/'/g,`&#39;`),ye=e=>e?Object.entries(e).map(([e,t])=>t==null?``:`${e.startsWith(`--`)?e:e.replace(/[A-Z]/g,e=>`-${e.toLowerCase()}`)}:${typeof t==`number`?`${t}px`:t};`).join(``):``,K=(e,t,n)=>{let r=e.querySelector(`pre`);r&&(r.style.margin=`0`,r.style.background=`transparent`,r.style.whiteSpace=t?`pre-wrap`:`pre`,t&&(r.style.wordBreak=`break-word`,r.style.overflowWrap=`break-word`));let i=e.querySelector(`code`);if(i){let e=ye(n);e&&i.setAttribute(`style`,`${i.getAttribute(`style`)??``}${e}`)}},be=e=>`<pre><code>${ve(e)}</code></pre>`,xe=e=>{let t=(0,k.c)(21),{code:n,language:r,className:i,style:a,codeStyle:o,wrap:s}=e,c=s!==void 0&&s,{currentTheme:l}=v(),u=O.useRef(null),d;t[0]===l?d=t[1]:(d=y(l),t[0]=l,t[1]=d);let p=d,m,h;t[2]!==n||t[3]!==o||t[4]!==c?(m=()=>{let e=u.current;e&&(e.innerHTML=be(n),K(e,c,o))},h=[n,c,o],t[2]=n,t[3]=o,t[4]=c,t[5]=m,t[6]=h):(m=t[5],h=t[6]),O.useLayoutEffect(m,h);let g,_;t[7]!==n||t[8]!==o||t[9]!==r||t[10]!==c?(g=()=>{let e=u.current;if(!e)return;let t=!0,i=new AbortController;return w(n,(r||`text`).toLowerCase(),{signal:i.signal,priority:`visible`}).then(n=>{!t||!e||!n||(e.innerHTML=n,K(e,c,o))}),()=>{t=!1,i.abort()}},_=[n,r,c,o],t[7]=n,t[8]=o,t[9]=r,t[10]=c,t[11]=g,t[12]=_):(g=t[11],_=t[12]),O.useEffect(g,_);let b;t[13]===i?b=t[14]:(b=f(`typography-code`,i),t[13]=i,t[14]=b);let x=p,S;t[15]!==a||t[16]!==x?(S={...x,...a},t[15]=a,t[16]=x,t[17]=S):S=t[17];let C;return t[18]!==b||t[19]!==S?(C=(0,A.jsx)(`div`,{ref:u,className:b,style:S}),t[18]=b,t[19]=S,t[20]=C):C=t[20],C},Se=e=>{let t=e.replace(/^<file>\s*\n?/,``).replace(/\n?<\/file>\s*$/,``);return t=t.replace(/^\s*\d{5}\|\s?/gm,``),t.trim()},Ce=(e,t=``)=>{if(typeof e==`string`)return e;if(e==null)return t;if(typeof e==`number`||typeof e==`boolean`||typeof e==`bigint`)return String(e);try{return JSON.stringify(e)}catch{return t}},we=e=>e?e.includes(`<diagnostics`)||e.includes(`<file_diagnostics>`)||e.includes(`LSP errors detected`)||e.includes(`This file has errors`):!1,Te=e=>e?e.replace(/\n{0,2}LSP errors detected[\s\S]*?<diagnostics[^>]*>[\s\S]*?<\/diagnostics>/g,``).replace(/\n{0,2}This file has errors[\s\S]*?<\/file_diagnostics>/g,``).replace(/<diagnostics[^>]*>[\s\S]*?<\/diagnostics>/g,``).replace(/<file_diagnostics>[\s\S]*?<\/file_diagnostics>/g,``).trim():``,Ee=(e,t)=>!e||typeof e!=`object`?String(e):C(e,t||``),q=e=>{if(typeof e==`string`){let t=e.trim();return t.length>0?t:void 0}if(e&&typeof e==`object`){let t=e.patch;if(typeof t==`string`){let e=t.trim();return e.length>0?e:void 0}}},De=e=>{if(!e||typeof e!=`object`)return;let t=q(e.patch)??q(e.diff);if(t)return t;let n=Array.isArray(e.files)?e.files:[];for(let e of n){if(!e||typeof e!=`object`)continue;let t=q(e.patch)??q(e.diff);if(t)return t}},Oe=e=>{if(!e||typeof e!=`string`)return{data:null,isJson:!1};let t=e.trim();if(!t.startsWith(`{`)&&!t.startsWith(`[`)||!t.endsWith(`}`)&&!t.endsWith(`]`)||t.length<2)return{data:null,isJson:!1};try{let e=JSON.parse(t);return typeof e==`object`&&e?{data:e,isJson:!0}:{data:null,isJson:!1}}catch{return{data:null,isJson:!1}}},ke=(e,t,n)=>{let r=Se(e);if((t===`edit`||t===`multiedit`||t===`write`||t===`apply_patch`)&&we(r)&&(r=Te(r)),(t===`edit`||t===`multiedit`||t===`apply_patch`)&&r.trim().length===0){let e=De(n);if(e)return e}return r},Ae=e=>{let t=e.match(/<type>(file|directory)<\/type>/i)?.[1]?.toLowerCase()??`unknown`,n=(e.match(/<content>([\s\S]*?)<\/content>/i)?.[1]??e).replace(/\r\n/g,`
2
2
  `).split(`
3
3
  `),r=e=>/\(\s*File has more lines\..*offset.*\)/i.test(e.trim());return{type:t,lines:n.map(e=>{let n=e.trim(),i=n.startsWith(`(`)&&n.endsWith(`)`)||r(n);if(t!==`directory`){let t=e.match(/^(\d+):\s?(.*)$/);if(t){let e=t[2],n=e.trim(),i=n.startsWith(`(`)&&n.endsWith(`)`)||r(n);return{lineNumber:i?null:Number(t[1]),text:e,isInfo:i}}}return{lineNumber:null,text:e,isInfo:i}}).filter((e,t,n)=>{if(e.text.trim().length>0)return!0;let r=n[t-1],i=n[t+1],a=!!(r?.isInfo||i?.isInfo),o=e.lineNumber!==null;return!(a&&o)})}},je=(e,t)=>{try{let n=e.trim().split(`
4
4
  `).filter(Boolean);if(n.length===0)return null;let r=[];return n.forEach(e=>{let t=e.match(/^(\s*)(.+)$/);if(t){let[,e,n]=t,i=Math.floor(e.length/2),a=!n.endsWith(`/`);r.push({name:n.replace(/\/$/,``),depth:i,isFile:a})}}),(0,A.jsx)(`div`,{className:f(`w-full min-w-0 font-mono space-y-0.5`,t?.unstyled?null:`p-3 bg-muted/20 rounded-xl border border-border/30`),style:s.tool.popup,children:r.map((e,t)=>(0,A.jsx)(`div`,{className:`min-w-0`,style:{paddingLeft:`${e.depth*20}px`},children:e.isFile?(0,A.jsx)(`span`,{className:`text-foreground/90 block truncate`,children:e.name}):(0,A.jsxs)(`span`,{className:`font-semibold text-foreground block truncate`,children:[e.name,`/`]})},t))})}catch{return null}},Me={backgroundColor:`var(--status-info)`,opacity:.6},Ne=(e,t,n)=>{try{let r=e.trim().split(`
package/dist/index.html CHANGED
@@ -552,7 +552,7 @@
552
552
  opacity: 0.72;
553
553
  }
554
554
  </style>
555
- <script type="module" crossorigin src="/assets/main-Fbjmo73O.js"></script>
555
+ <script type="module" crossorigin src="/assets/main-DZGXa6wk.js"></script>
556
556
  <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-C0FnF6B9.js">
557
557
  <link rel="modulepreload" crossorigin href="/assets/runtime-auth-D66yq6ie.js">
558
558
  <link rel="modulepreload" crossorigin href="/assets/runtime-switch-BJM2k_uH.js">
@@ -572,7 +572,7 @@
572
572
  <link rel="modulepreload" crossorigin href="/assets/terminalApi-DXyzaX3K.js">
573
573
  <link rel="modulepreload" crossorigin href="/assets/types-BuiqMmh_.js">
574
574
  <link rel="modulepreload" crossorigin href="/assets/capgoAdapter-DCowZ2ab.js">
575
- <link rel="modulepreload" crossorigin href="/assets/runtimeConfig-CCw0l6aJ.js">
575
+ <link rel="modulepreload" crossorigin href="/assets/runtimeConfig-CJE7T1Sr.js">
576
576
  <link rel="stylesheet" crossorigin href="/assets/src-Cp_AK_QO.css">
577
577
  </head>
578
578
  <body class="h-full bg-background text-foreground">
@@ -74,7 +74,7 @@
74
74
  }
75
75
  </style>
76
76
 
77
- <script type="module" crossorigin src="/assets/miniChat-BFctomLE.js"></script>
77
+ <script type="module" crossorigin src="/assets/miniChat-C8K4fwOO.js"></script>
78
78
  <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-C0FnF6B9.js">
79
79
  <link rel="modulepreload" crossorigin href="/assets/runtime-auth-D66yq6ie.js">
80
80
  <link rel="modulepreload" crossorigin href="/assets/runtime-switch-BJM2k_uH.js">
@@ -94,7 +94,7 @@
94
94
  <link rel="modulepreload" crossorigin href="/assets/terminalApi-DXyzaX3K.js">
95
95
  <link rel="modulepreload" crossorigin href="/assets/types-BuiqMmh_.js">
96
96
  <link rel="modulepreload" crossorigin href="/assets/capgoAdapter-DCowZ2ab.js">
97
- <link rel="modulepreload" crossorigin href="/assets/runtimeConfig-CCw0l6aJ.js">
97
+ <link rel="modulepreload" crossorigin href="/assets/runtimeConfig-CJE7T1Sr.js">
98
98
  <link rel="stylesheet" crossorigin href="/assets/src-Cp_AK_QO.css">
99
99
  </head>
100
100
  <body class="h-full bg-background text-foreground">
package/dist/mobile.html CHANGED
@@ -63,7 +63,7 @@
63
63
  })();
64
64
  </script>
65
65
 
66
- <script type="module" crossorigin src="/assets/mobile-CgrEAs5U.js"></script>
66
+ <script type="module" crossorigin src="/assets/mobile-Brtl2UnC.js"></script>
67
67
  <link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-C0FnF6B9.js">
68
68
  <link rel="modulepreload" crossorigin href="/assets/runtime-auth-D66yq6ie.js">
69
69
  <link rel="modulepreload" crossorigin href="/assets/runtime-switch-BJM2k_uH.js">
@@ -83,7 +83,7 @@
83
83
  <link rel="modulepreload" crossorigin href="/assets/terminalApi-DXyzaX3K.js">
84
84
  <link rel="modulepreload" crossorigin href="/assets/types-BuiqMmh_.js">
85
85
  <link rel="modulepreload" crossorigin href="/assets/capgoAdapter-DCowZ2ab.js">
86
- <link rel="modulepreload" crossorigin href="/assets/runtimeConfig-CCw0l6aJ.js">
86
+ <link rel="modulepreload" crossorigin href="/assets/runtimeConfig-CJE7T1Sr.js">
87
87
  <link rel="stylesheet" crossorigin href="/assets/src-Cp_AK_QO.css">
88
88
  </head>
89
89
  <body class="h-full bg-background text-foreground">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openchambery/web",
3
- "version": "2.0.5-beta.3",
3
+ "version": "2.0.5",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./server/index.js",
@@ -41,6 +41,10 @@ Auto-submit requires **settings ready + enabled + authoritative directory**.
41
41
 
42
42
  ## Architecture
43
43
 
44
+ `pause-store.js` owns monotonic per-question user holds shared by co-located Web, Electron and VS Code hosts. Default storage is the user's `.config/openchamber/question-pauses`; `OPENCHAMBER_QUESTION_PAUSE_DIR` can select a shared directory. Empty, atomically created files are keyed by the digest of globally unique upstream session/form IDs, contain no answers or credentials, survive host restart and are removed on authoritative settlement. All hosts attached to one upstream must use this shared location and the updated runtime; independent machines require a shared filesystem or a single OpenChamber host. This is not an upstream distributed lock or a cross-host submission claim.
45
+
46
+ Pause acknowledgement follows shared hold publication. Failure leaves the local timer stopped but returns an error so the UI can retry publication. An early pause with no recovered form records only a hold and still returns `not_found`; later discovery cannot arm it. Snapshot reads and automatic expiry adopt shared holds, and form IO rechecks immediately after schema GET, before answer POST. Unreadable coordination fails closed (local pause, partial coverage); explicit user reply/delegation remains allowed. A POST already dispatched upstream cannot be recalled. No polling loop or extra upstream request is introduced.
47
+
44
48
  | File | Role |
45
49
  |---|---|
46
50
  | `core.js` / `core.d.ts` | Platform-agnostic state machine (IO/timer injected). Shared contract for VS Code. |
@@ -4,6 +4,7 @@
4
4
  * API tip event: `openchamber:question-auto-delegate-changed` with `{ epoch, revision }` only —
5
5
  * consumers must GET `/api/question-auto-delegate` for the authoritative snapshot.
6
6
  */
7
+ import type { QuestionPauseStore } from './pause-store.js';
7
8
 
8
9
  export const QUESTION_AUTO_DELEGATE_DELAY_MS: 30000;
9
10
 
@@ -140,6 +141,8 @@ export interface QuestionAutoDelegateUpstreamResult {
140
141
  * body was never transmitted. Must not be set when the send may have reached upstream.
141
142
  */
142
143
  notSent?: boolean;
144
+ /** A shared user hold prevented the automatic answer before dispatch. */
145
+ paused?: boolean;
143
146
  status: number;
144
147
  body: unknown;
145
148
  }
@@ -170,6 +173,7 @@ export interface QuestionAutoDelegateIO {
170
173
  directory: string | undefined,
171
174
  answers: string[][],
172
175
  sessionID: string,
176
+ canReply?: () => boolean,
173
177
  ): Promise<QuestionAutoDelegateUpstreamResult>;
174
178
  postReject(
175
179
  requestID: string,
@@ -203,6 +207,7 @@ export interface QuestionAutoDelegateCoreOptions {
203
207
  io: QuestionAutoDelegateIO;
204
208
  delayMs?: number;
205
209
  autoAnswer?: string;
210
+ pauseStore?: QuestionPauseStore;
206
211
  }
207
212
 
208
213
  export interface QuestionAutoDelegateCore {
@@ -64,6 +64,7 @@ export function createQuestionAutoDelegateCore({
64
64
  io,
65
65
  delayMs = QUESTION_AUTO_DELEGATE_DELAY_MS,
66
66
  autoAnswer = QUESTION_AUTO_DELEGATE_ANSWER,
67
+ pauseStore,
67
68
  } = {}) {
68
69
  if (!io || typeof io !== 'object') {
69
70
  throw new TypeError('createQuestionAutoDelegateCore requires io');
@@ -107,18 +108,21 @@ export function createQuestionAutoDelegateCore({
107
108
  }
108
109
  };
109
110
 
110
- const snapshot = () => ({
111
- epoch,
112
- revision,
113
- serverNow: io.now(),
114
- enabled: settingsStatus === 'ready' ? enabled : false,
115
- delayMs,
116
- coverage: {
117
- state: settingsStatus === 'unavailable' && coverageState === 'ready' ? 'partial' : coverageState,
118
- failedDirectories: failedDirectories.slice(),
119
- },
120
- requests: Array.from(requests.values()).map(publicRequest),
121
- });
111
+ const snapshot = () => {
112
+ for (const entry of requests.values()) syncSharedPause(entry);
113
+ return {
114
+ epoch,
115
+ revision,
116
+ serverNow: io.now(),
117
+ enabled: settingsStatus === 'ready' ? enabled : false,
118
+ delayMs,
119
+ coverage: {
120
+ state: settingsStatus === 'unavailable' && coverageState === 'ready' ? 'partial' : coverageState,
121
+ failedDirectories: failedDirectories.slice(),
122
+ },
123
+ requests: Array.from(requests.values()).map(publicRequest),
124
+ };
125
+ };
122
126
 
123
127
  const rememberSession = (info, directoryHint = '') => {
124
128
  if (!info || typeof info !== 'object') return;
@@ -145,6 +149,23 @@ export function createQuestionAutoDelegateCore({
145
149
  }
146
150
  };
147
151
 
152
+ const syncSharedPause = (entry) => {
153
+ if (entry.state !== 'counting') return false;
154
+ try {
155
+ if (!pauseStore?.has(entry.requestID, entry.sessionID)) return false;
156
+ } catch {
157
+ // Unreadable coordination is not permission to answer. Pause locally and
158
+ // expose partial coverage; never let an event/timer rejection escape the hub.
159
+ coverageState = 'partial';
160
+ }
161
+ clearTimer(entry);
162
+ entry.state = 'paused';
163
+ entry.deadlineAt = null;
164
+ entry.pauseReason = 'interaction';
165
+ bump();
166
+ return true;
167
+ };
168
+
148
169
  const fireTakeover = (entry, reason) => {
149
170
  try {
150
171
  io.onUserTakeover?.({
@@ -191,6 +212,7 @@ export function createQuestionAutoDelegateCore({
191
212
  };
192
213
 
193
214
  const ensureCounting = (entry, { resetDeadline } = { resetDeadline: true }) => {
215
+ if (syncSharedPause(entry)) return false;
194
216
  if (entry.state === TERMINAL_SETTLED || entry.state === 'uncertain' || entry.state === 'submitting') {
195
217
  return false;
196
218
  }
@@ -304,6 +326,11 @@ export function createQuestionAutoDelegateCore({
304
326
  entry.resolution = resolution;
305
327
  entry.claimAuthority = entry.claimAuthority || 'done';
306
328
  if (submittedBy) entry.submittedBy = submittedBy;
329
+ try {
330
+ pauseStore?.remove(entry.requestID, entry.sessionID);
331
+ } catch {
332
+ // Retaining a settled hold is harmless; cleanup must not undo settlement.
333
+ }
307
334
  };
308
335
 
309
336
  const markUncertain = (entry, submittedBy) => {
@@ -538,6 +565,9 @@ export function createQuestionAutoDelegateCore({
538
565
  };
539
566
  }
540
567
  const existing = requests.get(requestID);
568
+ if (existing && (syncSharedPause(existing) || existing.state === 'paused')) {
569
+ return { outcome: 'paused', snapshot: snapshot() };
570
+ }
541
571
  if (existing && !asTrimmedString(existing.directory) && !asTrimmedString(input.directory)) {
542
572
  return {
543
573
  outcome: 'error',
@@ -620,7 +650,8 @@ export function createQuestionAutoDelegateCore({
620
650
  ? input.answers
621
651
  : buildAutoDelegateAnswers(count, autoAnswer);
622
652
  entry.upstreamDispatched = true;
623
- upstream = await io.postReply(requestID, directory, answers, entry.sessionID);
653
+ upstream = await io.postReply(requestID, directory, answers, entry.sessionID,
654
+ authority === 'auto' ? () => !pauseStore?.has(requestID, entry.sessionID) : undefined);
624
655
  }
625
656
  } catch (error) {
626
657
  // Throw before a classified upstream result: treat as pre-send failure → release for retry.
@@ -650,6 +681,11 @@ export function createQuestionAutoDelegateCore({
650
681
  // Compatible extension: only an explicit notSent===true means the request
651
682
  // never left the process. Release claim for human retry. Unknown status:0
652
683
  // without notSent stays uncertain (may have been sent).
684
+ if (upstream?.paused === true && upstream.notSent === true) {
685
+ releaseClaimToPaused(entry, 'interaction');
686
+ bump();
687
+ return { outcome: 'paused', snapshot: snapshot() };
688
+ }
653
689
  if (upstream?.notSent === true) {
654
690
  releaseClaimToPaused(entry, authority === 'manual' ? 'interaction' : 'user');
655
691
  bump();
@@ -793,6 +829,13 @@ export function createQuestionAutoDelegateCore({
793
829
 
794
830
  let entry = requests.get(requestID);
795
831
  if (!entry) {
832
+ // Publish the user's hold before asynchronous discovery: another host's
833
+ // deadline must not win while this host waits for its form list.
834
+ try {
835
+ pauseStore?.pause(requestID, sessionID);
836
+ } catch {
837
+ return { outcome: 'error', snapshot: snapshot(), status: 503, error: 'Could not publish question pause' };
838
+ }
796
839
  const recovered = await recoverPendingIdentity({
797
840
  requestID,
798
841
  sessionID,
@@ -863,6 +906,12 @@ export function createQuestionAutoDelegateCore({
863
906
  entry.state = 'paused';
864
907
  entry.deadlineAt = null;
865
908
  entry.pauseReason = reason === 'goal' ? 'goal' : reason;
909
+ try {
910
+ pauseStore?.pause(requestID, sessionID);
911
+ } catch {
912
+ bump();
913
+ return { outcome: 'error', snapshot: snapshot(), status: 503, error: 'Could not publish question pause' };
914
+ }
866
915
  if (reason !== 'goal') {
867
916
  fireTakeover(entry, reason);
868
917
  }
@@ -12,7 +12,7 @@ export function createQuestionFormIO(upstream) {
12
12
  if (!Array.isArray(rows)) return null;
13
13
  return rows.filter((form) => form?.metadata?.kind === 'question');
14
14
  },
15
- async postReply(requestID, directory, answers, sessionID) {
15
+ async postReply(requestID, directory, answers, sessionID, canReply) {
16
16
  const path = formPath(sessionID, requestID);
17
17
  const result = await upstream(path, { directory });
18
18
  // A failed schema read never means the answer POST was dispatched.
@@ -30,6 +30,9 @@ export function createQuestionFormIO(upstream) {
30
30
  field.options?.find((option) => (option.label || option.value) === value)?.value ?? value);
31
31
  return [field.key, field.type === 'multiselect' ? values : values[0] ?? ''];
32
32
  }));
33
+ if (canReply && !canReply()) {
34
+ return { ok: false, notSent: true, paused: true, status: 409, body: null };
35
+ }
33
36
  return upstream(`${path}/reply`, { directory, method: 'POST', body: { answer } });
34
37
  },
35
38
  async postReject(requestID, directory, _body, sessionID) {
@@ -0,0 +1,7 @@
1
+ export interface QuestionPauseStore {
2
+ has(requestID: string, sessionID: string): boolean;
3
+ pause(requestID: string, sessionID: string): void;
4
+ remove(requestID: string, sessionID: string): void;
5
+ }
6
+
7
+ export function createQuestionPauseStore(directory?: string): QuestionPauseStore;
@@ -0,0 +1,39 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { mkdirSync, statSync, unlinkSync, writeFileSync } from 'node:fs';
3
+ import { homedir } from 'node:os';
4
+ import { join } from 'node:path';
5
+
6
+ // All local hosts share this boundary, including desktop and VS Code. Form and
7
+ // session IDs are globally unique upstream identities; no URL or credential is stored.
8
+ export function createQuestionPauseStore(directory = process.env.OPENCHAMBER_QUESTION_PAUSE_DIR
9
+ || join(homedir(), '.config', 'openchamber', 'question-pauses')) {
10
+ const pathFor = (requestID, sessionID) => join(directory,
11
+ createHash('sha256').update(JSON.stringify([sessionID, requestID])).digest('hex'));
12
+ return {
13
+ has(requestID, sessionID) {
14
+ try {
15
+ statSync(pathFor(requestID, sessionID));
16
+ return true;
17
+ } catch (error) {
18
+ if (error?.code === 'ENOENT') return false;
19
+ throw error;
20
+ }
21
+ },
22
+ pause(requestID, sessionID) {
23
+ mkdirSync(directory, { recursive: true, mode: 0o700 });
24
+ try {
25
+ // Exclusive creation publishes an immutable hold atomically across processes.
26
+ writeFileSync(pathFor(requestID, sessionID), '', { flag: 'wx', mode: 0o600 });
27
+ } catch (error) {
28
+ if (error?.code !== 'EEXIST') throw error;
29
+ }
30
+ },
31
+ remove(requestID, sessionID) {
32
+ try {
33
+ unlinkSync(pathFor(requestID, sessionID));
34
+ } catch (error) {
35
+ if (error?.code !== 'ENOENT') throw error;
36
+ }
37
+ },
38
+ };
39
+ }
@@ -3,6 +3,7 @@ import {
3
3
  QUESTION_AUTO_DELEGATE_DELAY_MS,
4
4
  } from './core.js';
5
5
  import { createQuestionFormIO } from './form-io.js';
6
+ import { createQuestionPauseStore } from './pause-store.js';
6
7
 
7
8
  const REQUEST_TIMEOUT_MS = 15_000;
8
9
 
@@ -42,6 +43,7 @@ export function createQuestionAutoDelegateRuntime({
42
43
  },
43
44
  createEpoch = () => `qad-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`,
44
45
  onUserTakeover,
46
+ pauseStore = createQuestionPauseStore(),
45
47
  } = {}) {
46
48
  const upstream = async (path, { directory, method = 'GET', body } = {}) => {
47
49
  const url = new URL(buildOpenCodeUrl(path, ''));
@@ -103,6 +105,7 @@ export function createQuestionAutoDelegateRuntime({
103
105
 
104
106
  const core = createQuestionAutoDelegateCore({
105
107
  delayMs,
108
+ pauseStore,
106
109
  io: {
107
110
  now,
108
111
  createTimer,
@@ -1,6 +1,11 @@
1
- import { afterEach, expect, it, vi } from 'vitest';
1
+ import { afterEach, beforeEach, expect, it, vi } from 'vitest';
2
+ import { mkdtempSync, rmSync, writeFileSync } from 'node:fs';
3
+ import { execFileSync } from 'node:child_process';
4
+ import { tmpdir } from 'node:os';
5
+ import { join } from 'node:path';
2
6
  import { createQuestionAutoDelegateRuntime } from './runtime.js';
3
7
  import { QUESTION_AUTO_DELEGATE_ANSWER } from './core.js';
8
+ import { createQuestionPauseStore } from './pause-store.js';
4
9
 
5
10
  const form = {
6
11
  id: 'frm_question', sessionID: 'ses_test', title: 'Choose',
@@ -8,9 +13,12 @@ const form = {
8
13
  fields: [{ key: 'approach', type: 'string', custom: true, options: [{ label: 'A', value: 'a' }] }],
9
14
  };
10
15
  const runtimes = [];
16
+ let pauseDirectory;
17
+ beforeEach(() => { pauseDirectory = mkdtempSync(join(tmpdir(), 'question-pauses-')); });
11
18
  afterEach(() => {
12
19
  runtimes.splice(0).forEach((runtime) => runtime.dispose());
13
20
  vi.useRealTimers();
21
+ rmSync(pauseDirectory, { recursive: true, force: true });
14
22
  });
15
23
 
16
24
  const setup = async (pending = []) => {
@@ -30,6 +38,7 @@ const setup = async (pending = []) => {
30
38
  getOpenCodeAuthHeaders: () => ({}),
31
39
  readSettingsFromDiskMigrated: async () => ({ projects: [{ path: '/project' }] }),
32
40
  fetchImpl,
41
+ pauseStore: createQuestionPauseStore(pauseDirectory),
33
42
  });
34
43
  runtimes.push(runtime);
35
44
  runtime.start();
@@ -122,6 +131,124 @@ it('honors user takeover and explicit delegation of native forms', async () => {
122
131
  expect(posts()).toHaveLength(1);
123
132
  });
124
133
 
134
+ it('a confirmed desktop pause stops a second host and survives host recreation', async () => {
135
+ const desktop = await setup();
136
+ const web = await setup();
137
+ desktop.emit('form.created', { form });
138
+ web.emit('form.created', { form });
139
+ const result = await desktop.runtime.pause({ requestID: form.id, sessionID: form.sessionID, reason: 'interaction' });
140
+ expect(result.outcome).toBe('paused');
141
+ const restarted = await setup([form]);
142
+ await vi.advanceTimersByTimeAsync(60_000);
143
+ for (const host of [desktop, web, restarted]) {
144
+ expect(host.posts()).toHaveLength(0);
145
+ expect(host.runtime.snapshot().requests[0].state).toBe('paused');
146
+ }
147
+ await web.runtime.delegate({ requestID: form.id, sessionID: form.sessionID });
148
+ expect(web.posts()).toHaveLength(1);
149
+ expect(createQuestionPauseStore(pauseDirectory).has(form.id, form.sessionID)).toBe(false);
150
+ });
151
+
152
+ it('a shared hold for one question does not stop another question in the same session', async () => {
153
+ const { emit, runtime, fetchImpl, posts } = await setup();
154
+ const other = { ...form, id: 'frm_other' };
155
+ const original = fetchImpl.getMockImplementation();
156
+ fetchImpl.mockImplementation((url, options) => {
157
+ if (url.pathname.endsWith('/form/frm_other')) return Promise.resolve(Response.json({ data: other }));
158
+ if (url.pathname.endsWith('/form/frm_other/reply')) return Promise.resolve(new Response(null, { status: 204 }));
159
+ return original(url, options);
160
+ });
161
+ emit('form.created', { form });
162
+ emit('form.created', { form: other });
163
+ await runtime.pause({ requestID: form.id, sessionID: form.sessionID, reason: 'interaction' });
164
+ await vi.advanceTimersByTimeAsync(30_000);
165
+ expect(posts()).toHaveLength(1);
166
+ expect(posts()[0][0].pathname).toContain('/frm_other/reply');
167
+ });
168
+
169
+ it('checks a cross-host pause again after the asynchronous form schema read', async () => {
170
+ const desktop = await setup();
171
+ const web = await setup();
172
+ web.emit('form.created', { form });
173
+ await vi.advanceTimersByTimeAsync(1000);
174
+ desktop.emit('form.created', { form });
175
+ const original = web.fetchImpl.getMockImplementation();
176
+ let finishSchema;
177
+ web.fetchImpl.mockImplementation((url, options) => url.pathname.endsWith('/form/frm_question')
178
+ ? new Promise((resolve) => { finishSchema = () => resolve(Response.json({ data: form })); })
179
+ : original(url, options));
180
+ // Only the web host reaches its timer; desktop takeover arrives while its schema GET waits.
181
+ await vi.advanceTimersByTimeAsync(29_000);
182
+ expect(finishSchema).toBeTypeOf('function');
183
+ await desktop.runtime.pause({ requestID: form.id, sessionID: form.sessionID, reason: 'interaction' });
184
+ finishSchema();
185
+ await vi.advanceTimersByTimeAsync(0);
186
+ expect(web.posts()).toHaveLength(0);
187
+ expect(web.runtime.snapshot().requests[0].state).toBe('paused');
188
+ });
189
+
190
+ it('retains a hold sent before this host discovers the form', async () => {
191
+ const desktop = await setup();
192
+ const result = await desktop.runtime.pause({ requestID: form.id, sessionID: form.sessionID, reason: 'interaction' });
193
+ expect(result.outcome).toBe('not_found');
194
+ const web = await setup([form]);
195
+ await vi.advanceTimersByTimeAsync(30_000);
196
+ expect(web.posts()).toHaveLength(0);
197
+ expect(web.runtime.snapshot().requests[0].state).toBe('paused');
198
+ });
199
+
200
+ it('publishes the hold before a slow missing-identity recovery can cross the other host deadline', async () => {
201
+ const desktop = await setup();
202
+ const web = await setup([form]);
203
+ const original = desktop.fetchImpl.getMockImplementation();
204
+ let finishList;
205
+ desktop.fetchImpl.mockImplementation((url, options) => url.pathname === '/api/form'
206
+ ? new Promise((resolve) => { finishList = () => resolve(Response.json({ data: [form] })); })
207
+ : original(url, options));
208
+ const pausing = desktop.runtime.pause({ requestID: form.id, sessionID: form.sessionID, directory: '/project', reason: 'interaction' });
209
+ await vi.advanceTimersByTimeAsync(30_000);
210
+ expect(web.posts()).toHaveLength(0);
211
+ finishList();
212
+ expect((await pausing).outcome).toBe('paused');
213
+ });
214
+
215
+ it('reports shared pause publication failure and allows explicit retry', async () => {
216
+ const { runtime, emit } = await setup();
217
+ emit('form.created', { form });
218
+ const store = createQuestionPauseStore(pauseDirectory);
219
+ const identity = { requestID: form.id, sessionID: form.sessionID, reason: 'interaction' };
220
+ // A file where a directory belongs is a deterministic write failure on every platform.
221
+ rmSync(pauseDirectory, { recursive: true });
222
+ writeFileSync(pauseDirectory, 'blocked');
223
+ expect((await runtime.pause(identity)).outcome).toBe('error');
224
+ rmSync(pauseDirectory);
225
+ expect((await runtime.pause(identity)).outcome).toBe('paused');
226
+ expect(store.has(form.id, form.sessionID)).toBe(true);
227
+ });
228
+
229
+ it('blocks automatic replies on an unreadable shared store without an unhandled timer failure', async () => {
230
+ const { runtime, emit, posts } = await setup();
231
+ emit('form.created', { form });
232
+ rmSync(pauseDirectory, { recursive: true });
233
+ writeFileSync(pauseDirectory, 'blocked');
234
+ await vi.advanceTimersByTimeAsync(30_000);
235
+ expect(posts()).toHaveLength(0);
236
+ expect(runtime.snapshot().requests[0].state).toBe('paused');
237
+ expect(runtime.snapshot().coverage.state).toBe('partial');
238
+ });
239
+
240
+ it('observes a pause published by a separate Node host process', async () => {
241
+ const { runtime, emit, posts } = await setup();
242
+ emit('form.created', { form });
243
+ execFileSync(process.execPath, ['--input-type=module', '-e', `
244
+ import { createQuestionPauseStore } from ${JSON.stringify(new URL('./pause-store.js', import.meta.url).href)};
245
+ createQuestionPauseStore(process.argv[1]).pause(process.argv[2], process.argv[3]);
246
+ `, pauseDirectory, form.id, form.sessionID]);
247
+ await vi.advanceTimersByTimeAsync(30_000);
248
+ expect(posts()).toHaveLength(0);
249
+ expect(runtime.snapshot().requests[0].state).toBe('paused');
250
+ });
251
+
125
252
  it('uses the freshly read schema for multiple fields and array answers', async () => {
126
253
  const { emit, fetchImpl, posts } = await setup();
127
254
  const original = fetchImpl.getMockImplementation();
@@ -1,2 +0,0 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/MarkstreamRendererImpl-DLI17gOM.js","assets/rolldown-runtime-C0FnF6B9.js","assets/vendor-base-ui-CnHfUmDN.js","assets/useUIStore-Dfx6TKvi.js","assets/runtime-switch-BJM2k_uH.js","assets/runtime-auth-D66yq6ie.js","assets/vendor-zustand-DzRqcymP.js","assets/vendor-react-DLPElpoQ.js","assets/vendor-markstream-react-DX55XLGO.js","assets/vendor-aparajita-capacitor-secure-storage-CjQdwfjS.js","assets/vendor-markstream-core-Cm34iPLL.js","assets/vendor-floating-ui-dom-BHhLtF5l.js","assets/vendor-floating-ui-core-Co1I1lFV.js","assets/vendor-reactuses-core-Dq5ocTF8.js","assets/vendor-lodash-es-DfLbG5Af.js","assets/vendor-js-cookie-hSOiFTtX.js","assets/button-CUwjpv-i.js","assets/persistence-Dnj1QOdX.js","assets/runtime-fetch-CiqQd__Y.js","assets/vendor-pathe-vBmvQE8f.js","assets/vendor-tanstack-query-core-BWz0ose6.js","assets/store-l_X_jQNz.js","assets/vendor-class-variance-authority-BLUaYARZ.js","assets/vendor-tailwind-merge-BicNWLTg.js","assets/useMobileNavigationStore-BjIptzTV.js","assets/platform-wu6wSDfg.js","assets/vendor-opencode-client-MF2GBrFx.js","assets/vendor-tanstack-react-query-D7pys_c9.js","assets/vendor-sonner-DVzioF3d.js","assets/useAssistantUIStore-DBwfg9nX.js","assets/vendor-zod-Dzk5kdUU.js","assets/vendor-fuse.js-DB5wDJbI.js","assets/useThemeSystem-DMzWVJaW.js","assets/useRuntimeAPIs-DSLXJybW.js","assets/url-DNRMq_0R.js","assets/useEffectiveDirectory-BbQKZPcu.js","assets/markdownHeightCache-CGCWmHgq.js","assets/dualLimitLru-D8Sphgua.js","assets/MarkdownRendererImpl-DCim2MBS.js","assets/vendor-katex--B5dHUyk.js","assets/markdownTheme-DM5h1i18.js","assets/vendor-pierre-diffs-DX7XTPG3.js","assets/vendor-hast-util-to-html-B0p1k5Xa.js","assets/vendor-character-entities-legacy-Wut6vMuj.js","assets/vendor-character-entities-html4-DlN_yAFd.js","assets/vendor-ccount-CyGsA0u7.js","assets/vendor-comma-separated-tokens-B9ouxNNS.js","assets/vendor-oniguruma-to-es-CrHzjjSU.js","assets/vendor-oniguruma-parser-D2DIvhSP.js","assets/vendor-diff-Dq7CZNim.js","assets/vendor-lru_map-DpDied8H.js","assets/markdown-worker-bS5OgGO3.js","assets/FadeInOnReveal-BMSk_tY-.js","assets/imageSource-BpUsiwFd.js","assets/relay-image-stream-D2XooXKZ.js","assets/vendor-morphdom-BbKiNDAu.js","assets/vendor-beautiful-mermaid-DykqIK5D.js","assets/vendor-dompurify-CeJNOzik.js","assets/vendor-marked-WVekxjAN.js","assets/vendor-remend-C3cXc-tf.js","assets/MarkstreamRendererImpl-DKhVy3nF.css"])))=>i.map(i=>d[i]);
2
- import{o as e}from"./rolldown-runtime-C0FnF6B9.js";import{a as t}from"./vendor-zustand-DzRqcymP.js";import{nt as n,rt as r}from"./vendor-base-ui-CnHfUmDN.js";import{n as i}from"./vendor-react-DLPElpoQ.js";import{o as a}from"./vendor-aparajita-capacitor-secure-storage-CjQdwfjS.js";import{r as o}from"./button-CUwjpv-i.js";import{i as s,n as c,t as l}from"./markdownHeightCache-CGCWmHgq.js";var u=i(),d=e(r(),1),f=`openchamber:chunk-import-reload`,p=250,m=3e4,h=[/Importing a module script failed/i,/Failed to fetch dynamically imported module/i,/error loading dynamically imported module/i,/Loading chunk \S+ failed/i,/ChunkLoadError/i];function g(e){if(e instanceof Error)return`${e.name}\n${e.message}\n${e.stack??``}`;if(typeof e==`string`)return e;try{return JSON.stringify(e)}catch{return String(e)}}function _(e){let t=g(e);return h.some(e=>e.test(t))}function v(e){return`2.0.5-beta.3:${g(e).slice(0,500)}`}function y(e){if(typeof window>`u`)return;let t=Date.now(),n=v(e),r=null;try{let e=window.sessionStorage.getItem(f);if(e)try{r=JSON.parse(e)}catch{r=null}}catch{return}let i=typeof r?.timestamp==`number`?r.timestamp:0;if(!(r?.signature===n&&t-i<m)){try{window.sessionStorage.setItem(f,JSON.stringify({signature:n,timestamp:t}))}catch{return}console.error(`[refresh-debug] chunk-import-reload`,{error:g(e).slice(0,1e3)}),window.setTimeout(()=>{window.location.reload()},0)}}async function b(e,t={}){let n=t.retries??1,r;for(let t=0;t<=n;t+=1)try{return await e()}catch(e){if(r=e,!_(e)||t>=n)break;await new Promise(e=>setTimeout(e,p*(t+1)))}throw _(r)&&y(r),r}var x=e=>(0,d.lazy)(()=>b(e)),S=(e,t)=>{try{let n=t??(typeof localStorage>`u`?null:localStorage);return n?n.getItem(e)===`1`:!1}catch{return!1}},C=(e,t)=>{try{let n=t??(typeof localStorage>`u`?null:localStorage);return!n||n.getItem(e)!==`0`}catch{return!0}},w=(e,t)=>{try{typeof localStorage<`u`&&localStorage.setItem(e,t?`1`:`0`)}catch{}},T=`oc:legend-timeline`,E=e=>S(T,e),D=`oc:markstream-react`,O=e=>C(D,e),k=t(e=>({legendTimelineEnabled:E(),setLegendTimelineEnabled:t=>{w(T,t),e({legendTimelineEnabled:t})},markstreamReactEnabled:O(),setMarkstreamReactEnabled:t=>{w(D,t),e({markstreamReactEnabled:t})}})),A=null,j=()=>(A??=a(()=>import(`./MarkstreamRendererImpl-DLI17gOM.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60])).catch(e=>{throw A=null,e}),A),M=()=>{j().catch(()=>void 0)},N=null,P=()=>(N??=a(()=>import(`./MarkdownRendererImpl-DCim2MBS.js`).then(e=>e.n),__vite__mapDeps([38,1,4,5,18,17,6,2,3,7,19,20,25,26,9,39,13,14,15,16,21,22,23,24,27,28,29,30,31,32,40,41,42,43,44,45,46,47,48,49,50,33,34,51,37,35,52,53,54,36,55,56,57,58,59])).catch(e=>{throw N=null,e}),N),F=()=>{P().catch(()=>void 0),O()&&M()},I=class extends d.Component{state={hasError:!1};static getDerivedStateFromError(){return{hasError:!0}}componentDidCatch(e){console.warn(`[markstream-react] falling back to the current Markdown renderer`,e)}render(){return this.state.hasError?this.props.fallback:this.props.children}},L=d.createContext(!0),R=()=>d.useContext(L),z=n(),B=x(()=>P().then(e=>({default:e.MarkdownRenderer}))),V=x(()=>j().then(e=>({default:e.MarkstreamRenderer}))),H=x(()=>P().then(e=>({default:e.SimpleMarkdownRenderer}))),U=e=>e===`tool`?`markdown-content markdown-tool`:e===`reasoning`?`markdown-content markdown-reasoning`:`markdown-content leading-relaxed`,W=e=>{let t=(0,u.c)(15),n=k(q),r=typeof e.content==`string`?e.content:``,i=typeof e.variant==`string`?e.variant:`assistant`,a;t[0]!==r||t[1]!==n||t[2]!==e.reserveMeasuredHeight||t[3]!==i?(a=e.reserveMeasuredHeight?c(l(r,n?`markstream:${i}`:i)):void 0,t[0]=r,t[1]=n,t[2]=e.reserveMeasuredHeight,t[3]=i,t[4]=a):a=t[4];let d=a,f;t[5]!==e.className||t[6]!==e.variant?(f=o(`relative break-words w-full min-w-0`,U(e.variant),typeof e.className==`string`?e.className:void 0),t[5]=e.className,t[6]=e.variant,t[7]=f):f=t[7];let p;t[8]!==r||t[9]!==e.animated||t[10]!==d?(p=(0,z.jsx)(s,{animated:e.animated,content:r,reservedHeight:d}),t[8]=r,t[9]=e.animated,t[10]=d,t[11]=p):p=t[11];let m;return t[12]!==f||t[13]!==p?(m=(0,z.jsx)(`div`,{className:f,"aria-busy":`true`,"data-markdown-hydration":`deferred`,"data-markdown-ready":`false`,children:p}),t[12]=f,t[13]=p,t[14]=m):m=t[14],m},G=e=>{let t=(0,u.c)(9),n=R(),r=k(J);if(!n&&e.isStreaming!==!0){let n;return t[0]===e?n=t[1]:(n=(0,z.jsx)(W,{...e,animated:!1,reserveMeasuredHeight:!0}),t[0]=e,t[1]=n),n}let i;t[2]===e?i=t[3]:(i=(0,z.jsx)(d.Suspense,{fallback:(0,z.jsx)(W,{...e,reserveMeasuredHeight:!0}),children:(0,z.jsx)(B,{...e})}),t[2]=e,t[3]=i);let a=i;if(!r)return a;let o;t[4]===e?o=t[5]:(o=(0,z.jsx)(d.Suspense,{fallback:(0,z.jsx)(W,{...e,reserveMeasuredHeight:!0}),children:(0,z.jsx)(V,{...e})}),t[4]=e,t[5]=o);let s;return t[6]!==a||t[7]!==o?(s=(0,z.jsx)(I,{fallback:a,children:o}),t[6]=a,t[7]=o,t[8]=s):s=t[8],s},K=e=>{let t=(0,u.c)(4);if(!R()){let n;return t[0]===e?n=t[1]:(n=(0,z.jsx)(W,{...e,animated:!1}),t[0]=e,t[1]=n),n}let n;return t[2]===e?n=t[3]:(n=(0,z.jsx)(d.Suspense,{fallback:(0,z.jsx)(W,{...e}),children:(0,z.jsx)(H,{...e})}),t[2]=e,t[3]=n),n};function q(e){return e.markstreamReactEnabled}function J(e){return e.markstreamReactEnabled}export{k as a,F as i,K as n,x as o,L as r,G as t};