gestalt-mobile 0.41.1 → 0.41.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/assets/{index-G2PznC5F.js → index-9uZwieND.js} +1 -1
- package/dist/client/index.html +1 -1
- package/dist/server/server/composition.contracts.js +183 -37
- package/dist/server/server/composition.js +149 -31
- package/dist/server/server/features/agent-activity/model.js +8 -2
- package/dist/server/server/features/org-plan-checkpoint/application/validate.js +83 -15
- package/dist/server/server/features/plans/application/supervised-plan-registry.js +8 -1
- package/dist/server/server/platform/persistence/sqlite-pending-interaction-store.js +12 -6
- package/dist/server/shared/contracts/org-plan-attention.js +8 -1
- package/dist/server/shared/contracts/org-plan-checkpoint.js +5 -1
- package/dist/server/shared/contracts/plan-signal.js +3 -1
- package/package.json +1 -1
|
@@ -20,7 +20,7 @@ var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=
|
|
|
20
20
|
destinations.</p></div> <!> <button id="browse-files" type="button">Browse files</button></section> <form class="clone-form svelte-pudr3t"><div class="clone-controls svelte-pudr3t"><div class="clone-field clone-destination svelte-pudr3t"><span class="field-label svelte-pudr3t">Destination</span> <output aria-live="polite" class="svelte-pudr3t"> </output></div> <div class="clone-field svelte-pudr3t"><label for="git-clone-address">Git address</label> <input id="git-clone-address" name="address" required="" autocomplete="url" inputmode="url" enterkeyhint="done" placeholder="https://example.com/owner/repository.git" aria-describedby="clone-help"/></div> <button type="submit" class="svelte-pudr3t"> </button></div> <p id="clone-help" class="svelte-pudr3t">The repository is cloned inside the selected workspace.</p> <!></form> <section class="repository-details svelte-pudr3t" aria-labelledby="repository-details-title"><h3 id="repository-details-title" class="svelte-pudr3t">Repository details</h3> <!> <!></section></section>`);function Lu(e,t){Qe(t,!0);let n=I(``),r=P(()=>t.selectedWorkspace&&!t.selectedWorkspace.isGitRepository?t.selectedWorkspace:null);function i(e){e.preventDefault(),!(!G(n).trim()||t.cloning)&&t.onclone(G(n).trim())}var a=Iu(),o=V(z(a),2),s=V(z(o),2);{let e=P(()=>t.selectedWorkspace?.id??null);bu(s,{get roots(){return t.workspaceTree},get expandedIds(){return t.expandedIds},get selectedId(){return G(e)},label:`Git repository and clone destination`,get onexpandedchange(){return t.onexpandedchange},get onselect(){return t.onselect}})}var c=V(s,2);N(o);var l=V(o,2),u=z(l),d=z(u),f=V(z(d),2),p=z(f,!0);N(f),N(d);var m=V(d,2),h=V(z(m),2);Di(h),N(m);var g=V(m,2),_=z(g,!0);N(g),N(u);var v=V(u,4),y=e=>{var n=Tu(),r=z(n,!0);N(n),H(()=>Y(r,t.cloneStatus)),J(e,n)};X(v,e=>{t.cloneStatus&&e(y)}),N(l);var b=V(l,2),x=V(z(b),2),S=e=>{var n=Hr(),r=B(n),i=e=>{var n=Hr(),r=B(n),i=e=>{var n=Au(),r=B(n),i=z(r),a=V(z(i),2);Z(a,20,()=>t.summary.branches??[],e=>e,(e,t)=>{var n=Eu(),r=z(n,!0);N(n);var i={};H(()=>{Y(r,t),i!==(i=t)&&(n.value=(n.__value=t)??``)}),J(e,n)}),N(a);var o;bi(a);var s=V(a,2),c=z(s);N(s);var l=V(s,2),u=z(l);N(l);var d=V(l,2),f=z(d),p=z(f,!0);N(f),N(d);var m=V(d,2),h=z(m);N(m),N(i);var g=V(i,2),_=z(g),v=V(_,2),y=V(z(v));N(v),N(g),N(r);var b=V(r,2),x=e=>{var n=Du(),r=z(n),i=z(r);N(r);var a=V(r,2),o=V(a,2);N(n),H(()=>Y(i,`Push HEAD to ${t.summary.upstream??``}?`)),K(`click`,a,function(...e){t.onpush?.apply(this,e)}),K(`click`,o,function(...e){t.oncancelpush?.apply(this,e)}),J(e,n)};X(b,e=>{t.confirmingPush&&e(x)});var S=V(b,2),C=e=>{var n=ku(),r=V(z(n),2);Z(r,21,()=>t.summary.commits,e=>e.hash,(e,t)=>{var n=Ou(),r=z(n),i=z(r),a=z(i,!0);N(i);var o=V(i),s=z(o,!0);N(o),N(r);var c=V(r,2),l=z(c),u=z(l,!0);N(l);var d=V(l),f=z(d,!0);N(d),N(c),N(n),H(e=>{Q(i,`title`,G(t).hash),Y(a,G(t).shortHash),Y(s,G(t).subject),Y(u,G(t).author),Q(d,`datetime`,G(t).authoredAt),Q(d,`title`,G(t).authoredAt),Y(f,e)},[()=>wu(G(t).authoredAt)]),J(e,n)}),N(r),N(n),J(e,n)};X(S,e=>{t.summary.commits.length&&e(C)}),H(e=>{a.disabled=t.refreshing||t.checkingOut||!t.summary.branches?.length,o!==(o=t.summary.branch??``)&&(a.value=(a.__value=t.summary.branch??``)??``,yi(a,t.summary.branch??``)),Y(c,`Upstream: ${t.summary.upstream??`none`??``}`),Y(u,`Ahead ${t.summary.ahead??``}; behind ${t.summary.behind??``}.`),Q(f,`datetime`,t.summary.fetchedAt??void 0),Y(p,e),Y(h,`Changes: ${t.summary.dirty.staged??``} staged, ${t.summary.dirty.unstaged??``} unstaged, ${t.summary.dirty.untracked??``} untracked.`),_.disabled=t.refreshing||t.checkingOut||!t.summary.upstream||t.summary.ahead<1||t.summary.behind>0,v.disabled=t.refreshing||t.checkingOut,Y(y,` ${t.refreshing?`Pulling…`:`Pull`}`)},[()=>Cu(t.summary.fetchedAt)]),K(`change`,a,e=>t.oncheckout(e.currentTarget.value)),K(`click`,_,function(...e){t.onopenpushconfirmation?.apply(this,e)}),K(`click`,v,function(...e){t.onpull?.apply(this,e)}),J(e,n)},a=e=>{J(e,ju())};X(r,e=>{t.summary.available?e(i):e(a,-1)}),J(e,n)},a=e=>{J(e,Mu())};X(r,e=>{t.summary?e(i):t.error||e(a,1)}),J(e,n)},C=e=>{var n=Nu(),r=B(n),i=z(r),a=z(i,!0);N(i),He(),N(r),He(2),H(()=>Y(a,t.selectedWorkspace.name)),J(e,n)},w=e=>{var t=Pu();He(2),J(e,t)};X(x,e=>{t.selectedWorkspace?.isGitRepository?e(S):t.selectedWorkspace?e(C,1):e(w,-1)});var T=V(x,2),E=e=>{var n=Fu(),r=z(n,!0);N(n),H(()=>Y(r,t.error)),J(e,n)};X(T,e=>{t.error&&e(E)}),N(b),N(a),H(()=>{c.disabled=!t.selectedWorkspace,Y(p,G(r)?`~/${G(r).relativePath}`:`Select a non-repository folder`),g.disabled=t.cloning,Y(_,t.cloning?`Cloning…`:`Clone`)}),K(`click`,c,e=>t.onbrowsefiles(e.currentTarget)),Nr(`submit`,l,i),Ni(h,()=>G(n),e=>L(n,e)),J(e,a),$e()}Pr([`click`,`change`]);var Ru=class{transport;isRepository;onChange;errorMessage;#e={workspaceId:null,summary:null,loading:!1,refreshing:!1,checkingOut:!1,error:null};#t=0;#n=null;#r=!1;constructor(e,t,n,r){this.transport=e,this.isRepository=t,this.onChange=n,this.errorMessage=r}get state(){return this.#e}select(e){this.#a();let t=e,n=!!(t&&this.isRepository(t));this.#s({workspaceId:t,summary:null,loading:n,refreshing:!1,checkingOut:!1,error:null}),n&&this.refresh()}async refresh(){let e=this.#e.workspaceId;if(!e||!this.isRepository(e))return;let t=this.#i(),n=this.#t;this.#s({...this.#e,loading:!0,error:null});try{let r=await this.transport.getSummary(e,t.signal);this.#o(n,e,t)&&this.#s({...this.#e,summary:r,loading:!1})}catch(r){this.#o(n,e,t)&&!t.signal.aborted&&this.#s({...this.#e,summary:null,loading:!1,error:this.errorMessage(r,`GIT_SUMMARY_FAILED`)})}}async pull(e){let t=this.#e.workspaceId;if(!t||this.#e.refreshing)return;let n=this.#i(),r=this.#t;this.#s({...this.#e,refreshing:!0,error:null});try{await this.transport.pull(t,e,n.signal),this.#o(r,t,n)&&(this.#s({...this.#e,refreshing:!1}),await this.refresh())}catch(e){this.#o(r,t,n)&&!n.signal.aborted&&this.#s({...this.#e,refreshing:!1,error:this.errorMessage(e,`GIT_PULL_FAILED`)})}}async checkout(e){let t=this.#e.workspaceId;if(!t||this.#e.checkingOut||e===this.#e.summary?.branch)return;let n=this.#i(),r=this.#t;this.#s({...this.#e,checkingOut:!0,error:null});try{await this.transport.checkout(t,e,n.signal),this.#o(r,t,n)&&(this.#s({...this.#e,checkingOut:!1}),await this.refresh())}catch(e){this.#o(r,t,n)&&!n.signal.aborted&&this.#s({...this.#e,checkingOut:!1,error:this.errorMessage(e,`GIT_CHECKOUT_FAILED`)})}}dispose(){this.#r=!0,this.#a()}#i(){return this.#a(),this.#n=new AbortController,++this.#t,this.#n}#a(){this.#n?.abort(),this.#n=null,++this.#t}#o(e,t,n){return!this.#r&&e===this.#t&&this.#e.workspaceId===t&&this.#n===n}#s(e){this.#r||(this.#e=e,this.onChange(e))}};function zu(e,t,n,r,i){let a=new Set(Bu(e).filter(e=>e.isGitRepository).map(e=>e.id)),o=fu(t,n),s=o?Bu(o.children).filter(e=>e.isGitRepository&&!a.has(e.id)):[],c=Vu(r),l=s.find(e=>e.name===c)??(s.length===1?s[0]:void 0),u=l?.id??o?.id??null,d=new Set(i);return u&&du(t,u).forEach(e=>d.add(e)),!l&&o&&d.add(o.id),{selectedId:u,expandedIds:d}}function Bu(e){let t=[],n=e=>{t.push(e),e.children.forEach(n)};return e.forEach(n),t}function Vu(e){return(e.trim().replace(/[?#].*$/,``).replace(/\/+$/,``).split(/[/:]/).at(-1)??``).replace(/\.git$/i,``)}function Hu(e){if(typeof e!=`object`||!e)return null;let t=e.permissions;if(typeof t!=`object`||!t)return null;let n=t;return{permissions:{...n.network===null||n.network===void 0?{}:{network:n.network},...n.fileSystem===null||n.fileSystem===void 0?{}:{fileSystem:n.fileSystem}},scope:`turn`}}function Uu(e){return{answers:Object.fromEntries(e.filter(e=>e.answer.trim()).map(e=>[e.id,{answers:[e.answer]}]))}}function Wu(e){return[`Submitted quiz answers:`,...e.map(e=>`- ${e.header} — ${e.question}\n ${e.answer.trim().replaceAll(`
|
|
21
21
|
`,`
|
|
22
22
|
`)}`)].join(`
|
|
23
|
-
`)}function Gu(e=fetch){async function t(e){let t=await e.json().catch(()=>null),n=typeof t?.code==`string`&&/^[A-Z0-9_]+$/.test(t.code)?t.code:void 0,r=n?.startsWith(`AUTOPILOT_`)&&e.status===409?`Relay request failed (${e.status}).`:typeof t?.detail==`string`&&t.detail.length<=600?t.detail:typeof t?.title==`string`?t.title:`Relay request failed (${e.status}).`;return Object.assign(Error(r),{...n?{code:n}:{},...typeof t?.replaceAllowed==`boolean`?{replaceAllowed:t.replaceAllowed}:{},status:e.status})}async function n(n,r,i={},a){let o=await e(n,{method:`POST`,headers:{"content-type":`application/json`,...i},body:JSON.stringify(r),signal:a});if(!o.ok)throw await t(o);return o.json()}async function r(n,r,i={}){let a=await e(n,{method:`PUT`,headers:{"content-type":`application/json`,...i},body:JSON.stringify(r)});if(!a.ok)throw await t(a);return a.json()}async function i(n,r,i,a){let o=await e(n,{method:`PUT`,headers:{"content-type":`application/octet-stream`,"idempotency-key":i},body:r,signal:a});if(!o.ok)throw await t(o);return o.json()}async function a(n,r,i){let a=await e(n,{method:`DELETE`,headers:{"content-type":`application/json`,"idempotency-key":i},body:JSON.stringify(r)});if(!a.ok)throw await t(a);return a.json()}async function o(n){let r=await e(n,{method:`DELETE`});if(!r.ok)throw await t(r)}async function s(n,r){let i=await e(n,r?{signal:r}:void 0);if(!i.ok)throw await t(i);return i.json()}async function c(n,r){let i=await e(n,{signal:r});if(i.status===204)return null;if(!i.ok)throw await t(i);return i.json()}return{quit:()=>n(`/api/maintenance/quit`,{}),listSessions:e=>s(`/api/sessions`,e),listWorkspaceDirectory:(e,t={},n)=>{let r=new URLSearchParams;t.directory!==void 0&&r.set(`directory`,t.directory),t.cursor!==void 0&&r.set(`cursor`,t.cursor),t.limit!==void 0&&r.set(`limit`,String(t.limit));let i=r.size===0?``:`?${r}`;return s(`/api/workspaces/${encodeURIComponent(e)}/files${i}`,n)},copyWorkspaceEntry:(e,t,r)=>n(`/api/workspaces/${encodeURIComponent(e)}/files/copy`,t,{"idempotency-key":r}),moveWorkspaceEntry:(e,t,r)=>n(`/api/workspaces/${encodeURIComponent(e)}/files/move`,t,{"idempotency-key":r}),uploadWorkspaceFile:(e,t,n,r)=>{let a=new URLSearchParams({directory:t.directory,filename:t.filename,conflict:t.conflict});return i(`/api/workspaces/${encodeURIComponent(e)}/files/upload?${a}`,t.file,n,r)},deleteWorkspaceEntry:(e,t,n)=>a(`/api/workspaces/${encodeURIComponent(e)}/files`,{path:t,recursive:!0},n),getSession:e=>s(`/api/sessions/${encodeURIComponent(e)}`),refreshActivity:e=>n(`/api/sessions/${encodeURIComponent(e)}/activity/refresh`,{}),setAutopilot:(e,t,n)=>r(`/api/sessions/${encodeURIComponent(e)}/autopilot`,{enabled:t},n?{"idempotency-key":n}:{}),resolveAttention:(e,t,r)=>n(`/api/sessions/${encodeURIComponent(e)}/attention/${encodeURIComponent(t)}/resolve`,r),listRecentSessions:()=>s(`/api/sessions/recent-threads`),openRecentSession:(e,t,r=`codex`)=>n(`/api/sessions/recent-threads/open`,{threadId:e,cwd:t,provider:r}),listSessionModels:e=>n(`/api/session-models/${encodeURIComponent(e)}`,{}),startSession:(e,t={},r)=>n(`/api/sessions`,{workspaceId:e,profile:`default`,provider:`codex`,...t},r?{"idempotency-key":r}:{}),startTurn:(e,t,r)=>n(`/api/sessions/${encodeURIComponent(e)}/turns`,{text:t},r?{"idempotency-key":r}:{}),selectModel:(e,t)=>n(`/api/sessions/${encodeURIComponent(e)}/model`,{model:t}),interruptTurn:(e,t)=>n(`/api/sessions/${encodeURIComponent(e)}/turns/${encodeURIComponent(t)}/interrupt`,{}),queueTurnInput:(e,t,r,i)=>n(`/api/sessions/${encodeURIComponent(e)}/turns/${encodeURIComponent(t)}/queue`,{text:r},i?{"idempotency-key":i}:{}),restoreSession:e=>n(`/api/sessions/${encodeURIComponent(e)}/restore`,{}),releaseSession:e=>n(`/api/sessions/${encodeURIComponent(e)}/release`,{}),forgetSession:n=>e(`/api/sessions/${encodeURIComponent(n)}`,{method:`DELETE`}).then(async e=>{if(!e.ok)throw await t(e)}),getHistory:e=>s(`/api/sessions/${encodeURIComponent(e)}/history`),getPlan:(e,t)=>c(`/api/sessions/${encodeURIComponent(e)}/plan`,t),closePlan:e=>o(`/api/sessions/${encodeURIComponent(e)}/plan`),listWorkspacePlans:(e,t)=>s(`/api/workspaces/${encodeURIComponent(e)}/plans`,t),getWorkspacePlan:(e,t,n)=>s(`/api/workspaces/${encodeURIComponent(e)}/plans/${encodeURIComponent(t)}`,n),openSessionPlan:(e,t)=>r(`/api/sessions/${encodeURIComponent(e)}/plan`,{planName:t}),getGitSummary:(e,t)=>s(`/api/git/repositories/${encodeURIComponent(e)}`,t),cloneGitRepository:(e,t)=>n(`/api/git/clone`,{workspaceId:e,address:t}),refreshGit:(e,t)=>n(`/api/git/repositories/${encodeURIComponent(e)}/refresh`,{},t?{"idempotency-key":t}:{}),pullGit:(e,t,r)=>n(`/api/git/repositories/${encodeURIComponent(e)}/pull`,{},t?{"idempotency-key":t}:{},r),checkoutGitBranch:(e,t,r)=>n(`/api/git/repositories/${encodeURIComponent(e)}/checkout`,{branch:t},{},r),pushGit:(e,t)=>n(`/api/git/repositories/${encodeURIComponent(e)}/push`,{},t?{"idempotency-key":t}:{}),listAvailableSkills:(e,t,n=!1,r)=>s(`/api/skills?${new URLSearchParams({workspaceId:e,profile:t,...n?{refresh:`true`}:{}}).toString()}`,r),listSkillProfiles:e=>s(`/api/skill-profiles`,e),replaceSkillProfile:(e,t)=>r(`/api/skill-profiles/${encodeURIComponent(e)}`,t),deleteSkillProfile:e=>o(`/api/skill-profiles/${encodeURIComponent(e)}`),respondInteraction:(e,t,r,i)=>n(`/api/sessions/${encodeURIComponent(e)}/interactions/${encodeURIComponent(t)}`,r,i?{"idempotency-key":i}:{})}}var Ku=[`authoring-start`,`work-start`,`checkpoint`,`update`,`supervision-start`,`resync`];function qu(e){return typeof e==`string`&&Ku.includes(e)}function Ju(e){if(!e||typeof e!=`object`)return!1;let t=e;return Yu(t.plan)&&(t.reason===null||qu(t.reason))}function Yu(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.title==`string`&&Array.isArray(t.steps)&&typeof t.totalSteps==`number`&&typeof t.doneSteps==`number`&&typeof t.allDone==`boolean`&&typeof t.currentStepId==`string`}function Xu(e){return e instanceof Error?e.message:`Could not load the plan.`}function Zu(e){return{...e,...e.skills?{skills:[...e.skills]}:{},description:{...e.description},children:e.children.map(Zu)}}function Qu(e){return{...e,steps:e.steps.map(Zu)}}function $u(e,t){return e.kind===`unavailable`&&e.sessionId===t}function ed(e,t){let n=null,r={kind:`unavailable`,sessionId:null},i=0,a=0,o=null,s=0,c=e=>{++a,r=e,t(e)},l=(t,r)=>{o?.abort(),o=new AbortController;let a=++i,l=s;r||c({kind:`loading`,sessionId:t}),e.getPlan(t,o.signal).then(e=>{a!==i||n!==t||s===l&&c(e?{kind:`ready`,sessionId:t,plan:Qu(e)}:{kind:`unavailable`,sessionId:t})}).catch(e=>{o?.signal.aborted||a!==i||n!==t||c({kind:`error`,sessionId:t,error:Xu(e),...r?{plan:r}:{}})})};return{select(e){if(o?.abort(),n=e,s=0,!e){++i,c({kind:`unavailable`,sessionId:null});return}l(e,void 0)},refresh(e){if(n!==e)return;let t=r.kind===`ready`||r.kind===`closing`||r.kind===`error`?r.plan:void 0;l(e,t)},applyEvent(e,t){if(!(n!==e||t.sequence<=s)){if(t.type===`plan.updated`&&(Yu(t.payload)||Ju(t.payload))){let n=Ju(t.payload)?t.payload.plan:t.payload;s=t.sequence,c({kind:`ready`,sessionId:e,plan:Qu(n)})}t.type===`plan.closed`&&(s=t.sequence,c({kind:`unavailable`,sessionId:e}))}},async close(){if(r.kind!==`ready`&&r.kind!==`error`||!r.plan?.allDone)return null;let{sessionId:t,plan:i}=r;c({kind:`closing`,sessionId:t,plan:i});let o=a;try{return await e.closePlan(t),n===t?a===o?(c({kind:`unavailable`,sessionId:t}),`chat`):$u(r,t)?`chat`:null:null}catch(e){return n===t?a===o?(c({kind:`error`,sessionId:t,plan:i,error:Xu(e)}),null):$u(r,t)?`chat`:null:null}},dispose(){o?.abort(),o=null,n=null,++i,c({kind:`unavailable`,sessionId:null})}}}function td(e){if(!e)return null;let t=nd(e.steps,e.currentStepId)?.measurement?.weeklyRemainingCurrent;return typeof t==`number`&&Number.isFinite(t)&&t>=0&&t<=100?Math.round(t):null}function nd(e,t){for(let n of e){if(n.id===t)return n;let e=nd(n.children,t);if(e)return e}}function rd(e,t){return t===void 0?`L${e}`:`L${e}.${t}`}function id(e){let t=e.steps.filter(e=>e.reviewStatus===`REVIEWED`).length,n=e.steps.length,r=ad(e),i=e.steps.find(e=>e.state===`DONE`&&e.reviewStatus===`UNREVIEWED`);return i?{phase:`awaiting review`,label:`Awaiting ${rd(e.steps.indexOf(i)+1)} review`,current:r,reviewedL1s:t,totalL1s:n}:n>0&&t===n?{phase:`terminal review`,label:`Terminal review`,current:r,reviewedL1s:t,totalL1s:n}:t>0&&!r?{phase:`milestone reported`,label:`Preparing milestone summary`,current:r,reviewedL1s:t,totalL1s:n}:r?{phase:`implementing`,label:`Implementing ${r.position} ${r.title}`,current:r,reviewedL1s:t,totalL1s:n}:{phase:e.allDone?`terminal review`:`implementing`,label:e.allDone?`Terminal review`:`Implementing`,current:r,reviewedL1s:t,totalL1s:n}}function ad(e){for(let[t,n]of e.steps.entries()){if(n.id===e.currentStepId)return{id:n.id,position:rd(t+1),title:n.title,state:n.state};let r=n.children.findIndex(t=>t.id===e.currentStepId);if(r>=0){let e=n.children[r];return{id:e.id,position:rd(t+1,r+1),title:e.title,state:e.state}}}}var od=q(`<span class="wip-effort svelte-hmxg46"> </span>`),sd=q(`<li class="svelte-hmxg46"><span class="wip-position svelte-hmxg46" aria-hidden="true"> </span> <span class="wip-title svelte-hmxg46"> </span> <!></li>`),cd=q(`<ol class="wip-steps svelte-hmxg46" aria-label="Work in progress plan steps"></ol>`),ld=q(`<li class="svelte-hmxg46"><span aria-hidden="true" class="position svelte-hmxg46"> </span> <span aria-hidden="true" class="state"> </span></li>`),ud=q(`<ol class="step-markers svelte-hmxg46" aria-label="Plan step progress"></ol>`),dd=q(`<div><div class="progress-heading svelte-hmxg46"><span> </span> <span> </span></div> <progress class="svelte-hmxg46"> </progress> <span class="review-status"> </span> <!></div>`);function fd(e,t){Qe(t,!0);let n=$(t,`compact`,3,!1),r=$(t,`label`,3,`Plan progress`),i=P(()=>t.plan.steps.flatMap((e,t)=>[{id:e.id,position:rd(t+1),state:e.state,level:e.level,title:e.title,...e.description.effort?{effort:e.description.effort}:{}},...e.children.map((e,n)=>({id:e.id,position:rd(t+1,n+1),state:e.state,level:e.level,title:e.title}))])),a=P(()=>G(i).filter(e=>e.state===`WIP`)),o=P(()=>id(t.plan)),s=P(()=>Math.max(t.plan.totalSteps,1));var c=dd(),l=z(c),u=z(l),d=z(u);N(u);var f=V(u,2),p=z(f);N(f),N(l);var m=V(l,2),h=z(m);N(m);var g=V(m,2),_=z(g,!0);N(g);var v=V(g,2),y=e=>{var n=cd();Z(n,21,()=>G(a),e=>e.id,(e,n)=>{var r=sd(),i=z(r),a=z(i);N(i);var o=V(i,2),s=z(o,!0);N(o);var c=V(o,2),l=e=>{var t=od(),r=z(t);N(t),H(()=>Y(r,`Effort: ${G(n).effort??``}`)),J(e,t)};X(c,e=>{G(n).level===1&&G(n).effort&&e(l)}),N(r),H(()=>{Q(r,`aria-current`,G(n).id===t.plan.currentStepId?`step`:void 0),Q(r,`aria-label`,`${G(n).position}: ${G(n).title}, WIP${G(n).level===1&&G(n).effort?`, effort ${G(n).effort}`:``}`),Y(a,`${G(n).position??``} · WIP`),Y(s,G(n).title)}),J(e,r)}),N(n),J(e,n)},b=e=>{var n=ud();Z(n,21,()=>G(i),e=>e.id,(e,n)=>{var r=ld(),i=z(r),a=z(i,!0);N(i);var o=V(i,2),s=z(o,!0);N(o),N(r),H(()=>{Q(r,`data-state`,G(n).state),Q(r,`aria-current`,G(n).id===t.plan.currentStepId?`step`:void 0),Q(r,`aria-label`,`${G(n).position}: ${G(n).state}`),Y(a,G(n).position),Y(s,G(n).state)}),J(e,r)}),N(n),J(e,n)};X(v,e=>{n()&&G(a).length?e(y):!n()&&G(i).length&&e(b,1)}),N(c),H(()=>{gi(c,1,ui([`plan-progress`,{compact:n()}]),`svelte-hmxg46`),Y(d,`${t.plan.doneSteps??``} / ${t.plan.totalSteps??``} work items done`),Y(p,`· ${G(o).reviewedL1s??``} / ${G(o).totalL1s??``} reviewed`),Q(m,`aria-label`,r()),Oi(m,t.plan.doneSteps),Q(m,`max`,G(s)),Y(h,`${t.plan.doneSteps??``} of ${t.plan.totalSteps??``} work items done`),Q(g,`data-phase`,G(o).phase),Y(_,G(o).label)}),J(e,c),$e()}var pd=q(`<section aria-labelledby="plan-title" class="svelte-3rmyvg"><h2 id="plan-title" class="svelte-3rmyvg">Plan</h2> <p class="svelte-3rmyvg">Loading plan…</p></section>`),md=q(`<section aria-labelledby="plan-title" class="svelte-3rmyvg"><h2 id="plan-title" class="svelte-3rmyvg">Plan</h2> <p class="svelte-3rmyvg">No retained plan for this session.</p></section>`),hd=q(`<section aria-labelledby="plan-title" class="svelte-3rmyvg"><h2 id="plan-title" class="svelte-3rmyvg">Plan</h2> <p class="svelte-3rmyvg"> </p></section>`),gd=q(`<p class="svelte-3rmyvg"> </p>`),_d=q(`<div class="svelte-3rmyvg"><dt class="svelte-3rmyvg">Subtitle</dt> <dd class="svelte-3rmyvg"> </dd></div>`),vd=q(`<div class="svelte-3rmyvg"><dt class="svelte-3rmyvg">Date</dt> <dd class="svelte-3rmyvg"> </dd></div>`),yd=q(`<div class="svelte-3rmyvg"><dt class="svelte-3rmyvg">Keywords</dt> <dd class="svelte-3rmyvg"> </dd></div>`),bd=q(`<dl class="metadata svelte-3rmyvg"><!> <!> <!></dl>`),xd=q(`<p class="svelte-3rmyvg">No plan steps have been retained yet.</p>`),Sd=q(`<p class="svelte-3rmyvg"><strong class="svelte-3rmyvg"> </strong> </p>`),Cd=q(`<p class="svelte-3rmyvg"><strong class="svelte-3rmyvg">Skills:</strong> </p>`),wd=q(`<li class="svelte-3rmyvg"><details class="svelte-3rmyvg"><summary class="svelte-3rmyvg"><strong class="svelte-3rmyvg"><span class="position svelte-3rmyvg"> </span> </strong> <span class="svelte-3rmyvg"> </span> <span class="svelte-3rmyvg"> </span></summary> <!> <!></details></li>`),Td=q(`<ol class="svelte-3rmyvg"></ol>`),Ed=q(`<li class="svelte-3rmyvg"><details class="svelte-3rmyvg"><summary class="svelte-3rmyvg"><strong class="svelte-3rmyvg"><span class="position svelte-3rmyvg"> </span> </strong> <span class="svelte-3rmyvg"> </span> <span class="svelte-3rmyvg"> </span> <span class="measurement svelte-3rmyvg"> </span></summary> <!> <!> <!></details></li>`),Dd=q(`<ol class="plan-steps svelte-3rmyvg"></ol>`),Od=q(`<section class="plan svelte-3rmyvg" aria-labelledby="plan-title"><header class="svelte-3rmyvg"><div class="svelte-3rmyvg"><h2 id="plan-title" class="svelte-3rmyvg"> </h2></div> <button class="close svelte-3rmyvg" aria-label="Close plan and return to list">×</button></header> <!> <p class="svelte-3rmyvg"> </p> <!> <!> <!></section>`),kd=q(`<p class="visually-hidden svelte-3rmyvg" aria-live="polite" aria-atomic="true"> </p> <!>`,1);function Ad(e,t){Qe(t,!0);let n={effort:`Effort`,goal:`Goal`,notes:`Notes`,why:`Why`,change:`Change`,tests:`Tests`,doneWhen:`Done when`},r=I(R(new Set)),i=R({}),a=null,o=0,s=P(()=>t.state.kind===`ready`||t.state.kind===`closing`||t.state.kind===`error`?t.state.plan:void 0),c=P(()=>G(s)?p(G(s).steps,G(s).currentStepId):void 0),l=P(()=>G(s)?m(G(s).steps,G(s).currentStepId):void 0),u=P(()=>G(s)?id(G(s)):void 0),d=P(()=>G(s)?h(G(s).steps,G(s).currentStepId):new Set),f=P(()=>t.state.kind===`loading`?`Loading plan.`:t.state.kind===`unavailable`?`No retained plan for this session.`:t.state.kind===`error`&&!G(s)?t.state.error:t.state.kind===`closing`?`Closing completed plan.`:G(s)?G(c)?`${G(u)?.label??`Current step: ${G(l)} ${G(c).title}`}. ${G(s).doneSteps} of ${G(s).totalSteps} work items done.${t.state.kind===`error`?` ${t.state.error}`:``}`:`${G(u)?.label??`Plan progress`}. ${G(s).doneSteps} of ${G(s).totalSteps} work items done.${t.state.kind===`error`?` ${t.state.error}`:``}`:``);Mn(()=>{let e=G(s)?.currentStepId||null;if(!e||a===e)return;a=e;let t=++o;Cr().then(()=>{t!==o||G(s)?.currentStepId!==e||i[e]?.scrollIntoView({behavior:`auto`,block:`nearest`,inline:`nearest`})})});function p(e,t){for(let n of e){if(n.id===t)return n;let e=p(n.children,t);if(e)return e}}function m(e,t){for(let[n,r]of e.entries()){if(r.id===t)return rd(n+1);let e=r.children.findIndex(e=>e.id===t);if(e>=0)return rd(n+1,e+1)}}function h(e,t,n=[]){for(let r of e){if(r.id===t)return new Set([...n,r.id]);let e=h(r.children,t,[...n,r.id]);if(e.size)return e}return new Set}function g(e){return G(r).has(e)||G(d).has(e)}function _(e,t){L(r,t?new Set([...G(r),e]):new Set([...G(r)].filter(t=>t!==e)),!0)}function v(e){return e.description.goal??e.description.why??e.title}function y(e){let t=e.measurement;if(!t)return`Measurements unavailable`;let n=[];return t.elapsedSeconds!==void 0&&n.push(`${Math.floor(t.elapsedSeconds/60)}m ${t.elapsedSeconds%60}s elapsed`),t.weeklyPercentUsed!==void 0&&n.push(`${t.weeklyPercentUsed}% observed account-wide usage`),t.tokensUsed!==void 0&&n.push(`${t.tokensUsed.toLocaleString()} tokens used`),n.join(` · `)||`Measurements unavailable`}function b(e){return Object.keys(n).flatMap(t=>{let r=e.description[t];return r?[[n[t],r]]:[]})}var x=kd(),S=B(x),w=z(S,!0);N(S);var T=V(S,2),E=e=>{J(e,pd())},D=e=>{J(e,md())},ee=e=>{var n=hd(),r=V(z(n),2),i=z(r,!0);N(r),N(n),H(()=>Y(i,t.state.error)),J(e,n)},te=e=>{var n=Od(),r=z(n),a=z(r),o=z(a),d=z(o,!0);N(o),N(a);var f=V(a,2);N(r);var p=V(r,2);fd(p,{get plan(){return G(s)}});var m=V(p,2),h=z(m);N(m);var x=V(m,2),S=e=>{var n=gd(),r=z(n,!0);N(n),H(()=>Y(r,t.state.error)),J(e,n)};X(x,e=>{t.state.kind===`error`&&e(S)});var w=V(x,2),T=e=>{var t=bd(),n=z(t),r=e=>{var t=_d(),n=V(z(t),2),r=z(n,!0);N(n),N(t),H(()=>Y(r,G(s).subtitle)),J(e,t)};X(n,e=>{G(s).subtitle&&e(r)});var i=V(n,2),a=e=>{var t=vd(),n=V(z(t),2),r=z(n,!0);N(n),N(t),H(()=>Y(r,G(s).date)),J(e,t)};X(i,e=>{G(s).date&&e(a)});var o=V(i,2),c=e=>{var t=yd(),n=V(z(t),2),r=z(n,!0);N(n),N(t),H(()=>Y(r,G(s).keywords)),J(e,t)};X(o,e=>{G(s).keywords&&e(c)}),N(t),J(e,t)};X(w,e=>{(G(s).subtitle||G(s).date||G(s).keywords)&&e(T)});var E=V(w,2),D=e=>{J(e,xd())},ee=e=>{var t=Dd();Z(t,23,()=>G(s).steps,e=>e.id,(e,t,n)=>{var r=Ed(),a=z(r),o=z(a),s=z(o),c=z(s),l=z(c,!0);N(c);var u=V(c);N(s);var d=V(s,2),f=z(d);N(d);var p=V(d,2),m=z(p,!0);N(p);var h=V(p,2),x=z(h,!0);N(h),N(o);var S=V(o,2);Z(S,17,()=>b(G(t)),([e,t])=>e,(e,t)=>{var n=P(()=>C(G(t),2));let r=()=>G(n)[0],i=()=>G(n)[1];var a=Sd(),o=z(a),s=z(o);N(o);var c=V(o);N(a),H(()=>{Y(s,`${r()??``}:`),Y(c,` ${i()??``}`)}),J(e,a)});var w=V(S,2),T=e=>{var n=Cd(),r=V(z(n));N(n),H(e=>Y(r,` ${e??``}`),[()=>G(t).skills.join(`, `)]),J(e,n)};X(w,e=>{G(t).skills?.length&&e(T)});var E=V(w,2),D=e=>{var r=Td();Z(r,23,()=>G(t).children,e=>e.id,(e,t,r)=>{var a=wd(),o=z(a),s=z(o),c=z(s),l=z(c),u=z(l,!0);N(l);var d=V(l);N(c);var f=V(c,2),p=z(f);N(f);var m=V(f,2),h=z(m,!0);N(m),N(s);var y=V(s,2);Z(y,17,()=>b(G(t)),([e,t])=>e,(e,t)=>{var n=P(()=>C(G(t),2));let r=()=>G(n)[0],i=()=>G(n)[1];var a=Sd(),o=z(a),s=z(o);N(o);var c=V(o);N(a),H(()=>{Y(s,`${r()??``}:`),Y(c,` ${i()??``}`)}),J(e,a)});var x=V(y,2),S=e=>{var n=Cd(),r=V(z(n));N(n),H(e=>Y(r,` ${e??``}`),[()=>G(t).skills.join(`, `)]),J(e,n)};X(x,e=>{G(t).skills?.length&&e(S)}),N(o),Li(o,(e,t)=>i[t.id]=e,e=>i?.[e.id],()=>[G(t)]),N(a),H((e,n,r)=>{Q(o,`data-step-id`,G(t).id),o.open=e,Y(u,n),Y(d,` ${G(t).title??``}`),Y(p,`${G(t).state??``} · Priority ${G(t).priority??``}${G(t).reviewStatus?` · ${G(t).reviewStatus}`:``}`),Y(h,r)},[()=>g(G(t).id),()=>rd(G(n)+1,G(r)+1),()=>v(G(t))]),Nr(`toggle`,o,e=>_(G(t).id,e.currentTarget.open)),J(e,a)}),N(r),J(e,r)};X(E,e=>{G(t).children.length&&e(D)}),N(a),Li(a,(e,t)=>i[t.id]=e,e=>i?.[e.id],()=>[G(t)]),N(r),H((e,n,r,i)=>{Q(a,`data-step-id`,G(t).id),a.open=e,Y(l,n),Y(u,` ${G(t).title??``}`),Y(f,`${G(t).state??``} · Priority ${G(t).priority??``}${G(t).reviewStatus?` · ${G(t).reviewStatus}`:``}`),Y(m,r),Y(x,i)},[()=>g(G(t).id),()=>rd(G(n)+1),()=>v(G(t)),()=>y(G(t))]),Nr(`toggle`,a,e=>_(G(t).id,e.currentTarget.open)),J(e,r)}),N(t),J(e,t)};X(E,e=>{G(s).steps.length===0?e(D):e(ee,-1)}),N(n),H(()=>{Y(d,G(s).title),Y(h,`${G(u)?.label??``}. Current: ${G(c)?`${G(l)} ${G(c).title} (${G(c).state})`:`No current step`}`)}),K(`click`,f,function(...e){t.onclose?.apply(this,e)}),J(e,n)};X(T,e=>{t.state.kind===`loading`?e(E):t.state.kind===`unavailable`?e(D,1):t.state.kind===`error`&&!G(s)?e(ee,2):G(s)&&e(te,3)}),H(()=>Y(w,G(f))),J(e,x),$e()}Pr([`click`]);var jd=/^(\*+)\s+(?:(TODO|WIP|DONE)\s+)?(?:\[#([ABC])\]\s+)?(.+)$/,Md=/^#\+([A-Z][A-Z0-9_-]*):\s*(.*)$/i,Nd=/^:([A-Z][A-Z0-9_]*):\s*(.*)$/,Pd=/^-\s+([^:]+?)\s+::\s*(.*)$/;function Fd(e){let t=[],n=[],r=[],i=e.replace(/\r\n?/g,`
|
|
23
|
+
`)}function Gu(e=fetch){async function t(e){let t=await e.json().catch(()=>null),n=typeof t?.code==`string`&&/^[A-Z0-9_]+$/.test(t.code)?t.code:void 0,r=n?.startsWith(`AUTOPILOT_`)&&e.status===409?`Relay request failed (${e.status}).`:typeof t?.detail==`string`&&t.detail.length<=600?t.detail:typeof t?.title==`string`?t.title:`Relay request failed (${e.status}).`;return Object.assign(Error(r),{...n?{code:n}:{},...typeof t?.replaceAllowed==`boolean`?{replaceAllowed:t.replaceAllowed}:{},status:e.status})}async function n(n,r,i={},a){let o=await e(n,{method:`POST`,headers:{"content-type":`application/json`,...i},body:JSON.stringify(r),signal:a});if(!o.ok)throw await t(o);return o.json()}async function r(n,r,i={}){let a=await e(n,{method:`PUT`,headers:{"content-type":`application/json`,...i},body:JSON.stringify(r)});if(!a.ok)throw await t(a);return a.json()}async function i(n,r,i,a){let o=await e(n,{method:`PUT`,headers:{"content-type":`application/octet-stream`,"idempotency-key":i},body:r,signal:a});if(!o.ok)throw await t(o);return o.json()}async function a(n,r,i){let a=await e(n,{method:`DELETE`,headers:{"content-type":`application/json`,"idempotency-key":i},body:JSON.stringify(r)});if(!a.ok)throw await t(a);return a.json()}async function o(n){let r=await e(n,{method:`DELETE`});if(!r.ok)throw await t(r)}async function s(n,r){let i=await e(n,r?{signal:r}:void 0);if(!i.ok)throw await t(i);return i.json()}async function c(n,r){let i=await e(n,{signal:r});if(i.status===204)return null;if(!i.ok)throw await t(i);return i.json()}return{quit:()=>n(`/api/maintenance/quit`,{}),listSessions:e=>s(`/api/sessions`,e),listWorkspaceDirectory:(e,t={},n)=>{let r=new URLSearchParams;t.directory!==void 0&&r.set(`directory`,t.directory),t.cursor!==void 0&&r.set(`cursor`,t.cursor),t.limit!==void 0&&r.set(`limit`,String(t.limit));let i=r.size===0?``:`?${r}`;return s(`/api/workspaces/${encodeURIComponent(e)}/files${i}`,n)},copyWorkspaceEntry:(e,t,r)=>n(`/api/workspaces/${encodeURIComponent(e)}/files/copy`,t,{"idempotency-key":r}),moveWorkspaceEntry:(e,t,r)=>n(`/api/workspaces/${encodeURIComponent(e)}/files/move`,t,{"idempotency-key":r}),uploadWorkspaceFile:(e,t,n,r)=>{let a=new URLSearchParams({directory:t.directory,filename:t.filename,conflict:t.conflict});return i(`/api/workspaces/${encodeURIComponent(e)}/files/upload?${a}`,t.file,n,r)},deleteWorkspaceEntry:(e,t,n)=>a(`/api/workspaces/${encodeURIComponent(e)}/files`,{path:t,recursive:!0},n),getSession:e=>s(`/api/sessions/${encodeURIComponent(e)}`),refreshActivity:e=>n(`/api/sessions/${encodeURIComponent(e)}/activity/refresh`,{}),setAutopilot:(e,t,n)=>r(`/api/sessions/${encodeURIComponent(e)}/autopilot`,{enabled:t},n?{"idempotency-key":n}:{}),resolveAttention:(e,t,r)=>n(`/api/sessions/${encodeURIComponent(e)}/attention/${encodeURIComponent(t)}/resolve`,r),listRecentSessions:()=>s(`/api/sessions/recent-threads`),openRecentSession:(e,t,r=`codex`)=>n(`/api/sessions/recent-threads/open`,{threadId:e,cwd:t,provider:r}),listSessionModels:e=>n(`/api/session-models/${encodeURIComponent(e)}`,{}),startSession:(e,t={},r)=>n(`/api/sessions`,{workspaceId:e,profile:`default`,provider:`codex`,...t},r?{"idempotency-key":r}:{}),startTurn:(e,t,r)=>n(`/api/sessions/${encodeURIComponent(e)}/turns`,{text:t},r?{"idempotency-key":r}:{}),selectModel:(e,t)=>n(`/api/sessions/${encodeURIComponent(e)}/model`,{model:t}),interruptTurn:(e,t)=>n(`/api/sessions/${encodeURIComponent(e)}/turns/${encodeURIComponent(t)}/interrupt`,{}),queueTurnInput:(e,t,r,i)=>n(`/api/sessions/${encodeURIComponent(e)}/turns/${encodeURIComponent(t)}/queue`,{text:r},i?{"idempotency-key":i}:{}),restoreSession:e=>n(`/api/sessions/${encodeURIComponent(e)}/restore`,{}),releaseSession:e=>n(`/api/sessions/${encodeURIComponent(e)}/release`,{}),forgetSession:n=>e(`/api/sessions/${encodeURIComponent(n)}`,{method:`DELETE`}).then(async e=>{if(!e.ok)throw await t(e)}),getHistory:e=>s(`/api/sessions/${encodeURIComponent(e)}/history`),getPlan:(e,t)=>c(`/api/sessions/${encodeURIComponent(e)}/plan`,t),closePlan:e=>o(`/api/sessions/${encodeURIComponent(e)}/plan`),listWorkspacePlans:(e,t)=>s(`/api/workspaces/${encodeURIComponent(e)}/plans`,t),getWorkspacePlan:(e,t,n)=>s(`/api/workspaces/${encodeURIComponent(e)}/plans/${encodeURIComponent(t)}`,n),openSessionPlan:(e,t)=>r(`/api/sessions/${encodeURIComponent(e)}/plan`,{planName:t}),getGitSummary:(e,t)=>s(`/api/git/repositories/${encodeURIComponent(e)}`,t),cloneGitRepository:(e,t)=>n(`/api/git/clone`,{workspaceId:e,address:t}),refreshGit:(e,t)=>n(`/api/git/repositories/${encodeURIComponent(e)}/refresh`,{},t?{"idempotency-key":t}:{}),pullGit:(e,t,r)=>n(`/api/git/repositories/${encodeURIComponent(e)}/pull`,{},t?{"idempotency-key":t}:{},r),checkoutGitBranch:(e,t,r)=>n(`/api/git/repositories/${encodeURIComponent(e)}/checkout`,{branch:t},{},r),pushGit:(e,t)=>n(`/api/git/repositories/${encodeURIComponent(e)}/push`,{},t?{"idempotency-key":t}:{}),listAvailableSkills:(e,t,n=!1,r)=>s(`/api/skills?${new URLSearchParams({workspaceId:e,profile:t,...n?{refresh:`true`}:{}}).toString()}`,r),listSkillProfiles:e=>s(`/api/skill-profiles`,e),replaceSkillProfile:(e,t)=>r(`/api/skill-profiles/${encodeURIComponent(e)}`,t),deleteSkillProfile:e=>o(`/api/skill-profiles/${encodeURIComponent(e)}`),respondInteraction:(e,t,r,i)=>n(`/api/sessions/${encodeURIComponent(e)}/interactions/${encodeURIComponent(t)}`,r,i?{"idempotency-key":i}:{})}}var Ku=[`authoring-start`,`work-start`,`checkpoint`,`update`,`supervision-start`,`resync`];function qu(e){return typeof e==`string`&&(Ku.includes(e)||/^review:[A-Za-z0-9._-]{1,128}:REVIEWED$/.test(e))}function Ju(e){if(!e||typeof e!=`object`)return!1;let t=e;return Yu(t.plan)&&(t.reason===null||qu(t.reason))}function Yu(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.title==`string`&&Array.isArray(t.steps)&&typeof t.totalSteps==`number`&&typeof t.doneSteps==`number`&&typeof t.allDone==`boolean`&&typeof t.currentStepId==`string`}function Xu(e){return e instanceof Error?e.message:`Could not load the plan.`}function Zu(e){return{...e,...e.skills?{skills:[...e.skills]}:{},description:{...e.description},children:e.children.map(Zu)}}function Qu(e){return{...e,steps:e.steps.map(Zu)}}function $u(e,t){return e.kind===`unavailable`&&e.sessionId===t}function ed(e,t){let n=null,r={kind:`unavailable`,sessionId:null},i=0,a=0,o=null,s=0,c=e=>{++a,r=e,t(e)},l=(t,r)=>{o?.abort(),o=new AbortController;let a=++i,l=s;r||c({kind:`loading`,sessionId:t}),e.getPlan(t,o.signal).then(e=>{a!==i||n!==t||s===l&&c(e?{kind:`ready`,sessionId:t,plan:Qu(e)}:{kind:`unavailable`,sessionId:t})}).catch(e=>{o?.signal.aborted||a!==i||n!==t||c({kind:`error`,sessionId:t,error:Xu(e),...r?{plan:r}:{}})})};return{select(e){if(o?.abort(),n=e,s=0,!e){++i,c({kind:`unavailable`,sessionId:null});return}l(e,void 0)},refresh(e){if(n!==e)return;let t=r.kind===`ready`||r.kind===`closing`||r.kind===`error`?r.plan:void 0;l(e,t)},applyEvent(e,t){if(!(n!==e||t.sequence<=s)){if(t.type===`plan.updated`&&(Yu(t.payload)||Ju(t.payload))){let n=Ju(t.payload)?t.payload.plan:t.payload;s=t.sequence,c({kind:`ready`,sessionId:e,plan:Qu(n)})}t.type===`plan.closed`&&(s=t.sequence,c({kind:`unavailable`,sessionId:e}))}},async close(){if(r.kind!==`ready`&&r.kind!==`error`||!r.plan?.allDone)return null;let{sessionId:t,plan:i}=r;c({kind:`closing`,sessionId:t,plan:i});let o=a;try{return await e.closePlan(t),n===t?a===o?(c({kind:`unavailable`,sessionId:t}),`chat`):$u(r,t)?`chat`:null:null}catch(e){return n===t?a===o?(c({kind:`error`,sessionId:t,plan:i,error:Xu(e)}),null):$u(r,t)?`chat`:null:null}},dispose(){o?.abort(),o=null,n=null,++i,c({kind:`unavailable`,sessionId:null})}}}function td(e){if(!e)return null;let t=nd(e.steps,e.currentStepId)?.measurement?.weeklyRemainingCurrent;return typeof t==`number`&&Number.isFinite(t)&&t>=0&&t<=100?Math.round(t):null}function nd(e,t){for(let n of e){if(n.id===t)return n;let e=nd(n.children,t);if(e)return e}}function rd(e,t){return t===void 0?`L${e}`:`L${e}.${t}`}function id(e){let t=e.steps.filter(e=>e.reviewStatus===`REVIEWED`).length,n=e.steps.length,r=ad(e),i=e.steps.find(e=>e.state===`DONE`&&e.reviewStatus===`UNREVIEWED`);return i?{phase:`awaiting review`,label:`Awaiting ${rd(e.steps.indexOf(i)+1)} review`,current:r,reviewedL1s:t,totalL1s:n}:n>0&&t===n?{phase:`terminal review`,label:`Terminal review`,current:r,reviewedL1s:t,totalL1s:n}:t>0&&!r?{phase:`milestone reported`,label:`Preparing milestone summary`,current:r,reviewedL1s:t,totalL1s:n}:r?{phase:`implementing`,label:`Implementing ${r.position} ${r.title}`,current:r,reviewedL1s:t,totalL1s:n}:{phase:e.allDone?`terminal review`:`implementing`,label:e.allDone?`Terminal review`:`Implementing`,current:r,reviewedL1s:t,totalL1s:n}}function ad(e){for(let[t,n]of e.steps.entries()){if(n.id===e.currentStepId)return{id:n.id,position:rd(t+1),title:n.title,state:n.state};let r=n.children.findIndex(t=>t.id===e.currentStepId);if(r>=0){let e=n.children[r];return{id:e.id,position:rd(t+1,r+1),title:e.title,state:e.state}}}}var od=q(`<span class="wip-effort svelte-hmxg46"> </span>`),sd=q(`<li class="svelte-hmxg46"><span class="wip-position svelte-hmxg46" aria-hidden="true"> </span> <span class="wip-title svelte-hmxg46"> </span> <!></li>`),cd=q(`<ol class="wip-steps svelte-hmxg46" aria-label="Work in progress plan steps"></ol>`),ld=q(`<li class="svelte-hmxg46"><span aria-hidden="true" class="position svelte-hmxg46"> </span> <span aria-hidden="true" class="state"> </span></li>`),ud=q(`<ol class="step-markers svelte-hmxg46" aria-label="Plan step progress"></ol>`),dd=q(`<div><div class="progress-heading svelte-hmxg46"><span> </span> <span> </span></div> <progress class="svelte-hmxg46"> </progress> <span class="review-status"> </span> <!></div>`);function fd(e,t){Qe(t,!0);let n=$(t,`compact`,3,!1),r=$(t,`label`,3,`Plan progress`),i=P(()=>t.plan.steps.flatMap((e,t)=>[{id:e.id,position:rd(t+1),state:e.state,level:e.level,title:e.title,...e.description.effort?{effort:e.description.effort}:{}},...e.children.map((e,n)=>({id:e.id,position:rd(t+1,n+1),state:e.state,level:e.level,title:e.title}))])),a=P(()=>G(i).filter(e=>e.state===`WIP`)),o=P(()=>id(t.plan)),s=P(()=>Math.max(t.plan.totalSteps,1));var c=dd(),l=z(c),u=z(l),d=z(u);N(u);var f=V(u,2),p=z(f);N(f),N(l);var m=V(l,2),h=z(m);N(m);var g=V(m,2),_=z(g,!0);N(g);var v=V(g,2),y=e=>{var n=cd();Z(n,21,()=>G(a),e=>e.id,(e,n)=>{var r=sd(),i=z(r),a=z(i);N(i);var o=V(i,2),s=z(o,!0);N(o);var c=V(o,2),l=e=>{var t=od(),r=z(t);N(t),H(()=>Y(r,`Effort: ${G(n).effort??``}`)),J(e,t)};X(c,e=>{G(n).level===1&&G(n).effort&&e(l)}),N(r),H(()=>{Q(r,`aria-current`,G(n).id===t.plan.currentStepId?`step`:void 0),Q(r,`aria-label`,`${G(n).position}: ${G(n).title}, WIP${G(n).level===1&&G(n).effort?`, effort ${G(n).effort}`:``}`),Y(a,`${G(n).position??``} · WIP`),Y(s,G(n).title)}),J(e,r)}),N(n),J(e,n)},b=e=>{var n=ud();Z(n,21,()=>G(i),e=>e.id,(e,n)=>{var r=ld(),i=z(r),a=z(i,!0);N(i);var o=V(i,2),s=z(o,!0);N(o),N(r),H(()=>{Q(r,`data-state`,G(n).state),Q(r,`aria-current`,G(n).id===t.plan.currentStepId?`step`:void 0),Q(r,`aria-label`,`${G(n).position}: ${G(n).state}`),Y(a,G(n).position),Y(s,G(n).state)}),J(e,r)}),N(n),J(e,n)};X(v,e=>{n()&&G(a).length?e(y):!n()&&G(i).length&&e(b,1)}),N(c),H(()=>{gi(c,1,ui([`plan-progress`,{compact:n()}]),`svelte-hmxg46`),Y(d,`${t.plan.doneSteps??``} / ${t.plan.totalSteps??``} work items done`),Y(p,`· ${G(o).reviewedL1s??``} / ${G(o).totalL1s??``} reviewed`),Q(m,`aria-label`,r()),Oi(m,t.plan.doneSteps),Q(m,`max`,G(s)),Y(h,`${t.plan.doneSteps??``} of ${t.plan.totalSteps??``} work items done`),Q(g,`data-phase`,G(o).phase),Y(_,G(o).label)}),J(e,c),$e()}var pd=q(`<section aria-labelledby="plan-title" class="svelte-3rmyvg"><h2 id="plan-title" class="svelte-3rmyvg">Plan</h2> <p class="svelte-3rmyvg">Loading plan…</p></section>`),md=q(`<section aria-labelledby="plan-title" class="svelte-3rmyvg"><h2 id="plan-title" class="svelte-3rmyvg">Plan</h2> <p class="svelte-3rmyvg">No retained plan for this session.</p></section>`),hd=q(`<section aria-labelledby="plan-title" class="svelte-3rmyvg"><h2 id="plan-title" class="svelte-3rmyvg">Plan</h2> <p class="svelte-3rmyvg"> </p></section>`),gd=q(`<p class="svelte-3rmyvg"> </p>`),_d=q(`<div class="svelte-3rmyvg"><dt class="svelte-3rmyvg">Subtitle</dt> <dd class="svelte-3rmyvg"> </dd></div>`),vd=q(`<div class="svelte-3rmyvg"><dt class="svelte-3rmyvg">Date</dt> <dd class="svelte-3rmyvg"> </dd></div>`),yd=q(`<div class="svelte-3rmyvg"><dt class="svelte-3rmyvg">Keywords</dt> <dd class="svelte-3rmyvg"> </dd></div>`),bd=q(`<dl class="metadata svelte-3rmyvg"><!> <!> <!></dl>`),xd=q(`<p class="svelte-3rmyvg">No plan steps have been retained yet.</p>`),Sd=q(`<p class="svelte-3rmyvg"><strong class="svelte-3rmyvg"> </strong> </p>`),Cd=q(`<p class="svelte-3rmyvg"><strong class="svelte-3rmyvg">Skills:</strong> </p>`),wd=q(`<li class="svelte-3rmyvg"><details class="svelte-3rmyvg"><summary class="svelte-3rmyvg"><strong class="svelte-3rmyvg"><span class="position svelte-3rmyvg"> </span> </strong> <span class="svelte-3rmyvg"> </span> <span class="svelte-3rmyvg"> </span></summary> <!> <!></details></li>`),Td=q(`<ol class="svelte-3rmyvg"></ol>`),Ed=q(`<li class="svelte-3rmyvg"><details class="svelte-3rmyvg"><summary class="svelte-3rmyvg"><strong class="svelte-3rmyvg"><span class="position svelte-3rmyvg"> </span> </strong> <span class="svelte-3rmyvg"> </span> <span class="svelte-3rmyvg"> </span> <span class="measurement svelte-3rmyvg"> </span></summary> <!> <!> <!></details></li>`),Dd=q(`<ol class="plan-steps svelte-3rmyvg"></ol>`),Od=q(`<section class="plan svelte-3rmyvg" aria-labelledby="plan-title"><header class="svelte-3rmyvg"><div class="svelte-3rmyvg"><h2 id="plan-title" class="svelte-3rmyvg"> </h2></div> <button class="close svelte-3rmyvg" aria-label="Close plan and return to list">×</button></header> <!> <p class="svelte-3rmyvg"> </p> <!> <!> <!></section>`),kd=q(`<p class="visually-hidden svelte-3rmyvg" aria-live="polite" aria-atomic="true"> </p> <!>`,1);function Ad(e,t){Qe(t,!0);let n={effort:`Effort`,goal:`Goal`,notes:`Notes`,why:`Why`,change:`Change`,tests:`Tests`,doneWhen:`Done when`},r=I(R(new Set)),i=R({}),a=null,o=0,s=P(()=>t.state.kind===`ready`||t.state.kind===`closing`||t.state.kind===`error`?t.state.plan:void 0),c=P(()=>G(s)?p(G(s).steps,G(s).currentStepId):void 0),l=P(()=>G(s)?m(G(s).steps,G(s).currentStepId):void 0),u=P(()=>G(s)?id(G(s)):void 0),d=P(()=>G(s)?h(G(s).steps,G(s).currentStepId):new Set),f=P(()=>t.state.kind===`loading`?`Loading plan.`:t.state.kind===`unavailable`?`No retained plan for this session.`:t.state.kind===`error`&&!G(s)?t.state.error:t.state.kind===`closing`?`Closing completed plan.`:G(s)?G(c)?`${G(u)?.label??`Current step: ${G(l)} ${G(c).title}`}. ${G(s).doneSteps} of ${G(s).totalSteps} work items done.${t.state.kind===`error`?` ${t.state.error}`:``}`:`${G(u)?.label??`Plan progress`}. ${G(s).doneSteps} of ${G(s).totalSteps} work items done.${t.state.kind===`error`?` ${t.state.error}`:``}`:``);Mn(()=>{let e=G(s)?.currentStepId||null;if(!e||a===e)return;a=e;let t=++o;Cr().then(()=>{t!==o||G(s)?.currentStepId!==e||i[e]?.scrollIntoView({behavior:`auto`,block:`nearest`,inline:`nearest`})})});function p(e,t){for(let n of e){if(n.id===t)return n;let e=p(n.children,t);if(e)return e}}function m(e,t){for(let[n,r]of e.entries()){if(r.id===t)return rd(n+1);let e=r.children.findIndex(e=>e.id===t);if(e>=0)return rd(n+1,e+1)}}function h(e,t,n=[]){for(let r of e){if(r.id===t)return new Set([...n,r.id]);let e=h(r.children,t,[...n,r.id]);if(e.size)return e}return new Set}function g(e){return G(r).has(e)||G(d).has(e)}function _(e,t){L(r,t?new Set([...G(r),e]):new Set([...G(r)].filter(t=>t!==e)),!0)}function v(e){return e.description.goal??e.description.why??e.title}function y(e){let t=e.measurement;if(!t)return`Measurements unavailable`;let n=[];return t.elapsedSeconds!==void 0&&n.push(`${Math.floor(t.elapsedSeconds/60)}m ${t.elapsedSeconds%60}s elapsed`),t.weeklyPercentUsed!==void 0&&n.push(`${t.weeklyPercentUsed}% observed account-wide usage`),t.tokensUsed!==void 0&&n.push(`${t.tokensUsed.toLocaleString()} tokens used`),n.join(` · `)||`Measurements unavailable`}function b(e){return Object.keys(n).flatMap(t=>{let r=e.description[t];return r?[[n[t],r]]:[]})}var x=kd(),S=B(x),w=z(S,!0);N(S);var T=V(S,2),E=e=>{J(e,pd())},D=e=>{J(e,md())},ee=e=>{var n=hd(),r=V(z(n),2),i=z(r,!0);N(r),N(n),H(()=>Y(i,t.state.error)),J(e,n)},te=e=>{var n=Od(),r=z(n),a=z(r),o=z(a),d=z(o,!0);N(o),N(a);var f=V(a,2);N(r);var p=V(r,2);fd(p,{get plan(){return G(s)}});var m=V(p,2),h=z(m);N(m);var x=V(m,2),S=e=>{var n=gd(),r=z(n,!0);N(n),H(()=>Y(r,t.state.error)),J(e,n)};X(x,e=>{t.state.kind===`error`&&e(S)});var w=V(x,2),T=e=>{var t=bd(),n=z(t),r=e=>{var t=_d(),n=V(z(t),2),r=z(n,!0);N(n),N(t),H(()=>Y(r,G(s).subtitle)),J(e,t)};X(n,e=>{G(s).subtitle&&e(r)});var i=V(n,2),a=e=>{var t=vd(),n=V(z(t),2),r=z(n,!0);N(n),N(t),H(()=>Y(r,G(s).date)),J(e,t)};X(i,e=>{G(s).date&&e(a)});var o=V(i,2),c=e=>{var t=yd(),n=V(z(t),2),r=z(n,!0);N(n),N(t),H(()=>Y(r,G(s).keywords)),J(e,t)};X(o,e=>{G(s).keywords&&e(c)}),N(t),J(e,t)};X(w,e=>{(G(s).subtitle||G(s).date||G(s).keywords)&&e(T)});var E=V(w,2),D=e=>{J(e,xd())},ee=e=>{var t=Dd();Z(t,23,()=>G(s).steps,e=>e.id,(e,t,n)=>{var r=Ed(),a=z(r),o=z(a),s=z(o),c=z(s),l=z(c,!0);N(c);var u=V(c);N(s);var d=V(s,2),f=z(d);N(d);var p=V(d,2),m=z(p,!0);N(p);var h=V(p,2),x=z(h,!0);N(h),N(o);var S=V(o,2);Z(S,17,()=>b(G(t)),([e,t])=>e,(e,t)=>{var n=P(()=>C(G(t),2));let r=()=>G(n)[0],i=()=>G(n)[1];var a=Sd(),o=z(a),s=z(o);N(o);var c=V(o);N(a),H(()=>{Y(s,`${r()??``}:`),Y(c,` ${i()??``}`)}),J(e,a)});var w=V(S,2),T=e=>{var n=Cd(),r=V(z(n));N(n),H(e=>Y(r,` ${e??``}`),[()=>G(t).skills.join(`, `)]),J(e,n)};X(w,e=>{G(t).skills?.length&&e(T)});var E=V(w,2),D=e=>{var r=Td();Z(r,23,()=>G(t).children,e=>e.id,(e,t,r)=>{var a=wd(),o=z(a),s=z(o),c=z(s),l=z(c),u=z(l,!0);N(l);var d=V(l);N(c);var f=V(c,2),p=z(f);N(f);var m=V(f,2),h=z(m,!0);N(m),N(s);var y=V(s,2);Z(y,17,()=>b(G(t)),([e,t])=>e,(e,t)=>{var n=P(()=>C(G(t),2));let r=()=>G(n)[0],i=()=>G(n)[1];var a=Sd(),o=z(a),s=z(o);N(o);var c=V(o);N(a),H(()=>{Y(s,`${r()??``}:`),Y(c,` ${i()??``}`)}),J(e,a)});var x=V(y,2),S=e=>{var n=Cd(),r=V(z(n));N(n),H(e=>Y(r,` ${e??``}`),[()=>G(t).skills.join(`, `)]),J(e,n)};X(x,e=>{G(t).skills?.length&&e(S)}),N(o),Li(o,(e,t)=>i[t.id]=e,e=>i?.[e.id],()=>[G(t)]),N(a),H((e,n,r)=>{Q(o,`data-step-id`,G(t).id),o.open=e,Y(u,n),Y(d,` ${G(t).title??``}`),Y(p,`${G(t).state??``} · Priority ${G(t).priority??``}${G(t).reviewStatus?` · ${G(t).reviewStatus}`:``}`),Y(h,r)},[()=>g(G(t).id),()=>rd(G(n)+1,G(r)+1),()=>v(G(t))]),Nr(`toggle`,o,e=>_(G(t).id,e.currentTarget.open)),J(e,a)}),N(r),J(e,r)};X(E,e=>{G(t).children.length&&e(D)}),N(a),Li(a,(e,t)=>i[t.id]=e,e=>i?.[e.id],()=>[G(t)]),N(r),H((e,n,r,i)=>{Q(a,`data-step-id`,G(t).id),a.open=e,Y(l,n),Y(u,` ${G(t).title??``}`),Y(f,`${G(t).state??``} · Priority ${G(t).priority??``}${G(t).reviewStatus?` · ${G(t).reviewStatus}`:``}`),Y(m,r),Y(x,i)},[()=>g(G(t).id),()=>rd(G(n)+1),()=>v(G(t)),()=>y(G(t))]),Nr(`toggle`,a,e=>_(G(t).id,e.currentTarget.open)),J(e,r)}),N(t),J(e,t)};X(E,e=>{G(s).steps.length===0?e(D):e(ee,-1)}),N(n),H(()=>{Y(d,G(s).title),Y(h,`${G(u)?.label??``}. Current: ${G(c)?`${G(l)} ${G(c).title} (${G(c).state})`:`No current step`}`)}),K(`click`,f,function(...e){t.onclose?.apply(this,e)}),J(e,n)};X(T,e=>{t.state.kind===`loading`?e(E):t.state.kind===`unavailable`?e(D,1):t.state.kind===`error`&&!G(s)?e(ee,2):G(s)&&e(te,3)}),H(()=>Y(w,G(f))),J(e,x),$e()}Pr([`click`]);var jd=/^(\*+)\s+(?:(TODO|WIP|DONE)\s+)?(?:\[#([ABC])\]\s+)?(.+)$/,Md=/^#\+([A-Z][A-Z0-9_-]*):\s*(.*)$/i,Nd=/^:([A-Z][A-Z0-9_]*):\s*(.*)$/,Pd=/^-\s+([^:]+?)\s+::\s*(.*)$/;function Fd(e){let t=[],n=[],r=[],i=e.replace(/\r\n?/g,`
|
|
24
24
|
`).split(`
|
|
25
25
|
`),a=null,o=!1,s=()=>{a&&r.push({...a,properties:[...a.properties],descriptions:[...a.descriptions],body:Id(a.body)})};for(let e of i){let r=jd.exec(e);if(r){s(),a={level:r[1].length,title:r[4].trim(),...r[2]?{state:r[2]}:{},...r[3]?{priority:r[3]}:{},properties:[],descriptions:[],body:[]},o=!1;continue}if(!a){let r=Md.exec(e);r?t.push([r[1].toUpperCase(),r[2].trim()]):n.push(e);continue}if(e===`:PROPERTIES:`){o=!0;continue}if(o&&e===`:END:`){o=!1;continue}if(o){let t=Nd.exec(e);t&&a.properties.push([t[1],t[2].trim()]);continue}let i=Pd.exec(e);i?a.descriptions.push([i[1].trim(),i[2].trim()]):a.body.push(e)}return s(),{metadata:t,preamble:Id(n),sections:r}}function Id(e){let t=[...e];for(;t[0]?.trim()===``;)t.shift();for(;t.at(-1)?.trim()===``;)t.pop();return t}var Ld=q(`<div class="svelte-h7gaqo"><dt class="svelte-h7gaqo"> </dt> <dd class="svelte-h7gaqo"> </dd></div>`),Rd=q(`<dl class="metadata svelte-h7gaqo"></dl>`),zd=q(`<p class="svelte-h7gaqo"> </p>`),Bd=q(`<p class="svelte-h7gaqo">This Org document has no headings.</p>`),Vd=q(`<h3 class="svelte-h7gaqo"> </h3>`),Hd=q(`<h4 class="svelte-h7gaqo"> </h4>`),Ud=q(`<span> </span>`),Wd=q(`<span class="priority svelte-h7gaqo"> </span>`),Gd=q(`<dl class="descriptions svelte-h7gaqo"></dl>`),Kd=q(`<p> </p>`),qd=q(`<details class="properties svelte-h7gaqo"><summary class="svelte-h7gaqo">Properties</summary> <dl class="svelte-h7gaqo"></dl></details>`),Jd=q(`<section class="org-section svelte-h7gaqo"><div class="section-heading svelte-h7gaqo"><!> <!> <!></div> <!> <!> <!></section>`),Yd=q(`<div class="sections svelte-h7gaqo"></div>`),Xd=q(`<article class="org-document svelte-h7gaqo" aria-labelledby="org-document-title"><header class="svelte-h7gaqo"><div><h2 id="org-document-title" class="svelte-h7gaqo"> </h2> <code class="svelte-h7gaqo"> </code></div> <button class="close svelte-h7gaqo" type="button" aria-label="Close plan and return to list">×</button></header> <!> <!> <!></article>`);function Zd(e,t){Qe(t,!0);let n=P(()=>Fd(t.preview.source)),r=P(()=>G(n).metadata.filter(([e])=>e!==`TITLE`));var i=Xd(),a=z(i),o=z(a),s=z(o),c=z(s,!0);N(s);var l=V(s,2),u=z(l,!0);N(l),N(o);var d=V(o,2);N(a);var f=V(a,2),p=e=>{var t=Rd();Z(t,21,()=>G(r),([e,t])=>`${e}:${t}`,(e,t)=>{var n=P(()=>C(G(t),2));let r=()=>G(n)[0],i=()=>G(n)[1];var a=Ld(),o=z(a),s=z(o,!0);N(o);var c=V(o,2),l=z(c,!0);N(c),N(a),H(()=>{Y(s,r()),Y(l,i()||`—`)}),J(e,a)}),N(t),J(e,t)};X(f,e=>{G(r).length&&e(p)});var m=V(f,2);Z(m,19,()=>G(n).preamble,(e,t)=>`preamble:${t}:${e}`,(e,t)=>{var n=Hr(),r=B(n),i=e=>{var n=zd(),r=z(n,!0);N(n),H(()=>Y(r,G(t))),J(e,n)},a=P(()=>G(t).trim());X(r,e=>{G(a)&&e(i)}),J(e,n)});var h=V(m,2),g=e=>{J(e,Bd())},_=e=>{var t=Yd();Z(t,23,()=>G(n).sections,(e,t)=>`${t}:${e.level}:${e.title}`,(e,t)=>{var n=Jd();let r;var i=z(n),a=z(i),o=e=>{var n=Vd(),r=z(n,!0);N(n),H(()=>Y(r,G(t).title)),J(e,n)},s=e=>{var n=Hd(),r=z(n,!0);N(n),H(()=>Y(r,G(t).title)),J(e,n)};X(a,e=>{G(t).level===1?e(o):e(s,-1)});var c=V(a,2),l=e=>{var n=Ud(),r=z(n,!0);N(n),H(e=>{gi(n,1,e,`svelte-h7gaqo`),Y(r,G(t).state)},[()=>`state state-${G(t).state.toLowerCase()}`]),J(e,n)};X(c,e=>{G(t).state&&e(l)});var u=V(c,2),d=e=>{var n=Wd(),r=z(n);N(n),H(()=>Y(r,`Priority ${G(t).priority??``}`)),J(e,n)};X(u,e=>{G(t).priority&&e(d)}),N(i);var f=V(i,2),p=e=>{var n=Gd();Z(n,21,()=>G(t).descriptions,([e,t])=>`${e}:${t}`,(e,t)=>{var n=P(()=>C(G(t),2));let r=()=>G(n)[0],i=()=>G(n)[1];var a=Ld(),o=z(a),s=z(o,!0);N(o);var c=V(o,2),l=z(c,!0);N(c),N(a),H(()=>{Y(s,r()),Y(l,i()||`—`)}),J(e,a)}),N(n),J(e,n)};X(f,e=>{G(t).descriptions.length&&e(p)});var m=V(f,2);Z(m,19,()=>G(t).body,(e,t)=>`${t}:${e}`,(e,t)=>{var n=Hr(),r=B(n),i=e=>{var n=Kd();let r;var i=z(n,!0);N(n),H(e=>{r=gi(n,1,`svelte-h7gaqo`,null,r,e),Y(i,G(t))},[()=>({"list-item":G(t).trimStart().startsWith(`- `)})]),J(e,n)},a=P(()=>G(t).trim());X(r,e=>{G(a)&&e(i)}),J(e,n)});var h=V(m,2),g=e=>{var n=qd(),r=V(z(n),2);Z(r,21,()=>G(t).properties,([e,t])=>`${e}:${t}`,(e,t)=>{var n=P(()=>C(G(t),2));let r=()=>G(n)[0],i=()=>G(n)[1];var a=Ld(),o=z(a),s=z(o,!0);N(o);var c=V(o,2),l=z(c,!0);N(c),N(a),H(()=>{Y(s,r()),Y(l,i()||`—`)}),J(e,a)}),N(r),N(n),J(e,n)};X(h,e=>{G(t).properties.length&&e(g)}),N(n),H(e=>r=vi(n,``,r,e),[()=>({"--org-depth":Math.max(0,G(t).level-1)})]),J(e,n)}),N(t),J(e,t)};X(h,e=>{G(n).sections.length===0?e(g):e(_,-1)}),N(i),H(()=>{Y(c,t.preview.title),Y(u,t.preview.planName)}),K(`click`,d,function(...e){t.onclose?.apply(this,e)}),J(e,i),$e()}Pr([`click`]);var Qd=q(`<span> </span>`),$d=q(`<span> </span> <!>`,1),ef=q(`<span>Org document</span>`),tf=q(`<li><button class="svelte-x2ko9l"><strong> </strong> <code class="svelte-x2ko9l"> </code> <!></button></li>`),nf=q(`<p>Select a workspace to browse its local plans.</p>`),rf=q(`<p>Loading workspace plans…</p>`),af=q(`<p> </p>`),of=q(`<p>No Org files were found below this workspace.</p>`),sf=q(`<ul aria-label="Unfinished plans" class="svelte-x2ko9l"></ul>`),cf=q(`<section class="completed svelte-x2ko9l" aria-labelledby="completed-plans-title"><h3 id="completed-plans-title" class="svelte-x2ko9l">Completed</h3> <ul class="svelte-x2ko9l"></ul></section>`),lf=q(`<p class="scope svelte-x2ko9l">Org files below the selected workspace.</p> <!> <!>`,1),uf=q(`<section class="plans svelte-x2ko9l" aria-labelledby="plans-title"><h2 id="plans-title" tabindex="-1" class="svelte-x2ko9l">Plans</h2> <!></section>`);function df(e,t){Qe(t,!0);let n=(e,t=b)=>{var n=tf(),r=z(n),a=z(r),o=z(a,!0);N(a);var s=V(a,2),c=z(s,!0);N(s);var l=V(s,2),u=e=>{var n=$d(),r=B(n),i=z(r);N(r);var a=V(r,2),o=e=>{var n=Qd(),r=z(n,!0);N(n),H(()=>Y(r,t().subtitle)),J(e,n)};X(a,e=>{t().subtitle&&e(o)}),H(()=>Y(i,`${t().doneSteps??``} / ${t().totalSteps??``} complete`)),J(e,n)},f=e=>{J(e,ef())};X(l,e=>{t().previewAvailable===!1?e(f,-1):e(u)}),N(r),Li(r,e=>i[t().planName]=e,()=>i?.[t().planName]),N(n),H(()=>{Y(o,t().title),Y(c,t().planName)}),K(`click`,r,()=>d(t().planName)),J(e,n)},r=I(null),i=R({}),a=I(null),o=!1,s=!1,c=P(()=>t.catalog.kind===`ready`?t.catalog.entries.filter(e=>e.allDone!==!0):[]),l=P(()=>t.catalog.kind===`ready`?t.catalog.entries.filter(e=>e.allDone===!0):[]);function u(){t.onclose()}function d(e){L(a,e,!0),t.onopen(e)}Mn(()=>{if(t.state){o=!0;return}if(o&&(o=!1,s=!0),!s)return;let e=t.catalog.kind,n=G(a);queueMicrotask(()=>{let t=n?i[n]:void 0;t?.isConnected?(t.focus(),s=!1):e!==`loading`&&(G(r)?.focus(),s=!1)})});var f=Hr(),p=B(f),m=e=>{Zd(e,{get preview(){return t.state},onclose:u})},h=e=>{Ad(e,{get state(){return t.state},onclose:u})},g=e=>{var i=uf(),a=z(i);Li(a,e=>L(r,e),()=>G(r));var o=V(a,2),s=e=>{J(e,nf())},u=e=>{J(e,rf())},d=e=>{var n=af(),r=z(n,!0);N(n),H(()=>Y(r,t.catalog.error)),J(e,n)},f=e=>{J(e,of())},p=e=>{var t=lf(),r=V(B(t),2),i=e=>{var t=sf();Z(t,21,()=>G(c),e=>e.planName,(e,t)=>{n(e,()=>G(t))}),N(t),J(e,t)};X(r,e=>{G(c).length>0&&e(i)});var a=V(r,2),o=e=>{var t=cf(),r=V(z(t),2);Z(r,21,()=>G(l),e=>e.planName,(e,t)=>{n(e,()=>G(t))}),N(r),N(t),J(e,t)};X(a,e=>{G(l).length>0&&e(o)}),J(e,t)};X(o,e=>{t.catalog.kind===`no-workspace`?e(s):t.catalog.kind===`loading`?e(u,1):t.catalog.kind===`error`?e(d,2):t.catalog.entries.length===0?e(f,3):e(p,-1)}),N(i),J(e,i)};X(p,e=>{t.state?.kind===`org-source`?e(m):t.state?e(h,1):e(g,-1)}),J(e,f),$e()}Pr([`click`]);var ff=`settings`,pf=`drafts`,mf=`cursors`,hf=`selected-session`,gf={text:``,revision:0},_f=e=>{if(!e||typeof e!=`object`)return!1;let t=e,n=t.pending;return typeof t.text==`string`&&Number.isSafeInteger(t.revision)&&t.revision>=0&&(n===void 0||Array.isArray(n)&&n.every(e=>!!e&&typeof e.operationId==`string`&&typeof e.text==`string`&&Number.isSafeInteger(e.revision)&&e.revision>=0&&(e.kind===`send`||e.kind===`queue`||e.kind===`interrupt-send`)))};function vf(e=globalThis.indexedDB){if(!e)return yf;let t=Rc(e),n=new Map,r=new Map,i=async(e,i)=>{let a=r.get(e);if(a&&a.revision>i.revision)return;r.set(e,i);let o=(n.get(e)??Promise.resolve()).catch(()=>void 0).then(async()=>{if(r.get(e)===i)try{await Bc(await t,pf,e,i)}catch{}});n.set(e,o),await o};return{async readSelectedSession(){try{return await zc(await t,ff,hf)??null}catch{return null}},async saveSelectedSession(e){try{let n=await t;e?await Bc(n,ff,hf,e):await Vc(n,ff,hf)}catch{}},async readDraft(e){return(await this.readDraftEnvelope(e)).text},async saveDraft(e,t){let n=await this.readDraftEnvelope(e);await i(e,{text:t,revision:n.revision+1})},async readDraftEnvelope(e){try{let n=await zc(await t,pf,e),i=_f(n)?n:typeof n==`string`?{text:n,revision:0}:gf,a=r.get(e);return a&&a.revision>=i.revision?a:(r.set(e,i),i)}catch{return r.get(e)??gf}},saveDraftEnvelope:i,replaceDraftText:async(e,t,n)=>{let a=r.get(e);await i(e,{text:t,revision:n,pending:a?.pending})},addPendingDraftOperation:async(e,t)=>{let n=r.get(e)??gf;await i(e,{...n,pending:[...(n.pending??[]).filter(e=>e.operationId!==t.operationId),t].slice(-8)})},consumeAcceptedDraft:async(e,i,a)=>{let o=n.get(e)??Promise.resolve(),s=null,c=o.catch(()=>void 0).then(async()=>{let n=r.get(e);if(!n)try{let r=await zc(await t,pf,e);n=_f(r)?r:typeof r==`string`?{text:r,revision:0}:gf}catch{n=gf}if(!(n.revision!==i||!n.pending?.some(e=>e.operationId===a))){s={text:``,revision:n.revision+1,pending:n.pending.filter(e=>e.operationId!==a)},r.set(e,s);try{await Bc(await t,pf,e,s)}catch{r.get(e)===s&&r.set(e,n),s=null}}});return n.set(e,c),await c,s},async readCursor(e){try{let n=await zc(await t,mf,e);return typeof n==`number`&&Number.isSafeInteger(n)&&n>=0?n:0}catch{return 0}},async saveCursor(e,n){try{await Bc(await t,mf,e,n)}catch{}}}}var yf={readSelectedSession:async()=>null,saveSelectedSession:async()=>{},readDraft:async()=>``,saveDraft:async()=>{},readDraftEnvelope:async()=>gf,saveDraftEnvelope:async()=>{},replaceDraftText:async()=>{},addPendingDraftOperation:async()=>{},consumeAcceptedDraft:async()=>null,readCursor:async()=>0,saveCursor:async()=>{}};function bf(e,t=Date.now()){if(e===null)return`Unknown activity time`;let n=Math.max(0,t-e),r=Math.floor(n/(3600*1e3));if(r<1)return`Less than an hour ago`;if(r<24)return`${r} hour${r===1?``:`s`} ago`;let i=Math.floor(r/24);return`${i} day${i===1?``:`s`} ago`}function xf(e){let t=e.updatedAt?Date.parse(e.updatedAt):NaN;return{threadId:e.threadId??null,workspacePath:e.workspacePath??`Workspace unavailable`,updatedAt:Number.isFinite(t)?t:null}}function Sf(e,t){if(!t?.threadId||!t.workspacePath||!t.resumeCommand||e.some(e=>e.id===t.threadId&&(e.provider??`codex`)===(t.provider??`codex`)))return e;let n=t.updatedAt?Date.parse(t.updatedAt)/1e3:NaN,r={id:t.threadId,cwd:t.workspacePath,recencyAt:Number.isFinite(n)?n:null,resumeCommand:t.resumeCommand,...t.provider===void 0?{}:{provider:t.provider},...t.model===void 0?{}:{model:t.model},...t.effectiveSkillSelection?.selectedProfileName===void 0?{}:{skillProfile:t.effectiveSkillSelection.selectedProfileName},...t.lastOrgPlan===void 0?{}:{orgPlanFilename:t.lastOrgPlan.filename}};return[...e,r].sort((e,t)=>(t.recencyAt??-1/0)-(e.recencyAt??-1/0))}function Cf(e){let t=/^\/home\/[^/]+/.exec(e)?.[0];if(!t)return e;let n=e.slice(t.length);return n?`~${n}`:`~/`}function wf(e,t){let n=Date.parse(e);if(!Number.isFinite(n))return`Updated recently`;let r=Math.max(0,Math.floor((t-n)/1e3));return r<5?`Updated just now`:r<60?`Updated ${r}s ago`:`Updated ${Math.floor(r/60)}m ago`}var Tf=q(`<time class="svelte-2szxr9"> </time>`),Ef=q(`<span role="status"><span aria-hidden="true" class="dot svelte-2szxr9"></span> <span class="svelte-2szxr9"> </span> <!></span>`);function Df(e,t){Qe(t,!0);let n=$(t,`connected`,3,!0),r=P(()=>n()?t.autopilot?.state??`unknown`:`disconnected`),i=P(()=>!!t.autopilot?.health?.healthy),a=I(R(Date.now())),o=I(R(typeof document>`u`||document.visibilityState!==`hidden`)),s=P(()=>G(r)===`disconnected`?`Autopilot disconnected`:G(r)===`attentionRequired`?`Autopilot needs attention`:G(r)===`safetyPaused`?`Autopilot safety paused`:G(i)?`Autopilot continuation active`:`Autopilot continuation inactive`);function c(){L(o,document.visibilityState!==`hidden`),G(o)&&L(a,Date.now(),!0)}Mn(()=>{if(!G(i)||!G(o))return;let e=window.setInterval(()=>L(a,Date.now(),!0),1e3);return()=>window.clearInterval(e)});var l=Ef();Nr(`visibilitychange`,un,c);let u;var d=V(z(l),2),f=z(d,!0);N(d);var p=V(d,2),m=e=>{var n=Tf(),r=z(n,!0);N(n),H(e=>{Q(n,`datetime`,t.autopilot.updatedAt),Y(r,e)},[()=>wf(t.autopilot.updatedAt,G(a))]),J(e,n)};X(p,e=>{t.autopilot&&G(i)&&e(m)}),N(l),H(()=>{u=gi(l,1,`liveness svelte-2szxr9`,null,u,{active:G(i)}),Q(l,`data-state`,G(r)),Q(l,`aria-label`,G(s)),Y(f,G(s))}),J(e,l),$e()}var Of=q(`<details class="session-verdict svelte-hxb22h"><summary class="svelte-hxb22h"><span aria-hidden="true"></span> </summary> <p class="svelte-hxb22h"> </p></details>`),kf=q(`<time class="svelte-hxb22h"> </time>`),Af=q(`<div class="svelte-hxb22h"> </div>`),jf=q(`<span class="profile-badge svelte-hxb22h"> </span>`),Mf=q(`<span class="profile-badge svelte-hxb22h">Kimi</span>`),Nf=q(`<span class="org-plan-metadata svelte-hxb22h"><span class="org-plan-title svelte-hxb22h"> </span> <span class="org-plan-filename svelte-hxb22h"> </span></span>`),Pf=q(`<div class="session-plan-progress svelte-hxb22h"><!></div>`),Ff=q(`<li><div class="session-actions svelte-hxb22h" aria-label="Session actions"><!> <!> <!> <!> <!> <!></div> <div class="session-details svelte-hxb22h"><div class="session-summary svelte-hxb22h"><!> <!> <div class="workspace-path svelte-hxb22h"> </div> <!> <!> <!> <!> <!> <!></div> <!> <!></div></li>`),If=q(`<section aria-labelledby="open-sessions-title" class="svelte-hxb22h"><h3 id="open-sessions-title" class="svelte-hxb22h">Open sessions</h3> <ul class="session-list svelte-hxb22h" aria-label="Open sessions"></ul></section>`),Lf=q(`<li class="managed-session svelte-hxb22h"><div class="session-actions svelte-hxb22h"><!> <!> <!></div> <div class="session-details svelte-hxb22h"><!> <div class="workspace-path svelte-hxb22h"> </div> <!> <!> <!> <!></div></li>`),Rf=q(`<ul class="session-list svelte-hxb22h" aria-label="Saved sessions"></ul>`),zf=q(`<p class="svelte-hxb22h">No saved sessions yet.</p>`),Bf=q(`<label for="sandbox" class="svelte-hxb22h">Sandbox</label> <label for="approval-policy" class="svelte-hxb22h">Approval policy</label>`,1),Vf=q(`<option class="svelte-hxb22h"> </option>`),Hf=q(`<select id="sandbox" class="svelte-hxb22h"><option class="svelte-hxb22h">workspace-git (Git writable)</option><option class="svelte-hxb22h">workspace-write</option><option class="svelte-hxb22h">read-only</option><option class="svelte-hxb22h">danger-full-access</option></select> <select id="approval-policy" aria-describedby="approval-policy-help" class="svelte-hxb22h"><option class="svelte-hxb22h">Ask on all commands</option><option class="svelte-hxb22h">Ask out of workspace</option><option class="svelte-hxb22h">Approve everything</option></select>`,1),Uf=q(`<p id="approval-policy-help" class="svelte-hxb22h"> </p>`),Wf=q(`<p class="skills-profile-error svelte-hxb22h" role="alert"> </p>`),Gf=q(`<option class="svelte-hxb22h">Loading models…</option>`),Kf=q(`<option class="svelte-hxb22h">Choose automatically</option>`),qf=q(`<p id="provider-availability" class="provider-availability svelte-hxb22h">Kimi is unavailable because its CLI was not found when the relay started.</p>`),Jf=q(`<li class="recent-session svelte-hxb22h"><div class="session-details svelte-hxb22h"><!> <div class="workspace-path svelte-hxb22h"> </div> <!> <!> <!> <!></div> <div class="session-actions svelte-hxb22h"><!> <!></div></li>`),Yf=q(`<ul class="session-list recent-session-list svelte-hxb22h" aria-label="Recent sessions"></ul>`),Xf=q(`<p class="svelte-hxb22h">No other recent sessions found.</p>`),Zf=q(`<section aria-labelledby="sessions-title" class="svelte-hxb22h"><h2 id="sessions-title" class="visually-hidden svelte-hxb22h">Sessions</h2> <!> <!> <form class="svelte-hxb22h"><section class="session-base svelte-hxb22h" aria-labelledby="session-base-title"><div class="session-base-heading svelte-hxb22h"><h3 id="session-base-title" class="svelte-hxb22h">Session base</h3> <p class="svelte-hxb22h"> </p></div> <!></section> <section class="session-settings svelte-hxb22h" aria-label="New session settings"><div class="session-setting-labels svelte-hxb22h"><label for="skills-profile" class="svelte-hxb22h">Skills profile</label> <!></div> <div class="session-setting-controls svelte-hxb22h"><select id="skills-profile" class="svelte-hxb22h"><option class="svelte-hxb22h">Default</option><!></select> <!></div> <!> <!> <div class="session-secondary-actions svelte-hxb22h"><!> <div class="model-control svelte-hxb22h"><label for="session-provider" class="svelte-hxb22h">Provider</label> <select id="session-provider" class="svelte-hxb22h"><option class="svelte-hxb22h">Codex</option><option class="svelte-hxb22h"> </option></select></div> <div class="model-control svelte-hxb22h"><label for="model" class="svelte-hxb22h"> </label> <select id="model" class="svelte-hxb22h"><!><!></select></div> <!></div> <!></section></form> <section aria-labelledby="recent-sessions-title" class="svelte-hxb22h"><h3 id="recent-sessions-title" class="svelte-hxb22h">Recent sessions</h3> <!></section></section>`);function Qf(e,t){Qe(t,!0);let n=$(t,`activitySnapshots`,19,()=>new Map),r=$(t,`autopilotSnapshots`,19,()=>new Map),i=$(t,`autopilotPending`,19,()=>new Set),a=$(t,`autopilotAttention`,19,()=>new Map),o=$(t,`models`,19,()=>[]),s=$(t,`selectedModel`,3,``),c=$(t,`provider`,3,`codex`),l=$(t,`kimiAvailable`,3,!1),u=$(t,`modelsLoading`,3,!1),d=$(t,`onmodelchange`,3,()=>{}),f=$(t,`onproviderchange`,3,()=>{}),p=$(t,`onautopilottoggle`,3,()=>{}),m=$(t,`onactivityopen`,3,()=>{}),h=$(t,`onautopilotresolve`,3,()=>{}),g=P(()=>t.sessions.filter(e=>e.state===`ready`||e.state===`turnActive`)),_=P(()=>t.sessions.filter(e=>e.state!==`ready`&&e.state!==`turnActive`)),v=P(()=>t.recentSessions.filter(e=>!G(g).some(t=>t.threadId===e.id&&(t.provider??`codex`)===(e.provider??`codex`)))),y=P(()=>fu(t.workspaceTree,t.workspaceId)),b=P(()=>c()===`kimi`?`Kimi`:`Codex`);var x=Zf(),S=V(z(x),2),C=e=>{var s=If(),c=V(z(s),2);Z(c,21,()=>G(g),e=>e.id,(e,s)=>{let c=P(()=>xf(G(s))),l=P(()=>Vl(G(s).sessionStatus)?G(s).sessionStatus:null);var u=Ff();let d;var f=z(u),g=z(f);{let e=P(()=>G(s).id===t.selectedSessionId?`page`:void 0);Ta(g,{compact:!0,full:!0,get current(){return G(e)},onclick:()=>t.onselectopen(G(s).id),children:(e,t)=>{He(),J(e,Vr(`Open`))},$$slots:{default:!0}})}var _=V(g,2),v=e=>{Ta(e,{compact:!0,full:!0,onclick:()=>t.oncopyresume(G(s).resumeCommand),children:(e,t)=>{He(),J(e,Vr(`Copy`))},$$slots:{default:!0}})};X(_,e=>{G(s).resumeCommand&&G(s).provider!==`kimi`&&e(v)});var y=V(_,2),b=e=>{{let t=P(()=>r().get(G(s).id)??G(s).autopilot??null),n=P(()=>`session-autopilot-${G(s).id}`),a=P(()=>i().has(G(s).id));no(e,{compact:!0,indicatorOnly:!0,get autopilot(){return G(t)},get controlId(){return G(n)},get pending(){return G(a)},ontoggle:e=>p()(G(s).id,e)})}};X(y,e=>{G(s).provider!==`kimi`&&e(b)});var x=V(y,2);{let e=P(()=>n().get(G(s).id)??G(s).agentActivity??null),t=P(()=>G(s).model??o()?.[0]);La(x,{compact:!0,get activity(){return G(e)},popupAlign:`start`,get rootModel(){return G(t)},get plan(){return G(s).plan},onopen:()=>m()(G(s).id)})}var S=V(x,2);Ta(S,{compact:!0,full:!0,onclick:()=>t.onclose(G(s).id),children:(e,t)=>{He(),J(e,Vr(`Close`))},$$slots:{default:!0}});var C=V(S,2),w=e=>{{let t=P(()=>r().get(G(s).id)??G(s).autopilot??null),i=P(()=>(n().get(G(s).id)??G(s).agentActivity)?.root.state!==`disconnected`);Df(e,{get autopilot(){return G(t)},get connected(){return G(i)}})}};X(C,e=>{G(s).provider!==`kimi`&&e(w)}),N(f);var T=V(f,2),E=z(T),D=z(E),ee=e=>{var t=Of(),n=z(t),r=z(n);let i;var a=V(r);N(n);var o=V(n,2),s=z(o);N(o),N(t),H(()=>{Q(t,`data-state`,G(l).state),Q(t,`aria-label`,`${G(l).state===`working`?`Working`:`Idle`}: ${G(l).reason}`),Q(n,`aria-label`,`${G(l).state===`working`?`Working`:`Idle`}: ${G(l).reason}`),i=gi(r,1,`verdict-dot svelte-hxb22h`,null,i,{live:G(l).state===`working`&&G(l).confidence===`fresh`}),Y(a,` ${G(l).state===`working`?`Working`:`Idle`}`),Y(s,`${G(l).reason??``}. ${G(l).nextExpectedAction??``}
|
|
26
26
|
Evidence confidence: ${G(l).confidence??``}.`)}),J(e,t)};X(D,e=>{G(l)&&e(ee)});var te=V(D,2),ne=e=>{var t=kf(),n=z(t,!0);N(t),H((e,r)=>{Q(t,`datetime`,e),Y(n,r)},[()=>new Date(G(c).updatedAt).toISOString(),()=>bf(G(c).updatedAt)]),J(e,t)},re=e=>{var t=Af(),n=z(t,!0);N(t),H(e=>Y(n,e),[()=>bf(null)]),J(e,t)};X(te,e=>{G(c).updatedAt===null?e(re,-1):e(ne)});var ie=V(te,2),O=z(ie,!0);N(ie);var k=V(ie,2),ae=e=>{var t=jf(),n=z(t);N(t),H(()=>Y(n,`Model: ${G(s).model??``}`)),J(e,t)};X(k,e=>{G(s).model&&e(ae)});var A=V(k,2),oe=e=>{J(e,Mf())};X(A,e=>{G(s).provider===`kimi`&&e(oe)});var se=V(A,2),ce=e=>{var t=jf(),n=z(t);N(t),H(()=>Y(n,`Branch: ${G(s).branch??``}`)),J(e,t)};X(se,e=>{G(s).branch&&e(ce)});var le=V(se,2),ue=e=>{var t=jf(),n=z(t);N(t),H(()=>Y(n,`Skills profile: ${G(s).effectiveSkillSelection.selectedProfileName??``}`)),J(e,t)};X(le,e=>{G(s).effectiveSkillSelection?.selectedProfileName&&e(ue)});var de=V(le,2),fe=e=>{var t=Nf(),n=z(t),r=z(n,!0);N(n);var i=V(n,2),a=z(i,!0);N(i),N(t),H(()=>{Y(r,G(s).lastOrgPlan.title),Y(a,G(s).lastOrgPlan.filename)}),J(e,t)};X(de,e=>{G(s).lastOrgPlan&&e(fe)});var pe=V(de,2),me=e=>{var t=Pf(),n=z(t);{let e=P(()=>`Plan progress for ${G(s).plan.title}`);fd(n,{compact:!0,get plan(){return G(s).plan},get label(){return G(e)}})}N(t),J(e,t)};X(pe,e=>{G(s).plan&&e(me)}),N(E);var he=V(E,2);{let e=P(()=>a().get(G(s).id)??null),t=P(()=>`session-attention-${G(s).id}`),n=P(()=>i().has(G(s).id));io(he,{get attention(){return G(e)},get controlId(){return G(t)},get pending(){return G(n)},onresolve:(e,t)=>h()(G(s).id,e,t)})}var ge=V(he,2);{let e=P(()=>r().get(G(s).id)??G(s).autopilot??null),t=P(()=>a().get(G(s).id)??null),n=P(()=>`session-autopilot-safety-${G(s).id}`),o=P(()=>i().has(G(s).id));oo(ge,{get autopilot(){return G(e)},get attention(){return G(t)},get controlId(){return G(n)},get pending(){return G(o)},onrecover:()=>p()(G(s).id,!0),ondisable:()=>p()(G(s).id,!1)})}N(T),N(u),H(e=>{d=gi(u,1,`managed-session open-session svelte-hxb22h`,null,d,{"current-session":G(s).id===t.selectedSessionId}),Y(O,e)},[()=>Cf(G(c).workspacePath)]),J(e,u)}),N(c),N(s),J(e,s)};X(S,e=>{G(g).length&&e(C)});var w=V(S,2),T=e=>{var n=Rf();Z(n,21,()=>G(_),e=>e.id,(e,n)=>{let r=P(()=>xf(G(n)));var i=Lf(),a=z(i),o=z(a);{let e=P(()=>t.openingSessionId===G(n).id);Ta(o,{compact:!0,full:!0,get disabled(){return G(e)},onclick:()=>t.onopen(G(n).id),children:(e,r)=>{He();var i=Vr();H(()=>Y(i,t.openingSessionId===G(n).id?`Opening…`:`Open`)),J(e,i)},$$slots:{default:!0}})}var s=V(o,2),c=e=>{Ta(e,{compact:!0,full:!0,onclick:()=>t.oncopyresume(G(n).resumeCommand),children:(e,t)=>{He(),J(e,Vr(`Copy`))},$$slots:{default:!0}})};X(s,e=>{G(n).resumeCommand&&G(n).provider!==`kimi`&&e(c)}),Ta(V(s,2),{compact:!0,full:!0,onclick:()=>t.onforget(G(n).id),children:(e,t)=>{He(),J(e,Vr(`Forget`))},$$slots:{default:!0}}),N(a);var l=V(a,2),u=z(l),d=e=>{var t=kf(),n=z(t,!0);N(t),H((e,r)=>{Q(t,`datetime`,e),Y(n,r)},[()=>new Date(G(r).updatedAt).toISOString(),()=>bf(G(r).updatedAt)]),J(e,t)},f=e=>{var t=Af(),n=z(t,!0);N(t),H(e=>Y(n,e),[()=>bf(null)]),J(e,t)};X(u,e=>{G(r).updatedAt===null?e(f,-1):e(d)});var p=V(u,2),m=z(p,!0);N(p);var h=V(p,2),g=e=>{var t=jf(),r=z(t);N(t),H(()=>Y(r,`Model: ${G(n).model??``}`)),J(e,t)};X(h,e=>{G(n).model&&e(g)});var _=V(h,2),v=e=>{J(e,Mf())};X(_,e=>{G(n).provider===`kimi`&&e(v)});var y=V(_,2),b=e=>{var t=jf(),r=z(t);N(t),H(()=>Y(r,`Branch: ${G(n).branch??``}`)),J(e,t)};X(y,e=>{G(n).branch&&e(b)});var x=V(y,2),S=e=>{var t=jf(),r=z(t);N(t),H(()=>Y(r,`Skills profile: ${G(n).effectiveSkillSelection.selectedProfileName??``}`)),J(e,t)};X(x,e=>{G(n).effectiveSkillSelection?.selectedProfileName&&e(S)}),N(l),N(i),H(e=>Y(m,e),[()=>Cf(G(r).workspacePath)]),J(e,i)}),N(n),J(e,n)},E=e=>{J(e,zf())};X(w,e=>{G(_).length?e(T):G(g).length||e(E,1)});var D=V(w,2),ee=z(D),te=z(ee),ne=V(z(te),2),re=z(ne);N(ne),N(te);var ie=V(te,2);{let e=P(()=>G(y)?.id??null);bu(ie,{get roots(){return t.workspaceTree},get expandedIds(){return t.expandedIds},get selectedId(){return G(e)},get isSelectable(){return su.sessionBase},label:`Session base`,get onexpandedchange(){return t.onexpandedchange},onselect:e=>t.onworkspacechange(e.id)})}N(ee);var O=V(ee,2),k=z(O);let ae;var A=V(z(k),2),oe=e=>{var t=Bf();He(2),J(e,t)};X(A,e=>{c()!==`kimi`&&e(oe)}),N(k);var se=V(k,2);let ce;var le=z(se),ue=z(le);ue.value=ue.__value=``,Z(V(ue),17,()=>t.skillProfiles,e=>e.name,(e,t)=>{var n=Vf(),r=z(n,!0);N(n);var i={};H(()=>{Y(r,G(t).name),i!==(i=G(t).name)&&(n.value=(n.__value=G(t).name)??``)}),J(e,n)}),N(le);var de;bi(le);var fe=V(le,2),pe=e=>{var n=Hf(),r=B(n),i=z(r);i.value=i.__value=`workspace-git`;var a=V(i);a.value=a.__value=`workspace-write`;var o=V(a);o.value=o.__value=`read-only`;var s=V(o);s.value=s.__value=`danger-full-access`,N(r);var c;bi(r);var l=V(r,2),u=z(l);u.value=u.__value=`untrusted`;var d=V(u);d.value=d.__value=`on-request`;var f=V(d);f.value=f.__value=`never`,N(l);var p;bi(l),H(()=>{c!==(c=t.sandbox)&&(r.value=(r.__value=t.sandbox)??``,yi(r,t.sandbox)),p!==(p=t.approvalPolicy)&&(l.value=(l.__value=t.approvalPolicy)??``,yi(l,t.approvalPolicy))}),K(`change`,r,e=>t.onsandboxchange(e.currentTarget.value)),K(`change`,l,e=>t.onapprovalpolicychange(e.currentTarget.value)),J(e,n)};X(fe,e=>{c()!==`kimi`&&e(pe)}),N(se);var me=V(se,2),he=e=>{var t=Uf(),n=z(t);N(t),H(()=>Y(n,`This controls when ${G(b)??``} asks; it does not expand the sandbox's technical permissions.`)),J(e,t)};X(me,e=>{c()!==`kimi`&&e(he)});var ge=V(me,2),_e=e=>{var n=Wf(),r=z(n,!0);N(n),H(()=>Y(r,t.skillProfileError)),J(e,n)};X(ge,e=>{t.skillProfileError&&e(_e)});var ve=V(ge,2),ye=z(ve);Ta(ye,{id:`manage-skill-profiles`,onclick:e=>t.onmanageprofiles(e.currentTarget),children:(e,t)=>{He(),J(e,Vr(`Manage skill profiles`))},$$slots:{default:!0}});var be=V(ye,2),xe=V(z(be),2),Se=z(xe);Se.value=Se.__value=`codex`;var Ce=V(Se),we=z(Ce);N(Ce),Ce.value=Ce.__value=`kimi`,N(xe);var Te;bi(xe),N(be);var Ee=V(be,2),De=z(Ee),Oe=z(De);N(De);var ke=V(De,2),Ae=z(ke),je=e=>{var t=Gf();t.value=t.__value=``,J(e,t)},Me=e=>{var t=Kf();t.value=t.__value=``,J(e,t)};X(Ae,e=>{u()?e(je):o().length===0&&e(Me,1)}),Z(V(Ae),16,o,e=>e,(e,t)=>{var n=Vf(),r=z(n,!0);N(n);var i={};H(()=>{Y(r,t),i!==(i=t)&&(n.value=(n.__value=t)??``)}),J(e,n)}),N(ke);var Ne;bi(ke),N(Ee);var Pe=V(Ee,2);{let e=P(()=>!G(y)||t.startingSession||u()||o().length>0&&!s());Ta(Pe,{class:`new-session-button`,type:`submit`,primary:!0,get disabled(){return G(e)},children:(e,n)=>{He();var r=Vr();H(()=>Y(r,t.startingSession?`Creating…`:`Create session`)),J(e,r)},$$slots:{default:!0}})}N(ve);var Fe=V(ve,2),Ie=e=>{J(e,qf())};X(Fe,e=>{l()||e(Ie)}),N(O),N(D);var Le=V(D,2),Re=V(z(Le),2),j=e=>{var n=Yf();Z(n,21,()=>G(v),e=>(e.provider??`codex`)+`:`+e.id,(e,n)=>{var r=Jf(),i=z(r),a=z(i),o=e=>{var t=kf(),r=z(t,!0);N(t),H((e,n)=>{Q(t,`datetime`,e),Y(r,n)},[()=>new Date(G(n).recencyAt*1e3).toISOString(),()=>bf(G(n).recencyAt*1e3)]),J(e,t)},s=e=>{var t=Af(),n=z(t,!0);N(t),H(e=>Y(n,e),[()=>bf(null)]),J(e,t)};X(a,e=>{G(n).recencyAt===null?e(s,-1):e(o)});var c=V(a,2),l=z(c,!0);N(c);var u=V(c,2),d=e=>{var t=jf(),r=z(t);N(t),H(()=>Y(r,`Model: ${G(n).model??``}`)),J(e,t)};X(u,e=>{G(n).model&&e(d)});var f=V(u,2),p=e=>{J(e,Mf())};X(f,e=>{G(n).provider===`kimi`&&e(p)});var m=V(f,2),h=e=>{var t=jf(),r=z(t);N(t),H(()=>Y(r,`Skills profile: ${G(n).skillProfile??``}`)),J(e,t)};X(m,e=>{G(n).skillProfile&&e(h)});var g=V(m,2),_=e=>{var t=jf(),r=z(t);N(t),H(()=>Y(r,`Org plan: ${G(n).orgPlanFilename??``}`)),J(e,t)};X(g,e=>{G(n).orgPlanFilename&&e(_)}),N(i);var v=V(i,2),y=z(v);Ta(y,{onclick:()=>t.onopenrecent(G(n)),children:(e,t)=>{He(),J(e,Vr(`Open`))},$$slots:{default:!0}});var b=V(y,2),x=e=>{Ta(e,{onclick:()=>t.oncopyresume(G(n).resumeCommand),children:(e,t)=>{He(),J(e,Vr(`Copy`))},$$slots:{default:!0}})};X(b,e=>{G(n).resumeCommand&&e(x)}),N(v),N(r),H(e=>Y(l,e),[()=>Cf(G(n).cwd)]),J(e,r)}),N(n),J(e,n)},ze=e=>{J(e,Xf())};X(Re,e=>{G(v).length?e(j):e(ze,-1)}),N(Le),N(x),H(()=>{Y(re,`Select the folder or repository ${G(b)??``} should use as its working directory.`),ae=vi(k,``,ae,{"grid-template-columns":c()===`kimi`?`minmax(0, 1fr)`:`repeat(3, minmax(0, 1fr))`}),ce=vi(se,``,ce,{"grid-template-columns":c()===`kimi`?`minmax(0, 1fr)`:`repeat(3, minmax(0, 1fr))`}),de!==(de=t.selectedSkillProfile)&&(le.value=(le.__value=t.selectedSkillProfile)??``,yi(le,t.selectedSkillProfile)),Q(xe,`aria-describedby`,l()?void 0:`provider-availability`),Ce.disabled=!l(),Y(we,`Kimi${l()?``:` (unavailable)`}`),Te!==(Te=c())&&(xe.value=(xe.__value=c())??``,yi(xe,c())),Y(Oe,`${G(b)??``} model`),ke.disabled=u()||o().length===0,Ne!==(Ne=s())&&(ke.value=(ke.__value=s())??``,yi(ke,s()))}),Nr(`submit`,D,e=>{e.preventDefault(),t.onstart()}),K(`change`,le,e=>t.onskillprofilechange(e.currentTarget.value)),K(`change`,xe,e=>f()(e.currentTarget.value)),K(`change`,ke,e=>d()(e.currentTarget.value)),J(e,x),$e()}Pr([`change`]);function $f(e){let t={};return e.workspaceId||(t.workspaceId=`Choose a workspace.`),e.profile||(t.profile=`Choose a profile.`),e.profile&&e.profileState&&e.profileState!==`ok`&&(t.profile=`Sign in to this profile before starting Codex.`),t}var ep=class{transport;key;onChange;#e={starting:!1,error:null};#t=0;#n=!1;#r=null;constructor(e,t,n){this.transport=e,this.key=t,this.onChange=n}get state(){return this.#e}async start(e,t){if(this.#n||this.#e.starting||!e)return null;let n=++this.#t;this.#a({starting:!0,error:null});let r=this.#r??=this.key();try{let i=await this.transport.start(e,t,r);return this.#i(n)&&(this.#r=null),this.#i(n)?i:null}catch(e){return this.#i(n)&&this.#a({starting:!1,error:e instanceof Error?e.message:`Could not start session.`}),null}finally{this.#i(n)&&this.#a({...this.#e,starting:!1})}}dispose(){this.#n=!0,++this.#t}#i(e){return!this.#n&&e===this.#t}#a(e){this.#n||(this.#e=e,this.onChange(e))}};function tp({chatEnabled:e}){return[`sessions`,`git`,...e?[`chat`]:[],`plan`]}function np(e,t,n={chatEnabled:!0}){let r=tp(n);return r[(r.indexOf(e)+t+r.length)%r.length]}var rp=q(`<nav class="bottom-navigation" aria-label="Primary"><button>Sessions</button> <button>Git</button> <button>Chat</button> <button>Plan</button></nav>`);function ip(e,t){Qe(t,!0);let n=$(t,`focusTab`,3,null),r=R({});Mn(()=>{n()&&r[n()]?.focus()});function i(e){let n=e.key===`ArrowRight`?1:e.key===`ArrowLeft`?-1:null;if(n===null)return;e.preventDefault();let i=np(t.activeTab,n,{chatEnabled:t.chatEnabled});t.onselect(i),r[i]?.focus()}var a=rp(),o=z(a);Li(o,e=>r.sessions=e,()=>r?.sessions);var s=V(o,2);Li(s,e=>r.git=e,()=>r?.git);var c=V(s,2);Li(c,e=>r.chat=e,()=>r?.chat);var l=V(c,2);Li(l,e=>r.plan=e,()=>r?.plan),N(a),H(()=>{Q(o,`aria-pressed`,t.activeTab===`sessions`),Q(s,`aria-pressed`,t.activeTab===`git`),Q(c,`aria-pressed`,t.activeTab===`chat`),c.disabled=!t.chatEnabled,Q(l,`aria-pressed`,t.activeTab===`plan`)}),K(`keydown`,o,i),K(`click`,o,()=>t.onselect(`sessions`)),K(`keydown`,s,i),K(`click`,s,()=>t.onselect(`git`)),K(`keydown`,c,i),K(`click`,c,()=>t.onselect(`chat`)),K(`keydown`,l,i),K(`click`,l,()=>t.onselect(`plan`)),J(e,a),$e()}Pr([`keydown`,`click`]);var ap=q(`<option> </option>`),op=q(`<p id="skills-status" aria-live="polite">Loading skills…</p>`),sp=q(`<p id="skills-status">No skills were discovered for this workspace and Codex profile.</p>`),cp=q(`<p id="skills-status" class="notice svelte-dg6sjj" role="status"> </p>`),lp=q(`<p id="skills-status" class="error svelte-dg6sjj" role="alert"> </p>`),up=q(`<p id="skills-status" class="error svelte-dg6sjj" role="alert" tabindex="-1"> </p>`),dp=q(`<p id="skills-status" role="status">Profile saved.</p>`),fp=q(`<p id="skills-status" role="status">Profile deleted.</p>`),pp=q(`<li class="svelte-dg6sjj"><div class="svelte-dg6sjj"><strong> </strong> <span class="missing-state svelte-dg6sjj">Missing · disabled</span> <span class="path svelte-dg6sjj"> </span></div> <button type="button" class="remove-missing svelte-dg6sjj">Remove</button></li>`),mp=q(`<section class="missing-skills svelte-dg6sjj" aria-labelledby="missing-skills-title"><h3 id="missing-skills-title" class="svelte-dg6sjj">Missing skills</h3> <p class="svelte-dg6sjj">These saved paths no longer exist. They are disabled for new sessions until restored or
|
package/dist/client/index.html
CHANGED
|
@@ -16,7 +16,7 @@ SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
16
16
|
<link rel="icon" href="/icons/gestalt-mobile-192.png" />
|
|
17
17
|
<link rel="apple-touch-icon" href="/icons/gestalt-mobile-180.png" />
|
|
18
18
|
<title>Gestalt Mobile</title>
|
|
19
|
-
<script type="module" crossorigin src="/assets/index-
|
|
19
|
+
<script type="module" crossorigin src="/assets/index-9uZwieND.js"></script>
|
|
20
20
|
<link rel="stylesheet" crossorigin href="/assets/index-D57mr3B1.css">
|
|
21
21
|
</head>
|
|
22
22
|
<body>
|
|
@@ -19,7 +19,7 @@ import { authorizationSessionId, authorizedDeviceId, localOwnerId, webAuthnCrede
|
|
|
19
19
|
import { deviceNickname } from './features/auth/domain/device-nickname.js';
|
|
20
20
|
import { workspaceId } from './platform/catalog/workspace-id.js';
|
|
21
21
|
import { planStatusDirectoryPath, planStatusFilePath, } from './platform/plans/filesystem-plan-status-source.js';
|
|
22
|
-
import { toOrgPlanAttentionToolResponse } from '../shared/contracts/org-plan-attention.js';
|
|
22
|
+
import { toOrgPlanAttentionAcknowledgement, toOrgPlanAttentionToolResponse, } from '../shared/contracts/org-plan-attention.js';
|
|
23
23
|
import { toOrgPlanCheckpointToolResponse } from '../shared/contracts/org-plan-checkpoint.js';
|
|
24
24
|
import { applyProjectionEvent, createChatProjection, } from '../client/features/chat/chat-projection.js';
|
|
25
25
|
function fakeAppServer(calls) {
|
|
@@ -153,6 +153,25 @@ const autopilotPlanText = (childState = 'TODO') => `#+TITLE: Autopilot fixture
|
|
|
153
153
|
const completedAutopilotPlanText = () => autopilotPlanText('DONE')
|
|
154
154
|
.replace('* WIP [#A] Parent', '* DONE [#A] Parent')
|
|
155
155
|
.replace(':REVIEW_STATUS: UNREVIEWED', ':REVIEW_STATUS: REVIEWED');
|
|
156
|
+
const acceptedL1WithNextTodoPlanText = () => `${completedAutopilotPlanText()}
|
|
157
|
+
* TODO [#B] Next parent
|
|
158
|
+
:PROPERTIES:
|
|
159
|
+
:ID: next-parent
|
|
160
|
+
:SKILLS: $gestalt:org-plan
|
|
161
|
+
:REVIEW_STATUS: UNREVIEWED
|
|
162
|
+
:END:
|
|
163
|
+
- Effort :: Small
|
|
164
|
+
- Goal :: Continue on the next root turn.
|
|
165
|
+
- Notes :: Must remain pending at the accepted-L1 boundary.
|
|
166
|
+
** TODO [#B] Next child
|
|
167
|
+
:PROPERTIES:
|
|
168
|
+
:ID: next-child
|
|
169
|
+
:END:
|
|
170
|
+
- Why :: Verify boundary separation.
|
|
171
|
+
- Change :: Start only after durable handoff.
|
|
172
|
+
- Tests :: Exercise the next continuation.
|
|
173
|
+
- Done when :: The next L1 starts exactly once.
|
|
174
|
+
`;
|
|
156
175
|
async function installAutopilotPlan(app, sessionId, workspacePath, name, childState = 'TODO', reason = 'supervision-start') {
|
|
157
176
|
const planPath = join(workspacePath, `${name}.org`);
|
|
158
177
|
await writeFile(planPath, autopilotPlanText(childState));
|
|
@@ -958,6 +977,83 @@ describe('production composition', () => {
|
|
|
958
977
|
expect(checkpoint.count).toBe(1);
|
|
959
978
|
await fixture.app.close();
|
|
960
979
|
});
|
|
980
|
+
it('records and idempotently replays accepted L1 after REVIEWED advances to the next TODO L1', async () => {
|
|
981
|
+
const timers = [];
|
|
982
|
+
const fixture = await createProductionAutopilotFixture({
|
|
983
|
+
autopilotSchedule: (callback) => {
|
|
984
|
+
const timer = { callback, cancelled: false, fired: false };
|
|
985
|
+
timers.push(timer);
|
|
986
|
+
return () => {
|
|
987
|
+
timer.cancelled = true;
|
|
988
|
+
};
|
|
989
|
+
},
|
|
990
|
+
});
|
|
991
|
+
const initial = timers.find((timer) => !timer.cancelled && !timer.fired);
|
|
992
|
+
initial.fired = true;
|
|
993
|
+
initial.callback();
|
|
994
|
+
await vi.waitFor(() => expect(fixture.handles.flatMap((candidate) => candidate.requests.filter((request) => request.method === 'turn/start'))).toHaveLength(1));
|
|
995
|
+
const handle = fixture.handles.find((candidate) => candidate.request);
|
|
996
|
+
const session = (await fixture.app.inject(`/api/sessions/${fixture.sessionId}`)).json();
|
|
997
|
+
const threadId = session.threadId;
|
|
998
|
+
const turnId = session.activeTurnId;
|
|
999
|
+
await writeFile(join(fixture.workspacePath, 'autopilot.org'), acceptedL1WithNextTodoPlanText());
|
|
1000
|
+
await expect
|
|
1001
|
+
.poll(async () => (await fixture.app.inject(`/api/sessions/${fixture.sessionId}/plan`)).json()
|
|
1002
|
+
.currentStepId)
|
|
1003
|
+
.toBe('next-parent');
|
|
1004
|
+
handle.deferResponseSettlement = true;
|
|
1005
|
+
const checkpointCall = (id) => ({
|
|
1006
|
+
id,
|
|
1007
|
+
method: 'item/tool/call',
|
|
1008
|
+
params: {
|
|
1009
|
+
threadId,
|
|
1010
|
+
turnId,
|
|
1011
|
+
tool: 'gestalt_org_plan_checkpoint',
|
|
1012
|
+
arguments: { kind: 'l1Accepted' },
|
|
1013
|
+
},
|
|
1014
|
+
});
|
|
1015
|
+
const startsBefore = fixture.handles
|
|
1016
|
+
.flatMap((candidate) => candidate.requests)
|
|
1017
|
+
.filter((request) => request.method === 'turn/start').length;
|
|
1018
|
+
const first = handle.request(checkpointCall(813));
|
|
1019
|
+
await vi.waitFor(() => expect(handle.pendingResponses.has(813)).toBe(true));
|
|
1020
|
+
handle.responseSettled({ id: 813, outcome: 'resultWritten' });
|
|
1021
|
+
await expect(first).resolves.toEqual(toOrgPlanCheckpointToolResponse('recorded'));
|
|
1022
|
+
const replay = handle.request(checkpointCall(814));
|
|
1023
|
+
await vi.waitFor(() => expect(handle.pendingResponses.has(814)).toBe(true));
|
|
1024
|
+
handle.responseSettled({ id: 814, outcome: 'resultWritten' });
|
|
1025
|
+
await expect(replay).resolves.toEqual(toOrgPlanCheckpointToolResponse('alreadyRecorded'));
|
|
1026
|
+
const database = new DatabaseSync(join(fixture.dataDir, 'relay.sqlite'));
|
|
1027
|
+
const acceptedEvents = database
|
|
1028
|
+
.prepare("SELECT count(*) AS count FROM session_events WHERE session_id = ? AND type = 'org-plan.milestone-checkpointed'")
|
|
1029
|
+
.get(fixture.sessionId);
|
|
1030
|
+
const pendingInteractions = database
|
|
1031
|
+
.prepare('SELECT count(*) AS count FROM pending_interactions WHERE session_id = ? AND resolved_at IS NULL')
|
|
1032
|
+
.get(fixture.sessionId);
|
|
1033
|
+
database.close();
|
|
1034
|
+
expect(acceptedEvents.count).toBe(1);
|
|
1035
|
+
expect(pendingInteractions.count).toBe(0);
|
|
1036
|
+
expect(fixture.handles
|
|
1037
|
+
.flatMap((candidate) => candidate.requests)
|
|
1038
|
+
.filter((request) => request.method === 'turn/start')).toHaveLength(startsBefore);
|
|
1039
|
+
handle.notify({ method: 'turn/completed', params: { threadId, turn: { id: turnId } } });
|
|
1040
|
+
await expect
|
|
1041
|
+
.poll(async () => (await fixture.app.inject(`/api/sessions/${fixture.sessionId}`)).json().activeTurnId)
|
|
1042
|
+
.toBeNull();
|
|
1043
|
+
const startedTurns = () => fixture.handles
|
|
1044
|
+
.flatMap((candidate) => candidate.requests)
|
|
1045
|
+
.filter((request) => request.method === 'turn/start').length;
|
|
1046
|
+
for (let attempts = 0; attempts < 3 && startedTurns() === startsBefore; attempts += 1) {
|
|
1047
|
+
await vi.waitFor(() => expect(timers.find((timer) => !timer.cancelled && !timer.fired)).toBeDefined());
|
|
1048
|
+
const continuation = timers.find((timer) => !timer.cancelled && !timer.fired);
|
|
1049
|
+
continuation.fired = true;
|
|
1050
|
+
continuation.callback();
|
|
1051
|
+
await vi.waitFor(() => expect(startedTurns() > startsBefore ||
|
|
1052
|
+
timers.some((timer) => !timer.cancelled && !timer.fired)).toBe(true));
|
|
1053
|
+
}
|
|
1054
|
+
await vi.waitFor(() => expect(startedTurns()).toBe(startsBefore + 1));
|
|
1055
|
+
await fixture.app.close();
|
|
1056
|
+
});
|
|
961
1057
|
it('returns a typed failed checkpoint result when persistence never occurs', async () => {
|
|
962
1058
|
let coordinator;
|
|
963
1059
|
const timers = [];
|
|
@@ -980,7 +1076,13 @@ describe('production composition', () => {
|
|
|
980
1076
|
const { handle, response, startsBefore, writersBefore } = await holdCheckpointRequest(fixture, timers, 995, false);
|
|
981
1077
|
await vi.waitFor(() => expect(handle.pendingResponses.has(995)).toBe(true));
|
|
982
1078
|
handle.responseSettled({ id: 995, outcome: 'resultWritten' });
|
|
983
|
-
await
|
|
1079
|
+
const failure = (await response);
|
|
1080
|
+
expect(failure.success).toBe(false);
|
|
1081
|
+
expect(JSON.parse(failure.contentItems[0].text)).toMatchObject({
|
|
1082
|
+
status: 'failed',
|
|
1083
|
+
reasonCode: 'checkpointPersistenceFailed',
|
|
1084
|
+
correlationId: expect.any(String),
|
|
1085
|
+
});
|
|
984
1086
|
expect(coordinator.checkpointAccepted).not.toBe(original);
|
|
985
1087
|
expect(fixture.handles).toHaveLength(writersBefore);
|
|
986
1088
|
expect(fixture.handles
|
|
@@ -1340,7 +1442,13 @@ describe('production composition', () => {
|
|
|
1340
1442
|
const planIdentity = createHash('sha256')
|
|
1341
1443
|
.update(join(fixture.workspacePath, 'autopilot.org'))
|
|
1342
1444
|
.digest('hex');
|
|
1343
|
-
await
|
|
1445
|
+
const rejected = (await handle.request(l2CheckpointCall(812, threadId, active.active_turn_id, planIdentity)));
|
|
1446
|
+
expect(rejected.success).toBe(false);
|
|
1447
|
+
expect(JSON.parse(rejected.contentItems[0].text)).toMatchObject({
|
|
1448
|
+
status: 'failed',
|
|
1449
|
+
reasonCode: 'rootNotOwner',
|
|
1450
|
+
correlationId: expect.any(String),
|
|
1451
|
+
});
|
|
1344
1452
|
expect(timers).toHaveLength(timersAfterFinal);
|
|
1345
1453
|
expect(fixture.handles
|
|
1346
1454
|
.flatMap((candidate) => candidate.requests)
|
|
@@ -1356,6 +1464,7 @@ describe('production composition', () => {
|
|
|
1356
1464
|
payload: { enabled: true },
|
|
1357
1465
|
})).statusCode).toBe(200);
|
|
1358
1466
|
const attention = handle.request(attentionCall(810));
|
|
1467
|
+
await expect(attention).resolves.toEqual(toOrgPlanAttentionAcknowledgement());
|
|
1359
1468
|
await vi.waitFor(async () => expect((await fixture.app.inject(`/api/sessions/${fixture.sessionId}`)).json()).toMatchObject({
|
|
1360
1469
|
autopilot: { state: 'attentionRequired', enabled: false, reason: 'attentionRequired' },
|
|
1361
1470
|
}));
|
|
@@ -1365,7 +1474,6 @@ describe('production composition', () => {
|
|
|
1365
1474
|
url: `/api/sessions/${fixture.sessionId}/attention/810/resolve`,
|
|
1366
1475
|
payload: { operationKey: 'resume-attention', action: 'resume' },
|
|
1367
1476
|
})).statusCode).toBe(202);
|
|
1368
|
-
await expect(attention).resolves.toEqual(toOrgPlanAttentionToolResponse({ action: 'resume' }));
|
|
1369
1477
|
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
1370
1478
|
expect((await fixture.app.inject(`/api/sessions/${fixture.sessionId}`)).json()).toMatchObject({
|
|
1371
1479
|
autopilot: { state: 'attentionRequired', enabled: false },
|
|
@@ -1959,6 +2067,56 @@ describe('production composition', () => {
|
|
|
1959
2067
|
});
|
|
1960
2068
|
});
|
|
1961
2069
|
describeCompositionConcern('attention', () => {
|
|
2070
|
+
it('bounds a wedged attention acknowledgement writer without losing durable attention', async () => {
|
|
2071
|
+
const fixture = await createProductionAutopilotFixture({
|
|
2072
|
+
attentionAcknowledgementDeadlineMs: 100,
|
|
2073
|
+
});
|
|
2074
|
+
const handle = fixture.handles.find((candidate) => candidate.request);
|
|
2075
|
+
handle.deferResponseSettlement = true;
|
|
2076
|
+
const response = handle.request(attentionCall(699));
|
|
2077
|
+
const rejected = expect(response).rejects.toThrow('CODEX_SERVER_REQUEST_CANCELLED');
|
|
2078
|
+
await vi.waitFor(() => expect(handle.pendingResponses.has(699)).toBe(true));
|
|
2079
|
+
await rejected;
|
|
2080
|
+
expect((await fixture.app.inject(`/api/sessions/${fixture.sessionId}/attention`)).json()).toMatchObject({ requestId: '699', attention: { reason: 'hardBlock' } });
|
|
2081
|
+
await fixture.app.close();
|
|
2082
|
+
});
|
|
2083
|
+
it('returns a bounded failure when durable attention persistence fails', async () => {
|
|
2084
|
+
const root = await mkdtemp(join(tmpdir(), 'gestalt-mobile-root-'));
|
|
2085
|
+
const dataDir = await mkdtemp(join(tmpdir(), 'gestalt-mobile-state-'));
|
|
2086
|
+
ownTemporaryPaths(root, dataDir);
|
|
2087
|
+
await mkdir(join(root, 'workspace'));
|
|
2088
|
+
const handles = [];
|
|
2089
|
+
const app = await composeAuthorizedApp({
|
|
2090
|
+
root,
|
|
2091
|
+
dataDir,
|
|
2092
|
+
relyingParty,
|
|
2093
|
+
installedCodexVersion: 'codex-cli 0.144.3',
|
|
2094
|
+
startAppServers: true,
|
|
2095
|
+
launchAppServer: liveAppServer(handles),
|
|
2096
|
+
profiles: {
|
|
2097
|
+
list: async () => [],
|
|
2098
|
+
require: async () => ({
|
|
2099
|
+
name: 'default',
|
|
2100
|
+
state: 'ok',
|
|
2101
|
+
status: 'ready',
|
|
2102
|
+
}),
|
|
2103
|
+
},
|
|
2104
|
+
});
|
|
2105
|
+
await createComposedSession(app);
|
|
2106
|
+
const handle = await vi.waitFor(() => {
|
|
2107
|
+
const candidate = handles.find((item) => item.request);
|
|
2108
|
+
expect(candidate).toBeDefined();
|
|
2109
|
+
return candidate;
|
|
2110
|
+
});
|
|
2111
|
+
const database = new DatabaseSync(join(dataDir, 'relay.sqlite'));
|
|
2112
|
+
database.exec(`CREATE TRIGGER reject_attention_insert
|
|
2113
|
+
BEFORE INSERT ON pending_interactions
|
|
2114
|
+
WHEN NEW.kind = 'orgPlanAttention'
|
|
2115
|
+
BEGIN SELECT RAISE(ABORT, 'injected attention persistence failure'); END`);
|
|
2116
|
+
database.close();
|
|
2117
|
+
await expect(handle.request(attentionCall(700))).resolves.toEqual(toOrgPlanAttentionAcknowledgement({ accepted: false, reason: 'persistenceFailed' }));
|
|
2118
|
+
await app.close();
|
|
2119
|
+
});
|
|
1962
2120
|
it('publishes isolated typed required, resolved, and failed attention transitions through the feature-only seam', async () => {
|
|
1963
2121
|
const root = await mkdtemp(join(tmpdir(), 'gestalt-mobile-root-'));
|
|
1964
2122
|
const dataDir = await mkdtemp(join(tmpdir(), 'gestalt-mobile-state-'));
|
|
@@ -2004,6 +2162,7 @@ describe('production composition', () => {
|
|
|
2004
2162
|
const unsubscribeA = transitions.subscribe(sessionA, (event) => receivedA.push(event));
|
|
2005
2163
|
const unsubscribeB = transitions.subscribe(sessionB, (event) => receivedB.push(event));
|
|
2006
2164
|
const resolving = handleA.request(attentionCall(701));
|
|
2165
|
+
await expect(resolving).resolves.toEqual(toOrgPlanAttentionAcknowledgement());
|
|
2007
2166
|
await vi.waitFor(() => expect(receivedA).toEqual([
|
|
2008
2167
|
expect.objectContaining({ kind: 'required', requestId: '701' }),
|
|
2009
2168
|
]));
|
|
@@ -2013,12 +2172,12 @@ describe('production composition', () => {
|
|
|
2013
2172
|
url: `/api/sessions/${sessionA}/attention/701/resolve`,
|
|
2014
2173
|
payload: { operationKey: 'resolve-a', action: 'resume' },
|
|
2015
2174
|
})).statusCode).toBe(202);
|
|
2016
|
-
await expect(resolving).resolves.toEqual(toOrgPlanAttentionToolResponse({ action: 'resume' }));
|
|
2017
2175
|
await vi.waitFor(() => expect(receivedA).toEqual([
|
|
2018
2176
|
expect.objectContaining({ kind: 'required', requestId: '701' }),
|
|
2019
2177
|
expect.objectContaining({ kind: 'resolved', requestId: '701' }),
|
|
2020
2178
|
]));
|
|
2021
2179
|
const failing = handleB.request(attentionCall(702, 'permissionRequired'));
|
|
2180
|
+
await expect(failing).resolves.toEqual(toOrgPlanAttentionAcknowledgement());
|
|
2022
2181
|
await vi.waitFor(() => expect(receivedB).toEqual([
|
|
2023
2182
|
expect.objectContaining({ kind: 'required', requestId: '702' }),
|
|
2024
2183
|
]));
|
|
@@ -2026,13 +2185,10 @@ describe('production composition', () => {
|
|
|
2026
2185
|
method: 'serverRequest/resolved',
|
|
2027
2186
|
params: { threadId: 'thread-ignored', requestId: 702 },
|
|
2028
2187
|
});
|
|
2029
|
-
|
|
2030
|
-
await vi.waitFor(() => expect(receivedB).toEqual([
|
|
2031
|
-
expect.objectContaining({ kind: 'required', requestId: '702' }),
|
|
2032
|
-
expect.objectContaining({ kind: 'failed', requestId: '702' }),
|
|
2033
|
-
]));
|
|
2188
|
+
expect(receivedB).toEqual([expect.objectContaining({ kind: 'required', requestId: '702' })]);
|
|
2034
2189
|
unsubscribeA();
|
|
2035
2190
|
const afterUnsubscribe = handleA.request(attentionCall(703));
|
|
2191
|
+
await expect(afterUnsubscribe).resolves.toEqual(toOrgPlanAttentionAcknowledgement());
|
|
2036
2192
|
await vi.waitFor(async () => expect((await app.inject(`/api/sessions/${sessionA}/attention`)).json()).toMatchObject({
|
|
2037
2193
|
requestId: '703',
|
|
2038
2194
|
}));
|
|
@@ -2041,9 +2197,6 @@ describe('production composition', () => {
|
|
|
2041
2197
|
method: 'serverRequest/resolved',
|
|
2042
2198
|
params: { threadId: 'thread-ignored', requestId: 703 },
|
|
2043
2199
|
});
|
|
2044
|
-
await expect(afterUnsubscribe).rejects.toMatchObject({
|
|
2045
|
-
message: 'CODEX_SERVER_REQUEST_CLEARED',
|
|
2046
|
-
});
|
|
2047
2200
|
expect(receivedA).toHaveLength(2);
|
|
2048
2201
|
unsubscribeB();
|
|
2049
2202
|
await app.close();
|
|
@@ -2074,6 +2227,7 @@ describe('production composition', () => {
|
|
|
2074
2227
|
await vi.waitFor(() => expect(handles.find((handle) => handle.request)?.request).toBeDefined());
|
|
2075
2228
|
const handle = handles.find((candidate) => candidate.calls.includes('thread/start'));
|
|
2076
2229
|
const attentionFirst = handle.request(attentionCall(711, 'permissionRequired'));
|
|
2230
|
+
await expect(attentionFirst).resolves.toEqual(toOrgPlanAttentionAcknowledgement());
|
|
2077
2231
|
const inputFirst = handle.request({
|
|
2078
2232
|
id: 712,
|
|
2079
2233
|
method: 'item/tool/requestUserInput',
|
|
@@ -2096,11 +2250,11 @@ describe('production composition', () => {
|
|
|
2096
2250
|
url: `/api/sessions/${sessionId}/attention/711/resolve`,
|
|
2097
2251
|
payload: { operationKey: 'attention-first', action: 'resume' },
|
|
2098
2252
|
});
|
|
2099
|
-
await expect(attentionFirst).resolves.toEqual(toOrgPlanAttentionToolResponse({ action: 'resume' }));
|
|
2100
2253
|
await vi.waitFor(async () => expect((await app.inject(`/api/sessions/${sessionId}`)).json()).toMatchObject({
|
|
2101
2254
|
agentActivity: { root: { state: 'working' } },
|
|
2102
2255
|
}));
|
|
2103
2256
|
const attentionSecond = handle.request(attentionCall(713));
|
|
2257
|
+
await expect(attentionSecond).resolves.toEqual(toOrgPlanAttentionAcknowledgement());
|
|
2104
2258
|
const inputSecond = handle.request({
|
|
2105
2259
|
id: 714,
|
|
2106
2260
|
method: 'item/tool/requestUserInput',
|
|
@@ -2111,7 +2265,6 @@ describe('production composition', () => {
|
|
|
2111
2265
|
url: `/api/sessions/${sessionId}/attention/713/resolve`,
|
|
2112
2266
|
payload: { operationKey: 'attention-second', action: 'resume' },
|
|
2113
2267
|
});
|
|
2114
|
-
await expect(attentionSecond).resolves.toEqual(toOrgPlanAttentionToolResponse({ action: 'resume' }));
|
|
2115
2268
|
await vi.waitFor(async () => expect((await app.inject(`/api/sessions/${sessionId}`)).json()).toMatchObject({
|
|
2116
2269
|
agentActivity: { root: { state: 'awaitingHuman', reason: 'pendingInteraction' } },
|
|
2117
2270
|
}));
|
|
@@ -2150,10 +2303,8 @@ describe('production composition', () => {
|
|
|
2150
2303
|
const handle = handles.find((candidate) => candidate.calls.includes('thread/start'));
|
|
2151
2304
|
const active = handle.request(attentionCall(801));
|
|
2152
2305
|
const terminal = handle.request(attentionCall(802));
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
guidance: 'Sensitive terminal guidance.',
|
|
2156
|
-
});
|
|
2306
|
+
await expect(active).resolves.toEqual(toOrgPlanAttentionAcknowledgement());
|
|
2307
|
+
await expect(terminal).resolves.toEqual(toOrgPlanAttentionAcknowledgement());
|
|
2157
2308
|
const accepted = await first.inject({
|
|
2158
2309
|
method: 'POST',
|
|
2159
2310
|
url: `/api/sessions/${sessionId}/attention/802/resolve`,
|
|
@@ -2164,9 +2315,7 @@ describe('production composition', () => {
|
|
|
2164
2315
|
},
|
|
2165
2316
|
});
|
|
2166
2317
|
const resolvedAt = accepted.json().resolvedAt;
|
|
2167
|
-
await expect(terminal).resolves.toEqual(terminalResponse);
|
|
2168
2318
|
await first.close();
|
|
2169
|
-
await expect(active).rejects.toMatchObject({ message: 'CODEX_SERVER_REQUEST_CANCELLED' });
|
|
2170
2319
|
const reopened = await composeAuthorizedApp({
|
|
2171
2320
|
root,
|
|
2172
2321
|
dataDir,
|
|
@@ -2205,7 +2354,7 @@ describe('production composition', () => {
|
|
|
2205
2354
|
})).json()).toEqual({ code: 'ATTENTION_OPERATION_STALE' });
|
|
2206
2355
|
await reopened.close();
|
|
2207
2356
|
});
|
|
2208
|
-
it('
|
|
2357
|
+
it('resolves acknowledged attention offline while retaining legacy writer diagnostics', async () => {
|
|
2209
2358
|
const root = await mkdtemp(join(tmpdir(), 'gestalt-mobile-root-'));
|
|
2210
2359
|
const dataDir = await mkdtemp(join(tmpdir(), 'gestalt-mobile-state-'));
|
|
2211
2360
|
ownTemporaryPaths(root, dataDir);
|
|
@@ -2230,18 +2379,17 @@ describe('production composition', () => {
|
|
|
2230
2379
|
const started = handles.filter((handle) => handle.calls.includes('thread/start'));
|
|
2231
2380
|
const supportedRequest = started[0].request(attentionCall(901));
|
|
2232
2381
|
const legacyRequest = started[1].request(attentionCall(902));
|
|
2382
|
+
await expect(supportedRequest).resolves.toEqual(toOrgPlanAttentionAcknowledgement());
|
|
2383
|
+
await expect(legacyRequest).resolves.toEqual(toOrgPlanAttentionAcknowledgement());
|
|
2233
2384
|
await vi.waitFor(async () => expect((await first.inject(`/api/sessions/${legacySession}/attention`)).statusCode).toBe(200));
|
|
2234
2385
|
await first.close();
|
|
2235
|
-
await expect(supportedRequest).rejects.toMatchObject({
|
|
2236
|
-
message: 'CODEX_SERVER_REQUEST_CANCELLED',
|
|
2237
|
-
});
|
|
2238
|
-
await expect(legacyRequest).rejects.toMatchObject({
|
|
2239
|
-
message: 'CODEX_SERVER_REQUEST_CANCELLED',
|
|
2240
|
-
});
|
|
2241
2386
|
const database = new DatabaseSync(join(dataDir, 'relay.sqlite'));
|
|
2242
2387
|
database
|
|
2243
2388
|
.prepare('UPDATE relay_sessions SET attention_tool_capability = NULL WHERE id = ?')
|
|
2244
2389
|
.run(legacySession);
|
|
2390
|
+
database
|
|
2391
|
+
.prepare("UPDATE pending_interactions SET resolution_state = 'active' WHERE session_id = ? AND request_id = '902'")
|
|
2392
|
+
.run(legacySession);
|
|
2245
2393
|
database.close();
|
|
2246
2394
|
const offline = await composeAuthorizedApp({
|
|
2247
2395
|
root,
|
|
@@ -2254,7 +2402,7 @@ describe('production composition', () => {
|
|
|
2254
2402
|
method: 'POST',
|
|
2255
2403
|
url: `/api/sessions/${supportedSession}/attention/901/resolve`,
|
|
2256
2404
|
payload: { operationKey: 'offline-supported', action: 'resume' },
|
|
2257
|
-
})).
|
|
2405
|
+
})).statusCode).toBe(202);
|
|
2258
2406
|
expect((await offline.inject({
|
|
2259
2407
|
method: 'POST',
|
|
2260
2408
|
url: `/api/sessions/${legacySession}/attention/902/resolve`,
|
|
@@ -3703,6 +3851,7 @@ describe('production composition', () => {
|
|
|
3703
3851
|
},
|
|
3704
3852
|
},
|
|
3705
3853
|
});
|
|
3854
|
+
await expect(attention).resolves.toEqual(toOrgPlanAttentionAcknowledgement());
|
|
3706
3855
|
await vi.waitFor(async () => {
|
|
3707
3856
|
expect((await app.inject(`/api/sessions/${sessionId}`)).json()).toMatchObject({
|
|
3708
3857
|
pendingInteractions: [
|
|
@@ -3747,7 +3896,6 @@ describe('production composition', () => {
|
|
|
3747
3896
|
guidance: 'The release permission is now granted.',
|
|
3748
3897
|
},
|
|
3749
3898
|
})).toMatchObject({ statusCode: 202 });
|
|
3750
|
-
expect(await attention).toEqual(attentionResponse);
|
|
3751
3899
|
expect((await app.inject({
|
|
3752
3900
|
method: 'POST',
|
|
3753
3901
|
url: `/api/sessions/${sessionId}/attention/8/resolve`,
|
|
@@ -3773,8 +3921,8 @@ describe('production composition', () => {
|
|
|
3773
3921
|
}),
|
|
3774
3922
|
]));
|
|
3775
3923
|
expect(JSON.stringify(attentionHistory)).not.toContain('The release permission is now granted.');
|
|
3776
|
-
//
|
|
3777
|
-
//
|
|
3924
|
+
// Clearing the already-acknowledged dynamic request must not erase the
|
|
3925
|
+
// durable attention record or wedge the caller.
|
|
3778
3926
|
const clearedAttention = handle.request({
|
|
3779
3927
|
id: 9,
|
|
3780
3928
|
method: 'item/tool/call',
|
|
@@ -3788,6 +3936,7 @@ describe('production composition', () => {
|
|
|
3788
3936
|
},
|
|
3789
3937
|
},
|
|
3790
3938
|
});
|
|
3939
|
+
await expect(clearedAttention).resolves.toEqual(toOrgPlanAttentionAcknowledgement());
|
|
3791
3940
|
await vi.waitFor(async () => expect((await app.inject(`/api/sessions/${sessionId}`)).json()).toMatchObject({
|
|
3792
3941
|
agentActivity: { root: { state: 'awaitingHuman' } },
|
|
3793
3942
|
}));
|
|
@@ -3795,14 +3944,11 @@ describe('production composition', () => {
|
|
|
3795
3944
|
method: 'serverRequest/resolved',
|
|
3796
3945
|
params: { threadId: 'thread-1', requestId: 9 },
|
|
3797
3946
|
});
|
|
3798
|
-
await expect(clearedAttention).rejects.toMatchObject({
|
|
3799
|
-
message: 'CODEX_SERVER_REQUEST_CLEARED',
|
|
3800
|
-
});
|
|
3801
3947
|
await vi.waitFor(async () => expect((await app.inject(`/api/sessions/${sessionId}`)).json()).toMatchObject({
|
|
3802
|
-
agentActivity: { root: { state: '
|
|
3948
|
+
agentActivity: { root: { state: 'awaitingHuman' } },
|
|
3803
3949
|
}));
|
|
3804
3950
|
expect((await app.inject(`/api/sessions/${sessionId}/history`)).json().interactions).toEqual(expect.arrayContaining([
|
|
3805
|
-
expect.objectContaining({ requestId: '9', kind: 'orgPlanAttention',
|
|
3951
|
+
expect.objectContaining({ requestId: '9', kind: 'orgPlanAttention', resolvedAt: null }),
|
|
3806
3952
|
]));
|
|
3807
3953
|
const quiz = handle.request({
|
|
3808
3954
|
id: 71,
|
|
@@ -7,6 +7,7 @@ import { createHash, randomBytes, randomUUID } from 'node:crypto';
|
|
|
7
7
|
import { existsSync } from 'node:fs';
|
|
8
8
|
import { homedir } from 'node:os';
|
|
9
9
|
import { basename, dirname, join, resolve } from 'node:path';
|
|
10
|
+
import { debuglog } from 'node:util';
|
|
10
11
|
import { buildApp } from './app.js';
|
|
11
12
|
import { FilesystemWorkspaceCatalog } from './platform/catalog/filesystem-workspace-catalog.js';
|
|
12
13
|
import { FilesystemWorkspaceFiles } from './platform/filesystem/filesystem-workspace-files.js';
|
|
@@ -48,7 +49,7 @@ import { toAgentActivityDto } from './features/agent-activity/activity-dto.js';
|
|
|
48
49
|
import { decodeAgentActivityFacts } from './platform/codex/activity-facts.js';
|
|
49
50
|
import { completedCommandId, compactOrgPlanCheckpointKind, isAgentCapacityRecoveryCall, isAutopilotWaitLeaseCall, resolvedServerRequestId, toPendingInteraction, } from './platform/codex/server-request.js';
|
|
50
51
|
import { parseOrgPlanCheckpoint, toOrgPlanCheckpointToolResponse, } from '../shared/contracts/org-plan-checkpoint.js';
|
|
51
|
-
import { resolveOrgPlanCheckpointSignal,
|
|
52
|
+
import { hasActiveL1Writer, resolveOrgPlanCheckpointSignal, validateOrgPlanCheckpoint, } from './features/org-plan-checkpoint/application/validate.js';
|
|
52
53
|
import { isValidInteractionResponse, isValidQuizInteractionResponse, } from './features/sessions/interaction/response-validator.js';
|
|
53
54
|
import { promoteRecentThread } from './features/sessions/promote-recent-thread/use-case.js';
|
|
54
55
|
import { FilesystemSkillProfileStore } from './platform/skills/filesystem-skill-profile-store.js';
|
|
@@ -65,11 +66,13 @@ import { AutopilotCoordinator } from './features/autopilot/application/service.j
|
|
|
65
66
|
import { deriveSessionStatus } from './features/sessions/session-status.js';
|
|
66
67
|
import { AUTOPILOT_CONTINUATION_PROMPT, AUTOPILOT_EXECUTOR_CONTINUATION_PROMPT, autopilotExecutorLaunchPrompt, defaultAutopilotPolicy, } from './features/autopilot/application/policy.js';
|
|
67
68
|
import { createRelyingPartyConfig } from './config.js';
|
|
68
|
-
import { parseOrgPlanAttention } from '../shared/contracts/org-plan-attention.js';
|
|
69
|
+
import { parseOrgPlanAttention, toOrgPlanAttentionAcknowledgement, } from '../shared/contracts/org-plan-attention.js';
|
|
69
70
|
import { autopilotWaitLeaseToolResponse, } from '../shared/contracts/autopilot-wait-lease.js';
|
|
70
71
|
import { agentCapacityRecoveryToolResponse } from '../shared/contracts/agent-capacity-recovery.js';
|
|
71
72
|
import { pwaIconUrl } from './features/pwa/register-routes.js';
|
|
72
73
|
const generatedProtocolVersion = 'codex-cli 0.144.3';
|
|
74
|
+
const checkpointDiagnostic = debuglog('gestalt-mobile:checkpoint');
|
|
75
|
+
const attentionDiagnostic = debuglog('gestalt-mobile:attention');
|
|
73
76
|
export async function composeRelayApp(options) {
|
|
74
77
|
const passkeyAuthEnabled = options.passkeyAuthEnabled ?? true;
|
|
75
78
|
const relyingParty = createRelyingPartyConfig(options.relyingParty.publicOrigin);
|
|
@@ -104,6 +107,7 @@ export async function composeRelayApp(options) {
|
|
|
104
107
|
const autopilotStore = new SqliteAutopilotStore(database);
|
|
105
108
|
const attentionResolutionOperations = new Map();
|
|
106
109
|
const checkpointHandoffTimers = new Map();
|
|
110
|
+
const attentionAcknowledgementTimers = new Map();
|
|
107
111
|
const checkpointHandoffRecoveries = new Set();
|
|
108
112
|
const supervisedPlans = new SupervisedPlanRegistry();
|
|
109
113
|
const planStatusSource = new FilesystemPlanStatusSource(join(dirname(databasePath), 'plans'));
|
|
@@ -471,6 +475,9 @@ export async function composeRelayApp(options) {
|
|
|
471
475
|
// request: the client can deliver them as a follow-up prompt instead.
|
|
472
476
|
if (interaction.kind === 'quiz')
|
|
473
477
|
continue;
|
|
478
|
+
if (interaction.kind === 'orgPlanAttention' &&
|
|
479
|
+
interactions.resolutionState(sessionId, interaction.requestId) === 'acknowledged')
|
|
480
|
+
continue;
|
|
474
481
|
if (interactions.resolve(sessionId, interaction.requestId, occurredAt, outcome))
|
|
475
482
|
publishInteractionResolved(sessionId, interaction.requestId, occurredAt, outcome);
|
|
476
483
|
}
|
|
@@ -551,6 +558,36 @@ export async function composeRelayApp(options) {
|
|
|
551
558
|
handle.unref?.();
|
|
552
559
|
checkpointHandoffTimers.set(key, { handle, token });
|
|
553
560
|
};
|
|
561
|
+
const cancelAttentionAcknowledgementTimer = (sessionId, requestId) => {
|
|
562
|
+
const key = checkpointTimerKey(sessionId, requestId);
|
|
563
|
+
const timer = attentionAcknowledgementTimers.get(key);
|
|
564
|
+
if (!timer)
|
|
565
|
+
return;
|
|
566
|
+
clearTimeout(timer.handle);
|
|
567
|
+
attentionAcknowledgementTimers.delete(key);
|
|
568
|
+
};
|
|
569
|
+
const armAttentionAcknowledgementDeadline = (sessionId, requestId) => {
|
|
570
|
+
cancelAttentionAcknowledgementTimer(sessionId, requestId);
|
|
571
|
+
const key = checkpointTimerKey(sessionId, requestId);
|
|
572
|
+
const token = Symbol(key);
|
|
573
|
+
const handle = setTimeout(() => {
|
|
574
|
+
if (attentionAcknowledgementTimers.get(key)?.token !== token)
|
|
575
|
+
return;
|
|
576
|
+
attentionAcknowledgementTimers.delete(key);
|
|
577
|
+
const ownedRuntime = runtime;
|
|
578
|
+
const session = sessions.find(sessionId);
|
|
579
|
+
if (!ownedRuntime || !session || !ownedRuntime.abandonServerRequest(sessionId, requestId))
|
|
580
|
+
return;
|
|
581
|
+
void ownedRuntime
|
|
582
|
+
.recycle(session, new Date().toISOString())
|
|
583
|
+
.then((recovered) => saveSession(recovered))
|
|
584
|
+
.catch(() => {
|
|
585
|
+
// The durable attention survives; normal session recovery can reacquire the writer.
|
|
586
|
+
});
|
|
587
|
+
}, options.attentionAcknowledgementDeadlineMs ?? 5_000);
|
|
588
|
+
handle.unref?.();
|
|
589
|
+
attentionAcknowledgementTimers.set(key, { handle, token });
|
|
590
|
+
};
|
|
554
591
|
const failPendingCheckpointHandoffs = (sessionId, recoverBoundary) => {
|
|
555
592
|
for (const interaction of interactions.list(sessionId)) {
|
|
556
593
|
if (interaction.kind !== 'orgPlanCheckpoint')
|
|
@@ -568,28 +605,38 @@ export async function composeRelayApp(options) {
|
|
|
568
605
|
* enters the durable store, requests human attention, and notifies autopilot.
|
|
569
606
|
* Both the codex JSON-RPC handler and the kimi polling handler land here.
|
|
570
607
|
*/
|
|
571
|
-
const acceptPendingInteraction = (sessionId, rawInteraction, session) => {
|
|
608
|
+
const acceptPendingInteraction = (sessionId, rawInteraction, session, acknowledgeAttention = false) => {
|
|
572
609
|
const interaction = {
|
|
573
610
|
...rawInteraction,
|
|
574
611
|
turnId: session.activeTurnId,
|
|
575
612
|
requestedAt: new Date().toISOString(),
|
|
576
613
|
};
|
|
577
|
-
interactions.add(sessionId, interaction);
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
614
|
+
interactions.add(sessionId, interaction, acknowledgeAttention && interaction.kind === 'orgPlanAttention' ? 'acknowledged' : 'active');
|
|
615
|
+
try {
|
|
616
|
+
activity.observe({
|
|
617
|
+
sessionId,
|
|
618
|
+
occurredAt: interaction.requestedAt,
|
|
619
|
+
kind: 'interactionPending',
|
|
620
|
+
...(interaction.kind === 'orgPlanAttention'
|
|
621
|
+
? { attentionReason: interaction.payload.reason }
|
|
622
|
+
: {}),
|
|
623
|
+
});
|
|
624
|
+
autopilot.semanticEvent(sessionId, 'interactionChanged');
|
|
625
|
+
const updated = RelaySession.rehydrate(session).requestInteraction(interaction, new Date().toISOString()).snapshot;
|
|
626
|
+
sessions.save(updated);
|
|
627
|
+
events.publish(journal.append(sessionId, 'interaction.requested', interaction, updated.updatedAt));
|
|
628
|
+
if (interaction.kind === 'orgPlanAttention')
|
|
629
|
+
events.publish(journal.append(sessionId, 'org-plan.attention-required', interaction, updated.updatedAt));
|
|
630
|
+
autopilot.evaluate(sessionId);
|
|
631
|
+
}
|
|
632
|
+
catch (error) {
|
|
633
|
+
if (!acknowledgeAttention || interaction.kind !== 'orgPlanAttention')
|
|
634
|
+
throw error;
|
|
635
|
+
attentionDiagnostic('%o', {
|
|
636
|
+
requestId: interaction.requestId,
|
|
637
|
+
reasonCode: 'postPersistenceProjectionFailed',
|
|
638
|
+
});
|
|
639
|
+
}
|
|
593
640
|
return true;
|
|
594
641
|
};
|
|
595
642
|
const acceptPlanUpdate = (sessionId, update) => {
|
|
@@ -625,7 +672,9 @@ export async function composeRelayApp(options) {
|
|
|
625
672
|
if (resolvedRequestId) {
|
|
626
673
|
const interaction = interactions.find(sessionId, resolvedRequestId);
|
|
627
674
|
const outcome = interaction?.kind === 'orgPlanAttention' ? 'failed' : 'dismissed';
|
|
628
|
-
if (interaction?.kind
|
|
675
|
+
if (!(interaction?.kind === 'orgPlanAttention' &&
|
|
676
|
+
interactions.resolutionState(sessionId, resolvedRequestId) === 'acknowledged') &&
|
|
677
|
+
interaction?.kind !== 'quiz' &&
|
|
629
678
|
interactions.resolve(sessionId, resolvedRequestId, occurredAt, outcome)) {
|
|
630
679
|
if (outcome === 'failed')
|
|
631
680
|
publishAttentionSettlement(sessionId, resolvedRequestId, occurredAt, outcome);
|
|
@@ -683,7 +732,7 @@ export async function composeRelayApp(options) {
|
|
|
683
732
|
const retained = supervisedPlans.find(sessionId);
|
|
684
733
|
const identity = supervisedPlans.identity(sessionId);
|
|
685
734
|
const checkpoint = retained && identity
|
|
686
|
-
? resolveOrgPlanCheckpointSignal(compactCheckpointKind, retained, identity)
|
|
735
|
+
? resolveOrgPlanCheckpointSignal(compactCheckpointKind, retained, identity, supervisedPlans.publicationReason(sessionId))
|
|
687
736
|
: null;
|
|
688
737
|
if (checkpoint)
|
|
689
738
|
rawInteraction = {
|
|
@@ -741,23 +790,38 @@ export async function composeRelayApp(options) {
|
|
|
741
790
|
!identity ||
|
|
742
791
|
checkpoint.planIdentity !== identity ||
|
|
743
792
|
!rootOwned)
|
|
744
|
-
return (runtime?.resolveServerRequest(sessionId, rawInteraction.requestId,
|
|
745
|
-
|
|
793
|
+
return (runtime?.resolveServerRequest(sessionId, rawInteraction.requestId, checkpointFailureResponse(!checkpoint
|
|
794
|
+
? compactCheckpointKind === 'l1Accepted'
|
|
795
|
+
? 'acceptedL1NotResolved'
|
|
796
|
+
: 'checkpointPayloadInvalid'
|
|
797
|
+
: !retained
|
|
798
|
+
? 'planProjectionUnavailable'
|
|
799
|
+
: !identity || checkpoint.planIdentity !== identity
|
|
800
|
+
? 'planIdentityMismatch'
|
|
801
|
+
: 'rootNotOwner')) === true);
|
|
802
|
+
const validation = validateOrgPlanCheckpoint({
|
|
746
803
|
checkpoint,
|
|
747
804
|
plan: retained,
|
|
748
805
|
planIdentity: identity,
|
|
749
806
|
rootOwned,
|
|
750
807
|
hasActiveL1Writer: (position) => hasActiveL1Writer(activity.snapshot(sessionId, new Date().toISOString()), position),
|
|
751
808
|
});
|
|
752
|
-
if (!valid || !session.activeTurnId)
|
|
753
|
-
return (runtime?.resolveServerRequest(sessionId, rawInteraction.requestId,
|
|
809
|
+
if (!validation.valid || !session.activeTurnId)
|
|
810
|
+
return (runtime?.resolveServerRequest(sessionId, rawInteraction.requestId, checkpointFailureResponse(validation.valid ? 'rootTurnNotActive' : validation.reasonCode, {
|
|
811
|
+
...(!validation.valid && validation.expected
|
|
812
|
+
? { expected: validation.expected }
|
|
813
|
+
: {}),
|
|
814
|
+
...(!validation.valid && validation.observed
|
|
815
|
+
? { observed: validation.observed }
|
|
816
|
+
: {}),
|
|
817
|
+
})) === true);
|
|
754
818
|
let recordStatus = 'failed';
|
|
755
819
|
try {
|
|
756
820
|
recordStatus = autopilot.checkpointAccepted(sessionId, checkpoint, session.activeTurnId, new Date().toISOString());
|
|
757
821
|
}
|
|
758
822
|
catch {
|
|
759
823
|
if (!autopilot.checkpointHandoffFailed(sessionId, session.activeTurnId))
|
|
760
|
-
return (runtime?.resolveServerRequest(sessionId, rawInteraction.requestId,
|
|
824
|
+
return (runtime?.resolveServerRequest(sessionId, rawInteraction.requestId, checkpointFailureResponse('checkpointPersistenceFailed')) === true);
|
|
761
825
|
const interaction = {
|
|
762
826
|
...rawInteraction,
|
|
763
827
|
turnId: session.activeTurnId,
|
|
@@ -768,7 +832,7 @@ export async function composeRelayApp(options) {
|
|
|
768
832
|
return true;
|
|
769
833
|
}
|
|
770
834
|
if (recordStatus === 'failed')
|
|
771
|
-
return (runtime?.resolveServerRequest(sessionId, rawInteraction.requestId,
|
|
835
|
+
return (runtime?.resolveServerRequest(sessionId, rawInteraction.requestId, checkpointFailureResponse('checkpointStateConflict')) === true);
|
|
772
836
|
if (recordStatus === 'alreadyRecorded')
|
|
773
837
|
return (runtime?.resolveServerRequest(sessionId, rawInteraction.requestId, toOrgPlanCheckpointToolResponse('alreadyRecorded')) === true);
|
|
774
838
|
const interaction = {
|
|
@@ -788,6 +852,24 @@ export async function composeRelayApp(options) {
|
|
|
788
852
|
// is cancelled solely by the JSON-RPC write-settlement callback.
|
|
789
853
|
return true;
|
|
790
854
|
}
|
|
855
|
+
if (rawInteraction.kind === 'orgPlanAttention') {
|
|
856
|
+
try {
|
|
857
|
+
acceptPendingInteraction(sessionId, rawInteraction, session, true);
|
|
858
|
+
const acknowledged = runtime?.resolveServerRequest(sessionId, rawInteraction.requestId, toOrgPlanAttentionAcknowledgement()) === true;
|
|
859
|
+
if (acknowledged)
|
|
860
|
+
armAttentionAcknowledgementDeadline(sessionId, rawInteraction.requestId);
|
|
861
|
+
return acknowledged;
|
|
862
|
+
}
|
|
863
|
+
catch {
|
|
864
|
+
const rejected = runtime?.resolveServerRequest(sessionId, rawInteraction.requestId, toOrgPlanAttentionAcknowledgement({
|
|
865
|
+
accepted: false,
|
|
866
|
+
reason: 'persistenceFailed',
|
|
867
|
+
})) === true;
|
|
868
|
+
if (rejected)
|
|
869
|
+
armAttentionAcknowledgementDeadline(sessionId, rawInteraction.requestId);
|
|
870
|
+
return rejected;
|
|
871
|
+
}
|
|
872
|
+
}
|
|
791
873
|
return acceptPendingInteraction(sessionId, rawInteraction, session);
|
|
792
874
|
}, (sessionId) => {
|
|
793
875
|
activity.disconnected(sessionId, new Date().toISOString());
|
|
@@ -827,7 +909,18 @@ export async function composeRelayApp(options) {
|
|
|
827
909
|
const handleKimiServerRequest = (sessionId, request) => {
|
|
828
910
|
const rawInteraction = toPendingInteraction(request);
|
|
829
911
|
const session = withPendingInteractions(sessions.find(sessionId));
|
|
830
|
-
|
|
912
|
+
if (!rawInteraction || !session)
|
|
913
|
+
return false;
|
|
914
|
+
if (rawInteraction.kind !== 'orgPlanAttention')
|
|
915
|
+
return acceptPendingInteraction(sessionId, rawInteraction, session);
|
|
916
|
+
try {
|
|
917
|
+
acceptPendingInteraction(sessionId, rawInteraction, session, true);
|
|
918
|
+
void kimiRuntime?.resolveServerRequest(sessionId, rawInteraction.requestId, toOrgPlanAttentionAcknowledgement());
|
|
919
|
+
}
|
|
920
|
+
catch {
|
|
921
|
+
void kimiRuntime?.resolveServerRequest(sessionId, rawInteraction.requestId, toOrgPlanAttentionAcknowledgement({ accepted: false, reason: 'persistenceFailed' }));
|
|
922
|
+
}
|
|
923
|
+
return true;
|
|
831
924
|
};
|
|
832
925
|
kimiRuntime = kimiManager
|
|
833
926
|
? new KimiSessionRuntime({
|
|
@@ -850,6 +943,10 @@ export async function composeRelayApp(options) {
|
|
|
850
943
|
})
|
|
851
944
|
: null;
|
|
852
945
|
runtime?.onServerResponseSettled((sessionId, requestId, outcome) => {
|
|
946
|
+
if (attentionAcknowledgementTimers.has(checkpointTimerKey(sessionId, requestId))) {
|
|
947
|
+
cancelAttentionAcknowledgementTimer(sessionId, requestId);
|
|
948
|
+
return;
|
|
949
|
+
}
|
|
853
950
|
const interaction = interactions.find(sessionId, requestId);
|
|
854
951
|
if (interaction?.kind !== 'orgPlanCheckpoint')
|
|
855
952
|
return;
|
|
@@ -1347,6 +1444,18 @@ export async function composeRelayApp(options) {
|
|
|
1347
1444
|
return { kind: 'staleOperation' };
|
|
1348
1445
|
if (claim === 'missing')
|
|
1349
1446
|
return { kind: 'noActive' };
|
|
1447
|
+
const acknowledged = interactions.resolutionState(sessionId, requestId) === 'acknowledged';
|
|
1448
|
+
if (acknowledged) {
|
|
1449
|
+
if (!interactions.beginDelivery(sessionId, requestId, operationKey))
|
|
1450
|
+
return { kind: 'staleOperation' };
|
|
1451
|
+
const resolvedAt = new Date().toISOString();
|
|
1452
|
+
if (!interactions.settleOperation(sessionId, requestId, operationKey, resolvedAt, 'answered'))
|
|
1453
|
+
return { kind: 'staleOperation' };
|
|
1454
|
+
const accepted = { kind: 'accepted', resolvedAt };
|
|
1455
|
+
idempotency.put(scope, operationKey, 202, JSON.stringify({ kind: 'replayed', resolvedAt }));
|
|
1456
|
+
publishAttentionSettlement(sessionId, requestId, resolvedAt, 'answered');
|
|
1457
|
+
return accepted;
|
|
1458
|
+
}
|
|
1350
1459
|
// A durable capability belongs to the session/thread, not the
|
|
1351
1460
|
// relay process. A supported stopped writer is retryable;
|
|
1352
1461
|
// missing capability identifies a pre-rollout legacy thread.
|
|
@@ -1468,6 +1577,14 @@ export async function composeRelayApp(options) {
|
|
|
1468
1577
|
checkpointHandoffTimers.delete(key);
|
|
1469
1578
|
}
|
|
1470
1579
|
}
|
|
1580
|
+
for (const key of [...attentionAcknowledgementTimers.keys()]) {
|
|
1581
|
+
if (key.startsWith(`${session.id}:`)) {
|
|
1582
|
+
const timer = attentionAcknowledgementTimers.get(key);
|
|
1583
|
+
if (timer)
|
|
1584
|
+
clearTimeout(timer.handle);
|
|
1585
|
+
attentionAcknowledgementTimers.delete(key);
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1471
1588
|
// Relay shutdown only releases this process's writer. A typed attention
|
|
1472
1589
|
// request remains a durable human-visible blocker for the next relay
|
|
1473
1590
|
// instance; only an app-server-cleared request is a failed audit outcome.
|
|
@@ -1497,7 +1614,8 @@ function resolveStateDatabasePath(root, stateHome) {
|
|
|
1497
1614
|
const legacyPath = legacyRelayStatePath(root, stateHome);
|
|
1498
1615
|
return existsSync(legacyPath) ? legacyPath : currentPath;
|
|
1499
1616
|
}
|
|
1500
|
-
function
|
|
1501
|
-
|
|
1502
|
-
|
|
1617
|
+
function checkpointFailureResponse(reasonCode, details = {}) {
|
|
1618
|
+
const correlationId = randomUUID();
|
|
1619
|
+
checkpointDiagnostic('%o', { correlationId, reasonCode, ...details });
|
|
1620
|
+
return toOrgPlanCheckpointToolResponse('failed', { reasonCode, correlationId, ...details });
|
|
1503
1621
|
}
|
|
@@ -201,7 +201,10 @@ function childOutcome(status, action, previous) {
|
|
|
201
201
|
function childState(status, action, previous = 'working') {
|
|
202
202
|
if (status === 'error' || status === 'failed' || status === 'systemError' || status === 'errored')
|
|
203
203
|
return 'blocked';
|
|
204
|
-
if (status === 'completed' ||
|
|
204
|
+
if (status === 'completed' ||
|
|
205
|
+
status === 'idle' ||
|
|
206
|
+
status === 'interrupted' ||
|
|
207
|
+
action === 'close_agent')
|
|
205
208
|
return 'idle';
|
|
206
209
|
// `wait` belongs to the caller/root; it does not rewrite the child which may
|
|
207
210
|
// still be working. A child can explicitly report its own waiting status.
|
|
@@ -229,7 +232,10 @@ function childReason(status, action) {
|
|
|
229
232
|
return 'processExited';
|
|
230
233
|
if (action === 'wait')
|
|
231
234
|
return 'collaborationWait';
|
|
232
|
-
if (status === 'completed' ||
|
|
235
|
+
if (status === 'completed' ||
|
|
236
|
+
status === 'idle' ||
|
|
237
|
+
status === 'interrupted' ||
|
|
238
|
+
action === 'close_agent')
|
|
233
239
|
return 'turnCompleted';
|
|
234
240
|
return 'turnActive';
|
|
235
241
|
}
|
|
@@ -3,8 +3,13 @@
|
|
|
3
3
|
* Designed by Denis Roio <jaromil@dyne.org>
|
|
4
4
|
* SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
5
|
*/
|
|
6
|
+
/** Terminal roster entries remain visible and are not active implementation writers. */
|
|
7
|
+
export function hasActiveL1Writer(snapshot, position) {
|
|
8
|
+
return snapshot.subagents.some((child) => child.canonicalPosition === position &&
|
|
9
|
+
['working', 'awaitingAgent', 'awaitingHuman'].includes(child.state));
|
|
10
|
+
}
|
|
6
11
|
/** Expands a host-owned compact boundary signal from authoritative plan state. */
|
|
7
|
-
export function resolveOrgPlanCheckpointSignal(kind, plan, planIdentity) {
|
|
12
|
+
export function resolveOrgPlanCheckpointSignal(kind, plan, planIdentity, publicationReason = null) {
|
|
8
13
|
if (kind === 'terminalReviewAccepted')
|
|
9
14
|
return {
|
|
10
15
|
version: 1,
|
|
@@ -12,8 +17,16 @@ export function resolveOrgPlanCheckpointSignal(kind, plan, planIdentity) {
|
|
|
12
17
|
planIdentity,
|
|
13
18
|
verdict: 'ACCEPT',
|
|
14
19
|
};
|
|
15
|
-
const
|
|
16
|
-
|
|
20
|
+
const reviewedId = publicationReason?.match(/^review:([^:]{1,128}):REVIEWED$/)?.[1];
|
|
21
|
+
const selected = kind === 'l1Accepted'
|
|
22
|
+
? ((reviewedId
|
|
23
|
+
? plan.steps.find((step) => step.id === reviewedId && step.state === 'DONE' && step.reviewStatus === 'REVIEWED')
|
|
24
|
+
: undefined) ??
|
|
25
|
+
[...plan.steps]
|
|
26
|
+
.reverse()
|
|
27
|
+
.find((step) => step.state === 'DONE' && step.reviewStatus === 'REVIEWED'))
|
|
28
|
+
: (plan.steps.find((step) => step.id === plan.currentStepId) ??
|
|
29
|
+
[...plan.steps].reverse().find((step) => step.state === 'DONE' || step.state === 'WIP'));
|
|
17
30
|
if (!selected)
|
|
18
31
|
return null;
|
|
19
32
|
const l1Position = `L${plan.steps.indexOf(selected) + 1}`;
|
|
@@ -44,25 +57,80 @@ export function resolveOrgPlanCheckpointSignal(kind, plan, planIdentity) {
|
|
|
44
57
|
};
|
|
45
58
|
}
|
|
46
59
|
export function validOrgPlanCheckpoint(input) {
|
|
60
|
+
return validateOrgPlanCheckpoint(input).valid;
|
|
61
|
+
}
|
|
62
|
+
export function validateOrgPlanCheckpoint(input) {
|
|
47
63
|
const { checkpoint, plan, planIdentity, rootOwned } = input;
|
|
48
|
-
if (!rootOwned
|
|
49
|
-
return false;
|
|
64
|
+
if (!rootOwned)
|
|
65
|
+
return { valid: false, reasonCode: 'rootNotOwner' };
|
|
66
|
+
if (checkpoint.planIdentity !== planIdentity)
|
|
67
|
+
return { valid: false, reasonCode: 'planIdentityMismatch' };
|
|
50
68
|
if (checkpoint.kind === 'terminalReviewAccepted')
|
|
51
|
-
return plan.steps.every((step) => step.state === 'DONE' && step.reviewStatus === 'REVIEWED')
|
|
69
|
+
return plan.steps.every((step) => step.state === 'DONE' && step.reviewStatus === 'REVIEWED')
|
|
70
|
+
? { valid: true }
|
|
71
|
+
: { valid: false, reasonCode: 'terminalReviewIncomplete' };
|
|
52
72
|
const l1 = plan.steps.find((step) => step.id === checkpoint.l1Id);
|
|
53
73
|
if (!l1)
|
|
54
|
-
return false;
|
|
74
|
+
return { valid: false, reasonCode: 'l1NotFound' };
|
|
55
75
|
const position = `L${plan.steps.indexOf(l1) + 1}`;
|
|
56
76
|
if (checkpoint.kind === 'l2Completed') {
|
|
57
77
|
const l2 = l1.children.find((step) => step.id === checkpoint.l2Id);
|
|
58
78
|
if (!l2)
|
|
59
|
-
return false;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
79
|
+
return { valid: false, reasonCode: 'l2NotFound' };
|
|
80
|
+
const expectedPosition = `${position}.${l1.children.indexOf(l2) + 1}`;
|
|
81
|
+
if (checkpoint.position !== expectedPosition)
|
|
82
|
+
return {
|
|
83
|
+
valid: false,
|
|
84
|
+
reasonCode: 'checkpointPositionMismatch',
|
|
85
|
+
expected: { position: expectedPosition },
|
|
86
|
+
observed: { position: checkpoint.position },
|
|
87
|
+
};
|
|
88
|
+
if (l2.state !== 'DONE')
|
|
89
|
+
return {
|
|
90
|
+
valid: false,
|
|
91
|
+
reasonCode: 'l2NotDone',
|
|
92
|
+
expected: { l2State: 'DONE' },
|
|
93
|
+
observed: { l2State: l2.state },
|
|
94
|
+
};
|
|
95
|
+
return l1.reviewStatus === 'UNREVIEWED'
|
|
96
|
+
? { valid: true }
|
|
97
|
+
: { valid: false, reasonCode: 'l1AlreadyReviewed' };
|
|
63
98
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
99
|
+
if (checkpoint.position !== position)
|
|
100
|
+
return {
|
|
101
|
+
valid: false,
|
|
102
|
+
reasonCode: 'checkpointPositionMismatch',
|
|
103
|
+
expected: { position },
|
|
104
|
+
observed: { position: checkpoint.position },
|
|
105
|
+
};
|
|
106
|
+
if (l1.state !== 'DONE')
|
|
107
|
+
return {
|
|
108
|
+
valid: false,
|
|
109
|
+
reasonCode: 'l1NotDone',
|
|
110
|
+
expected: { l1State: 'DONE' },
|
|
111
|
+
observed: { l1State: l1.state },
|
|
112
|
+
};
|
|
113
|
+
if (l1.reviewStatus !== 'REVIEWED')
|
|
114
|
+
return {
|
|
115
|
+
valid: false,
|
|
116
|
+
reasonCode: 'l1NotReviewed',
|
|
117
|
+
expected: { reviewStatus: 'REVIEWED' },
|
|
118
|
+
observed: { reviewStatus: l1.reviewStatus ?? null },
|
|
119
|
+
};
|
|
120
|
+
const incompleteChild = l1.children.find((child) => child.state !== 'DONE');
|
|
121
|
+
if (incompleteChild)
|
|
122
|
+
return {
|
|
123
|
+
valid: false,
|
|
124
|
+
reasonCode: 'l1ChildrenIncomplete',
|
|
125
|
+
expected: { childrenDone: true },
|
|
126
|
+
observed: { childrenDone: false, childState: incompleteChild.state },
|
|
127
|
+
};
|
|
128
|
+
if (input.hasActiveL1Writer(position))
|
|
129
|
+
return {
|
|
130
|
+
valid: false,
|
|
131
|
+
reasonCode: 'executorStillActive',
|
|
132
|
+
expected: { executorTerminal: true },
|
|
133
|
+
observed: { executorTerminal: false },
|
|
134
|
+
};
|
|
135
|
+
return { valid: true };
|
|
68
136
|
}
|
|
@@ -8,7 +8,11 @@ export class SupervisedPlanRegistry {
|
|
|
8
8
|
plans = new Map();
|
|
9
9
|
accept(sessionId, update) {
|
|
10
10
|
if (update.kind === 'updated')
|
|
11
|
-
this.plans.set(sessionId, {
|
|
11
|
+
this.plans.set(sessionId, {
|
|
12
|
+
plan: update.plan,
|
|
13
|
+
identity: update.identity,
|
|
14
|
+
publicationReason: update.reason,
|
|
15
|
+
});
|
|
12
16
|
}
|
|
13
17
|
find(sessionId) {
|
|
14
18
|
return this.plans.get(sessionId)?.plan ?? null;
|
|
@@ -16,6 +20,9 @@ export class SupervisedPlanRegistry {
|
|
|
16
20
|
identity(sessionId) {
|
|
17
21
|
return this.plans.get(sessionId)?.identity ?? null;
|
|
18
22
|
}
|
|
23
|
+
publicationReason(sessionId) {
|
|
24
|
+
return this.plans.get(sessionId)?.publicationReason ?? null;
|
|
25
|
+
}
|
|
19
26
|
clear(sessionId) {
|
|
20
27
|
this.plans.delete(sessionId);
|
|
21
28
|
}
|
|
@@ -17,16 +17,22 @@ export class SqlitePendingInteractionStore {
|
|
|
17
17
|
constructor(db) {
|
|
18
18
|
this.db = db;
|
|
19
19
|
}
|
|
20
|
-
add(sessionId, interaction) {
|
|
20
|
+
add(sessionId, interaction, initialResolutionState = 'active') {
|
|
21
21
|
this.db
|
|
22
|
-
.prepare(`INSERT INTO pending_interactions (session_id,request_id,kind,payload_json,turn_id,requested_at)
|
|
23
|
-
VALUES (
|
|
22
|
+
.prepare(`INSERT INTO pending_interactions (session_id,request_id,kind,payload_json,turn_id,requested_at,resolution_state)
|
|
23
|
+
VALUES (?,?,?,?,?,?,?)
|
|
24
24
|
ON CONFLICT(session_id,request_id) DO UPDATE SET
|
|
25
25
|
kind = excluded.kind, payload_json = excluded.payload_json, turn_id = excluded.turn_id,
|
|
26
26
|
requested_at = excluded.requested_at, resolved_at = NULL, outcome = NULL, operation_key = NULL,
|
|
27
|
-
resolution_state =
|
|
27
|
+
resolution_state = excluded.resolution_state
|
|
28
28
|
WHERE pending_interactions.kind != 'orgPlanAttention'`)
|
|
29
|
-
.run(sessionId, interaction.requestId, interaction.kind, JSON.stringify(interaction.payload), interaction.turnId ?? null, interaction.requestedAt ?? null);
|
|
29
|
+
.run(sessionId, interaction.requestId, interaction.kind, JSON.stringify(interaction.payload), interaction.turnId ?? null, interaction.requestedAt ?? null, initialResolutionState);
|
|
30
|
+
}
|
|
31
|
+
resolutionState(sessionId, requestId) {
|
|
32
|
+
const row = this.db
|
|
33
|
+
.prepare('SELECT resolution_state FROM pending_interactions WHERE session_id = ? AND request_id = ? AND resolved_at IS NULL')
|
|
34
|
+
.get(sessionId, requestId);
|
|
35
|
+
return row?.resolution_state ?? null;
|
|
30
36
|
}
|
|
31
37
|
resolve(sessionId, requestId, resolvedAt, outcome = 'answered') {
|
|
32
38
|
return (this.db
|
|
@@ -56,7 +62,7 @@ export class SqlitePendingInteractionStore {
|
|
|
56
62
|
/** Persist the in-flight delivery boundary before the app-server is notified. */
|
|
57
63
|
beginDelivery(sessionId, requestId, operationKey) {
|
|
58
64
|
return (this.db
|
|
59
|
-
.prepare("UPDATE pending_interactions SET resolution_state = 'delivering' WHERE session_id = ? AND request_id = ? AND operation_key = ? AND resolved_at IS NULL AND resolution_state IN ('active','delivering')")
|
|
65
|
+
.prepare("UPDATE pending_interactions SET resolution_state = 'delivering' WHERE session_id = ? AND request_id = ? AND operation_key = ? AND resolved_at IS NULL AND resolution_state IN ('active','acknowledged','delivering')")
|
|
60
66
|
.run(sessionId, requestId, operationKey).changes === 1);
|
|
61
67
|
}
|
|
62
68
|
/** A local writer outage is retryable only by the already-claimed key. */
|
|
@@ -93,13 +93,20 @@ export function parseOrgPlanAttentionResponse(value) {
|
|
|
93
93
|
...(typeof value.guidance === 'string' ? { guidance: value.guidance } : {}),
|
|
94
94
|
};
|
|
95
95
|
}
|
|
96
|
-
/**
|
|
96
|
+
/** Legacy human resolution payload used only for pre-acknowledgement held requests. */
|
|
97
97
|
export function toOrgPlanAttentionToolResponse(response) {
|
|
98
98
|
return {
|
|
99
99
|
success: true,
|
|
100
100
|
contentItems: [{ type: 'inputText', text: JSON.stringify(response) }],
|
|
101
101
|
};
|
|
102
102
|
}
|
|
103
|
+
/** Immediate persist-first acknowledgement returned to the dynamic-tool caller. */
|
|
104
|
+
export function toOrgPlanAttentionAcknowledgement(acknowledgement = { accepted: true }) {
|
|
105
|
+
return {
|
|
106
|
+
success: acknowledgement.accepted,
|
|
107
|
+
contentItems: [{ type: 'inputText', text: JSON.stringify(acknowledgement) }],
|
|
108
|
+
};
|
|
109
|
+
}
|
|
103
110
|
export function isOrgPlanAttentionToolResponse(value) {
|
|
104
111
|
if (!isRecord(value) || value.success !== true || !Array.isArray(value.contentItems))
|
|
105
112
|
return false;
|
|
@@ -176,7 +176,7 @@ export function parseOrgPlanCheckpoint(value) {
|
|
|
176
176
|
};
|
|
177
177
|
}
|
|
178
178
|
/** Acknowledgement deliberately contains no plan path, findings, or model text. */
|
|
179
|
-
export function toOrgPlanCheckpointToolResponse(status) {
|
|
179
|
+
export function toOrgPlanCheckpointToolResponse(status, failure) {
|
|
180
180
|
const result = status === 'recorded'
|
|
181
181
|
? {
|
|
182
182
|
status,
|
|
@@ -193,7 +193,11 @@ export function toOrgPlanCheckpointToolResponse(status) {
|
|
|
193
193
|
}
|
|
194
194
|
: {
|
|
195
195
|
status,
|
|
196
|
+
reasonCode: failure?.reasonCode ?? 'checkpointPersistenceFailed',
|
|
196
197
|
durable: false,
|
|
198
|
+
...(failure?.expected ? { expected: failure.expected } : {}),
|
|
199
|
+
...(failure?.observed ? { observed: failure.observed } : {}),
|
|
200
|
+
...(failure?.correlationId ? { correlationId: failure.correlationId } : {}),
|
|
197
201
|
next: 'reconcileCheckpointState',
|
|
198
202
|
allowBoundaryFinal: false,
|
|
199
203
|
};
|
|
@@ -13,5 +13,7 @@ export const planSignalReasons = [
|
|
|
13
13
|
'resync',
|
|
14
14
|
];
|
|
15
15
|
export function isPlanSignalReason(value) {
|
|
16
|
-
return typeof value === 'string' &&
|
|
16
|
+
return (typeof value === 'string' &&
|
|
17
|
+
(planSignalReasons.includes(value) ||
|
|
18
|
+
/^review:[A-Za-z0-9._-]{1,128}:REVIEWED$/.test(value)));
|
|
17
19
|
}
|