@sapiom/harness 0.8.8 → 0.8.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @sapiom/harness
2
2
 
3
+ ## 0.8.9
4
+
5
+ ### Patch Changes
6
+
7
+ - 9165f18: Studio's coding-agent system prompt now says to omit `model`, states that `smart` is a no-op, and keeps size labels as the deliberate choice — matching the authoring skill, the MCP instructions, and the call-surface guide.
8
+ - Updated dependencies [054f749]
9
+ - Updated dependencies [db81e32]
10
+ - Updated dependencies [054f749]
11
+ - @sapiom/mcp@0.13.0
12
+ - @sapiom/agent@0.12.2
13
+ - @sapiom/agent-core@0.13.2
14
+
3
15
  ## 0.8.8
4
16
 
5
17
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"default.d.ts","sourceRoot":"","sources":["../../src/profiles/default.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,QA6E1B,CAAC"}
1
+ {"version":3,"file":"default.d.ts","sourceRoot":"","sources":["../../src/profiles/default.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,QA+E1B,CAAC"}
@@ -27,8 +27,10 @@ platform-driven multi-turn loop → \`ctx.sapiom.models.run\` (never for a
27
27
  one-shot — it overthinks); dispatching a deployed agent by slug →
28
28
  \`ctx.sapiom.agents.run\`. Structured output = tool-use/schema output — read
29
29
  the \`tool_use\` block's input, never string-parse; a plain-text reply reads
30
- only \`type === 'text'\` blocks. Omit \`model\`
31
- (recommended) or pin the \`smart\` label; raw provider ids are never
30
+ only \`type === 'text'\` blocks. **Omit \`model\` entirely** — the platform
31
+ routes it, and \`smart\` is already the default, so naming it changes
32
+ nothing. Reach for \`small\`/\`medium\`/\`large\` only to choose a class
33
+ deliberately. Raw provider ids are never
32
34
  honored. Results disclose the served class + lane. Debugging a run: the
33
35
  Run Inspector, or the per-step I/O endpoint documented in the guide.
34
36
  Guide: https://docs.sapiom.ai/guides/choose-a-call-surface.
@@ -1 +1 @@
1
- {"version":3,"file":"default.js","sourceRoot":"","sources":["../../src/profiles/default.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6EpC,CAAC,IAAI,EAAE,CAAC"}
1
+ {"version":3,"file":"default.js","sourceRoot":"","sources":["../../src/profiles/default.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+EpC,CAAC,IAAI,EAAE,CAAC"}
@@ -491,4 +491,4 @@ ${o}`:o}function Im(e){return nc(e)}async function k$(e,t,i){const r=Im(e.trim()
491
491
  `)}const I6={entries:[],index:-1};function P6(e,t){return e.kind!==t.kind?!1:e.kind==="session"&&t.kind==="session"?e.sessionId===t.sessionId:e.kind==="agent"&&t.kind==="agent"?e.agentPath===t.agentPath:e.kind==="review"&&t.kind==="review"?e.summary.agentSessionId===t.summary.agentSessionId:e.kind===t.kind}function $2(e){return e.index>0}function L2(e){return e.index>=0&&e.index<e.entries.length-1}function B6(e,t){const i=e.index>=0?e.entries[e.index]:null;if(i&&P6(i,t)){if(JSON.stringify(i)===JSON.stringify(t))return e;const c=[...e.entries];return c[e.index]=t,{...e,entries:c}}const o=[...e.entries.slice(0,e.index+1),t].slice(-50);return{entries:o,index:o.length-1}}function H6(e,t){if(!(t==="back"?$2(e):L2(e)))return{state:e,visit:null};const r=t==="back"?e.index-1:e.index+1;return{state:{...e,index:r},visit:e.entries[r]??null}}function z6(){const[e,t]=z.useState(I6),i=z.useRef(e);i.current=e;const r=z.useCallback(c=>{const f=B6(i.current,c);f!==i.current&&(i.current=f,t(f))},[]),o=z.useCallback(c=>{const f=H6(i.current,c);return f.visit?(i.current=f.state,t(f.state),f.visit):null},[]);return{canGoBack:$2(e),canGoForward:L2(e),record:r,goBack:()=>o("back"),goForward:()=>o("forward")}}const I2="(max-width: 768px)";function Hv(){return typeof window<"u"&&window.matchMedia(I2).matches}function U6(e){const t=window.matchMedia(I2);return t.addEventListener("change",e),()=>t.removeEventListener("change",e)}function q6(){return z.useSyncExternalStore(U6,Hv,()=>!1)}const P2="sapiom-harness-pane-widths",Ag=180,B2=480,zv=320,ac=320,H2=720;function Uv(e,t,i){return Math.min(Math.max(e,t),i)}function F6(){const e={rail:zv,canvas:null};if(typeof window>"u")return e;try{const t=window.localStorage.getItem(P2);if(!t)return e;const i=JSON.parse(t);return{rail:Uv(typeof i.rail=="number"?i.rail:zv,Ag,B2),canvas:typeof i.canvas=="number"?Uv(i.canvas,ac,H2):null}}catch{return e}}function Hw(e){window.localStorage.setItem(P2,JSON.stringify(e))}function V6(){const[e,t]=z.useState(F6),[i,r]=z.useState(!1),[o,c]=z.useState(!1),f=(d,m,y,v,S,w)=>R=>{const x=R.currentTarget;x.setPointerCapture(R.pointerId),w==null||w(!0);const g=R.clientX,b=S(),p=k=>{const A=Uv(b+(k.clientX-g)*m,y,v);t(C=>C[d]===A?C:{...C,[d]:A})},_=()=>{x.removeEventListener("pointermove",p),x.removeEventListener("pointerup",_),w==null||w(!1),t(k=>(Hw(k),k))};x.addEventListener("pointermove",p),x.addEventListener("pointerup",_)},l=(d,m)=>{t(y=>{const v={...y,[d]:m};return Hw(v),v})};return{widths:e,canvasResizing:i,railResizing:o,startRailDrag:f("rail",1,Ag,B2,()=>e.rail,c),startCanvasDrag:f("canvas",-1,ac,H2,()=>{if(e.canvas!=null)return e.canvas;const d=document.querySelector(".canvas-pane");return d?d.getBoundingClientRect().width:ac},r),resetRail:()=>{c(!0),l("rail",zv),window.setTimeout(()=>c(!1),0)},resetCanvas:()=>{r(!0),l("canvas",null),window.setTimeout(()=>r(!1),0)}}}function Fs(e,t="error"){return{message:e,tone:t}}const W6=2e3;function G6(e){const t=new URL("/ws/events",window.location.href);t.protocol=t.protocol==="https:"?"wss:":"ws:",t.searchParams.set("token",co());let i=null,r=null,o=!1;const c=()=>{i=new WebSocket(t),i.addEventListener("message",f=>{try{e(JSON.parse(f.data))}catch{}}),i.addEventListener("close",()=>{o||(r=setTimeout(c,W6))})};return c(),()=>{o=!0,r&&clearTimeout(r),i==null||i.close()}}function Nd(e){const t=e.split(/[\\/]/).filter(Boolean);return t[t.length-1]??e}function K6(e,t){const i=[];for(const r of t)e.has(r.path)||i.push(r.path);return i}function zw(e,t){return t?"exception":e==="linking"?"link_failed":"build_failed"}function Y6(e){return e==="cancelled"?"cancelled":"failed"}function X6(e){return e==="completed"?"succeeded":e==="failed"?"failed":"pending"}const J6=5;function Z6(){return{started:!1,settled:!1,observed:!1,failures:0}}const Md={event:null};function Q6(e,t,i=J6){if(t.kind==="announced")return t.duplicate||e.started?{state:e,emit:Md}:{state:{...e,started:!0},emit:{event:"agent.run_started"}};if(t.kind==="polled"){const c={...e,observed:!0,failures:0};if(t.status==="running")return{state:c,emit:Md};if(e.settled)return{state:c,emit:Md};const f={...c,settled:!0};return t.status==="completed"?{state:f,emit:{event:"agent.run_succeeded"}}:{state:f,emit:{event:"agent.run_failed",error_kind:Y6(t.status)}}}const r=e.failures+1,o={...e,failures:r};return r<i||e.settled?{state:o,emit:Md}:{state:{...o,settled:!0},emit:{event:"agent.run_failed",error_kind:e.observed?"exception":"unobservable"}}}function Xl(e){return typeof e=="string"&&e!==""?e:void 0}function eL(e){if(Xl(e.templateId))return"template";const t=Xl(e.starterId);return t&&t!=="default"?"starter":Xl(e.forkId)?"fork":"scratch"}function Uw(e){if(!e)return{};const t=eL(e);return t==="template"?{source:t,template_id:Xl(e.templateId)}:t==="starter"?{source:t,template_id:Xl(e.starterId)}:{source:t}}const qw=4e3;function tL(e){if(typeof e=="string")return e;if(e!==null&&typeof e=="object"){const t=e,i=[t.ts,t.level,t.msg??t.message].filter(r=>typeof r=="string"||typeof r=="number");if(i.length>0)return i.map(String).join(" ")}return String(e)}function sL(e){if(!Array.isArray(e)||e.length===0)return;const t=e.map(tL).join(`
492
492
  `).trim();if(t!=="")return t.length>qw?t.slice(t.length-qw):t}function iL(e){return e==="running"?"running":e==="succeeded"?"passed":e==="threw"?"failed":"pending"}function nL(e){return e==="completed"?"completed":e==="failed"?"failed":"running"}function rL(e){var r;const t={id:`${e.step}-${e.attempt}`,name:e.step,attempt:e.attempt,status:iL(e.status)};if(e.startedAt&&(t.startedAt=e.startedAt),e.finishedAt&&(t.finishedAt=e.finishedAt),e.startedAt&&e.finishedAt){const o=Date.parse(e.startedAt),c=Date.parse(e.finishedAt);Number.isFinite(o)&&Number.isFinite(c)&&c>=o&&(t.latencyMs=c-o)}e.input!==void 0&&(t.input=e.input),e.output!==void 0&&(t.output=e.output),e.sharedStateAfter!==void 0&&(t.sharedState=e.sharedStateAfter),e.directive!==void 0&&(t.directive=e.directive),(r=e.error)!=null&&r.message&&(t.error=e.error.message);const i=sL(e.logs);return i!==void 0&&(t.logSlice=i),e.calls&&e.calls.length>0&&(t.calls=e.calls.map(o=>({capability:o.capability,stubUsed:o.stubUsed,args:o.args,result:o.result}))),t}function aL(e,t={}){const i={executionId:t.executionId??"",status:nL(t.outcome),steps:e.map(rL),stubbed:!0};return t.unusedStubs&&t.unusedStubs.length>0&&(i.unusedStubs=t.unusedStubs),t.stubWarnings&&t.stubWarnings.length>0&&(i.stubWarnings=t.stubWarnings),t.input!==void 0&&(i.input=t.input),t.output!==void 0&&(i.output=t.output),t.error!==void 0&&(i.error=t.error),t.startedAt&&(i.startedAt=t.startedAt),t.finishedAt&&(i.finishedAt=t.finishedAt),i}const Pt=Kw(),oL=3e3,lL=8,cL=500;function uL(){const[e,t]=z.useState(null),[i,r]=z.useState(null),o=z.useRef(null);o.current=i;const c=z.useRef([]);c.current=(e==null?void 0:e.workflows)??[];const[f,l]=z.useState(!0),[d,m]=z.useState(null),[y,v]=z.useState(null),[S,w]=z.useState(0),[R,x]=z.useState(null),[g,b]=z.useState(null),[p,_]=z.useState([]),[k,A]=z.useState(null),[C,N]=z.useState(!1),j=z.useRef(new Map),M=z.useRef(0),O=z.useRef(new Map),[B,q]=z.useState(null),[V,J]=z.useState(new Set),[ee,W]=z.useState([]),Q=z.useRef(new Map),[ie,I]=z.useState(new Map),[P,D]=z.useState(new Map),[H,U]=z.useState(new Map),L=z.useRef(new Map),G=z.useRef(new Set),[se,Y]=z.useState(new Map),[F,le]=z.useState(new Map),[ae,X]=z.useState(new Map),te=z.useCallback((oe,fe)=>{X(ye=>{if(fe===null){if(!ye.has(oe))return ye;const xe=new Map(ye);return xe.delete(oe),xe}return new Map(ye).set(oe,fe)})},[]),[ue,me]=z.useState([]),je=z.useCallback(oe=>{me(fe=>fe.some(ye=>ye.cwd===oe)?fe:[{cwd:oe,sessionSeen:!1},...fe])},[]),Oe=z.useCallback(oe=>{me(fe=>fe.some(ye=>ye.cwd===oe)?fe.filter(ye=>ye.cwd!==oe):fe)},[]);z.useEffect(()=>{if(ue.length===0)return;const oe=(e==null?void 0:e.sessions)??[],fe=(e==null?void 0:e.workflows)??[],ye=(xe,Te)=>mg(Te,xe);me(xe=>{let Te=!1;const ct=[];for(const xt of xe){if(fe.some(Ct=>ye(Ct.path,xt.cwd))){Te=!0;continue}const Rt=oe.some(Ct=>Ct.status!=="exited"&&ye(Ct.cwd,xt.cwd));if(xt.sessionSeen&&!Rt){Te=!0;continue}if(Rt&&!xt.sessionSeen){ct.push({...xt,sessionSeen:!0}),Te=!0;continue}ct.push(xt)}return Te?ct:xe})},[e==null?void 0:e.sessions,e==null?void 0:e.workflows,ue]);const[Le,at]=z.useState(0),Ee=z.useCallback(()=>{at(oe=>oe+1)},[]),qe=z.useRef(0),We=z.useCallback(oe=>{qe.current+=1,b(oe)},[]),it=z.useRef([]),Ze=z.useCallback(oe=>{Pt.getRunState(oe).then(fe=>I(ye=>{const xe=ye.get(oe);return xe?new Map(ye).set(oe,{...xe,run:fe}):ye})).catch(()=>{})},[]),Je=z.useCallback((oe,fe,ye)=>{const xe=L.current.get(oe);xe&&clearInterval(xe);const Te=ra(it.current.find(Fe=>Fe.id===oe)),ct=Date.now();D(Fe=>{const Ke=Fe.get(oe)??[];return Ke.includes(fe)?Fe:new Map(Fe).set(oe,[...Ke,fe])}),U(Fe=>{if(!Fe.has(oe))return Fe;const Ke=new Map(Fe);return Ke.delete(oe),Ke});const Dt={workflow_slug:Te?Nd(Te):void 0,session_id:oe,target:ye};let Rt=Z6();const Ct=Fe=>{const{state:Ke,emit:es}=Q6(Rt,Fe);if(Rt=Ke,es.event===null)return;if(es.event==="agent.run_started"){Os("agent.run_started",Dt);return}const Ye=Date.now()-ct;if(es.event==="agent.run_succeeded"){Os("agent.run_succeeded",{...Dt,duration_ms:Ye});return}Os("agent.run_failed",{...Dt,duration_ms:Ye,error_kind:es.error_kind})},ve=G.current.has(fe);if(G.current.size>=cL){const Fe=G.current.values().next().value;Fe!==void 0&&G.current.delete(Fe)}G.current.add(fe),Ct({kind:"announced",duplicate:ve});const $e=()=>{const Fe=L.current.get(oe);Fe&&clearInterval(Fe),L.current.delete(oe)},Be=async()=>{try{const Fe=await Pt.getRunState(fe);I(Ke=>new Map(Ke).set(fe,{run:Fe,target:ye,workflowPath:Te,observedAt:ct})),Ct({kind:"polled",status:Fe.status}),Fe.status!=="running"&&$e()}catch{Ct({kind:"poll_failed"}),Rt.settled&&$e()}};Be(),L.current.set(oe,setInterval(()=>void Be(),2e3))},[]),wt=z.useRef(0),mt=z.useCallback(async(oe,fe,ye)=>{wt.current+=1;const xe=`local-${Date.now()}-${wt.current}`,Te=ra(it.current.find(et=>et.id===oe)),ct=Date.now(),xt=new Date(ct).toISOString(),Dt=[];let Rt,Ct,ve,$e,Be,Fe;D(et=>{const dt=et.get(oe)??[];return dt.includes(xe)?et:new Map(et).set(oe,[...dt,xe])}),U(et=>{if(!et.has(oe))return et;const dt=new Map(et);return dt.delete(oe),dt});const Ke=()=>{const et=aL(Dt,{executionId:xe,outcome:Rt,unusedStubs:Be,stubWarnings:Fe,input:ye,output:Ct,error:ve,startedAt:xt,finishedAt:$e});I(dt=>new Map(dt).set(xe,{run:et,target:"local",workflowPath:Te,observedAt:ct}))};Ke();const es={workflow_slug:Te?Nd(Te):void 0,session_id:oe,target:"local"};let Ye=!1;Os("agent.run_started",es);const ts=et=>{if(et.kind==="summary")Rt=et.outcome,Ct=et.output,ve=et.error,$e=new Date().toISOString(),Be=et.unusedStubs,Fe=et.stubWarnings;else if(et.kind==="error"){Rt="failed",ve=et.error,$e=new Date().toISOString();const dt={step:"run-local",attempt:1,input:ye,status:"threw",startedAt:xt,finishedAt:$e,error:{name:"RunLocalError",message:et.error},logs:[]},It=Dt.findIndex(Ys=>Ys.step===dt.step&&Ys.attempt===dt.attempt);It>=0?Dt[It]=dt:Dt.push(dt)}else if(et.kind==="step"){const dt=et.trace,It=Dt.findIndex(Ys=>Ys.step===dt.step&&Ys.attempt===dt.attempt);It>=0?Dt[It]=dt:Dt.push(dt)}else{const dt=Dt.findIndex(It=>It.step===et.step&&It.attempt===et.attempt);dt>=0?Dt[dt]=et:Dt.push(et)}Ke()};try{await Pt.runLocal({sourceDir:fe,input:ye},ts)}catch(et){const dt=et instanceof ji&&et.reason?et.reason:et instanceof Error?et.message:"Local execution failed.";Rt="failed",Ye=!0,ve=dt,$e=new Date().toISOString();const It={step:"run-local",attempt:1,input:ye,status:"threw",startedAt:xt,finishedAt:$e,error:{name:"RunLocalError",message:dt},logs:[{level:"error",msg:dt}]},Ys=Dt.findIndex(nn=>nn.step===It.step&&nn.attempt===It.attempt);Ys>=0?Dt[Ys]=It:Dt.push(It),Ke(),A(Fs(dt))}finally{const et=X6(Rt),dt=Date.now()-ct;et==="succeeded"?Os("agent.run_succeeded",{...es,duration_ms:dt}):et==="failed"&&Os("agent.run_failed",{...es,duration_ms:dt,error_kind:Ye?"exception":"failed"}),Ee()}},[Ee]),Qt=z.useCallback((oe,fe)=>{U(ye=>new Map(ye).set(oe,fe)),Ze(fe)},[Ze]),Mt=z.useMemo(()=>{const oe=new Map;return P.forEach((fe,ye)=>{const xe=H.get(ye),Te=xe&&fe.includes(xe)?xe:fe[fe.length-1],ct=Te?ie.get(Te):void 0;ct&&oe.set(ye,ct)}),oe},[P,H,ie]);z.useEffect(()=>{it.current=(e==null?void 0:e.sessions)??[]},[e]),z.useEffect(()=>{const oe=L.current;return()=>{oe.forEach(fe=>clearInterval(fe)),oe.clear()}},[]),z.useEffect(()=>{const oe=Q.current;return()=>{oe.forEach(fe=>clearTimeout(fe)),oe.clear()}},[]);const At=z.useRef(null);z.useEffect(()=>{let oe=!1;return S>0&&(l(!0),m(null),v(null)),Promise.all([Pt.getState(),Pt.getSettings()]).then(([fe,ye])=>{if(oe)return;t(fe);const xe=At.current??(At.current=new Set);for(const ct of fe.workflows)xe.add(ct.path);r(ye),v(null),fe.tasks&&W(fe.tasks);const Te=fe.sessions.find(ct=>ct.status!=="exited");Te&&b(Te.id),fe.workflows[0]&&x(fe.workflows[0].path)}).catch(fe=>{oe||(m(fe.message),v(fe instanceof ji?{status:fe.status}:{networkError:!0}))}).finally(()=>!oe&&l(!1)),()=>{oe=!0}},[S]);const hs=z.useCallback(()=>w(oe=>oe+1),[]);z.useEffect(()=>{if(!g)return;const oe=e==null?void 0:e.sessions.find(fe=>fe.id===g);x(ra(oe)??null)},[g]);const Ft=z.useCallback(async()=>{const oe=await Pt.listWorkflows();return t(fe=>fe&&{...fe,workflows:oe}),oe},[]);z.useEffect(()=>G6(oe=>{if(q(oe),oe.type==="session.status"){if(t(fe=>{if(!fe)return fe;const xe=fe.sessions.some(Te=>Te.id===oe.session.id)?fe.sessions.map(Te=>Te.id===oe.session.id?oe.session:Te):[...fe.sessions,oe.session];return{...fe,sessions:xe}}),oe.session.status==="exited"){const fe=oe.session.id,ye=Q.current.get(fe);ye&&(clearTimeout(ye),Q.current.delete(fe)),J(xe=>{if(!xe.has(fe))return xe;const Te=new Set(xe);return Te.delete(fe),Te})}}else if(oe.type==="workflows.changed")Ft().then(fe=>{const ye=At.current;if(ye===null){At.current=new Set(fe.map(xe=>xe.path));return}for(const xe of K6(ye,fe))ye.add(xe),Os("agent.created",{workflow_slug:Nd(xe),...Uw(fe.find(Te=>Te.path===xe))})});else if(oe.type==="execution.started")Je(oe.harnessSessionId,oe.executionId,oe.target);else if(oe.type==="port.detected")Y(fe=>new Map(fe).set(oe.harnessSessionId,{port:oe.port,url:oe.url}));else if(oe.type==="task.status")W(fe=>fe.some(xe=>xe.id===oe.task.id)?fe.map(xe=>xe.id===oe.task.id?oe.task:xe):[...fe,oe.task]);else if(oe.type==="session.activity"){const fe=oe.harnessSessionId;J(xe=>xe.has(fe)?xe:new Set(xe).add(fe));const ye=Q.current.get(fe);ye&&clearTimeout(ye),Q.current.set(fe,setTimeout(()=>{Q.current.delete(fe),J(xe=>{if(!xe.has(fe))return xe;const Te=new Set(xe);return Te.delete(fe),Te})},oL))}else oe.type==="auth.changed"&&(t(fe=>fe&&{...fe,authenticated:oe.authenticated,organizationName:oe.organizationName}),Ft())}),[Ft,Je]);const pt=z.useCallback(async oe=>{const fe=Array.from(new Set(oe)),ye=fe.map(xe=>{const Te=j.current.get(xe);if(Te)return Te;const ct=Pt.sessionHistory(xe).finally(()=>{j.current.delete(xe)});return j.current.set(xe,ct),ct});M.current+=1,N(!0);try{const xe=await Promise.allSettled(ye),Te=[],ct=new Set;xe.forEach((xt,Dt)=>{xt.status==="fulfilled"&&(ct.add(fe[Dt]),Te.push(...xt.value))}),_(xt=>k5(xt,Te,ct))}finally{M.current-=1,M.current===0&&N(!1)}},[]),xs=z.useCallback(async oe=>{var xe;const fe=await Pt.createSession(oe);t(Te=>Te&&!Te.sessions.some(ct=>ct.id===fe.id)?{...Te,sessions:[...Te.sessions,fe]}:Te),We(fe.id);const ye=[oe.cwd,...(((xe=o.current)==null?void 0:xe.recentDirs)??[]).filter(Te=>Te!==oe.cwd)].slice(0,lL);r(Te=>Te&&{...Te,recentDirs:ye});try{const Te=await Pt.updateSettings({recentDirs:ye});r(ct=>ct&&{...ct,recentDirs:Te.recentDirs})}catch{}return fe},[We]),Lt=z.useCallback((oe,fe)=>Pt.attachFile(oe,fe),[]),Ns=z.useCallback(()=>Pt.listTemplates(),[]),fs=z.useCallback(oe=>Pt.getTemplate(oe),[]),jt=z.useCallback(oe=>Pt.sessionRecord(oe),[]),ps=z.useCallback(async oe=>{const fe=qe.current;try{const ye=await Pt.resumeSession(oe);return t(xe=>xe&&{...xe,sessions:xe.sessions.map(Te=>Te.id===ye.id?ye:Te)}),qe.current===fe&&We(ye.id),ye}catch(ye){throw A(Fs(ye instanceof ji&&ye.reason?ye.reason:ye.message)),ye}},[We]),_s=z.useCallback(async({cwd:oe,harness:fe,from:ye})=>{const xe=await xs({cwd:oe,harness:fe,rehydrateFrom:ye});return xe.rehydratedFrom||A(Fs("Nothing was recorded for that session, so this one starts fresh.","info")),xe},[xs]),Qs=z.useCallback(async oe=>{var ye;const fe=oe.harnessSessionId??((ye=e==null?void 0:e.sessions.find(xe=>xe.agentSessionId===oe.agentSessionId))==null?void 0:ye.id);if(oe.resumeMode==="rehydrate")return _s({cwd:oe.cwd,harness:oe.harness,from:fe??oe.agentSessionId});if(fe)return ps(fe);try{const xe=await Pt.adoptSession({agentSessionId:oe.agentSessionId,harness:oe.harness,cwd:oe.cwd,title:oe.title,lastActiveAt:oe.lastActiveAt});return t(Te=>{if(!Te)return Te;const ct=Te.sessions.some(xt=>xt.id===xe.id)?Te.sessions.map(xt=>xt.id===xe.id?xe:xt):[...Te.sessions,xe];return{...Te,sessions:ct}}),We(xe.id),xe}catch(xe){throw A(Fs(xe instanceof ji&&xe.reason?xe.reason:xe.message)),xe}},[e,ps,_s,We]),ei=z.useCallback(async oe=>{try{await Pt.killSession(oe)}catch(ye){throw A(Fs(ye instanceof ji&&ye.reason?ye.reason:ye.message)),ye}const fe=((e==null?void 0:e.sessions)??[]).filter(ye=>ye.id!==oe);if(t(ye=>ye&&{...ye,sessions:fe}),g===oe){const ye=fe.find(xe=>xe.status!=="exited");We(ye?ye.id:null)}},[e,g,We]),Ks=z.useCallback(async oe=>{const fe=await Pt.connectWorkflow(oe);return t(ye=>ye&&{...ye,workflows:[...ye.workflows.filter(xe=>xe.path!==fe.path),fe]}),(At.current??(At.current=new Set)).add(fe.path),fe},[]),$s=z.useCallback(async oe=>{const fe=await Pt.scanWorkflows(oe),ye=await Ft(),xe=At.current??(At.current=new Set);for(const Te of ye)xe.add(Te.path);return fe},[Ft]),gi=z.useCallback(()=>Pt.listHarnesses(),[]),ds=z.useCallback(async(oe,fe)=>{const ye=await Pt.bindWorkflow(oe,fe);t(xe=>xe&&{...xe,sessions:xe.sessions.map(Te=>Te.id===ye.id?ye:Te)})},[]),Ls=z.useCallback(async oe=>{const fe=await Pt.updateSettings(oe);return r(fe),oe.telemetryOptIn!==void 0&&t(ye=>ye&&{...ye,telemetryOptIn:fe.telemetryOptIn}),oe.productAnalyticsOptIn!==void 0&&t(ye=>ye&&{...ye,productAnalyticsOptIn:fe.productAnalyticsOptIn!==!1}),fe},[]),_i=z.useCallback(async(oe,fe)=>{try{await Pt.runMacro(oe,fe)}catch(ye){A(Fs(ye instanceof ji&&ye.reason?ye.reason:ye.message))}},[]),ys=z.useCallback(oe=>{const fe=O.current.get(oe);if(fe)return fe;const ye=(async()=>{A(Fs("Deploying…","info"));const xe=Nd(oe),Te=Uw(c.current.find(Ct=>Ct.path===oe)),ct=performance.now();Os("agent.deploy_started",{workflow_slug:xe,...Te});let xt=null,Dt=null,Rt=!1;try{const Ct=await Pt.deploy(oe,ve=>{ve.phase==="linking"?(xt="linking",te(oe,{phase:"linking"}),A(Fs(`Deploying — creating the agent "${ve.name}" on Sapiom…`,"info"))):ve.phase==="warning"?(Dt=ve.message,A(Fs(ve.message))):ve.phase==="building"&&(xt="building",te(oe,{phase:"building"}),A(Fs("Deploying — building on Sapiom…","info")),Ft())});if(Ct.phase==="ready")te(oe,{phase:"ready"}),Os("agent.deploy_succeeded",{workflow_slug:xe,duration_ms:Math.round(performance.now()-ct),...Te}),Rt=!0,A(Dt?Fs(`Deployed to Sapiom. ${Dt}`):Fs("Deployed to Sapiom.","success")),le(ve=>{if(!ve.has(oe))return ve;const $e=new Map(ve);return $e.delete(oe),$e}),await Ft();else if(Ct.phase==="error"){const ve=xt==="linking"?"Couldn't create the agent":"Deploy failed",$e=Ct.hint?`${ve}: ${Ct.message} (${Ct.hint})`:`${ve}: ${Ct.message}`;te(oe,{phase:"error",message:$e}),Os("agent.deploy_failed",{workflow_slug:xe,error_kind:zw(xt,!1),...Te}),Rt=!0,A(Fs($e)),le(Be=>new Map(Be).set(oe,$e)),await Ft()}}catch(Ct){const ve=Ct instanceof ji&&Ct.reason?Ct.reason:Ct.message;te(oe,{phase:"error",message:ve}),Rt||Os("agent.deploy_failed",{workflow_slug:xe,error_kind:zw(xt,!0),...Te}),A(Fs(ve)),le($e=>new Map($e).set(oe,ve))}finally{Ee(),O.current.delete(oe)}})();return O.current.set(oe,ye),ye},[Ft,Ee,te]),Ae=z.useCallback(async(oe,fe,ye)=>{try{const{executionId:xe}=await Pt.run({definitionId:fe,input:ye});Je(oe,xe,"prod")}catch(xe){A(Fs(xe instanceof ji&&xe.reason?xe.reason:xe.message))}finally{Ee()}},[Je,Ee]),Pe=z.useCallback(async()=>Pt.startAuth(),[]),Qe=z.useCallback(async()=>{try{await Pt.disconnect()}catch(oe){A(Fs(oe instanceof ji&&oe.reason?oe.reason:oe.message))}},[]),Ms=z.useCallback(()=>A(null),[]),Is=z.useCallback(async(oe,fe)=>{await Pt.injectInput(oe,{text:fe,submit:!0})},[]),Cs=z.useCallback((oe,fe="error")=>{A(Fs(oe,fe))},[]),sn=z.useCallback(oe=>F.get(oe)??null,[F]),Di=z.useCallback(oe=>Pt.listDir(oe),[]),li=z.useCallback(oe=>Pt.getWorkflowInputContract(oe),[]);return{state:e,loading:f,error:d,errorKind:y,reload:hs,settings:i,bootToken:co(),selectedWorkflowPath:R,setSelectedWorkflowPath:x,activeSessionId:g,setActiveSessionId:We,history:p,historyLoading:C,loadHistory:pt,createSession:xs,attachFile:Lt,listTemplates:Ns,getTemplate:fs,getWorkflowInputContract:li,sessionRecord:jt,resumeSession:ps,rehydrateSession:_s,resumeFromHistory:Qs,closeSession:ei,connectWorkflow:Ks,scanWorkflows:$s,listHarnesses:gi,bindWorkflow:ds,updateSettings:Ls,runMacro:_i,deploy:ys,startProdRun:Ae,runLocal:mt,injectInput:Is,showToast:Cs,lastDeployErrorFor:sn,deployStateByPath:ae,dismissDeployState:oe=>te(oe,null),pendingWorkspaces:ue,addPendingWorkspace:je,removePendingWorkspace:Oe,directActionSettleSeq:Le,listDir:Di,lastMessage:B,runsBySession:Mt,runsByExecution:ie,runIdsBySession:P,selectRun:Qt,previewBySession:se,toast:k,dismissToast:Ms,busySessionIds:V,tasks:ee,api:Pt,startAuth:Pe,disconnect:Qe}}const dL=10*6e4,hL=4e3;function Ll(e,t){return t?e.filter(i=>i.status!=="exited"&&(Nv(i.boundWorkflowPath??"",t)||i.boundWorkflowPath==null&&Nv(i.cwd,t))).sort((i,r)=>i.createdAt.localeCompare(r.createdAt)||i.id.localeCompare(r.id)):[]}const fL=()=>{var fa,mn,Ao,jo,vn,uc,Ro,To,pa,dc,hc,Er,Oi,ma,va,gn,_n,No,ga,Mo,Jn;const e=uL(),t=p6(),[i,r]=z.useState(!1),[o,c]=z.useState(null),f=z.useRef(new Map),l=z.useCallback(async Z=>{const Se=f.current.get(Z);try{const Ne=await e.getWorkflowInputContract(Z);return Ne.status==="unavailable"&&Se?Se:Ne}catch(Ne){if(Se)return Se;throw Ne}},[e.getWorkflowInputContract]),[d,m]=z.useState(!1),[y,v]=z.useState(!1),S=z.useRef(!1),[w,R]=z.useState(null),x=z.useRef(null),g=z.useRef(null),b=z.useRef(m6()),p=z.useRef(!1),_=z.useRef(null),[k,A]=z.useState(null),[C,N]=z.useState(null),[j,M]=z.useState(!1),[O,B]=z.useState(()=>{const Z=dn().rightTab;return Z==="canvas"||Z==="steps"||Z==="code"?Z:"canvas"}),[q,V]=z.useState(O==="code"),[J,ee]=z.useState(null),[W,Q]=z.useState(!1),[ie,I]=z.useState(!1),[P,D]=z.useState(()=>dn().sessionNames??{}),H=(Z,Se)=>{D(Ne=>{const ze={...Ne},Et=Se.trim();return Et?ze[Z]=Et:delete ze[Z],Kn({sessionNames:ze}),ze})},U=z.useRef(new Map),L=z.useRef([]),G=z.useCallback(Z=>{const Se=U.current.get(Z);if(Se)return window.clearTimeout(Se.timer),window.clearTimeout(Se.hintTimer),U.current.delete(Z),Se},[]),se=z.useCallback(Z=>{const Se=U.current.get(Z);if(!Se)return;const Ne=L.current.find(ze=>ze.id===Z);Ne&&(Ne.ready?(G(Z),e.injectInput(Z,Se.prompt).catch(()=>e.showToast(Se.failMessage))):Ne.status==="exited"&&(G(Z),e.showToast(Se.failMessage)))},[G,e.injectInput,e.showToast]),Y=z.useCallback((Z,Se,Ne)=>{G(Z);const ze=window.setTimeout(()=>{G(Z)&&e.showToast(Ne)},dL),Et=window.setTimeout(()=>{U.current.has(Z)&&e.showToast("Finish signing in or dismiss any trust or setup prompt in the terminal — your prompt sends automatically once the coding agent is ready.")},hL);U.current.set(Z,{prompt:Se,failMessage:Ne,timer:ze,hintTimer:Et}),se(Z)},[G,e.showToast,se]);z.useEffect(()=>{var Z;if(L.current=((Z=e.state)==null?void 0:Z.sessions)??[],U.current.size!==0)for(const Se of[...U.current.keys()])se(Se)},[(fa=e.state)==null?void 0:fa.sessions,se]);const[F,le]=z.useState(()=>Hv()||(dn().railCollapsed??!1)),[ae,X]=z.useState(()=>Hv()||(dn().rightCollapsed??!1)),[te,ue]=z.useState(!1),me=q6(),je=z6(),{widths:Oe,canvasResizing:Le,railResizing:at,startRailDrag:Ee,startCanvasDrag:qe,resetRail:We,resetCanvas:it}=V6(),[Ze,Je]=z.useState(!1),wt=z.useRef(!1),mt=z.useRef(null),Qt=z.useRef(null),Mt=z.useRef(!1),At=z.useRef(!1),hs=z.useRef(null),Ft=z.useRef(null),pt=z.useCallback(Z=>{Z&&!wt.current&&Z.style.setProperty("--rp-w",`${Z.offsetWidth}px`)},[]),xs=z.useCallback(Z=>{var Ne;if((Ne=Ft.current)==null||Ne.disconnect(),hs.current=Z,!Z){Ft.current=null;return}const Se=new ResizeObserver(()=>{At.current||pt(Z)});Se.observe(Z),Ft.current=Se},[pt]);wt.current=ae,At.current=Ze,z.useLayoutEffect(()=>{if(me)return;Je(!0);const Z=window.setTimeout(()=>{Je(!1),pt(hs.current)},260);return()=>window.clearTimeout(Z)},[ae,me,pt]),z.useEffect(()=>{const Z=Se=>{var ze;const Ne=Se.key.toLowerCase();if((Se.metaKey||Se.ctrlKey)&&(Ne==="k"||Ne==="p")){Se.preventDefault(),r(!0);return}if((Se.metaKey||Se.ctrlKey)&&/^[1-9]$/.test(Se.key)){const ms=Ll(((ze=e.state)==null?void 0:ze.sessions)??[],w)[Number(Se.key)-1];ms&&(Se.preventDefault(),m(!1),ee(null),Q(!1),I(!1),e.setActiveSessionId(ms.id))}};return window.addEventListener("keydown",Z),()=>window.removeEventListener("keydown",Z)},[(mn=e.state)==null?void 0:mn.sessions,w]);const Lt=l5({settingsRoot:(Ao=e.settings)==null?void 0:Ao.projectRoot,defaultProjectRoot:(jo=e.state)==null?void 0:jo.defaultProjectRoot,launchDir:(vn=e.state)==null?void 0:vn.launchDir}),Ns=async Z=>{await e.updateSettings({projectRoot:Z})};z.useEffect(()=>{var Se;if(!i||!e.state)return;const Z=ZC(e.state.sessions,((Se=e.settings)==null?void 0:Se.recentDirs)??[],e.activeSessionId);Z.length>0&&e.loadHistory(Z)},[i]);const fs=z.useRef(!1);z.useEffect(()=>{var Se;if(fs.current||!e.state)return;fs.current=!0;const Z=e.state.sessions.find(Ne=>Ne.id===e.activeSessionId);R(ra(Z)??((Se=e.state.workflows[0])==null?void 0:Se.path)??null)},[e.state,e.activeSessionId]);const jt=e.state;z.useEffect(()=>{jt&&O6(jt)},[jt,jt==null?void 0:jt.authenticated,jt==null?void 0:jt.userId,jt==null?void 0:jt.tenantId,jt==null?void 0:jt.consentSource,jt==null?void 0:jt.productAnalyticsOptIn,jt==null?void 0:jt.version]),z.useEffect(()=>{if(!jt)return;const Z=jt.sessions.find(Ne=>Ne.id===e.activeSessionId),Se={firstRun:jt.firstRun===!0,settingsOpen:j,templatesOpen:W,hasLiveSession:jt.sessions.some(Ne=>Ne.status!=="exited"),inspectingDeadSession:(Z==null?void 0:Z.status)==="exited",rightTab:O};h4(Se),$6((Z==null?void 0:Z.harness)??null)},[jt,e.activeSessionId,j,W,O]);const ps=z.useRef(me);z.useEffect(()=>{ps.current!==me&&(ps.current=me,le(me),X(me))},[me]),z.useEffect(()=>{me||Kn({railCollapsed:F,rightCollapsed:ae})},[F,ae,me]),z.useEffect(()=>{Kn({rightTab:O})},[O]);const _s=je.record,Qs=e.activeSessionId,ei=w!=null&&Ll(((uc=e.state)==null?void 0:uc.sessions)??[],w).length>0,Ks=z.useRef(!1);z.useEffect(()=>{if(Ks.current){Ks.current=!1;return}W?_s({kind:"templates"}):J?_s({kind:"review",summary:J}):d?_s({kind:"composer"}):Qs&&(w==null||ei)?_s({kind:"session",sessionId:Qs,agentPath:w}):w&&_s({kind:"agent",agentPath:w})},[_s,W,J,d,Qs,w,ei]);const $s=e.setActiveSessionId,gi=z.useCallback(Z=>{Z&&(Ks.current=!0,I(!1),Q(Z.kind==="templates"),m(Z.kind==="composer"),ee(Z.kind==="review"?Z.summary:null),Z.kind==="session"?(R(Z.agentPath),$s(Z.sessionId)):Z.kind==="agent"&&R(Z.agentPath))},[$s]),ds=((Ro=e.state)==null?void 0:Ro.sessions.find(Z=>Z.id===e.activeSessionId&&Z.status==="exited"))??null,Ls=ds!=null&&ds.agentSessionId?(To=e.history.find(Z=>Z.agentSessionId===ds.agentSessionId))==null?void 0:To.resumeMode:"rehydrate",_i=(ds==null?void 0:ds.agentSessionId)!=null&&Ls===void 0?ds.cwd:null,ys=e.loadHistory;z.useEffect(()=>{_i&&ys([_i])},[_i,ys]);const Ae=z.useRef(new Map);if(z.useEffect(()=>{for(const Z of e.tasks){if(Z.macroId!=="describe")continue;Ae.current.get(Z.id)==="running"&&Z.status!=="running"&&e.showToast(Z.status==="failed"?"Couldn't generate descriptions — check the agent terminal for details.":"Describe run finished — the canvas updates if the agent changed the source.",Z.status==="failed"?"error":"success"),Ae.current.set(Z.id,Z.status)}},[e.tasks,e.showToast]),z.useEffect(()=>{const Z=Xn();if(Z!=null&&Z.onDeepLink)return Z.onDeepLink(Se=>{var Ne;return(Ne=x.current)==null?void 0:Ne.call(x,Se)})},[]),z.useEffect(()=>{var Se;if(e.loading)return;const Z=b.current;!Z||p.current||(p.current=!0,(Se=x.current)==null||Se.call(x,Z))},[e.loading]),z.useEffect(()=>{var Se;const Z=_.current;Z&&((Se=g.current)!=null&&Se.call(g,Z))&&(_.current=null)},[(pa=e.state)==null?void 0:pa.workflows]),e.loading)return h.jsx("div",{className:"app-status",children:"Loading Agent Studio…"});if(e.error||!e.state){const Z=f6({online:t,error:e.errorKind});return h.jsx(C5,{status:Z==="online"?"error":Z,onRetry:e.reload,detail:e.error,onStartAuth:Z==="auth"?e.startAuth:void 0})}const{state:Pe}=e,Qe=Pe.sessions.find(Z=>Z.id===e.activeSessionId)??null,Ms=ra(Qe),Is=Pe.workflows.find(Z=>Z.path===Ms)??null,Cs=Pe.workflows.find(Z=>Z.path===w)??null,sn=Ll(Pe.sessions,w),Di=J!=null,li=!Di&&(Qe==null?void 0:Qe.status)==="exited",oe=!Di&&!li&&!d&&Cs!=null&&sn.length===0,fe=!Di&&!li&&!d&&!oe&&Qe!=null&&Qe.status!=="exited",ye=!Di&&!li&&(d||!oe&&!fe),xe=d&&Qe!=null&&Qe.status!=="exited",Te=oe?null:Is,ct=oe?(Cs==null?void 0:Cs.name)??null:null,xt=`${e.activeSessionId??""}::${(Te==null?void 0:Te.path)??""}`,Dt=()=>{Qt.current=e.activeSessionId??null,Mt.current=e.activeSessionId==null,X(!1)},Rt=Te?wo(Te,e.lastDeployErrorFor(Te.path)):null,Ct=e.activeSessionId?e.runsBySession.get(e.activeSessionId)??null:null,ve=Iw(Ct,Ms)?Ct:null,$e=e.activeSessionId?(e.runIdsBySession.get(e.activeSessionId)??[]).map(Z=>e.runsByExecution.get(Z)).filter(Z=>Z!==void 0).filter(Z=>Iw(Z,Ms)):[],Be=(ve==null?void 0:ve.run.status)==="running"?ve.target:null,Fe=()=>{me&&le(!0)},Ke=async(Z,Se,Ne={})=>{Ne.keepComposerOpen||m(!1),ee(null),I(!1),R(Z),e.addPendingWorkspace(Z),Fe();try{const ze=await e.createSession({cwd:Z,harness:Se});return rc("session.created"),Os("session.started",{harness_kind:Se,origin:"user"}),ze}catch(ze){throw e.removePendingWorkspace(Z),ze}},es=async(Z,Se)=>{await Ke(Z,Se)},Ye=(Z,Se,Ne)=>{const ze=`Scaffold a new Sapiom agent project in this directory: ${Ov(Se,"default")}, then run npm install, read AGENTS.md, and use the sapiom-agent-authoring skill to`,Et=Ne==null?void 0:Ne.trim();Y(Z.id,Et?`${ze} build this:
493
493
 
494
- ${Et}`:`${ze} define the first agent.`,"Couldn't send the scaffold prompt. Ask the coding agent to call sapiom_dev_agents_scaffold.")},ts=async(Z,Se,Ne)=>{const ze=await Ke(Z,Se);Ye(ze,Z,Ne)},et=Z=>{var Et;if(S.current)return;S.current=!0,v(!0);const Se=w,Ne=ra(Z),ze=Ne?((Et=Pe.workflows.find(ms=>Nv(ms.path,Ne)))==null?void 0:Et.name)??Gn(Ne):null;(async()=>{try{const ms=await Ke(Z.cwd,Z.harness);if(!Ne){R(Z.cwd);return}try{await e.bindWorkflow(ms.id,Ne),R(Ne)}catch{R(Z.cwd),e.showToast(`Session started, but couldn't attach it to ${ze??"the agent"}.`)}}catch{R(Se??Ne??Z.cwd),e.setActiveSessionId(Z.id),e.showToast("Couldn't start the session.")}finally{S.current=!1,v(!1)}})()},dt=Z=>{(async()=>{const Se=Ll(Pe.sessions,Z.path)[0],Ne=(Se==null?void 0:Se.cwd)??Z.path;try{const ze=await Ke(Ne,"claude-code");await e.bindWorkflow(ze.id,Z.path),R(Z.path)}catch(ze){e.showToast(ze.message||"Couldn't start the session.")}})()},It=Z=>{var Ne;const Se=((Ne=Pe.sessions.find(ze=>ze.id===Z))==null?void 0:Ne.cwd)??".";Y(Z,`Scaffold a new Sapiom agent project in this directory: ${Ov(Se,"default")}, then run npm install, read AGENTS.md, and use the sapiom-agent-authoring skill to define the first agent.`,"Couldn't send the scaffold prompt. Ask the coding agent to call sapiom_dev_agents_scaffold.")},Ys=async(Z,Se,Ne="template_gallery")=>{const ze=await Ke(Z,"claude-code");Os("agent.template_cloned",{template_slug:Se.id,template_id:Se.id,surface:Ne}),Y(ze.id,p5(Se,Z),Se.kind==="gallery"?"Couldn't send the clone prompt. Ask the coding agent to run sapiom_dev_agents_clone.":"Couldn't send the starter prompt. Ask the coding agent to call sapiom_dev_agents_scaffold.")},nn=Z=>{const Se=new Set;for(const Ne of Pe.sessions){const ze=Gn(Ne.cwd);ze&&Se.add(ze)}for(const Ne of Pe.workflows){const ze=Gn(Ne.path);ze&&Se.add(ze)}return XC(u5(Z,Se),Lt||null)},pn=async(Z,Se,Ne)=>{const ze=nn(Z.trim()?o5(Z):vg);if(!ze)throw new Error("Set a project folder first — use the + to open one.");X(!0);const Et=await Ke(ze,Se,{keepComposerOpen:!0});try{const ms=await C$(Et.id,Ne,e.attachFile);Ye(Et,ze,E$(Z,ms)),m(!1)}catch(ms){throw await e.closeSession(Et.id).catch(Es=>{console.error("[harness] attachment rollback failed:",Es)}),e.removePendingWorkspace(ze),ms}},ua=Z=>{const Se=nn(Z.id);if(!Se){e.showToast("Set a project folder first — use the + to open one.");return}X(!0),Ys(Se,Z,"welcome")},yi=async Z=>{const Se=await e.scanWorkflows(Z);return e.showToast(Se.length===0?"No agent projects found under this folder.":Se.length===1?"Found 1 agent project.":`Found ${Se.length} agent projects.`,Se.length===0?"info":"success"),Se.length},ti=Z=>{m(!1),ee(null),Q(!1),I(!1),Fe();const Se=Pe.sessions.find(Ne=>Ne.id===Z);Se&&R(ra(Se)??Se.cwd),e.setActiveSessionId(Z)},oc=Z=>{m(!1),ee(null),Q(!1),I(!1),e.setActiveSessionId(Z)},lc=Z=>{m(!1),ee(Z),Q(!1),I(!1),Fe()},Co=Z=>{var Ne;const Se=(Ne=e.settings)==null?void 0:Ne.editor;e.showToast(`Opening in ${Dw(Se)}… Pick a different editor in Settings.`,"info"),window.location.href=J$(Se,Z)},Eo=Z=>{var ze;m(!1),ee(null),Q(!1),I(!1),R(Z),Fe();const Se=Ll(Pe.sessions,Z),Ne=Se.some(Et=>Et.id===e.activeSessionId)?e.activeSessionId:((ze=Se[Se.length-1])==null?void 0:ze.id)??null;Ne!==e.activeSessionId&&e.setActiveSessionId(Ne)};g.current=Z=>{const Se=Pe.workflows.find(Ne=>Ne.definitionId!=null&&String(Ne.definitionId)===Z);return Se?(Eo(Se.path),!0):!1},x.current=Z=>{var Se;if(Z.kind==="template"){N(Z.templateId),Q(!0),I(!1);return}(Se=g.current)!=null&&Se.call(g,Z.definitionId)||A(Z)};const da=async Z=>{var Ne;A(null);const Se=nn(((Ne=Z.slug)==null?void 0:Ne.trim())||`agent-${Z.definitionId}`);if(!Se){e.showToast("Set a project folder first — use the + to open one.");return}_.current=Z.definitionId,X(!0);try{const ze=await Ke(Se,"claude-code");Y(ze.id,m5(Z.definitionId,Se),"Couldn't send the clone prompt. Ask the coding agent to run sapiom_dev_agents_clone.")}catch(ze){_.current=null,e.showToast(ze.message||"Couldn't start a session to clone the agent.")}},ha=async Z=>{Fe();const Se=Pe.sessions.filter(Es=>Es.status!=="exited"),Ne=Es=>Es.boundWorkflowPath===Z||mg(Es.cwd,Z),ze=Se.find(Es=>Es.id===e.activeSessionId),Et=ze&&Ne(ze)?ze:Se.filter(Ne).sort((Es,kr)=>kr.cwd.length-Es.cwd.length||kr.createdAt.localeCompare(Es.createdAt))[0];let ms;if(Et)m(!1),ee(null),I(!1),Et.id!==e.activeSessionId&&e.setActiveSessionId(Et.id),ms=Et.id;else try{ms=(await Ke(Z,"claude-code")).id}catch(Es){return e.showToast(Es.message||"Couldn't start a session in this folder."),null}return await e.bindWorkflow(ms,Z),R(Z),ms},si=(Z,Se)=>{(async()=>{const Ne=n2(Se.id);((Ne==="deploy"||Ne==="run-local")&&Z!=null||Ne==="prod-run"&&(Z==null?void 0:Z.definitionId)!=null&&zd(Z))&&(B("steps"),X(!1));let Et=e.activeSessionId;if(Z&&(Et=await ha(Z.path)??Et),Se.action.kind==="open-url"){window.open(V5(Se.action.url,Z),"_blank","noopener,noreferrer");return}if(Et){if(Ne!==null){if(Ne==="deploy")Z?e.deploy(Z.path):e.showToast("Select an agent first.");else if(Ne==="prod-run")if((Z==null?void 0:Z.definitionId)!=null&&zd(Z))e.startProdRun(Et,String(Z.definitionId));else{const ms=Z?e.lastDeployErrorFor(Z.path):null,Es=Z?wo(Z,ms):"draft";e.showToast(Es==="failed"?"Last deploy failed — retry Deploy.":Es==="building"?"The cloud build is still in progress.":Es==="linked"?"No ready deployment yet — deploy it first.":"This agent isn't deployed yet — deploy it first.")}else Ne==="run-local"&&(Z?e.runLocal(Et,Z.path):e.showToast("Select an agent first."));return}e.runMacro(Se.id,{harnessSessionId:Et,workflowPath:Z==null?void 0:Z.path})}})()},ko=Z=>{const Se=o;Se&&(c(null),B("steps"),X(!1),(async()=>{const Ne=await ha(Se.workflow.path)??e.activeSessionId;if(Ne)if(Se.target==="prod"){if(Se.workflow.definitionId==null||!zd(Se.workflow)){e.showToast("This agent needs a ready cloud deployment first.");return}await e.startProdRun(Ne,String(Se.workflow.definitionId),Z)}else await e.runLocal(Ne,Se.workflow.path,Z)})())},cc=Z=>{(async()=>{const Se=await ha(Z.path)??e.activeSessionId;Se&&e.runMacro("describe",{harnessSessionId:Se,workflowPath:Z.path,subject:L6(Z)})})()};return h.jsxs("div",{className:"app-shell","data-rail-collapsed":F||void 0,children:[me&&!F&&h.jsx("div",{className:"shell-scrim","data-testid":"rail-drawer-scrim","aria-hidden":"true",onClick:()=>le(!0)}),(!me||!F)&&h.jsx("div",{className:"rail-slot"+(at?" is-resizing":"")+(!me&&F?" is-collapsed":""),inert:!me&&F?!0:void 0,style:me?void 0:{width:F?0:Oe.rail},children:h.jsx(l6,{projectRoot:Lt||null,onSaveProjectRoot:Ns,width:Oe.rail,minWidth:Ag,workflows:Pe.workflows,sessions:Pe.sessions,pendingWorkspaces:e.pendingWorkspaces,activeSessionId:e.activeSessionId,focusedAgentPath:w,onFocusAgent:Eo,onOpenPalette:()=>r(!0),onConnect:async Z=>{await e.connectWorkflow(Z)},onCollapse:()=>le(!0),canGoBack:je.canGoBack,canGoForward:je.canGoForward,onGoBack:()=>gi(je.goBack()),onGoForward:()=>gi(je.goForward()),onSelectSession:ti,overviewSelected:ie,onSelectOverview:()=>{I(!0),m(!1),ee(null),Q(!1),Fe()},onNewSession:()=>{m(!0),Q(!1),I(!1)},onReviewSummary:lc,history:e.history,historyLoading:e.historyLoading,onOpenHistory:Z=>void e.loadHistory(Z),recentDirs:((dc=e.settings)==null?void 0:dc.recentDirs)??[],launchDir:Pe.launchDir??null,listDir:e.listDir,onCreateSession:es,listHarnesses:e.listHarnesses,onScaffoldSession:ts,onScaffoldInSession:It,onBrowseTemplates:()=>{Q(!0),I(!1)},templatesActive:W,onScanWorkflows:yi,onToast:e.showToast,telemetryOptIn:((hc=e.settings)==null?void 0:hc.telemetryOptIn)??Pe.telemetryOptIn,consentSource:Pe.consentSource,consentEnvReason:Pe.consentEnvReason,authenticated:Pe.authenticated,organizationName:Pe.organizationName,onToggleTelemetry:async Z=>{await e.updateSettings({telemetryOptIn:Z})},productAnalyticsOptIn:Pe.productAnalyticsOptIn,onToggleProductAnalytics:async Z=>{await e.updateSettings({productAnalyticsOptIn:Z})},rollingSummary:((Er=e.settings)==null?void 0:Er.rollingSummary)===!0,onToggleRollingSummary:async Z=>{await e.updateSettings({rollingSummary:Z})},editor:$h((Oi=e.settings)==null?void 0:Oi.editor),onSelectEditor:async Z=>{await e.updateSettings({editor:Z})},onStartAuth:e.startAuth,onDisconnect:e.disconnect,settingsOpen:j,onSetSettingsOpen:M})}),!F&&!me&&h.jsx("div",{className:"pane-resize-handle pane-resize-handle-rail",style:{left:Oe.rail},onPointerDown:Ee,onDoubleClick:We,role:"separator","aria-orientation":"vertical","aria-label":"Resize workspace rail","data-testid":"resize-handle-rail"}),h.jsxs("div",{className:"workspace-main",children:[!t&&h.jsx(E5,{}),Pe.consentSource==="default-silent"&&!((ma=e.settings)!=null&&ma.telemetryNoticeDismissed)&&h.jsx(TO,{onDismiss:()=>{e.updateSettings({telemetryNoticeDismissed:!0})},onOpenSettings:()=>M(!0)}),h.jsxs("div",{className:"app"+(W?" is-browsing":"")+(!W&&!me&&!ye?" canvas-animated":"")+(Ze?" canvas-sliding":"")+(Le?" canvas-dragging":""),style:{gridTemplateColumns:W||me||ye?"minmax(0, 1fr)":`minmax(${ac}px, 1fr) ${ae?Oe.canvas==null?"0fr":"0px":Oe.canvas==null?"1fr":`${Oe.canvas}px`}`},children:[W&&h.jsx(FO,{projectRoot:Lt||null,recentDirs:((va=e.settings)==null?void 0:va.recentDirs)??[],listDir:e.listDir,onExit:()=>Q(!1),onUse:Ys,listTemplates:e.listTemplates,getTemplate:e.getTemplate,openTemplateId:C}),h.jsxs("div",{className:"center-pane",children:[h.jsx(U5,{openedAgentName:ct,reviewTitle:J?J.title:null,composing:ye,onBack:xe?()=>m(!1):null,activeSession:fe||li?Qe:null,sessionName:Qe?mh(Qe,Pe.sessions,P):null,onRenameSession:H,boundWorkflowName:(Is==null?void 0:Is.name)??null,sessions:fe?sn:[],busySessionIds:e.busySessionIds,onSelectSession:oc,labelOf:Z=>mh(Z,Pe.sessions,P),busy:Qe!=null&&e.busySessionIds.has(Qe.id),onCloseSession:Z=>void e.closeSession(Z),onOpenInEditor:Co,editorLabel:Dw((gn=e.settings)==null?void 0:gn.editor),onToast:e.showToast,onExpandRail:F?()=>le(!1):null,onExpandRight:ae?Dt:null,subjectName:(Cs==null?void 0:Cs.name)??(Qe?Gn(Qe.cwd):null),newSessionPending:y,onNewSession:Qe?()=>et(Qe):null,actions:fe&&Qe&&Is?h.jsx(CO,{workflow:Is,activeSessionId:e.activeSessionId,sessionReady:Qe.ready===!0&&Qe.status!=="exited",macros:Pe.macros,onRunMacro:Z=>si(Is,Z),onRequestRun:(Z,Se)=>c({workflow:Is,target:Z,returnFocus:Se}),preview:e.previewBySession.get(Qe.id)??null,lastDeployError:e.lastDeployErrorFor(Is.path),authenticated:Pe.authenticated,directActionSettleSeq:e.directActionSettleSeq,runningTarget:Be}):null}),h.jsx("div",{className:"terminal-slot",children:Di&&J?h.jsx(P5,{summary:J,loadRecord:e.sessionRecord,onStart:()=>{const Z=J;ee(null),e.resumeFromHistory(Z)},onClose:()=>ee(null)}):li&&Qe?h.jsx(I5,{session:Qe,resumeMode:Ls,loadRecord:e.sessionRecord,onResume:()=>void e.resumeSession(Qe.id),onContinue:()=>void e.rehydrateSession({cwd:Qe.cwd,harness:Qe.harness,from:Qe.id}),onClose:()=>void e.closeSession(Qe.id)}):oe&&Cs?h.jsx(Zi,{className:"terminal-empty",testId:"open-agent-empty",icon:"Radio",title:`No running session for ${Cs.name}`,body:"Start a session to map, run, and inspect this agent.",cta:h.jsxs("button",{className:"btn-primary","data-testid":"open-agent-start-session",onClick:()=>dt(Cs),children:[h.jsx(de,{name:"Plus",size:14})," Start session"]})}):fe&&e.activeSessionId?h.jsx("div",{className:"agent-view","data-testid":"agent-view",children:h.jsx("div",{className:"agent-view-panel",id:"agent-panel-terminal",children:h.jsx(a$,{sessionId:e.activeSessionId,token:e.bootToken,cwd:(Qe==null?void 0:Qe.cwd)??null})})}):h.jsx(P$,{firstRun:Pe.firstRun===!0,onSubmitIdea:pn,onAttachmentError:e.showToast,onUseTemplate:ua,onBrowseTemplates:()=>Q(!0),listHarnesses:e.listHarnesses,listTemplates:e.listTemplates,telemetryOptIn:((_n=e.settings)==null?void 0:_n.telemetryOptIn)??Pe.telemetryOptIn,onToggleTelemetry:async Z=>{await e.updateSettings({telemetryOptIn:Z})},recentDirs:((No=e.settings)==null?void 0:No.recentDirs)??[],projectRoot:Lt||null,listDir:e.listDir,onConnect:async Z=>{await e.connectWorkflow(Z)},onScan:yi,onScaffold:ts,onSaveProjectRoot:Ns})})]}),!ae&&!me&&!ye&&h.jsx("div",{className:"pane-resize-handle pane-resize-handle-canvas",style:{right:Oe.canvas==null?"50%":`min(${Oe.canvas}px, calc(100% - ${ac}px))`},onPointerDown:qe,onDoubleClick:it,role:"separator","aria-orientation":"vertical","aria-label":"Resize canvas pane","data-testid":"resize-handle-canvas"}),me&&!ae&&h.jsx("div",{className:"shell-scrim","data-testid":"right-sheet-scrim","aria-hidden":"true",onClick:()=>X(!0)}),h.jsxs("div",{ref:xs,className:"right-pane"+(ae||ye?" is-collapsed":""),children:[h.jsxs("div",{className:"right-pane-tabs",role:"tablist","aria-label":"Right pane",children:[h.jsxs("button",{role:"tab","aria-selected":O==="canvas",className:"right-pane-tab"+(O==="canvas"?" is-active":""),onClick:()=>B("canvas"),"data-testid":"right-tab-canvas",children:[h.jsx(de,{name:"Workflow",size:14}),"Canvas"]}),h.jsxs("button",{role:"tab","aria-selected":O==="steps",className:"right-pane-tab"+(O==="steps"?" is-active":""),onClick:()=>B("steps"),"data-testid":"right-tab-steps",children:[h.jsx(de,{name:"List",size:14}),"Steps"]}),h.jsxs("button",{role:"tab","aria-selected":O==="code",className:"right-pane-tab"+(O==="code"?" is-active":""),onClick:()=>{B("code"),V(!0)},"data-testid":"right-tab-code",children:[h.jsx(de,{name:"Code",size:14}),"Code"]}),h.jsxs("div",{className:"right-pane-corner",children:[O==="canvas"&&(Te==null?void 0:Te.definitionId)!=null&&h.jsxs("a",{className:"status-tag status-tag-action workflow-deployed-tag right-pane-deployed","data-testid":"workflow-dashboard-link","data-deployment-state":Rt??void 0,href:xh(Te.definitionId),target:"_blank",rel:"noreferrer","aria-label":`${Rt} — open in the Sapiom dashboard`,"data-tooltip":"Open this agent in the Sapiom dashboard",children:[h.jsx(de,{name:"Cloud",size:12}),Rt==="ready"?"deployed":Rt==="building"?"building":Rt==="failed"?"deploy failed":"linked"]}),(O==="canvas"||O==="steps")&&h.jsx("button",{className:"theme-toggle","data-testid":"canvas-expand",hidden:te,"aria-label":O==="steps"?"Open Focus mode":"Expand canvas",title:O==="steps"?"Open Focus mode":"Expand canvas",onClick:()=>ue(Z=>!Z),children:h.jsx(de,{name:"Maximize2",size:15})}),h.jsx("button",{className:"theme-toggle right-pane-collapse","data-testid":"right-collapse","aria-label":"Collapse canvas panel",title:"Collapse canvas panel",onClick:()=>X(!0),children:h.jsx(de,{name:"PanelRightClose",size:15})})]})]}),h.jsx("div",{className:"right-pane-panel"+(O==="canvas"||O==="steps"?"":" is-hidden"),"data-testid":"right-panel-canvas",children:h.jsx(v4,{sessionId:e.activeSessionId,lastMessage:e.lastMessage,boundWorkflow:Te,noSessionAgent:ct,overviewActive:ye,sessionExited:li,onCanvasState:Z=>{var ze;if(me)return;const Se=((ze=Pe.sessions.find(Et=>Et.id===e.activeSessionId))==null?void 0:ze.status)==="exited";if(Z||Se){mt.current=null,X(!1);return}if(Mt.current){Mt.current=!1,Qt.current=e.activeSessionId??null;return}const Ne=Qt.current;Ne!=null&&Ne===e.activeSessionId||mt.current!==xt&&(mt.current=xt,X(!0))},onGraphChange:(Z,Se)=>{const Ne=bO(Se);Ne&&f.current.set(Z,Ne)},expanded:te,onToggleExpanded:()=>ue(Z=>!Z),macros:Pe.macros,tasks:e.tasks,surface:O==="steps"?"steps":"board",onOpenSteps:()=>B("steps"),run:(ve==null?void 0:ve.run)??null,runTarget:(ve==null?void 0:ve.target)??null,runs:$e,onSelectRun:Z=>{e.activeSessionId&&e.selectRun(e.activeSessionId,Z)},preview:e.activeSessionId?e.previewBySession.get(e.activeSessionId)??null:null,deployState:Te?e.deployStateByPath.get(Te.path)??null:null,onDismissDeploy:()=>{Te&&e.dismissDeployState(Te.path)},onOpenCode:()=>{B("code"),V(!0)},workflows:Pe.workflows,onOpenWorkflow:Z=>void ha(Z),onRunMacro:Z=>si(Is,Z),onInjectPrompt:Z=>{e.activeSessionId&&e.injectInput(e.activeSessionId,Z)},onDescribeWorkflow:cc})}),(O==="code"||q)&&h.jsx("div",{className:"right-pane-panel"+(O==="code"?"":" is-hidden"),"data-testid":"right-panel-code",children:h.jsx(N4,{boundWorkflow:Te,noSessionAgent:ct,agentsBaseUrl:Pe.agentsBaseUrl,lastDeployError:Te?e.lastDeployErrorFor(Te.path):null})})]})]})]}),ie&&h.jsx(B$,{firstRun:Pe.firstRun===!0,appVersion:((ga=Xn())==null?void 0:ga.appVersion)||"0.8.8",recentDirs:((Mo=e.settings)==null?void 0:Mo.recentDirs)??[],projectRoot:Lt||null,listDir:e.listDir,onConnect:async Z=>{await e.connectWorkflow(Z),I(!1)},onScan:yi,onBrowseTemplates:()=>{I(!1),Q(!0)},onDismiss:()=>I(!1)}),i&&h.jsx(w5,{sessions:Pe.sessions,workflows:Pe.workflows,recentDirs:((Jn=e.settings)==null?void 0:Jn.recentDirs)??[],history:e.history,sessionNames:P,activeSessionId:e.activeSessionId,listDir:e.listDir,listTemplates:e.listTemplates,onSelectSession:ti,onReviewSummary:lc,onOpenPath:Z=>void es(Z,"claude-code"),onOpenTemplate:Z=>{N(Z),Q(!0),I(!1)},actions:[{id:"browse-templates",label:"Browse templates",meta:"Gallery and starters",icon:"LayoutTemplate",run:()=>{Q(!0),I(!1)}},{id:"toggle-theme",label:"Toggle theme",meta:"Light and dark",icon:"Sun",run:Ww},{id:"toggle-rail",label:F?"Show workspace panel":"Hide workspace panel",meta:"Left pane",icon:"Menu",run:()=>le(Z=>!Z)},{id:"toggle-right",label:ae?"Show canvas panel":"Hide canvas panel",meta:"Right pane",icon:ae?"PanelRightOpen":"PanelRightClose",run:()=>X(Z=>!Z)},...Qe?[{id:"new-session-here",label:"New session in this folder",meta:Qe.cwd,icon:"Plus",run:()=>void es(Qe.cwd,"claude-code")}]:[]],onClose:()=>r(!1)}),k&&h.jsx(v6,{agentLabel:k.slug?`“${k.slug}”`:`Agent ${k.definitionId}`,onCancel:()=>A(null),onConfirm:()=>void da(k)}),o&&h.jsx(RO,{workflow:o.workflow,target:o.target,loadContract:l,returnFocus:o.returnFocus,onClose:()=>c(null),onRun:ko}),e.toast&&h.jsx(u$,{message:e.toast.message,tone:e.toast.tone,onDismiss:e.dismissToast}),h.jsx(d$,{})]})};function pL(e=document.documentElement,t=window){const i=c=>{e.dataset.windowFocused=c?"true":"false"};i(t.document.hasFocus());const r=()=>i(!0),o=()=>i(!1);return t.addEventListener("focus",r),t.addEventListener("blur",o),()=>{t.removeEventListener("focus",r),t.removeEventListener("blur",o)}}function mL(e=typeof window>"u"?"":window.location.search){return new URLSearchParams(e).get("frame")==="macos"?"macos":"web"}document.documentElement.dataset.windowFrame=mL();pL();window.addEventListener("scroll",()=>{(window.scrollX!==0||window.scrollY!==0)&&window.scrollTo(0,0)},{passive:!0});window.addEventListener("dragover",e=>{var t;(t=e.dataTransfer)!=null&&t.types.includes("Files")&&e.preventDefault()});window.addEventListener("drop",e=>{var t;(t=e.dataTransfer)!=null&&t.types.includes("Files")&&e.preventDefault()});eA.createRoot(document.getElementById("root")).render(h.jsx(z.StrictMode,{children:h.jsx(fL,{})}));
494
+ ${Et}`:`${ze} define the first agent.`,"Couldn't send the scaffold prompt. Ask the coding agent to call sapiom_dev_agents_scaffold.")},ts=async(Z,Se,Ne)=>{const ze=await Ke(Z,Se);Ye(ze,Z,Ne)},et=Z=>{var Et;if(S.current)return;S.current=!0,v(!0);const Se=w,Ne=ra(Z),ze=Ne?((Et=Pe.workflows.find(ms=>Nv(ms.path,Ne)))==null?void 0:Et.name)??Gn(Ne):null;(async()=>{try{const ms=await Ke(Z.cwd,Z.harness);if(!Ne){R(Z.cwd);return}try{await e.bindWorkflow(ms.id,Ne),R(Ne)}catch{R(Z.cwd),e.showToast(`Session started, but couldn't attach it to ${ze??"the agent"}.`)}}catch{R(Se??Ne??Z.cwd),e.setActiveSessionId(Z.id),e.showToast("Couldn't start the session.")}finally{S.current=!1,v(!1)}})()},dt=Z=>{(async()=>{const Se=Ll(Pe.sessions,Z.path)[0],Ne=(Se==null?void 0:Se.cwd)??Z.path;try{const ze=await Ke(Ne,"claude-code");await e.bindWorkflow(ze.id,Z.path),R(Z.path)}catch(ze){e.showToast(ze.message||"Couldn't start the session.")}})()},It=Z=>{var Ne;const Se=((Ne=Pe.sessions.find(ze=>ze.id===Z))==null?void 0:Ne.cwd)??".";Y(Z,`Scaffold a new Sapiom agent project in this directory: ${Ov(Se,"default")}, then run npm install, read AGENTS.md, and use the sapiom-agent-authoring skill to define the first agent.`,"Couldn't send the scaffold prompt. Ask the coding agent to call sapiom_dev_agents_scaffold.")},Ys=async(Z,Se,Ne="template_gallery")=>{const ze=await Ke(Z,"claude-code");Os("agent.template_cloned",{template_slug:Se.id,template_id:Se.id,surface:Ne}),Y(ze.id,p5(Se,Z),Se.kind==="gallery"?"Couldn't send the clone prompt. Ask the coding agent to run sapiom_dev_agents_clone.":"Couldn't send the starter prompt. Ask the coding agent to call sapiom_dev_agents_scaffold.")},nn=Z=>{const Se=new Set;for(const Ne of Pe.sessions){const ze=Gn(Ne.cwd);ze&&Se.add(ze)}for(const Ne of Pe.workflows){const ze=Gn(Ne.path);ze&&Se.add(ze)}return XC(u5(Z,Se),Lt||null)},pn=async(Z,Se,Ne)=>{const ze=nn(Z.trim()?o5(Z):vg);if(!ze)throw new Error("Set a project folder first — use the + to open one.");X(!0);const Et=await Ke(ze,Se,{keepComposerOpen:!0});try{const ms=await C$(Et.id,Ne,e.attachFile);Ye(Et,ze,E$(Z,ms)),m(!1)}catch(ms){throw await e.closeSession(Et.id).catch(Es=>{console.error("[harness] attachment rollback failed:",Es)}),e.removePendingWorkspace(ze),ms}},ua=Z=>{const Se=nn(Z.id);if(!Se){e.showToast("Set a project folder first — use the + to open one.");return}X(!0),Ys(Se,Z,"welcome")},yi=async Z=>{const Se=await e.scanWorkflows(Z);return e.showToast(Se.length===0?"No agent projects found under this folder.":Se.length===1?"Found 1 agent project.":`Found ${Se.length} agent projects.`,Se.length===0?"info":"success"),Se.length},ti=Z=>{m(!1),ee(null),Q(!1),I(!1),Fe();const Se=Pe.sessions.find(Ne=>Ne.id===Z);Se&&R(ra(Se)??Se.cwd),e.setActiveSessionId(Z)},oc=Z=>{m(!1),ee(null),Q(!1),I(!1),e.setActiveSessionId(Z)},lc=Z=>{m(!1),ee(Z),Q(!1),I(!1),Fe()},Co=Z=>{var Ne;const Se=(Ne=e.settings)==null?void 0:Ne.editor;e.showToast(`Opening in ${Dw(Se)}… Pick a different editor in Settings.`,"info"),window.location.href=J$(Se,Z)},Eo=Z=>{var ze;m(!1),ee(null),Q(!1),I(!1),R(Z),Fe();const Se=Ll(Pe.sessions,Z),Ne=Se.some(Et=>Et.id===e.activeSessionId)?e.activeSessionId:((ze=Se[Se.length-1])==null?void 0:ze.id)??null;Ne!==e.activeSessionId&&e.setActiveSessionId(Ne)};g.current=Z=>{const Se=Pe.workflows.find(Ne=>Ne.definitionId!=null&&String(Ne.definitionId)===Z);return Se?(Eo(Se.path),!0):!1},x.current=Z=>{var Se;if(Z.kind==="template"){N(Z.templateId),Q(!0),I(!1);return}(Se=g.current)!=null&&Se.call(g,Z.definitionId)||A(Z)};const da=async Z=>{var Ne;A(null);const Se=nn(((Ne=Z.slug)==null?void 0:Ne.trim())||`agent-${Z.definitionId}`);if(!Se){e.showToast("Set a project folder first — use the + to open one.");return}_.current=Z.definitionId,X(!0);try{const ze=await Ke(Se,"claude-code");Y(ze.id,m5(Z.definitionId,Se),"Couldn't send the clone prompt. Ask the coding agent to run sapiom_dev_agents_clone.")}catch(ze){_.current=null,e.showToast(ze.message||"Couldn't start a session to clone the agent.")}},ha=async Z=>{Fe();const Se=Pe.sessions.filter(Es=>Es.status!=="exited"),Ne=Es=>Es.boundWorkflowPath===Z||mg(Es.cwd,Z),ze=Se.find(Es=>Es.id===e.activeSessionId),Et=ze&&Ne(ze)?ze:Se.filter(Ne).sort((Es,kr)=>kr.cwd.length-Es.cwd.length||kr.createdAt.localeCompare(Es.createdAt))[0];let ms;if(Et)m(!1),ee(null),I(!1),Et.id!==e.activeSessionId&&e.setActiveSessionId(Et.id),ms=Et.id;else try{ms=(await Ke(Z,"claude-code")).id}catch(Es){return e.showToast(Es.message||"Couldn't start a session in this folder."),null}return await e.bindWorkflow(ms,Z),R(Z),ms},si=(Z,Se)=>{(async()=>{const Ne=n2(Se.id);((Ne==="deploy"||Ne==="run-local")&&Z!=null||Ne==="prod-run"&&(Z==null?void 0:Z.definitionId)!=null&&zd(Z))&&(B("steps"),X(!1));let Et=e.activeSessionId;if(Z&&(Et=await ha(Z.path)??Et),Se.action.kind==="open-url"){window.open(V5(Se.action.url,Z),"_blank","noopener,noreferrer");return}if(Et){if(Ne!==null){if(Ne==="deploy")Z?e.deploy(Z.path):e.showToast("Select an agent first.");else if(Ne==="prod-run")if((Z==null?void 0:Z.definitionId)!=null&&zd(Z))e.startProdRun(Et,String(Z.definitionId));else{const ms=Z?e.lastDeployErrorFor(Z.path):null,Es=Z?wo(Z,ms):"draft";e.showToast(Es==="failed"?"Last deploy failed — retry Deploy.":Es==="building"?"The cloud build is still in progress.":Es==="linked"?"No ready deployment yet — deploy it first.":"This agent isn't deployed yet — deploy it first.")}else Ne==="run-local"&&(Z?e.runLocal(Et,Z.path):e.showToast("Select an agent first."));return}e.runMacro(Se.id,{harnessSessionId:Et,workflowPath:Z==null?void 0:Z.path})}})()},ko=Z=>{const Se=o;Se&&(c(null),B("steps"),X(!1),(async()=>{const Ne=await ha(Se.workflow.path)??e.activeSessionId;if(Ne)if(Se.target==="prod"){if(Se.workflow.definitionId==null||!zd(Se.workflow)){e.showToast("This agent needs a ready cloud deployment first.");return}await e.startProdRun(Ne,String(Se.workflow.definitionId),Z)}else await e.runLocal(Ne,Se.workflow.path,Z)})())},cc=Z=>{(async()=>{const Se=await ha(Z.path)??e.activeSessionId;Se&&e.runMacro("describe",{harnessSessionId:Se,workflowPath:Z.path,subject:L6(Z)})})()};return h.jsxs("div",{className:"app-shell","data-rail-collapsed":F||void 0,children:[me&&!F&&h.jsx("div",{className:"shell-scrim","data-testid":"rail-drawer-scrim","aria-hidden":"true",onClick:()=>le(!0)}),(!me||!F)&&h.jsx("div",{className:"rail-slot"+(at?" is-resizing":"")+(!me&&F?" is-collapsed":""),inert:!me&&F?!0:void 0,style:me?void 0:{width:F?0:Oe.rail},children:h.jsx(l6,{projectRoot:Lt||null,onSaveProjectRoot:Ns,width:Oe.rail,minWidth:Ag,workflows:Pe.workflows,sessions:Pe.sessions,pendingWorkspaces:e.pendingWorkspaces,activeSessionId:e.activeSessionId,focusedAgentPath:w,onFocusAgent:Eo,onOpenPalette:()=>r(!0),onConnect:async Z=>{await e.connectWorkflow(Z)},onCollapse:()=>le(!0),canGoBack:je.canGoBack,canGoForward:je.canGoForward,onGoBack:()=>gi(je.goBack()),onGoForward:()=>gi(je.goForward()),onSelectSession:ti,overviewSelected:ie,onSelectOverview:()=>{I(!0),m(!1),ee(null),Q(!1),Fe()},onNewSession:()=>{m(!0),Q(!1),I(!1)},onReviewSummary:lc,history:e.history,historyLoading:e.historyLoading,onOpenHistory:Z=>void e.loadHistory(Z),recentDirs:((dc=e.settings)==null?void 0:dc.recentDirs)??[],launchDir:Pe.launchDir??null,listDir:e.listDir,onCreateSession:es,listHarnesses:e.listHarnesses,onScaffoldSession:ts,onScaffoldInSession:It,onBrowseTemplates:()=>{Q(!0),I(!1)},templatesActive:W,onScanWorkflows:yi,onToast:e.showToast,telemetryOptIn:((hc=e.settings)==null?void 0:hc.telemetryOptIn)??Pe.telemetryOptIn,consentSource:Pe.consentSource,consentEnvReason:Pe.consentEnvReason,authenticated:Pe.authenticated,organizationName:Pe.organizationName,onToggleTelemetry:async Z=>{await e.updateSettings({telemetryOptIn:Z})},productAnalyticsOptIn:Pe.productAnalyticsOptIn,onToggleProductAnalytics:async Z=>{await e.updateSettings({productAnalyticsOptIn:Z})},rollingSummary:((Er=e.settings)==null?void 0:Er.rollingSummary)===!0,onToggleRollingSummary:async Z=>{await e.updateSettings({rollingSummary:Z})},editor:$h((Oi=e.settings)==null?void 0:Oi.editor),onSelectEditor:async Z=>{await e.updateSettings({editor:Z})},onStartAuth:e.startAuth,onDisconnect:e.disconnect,settingsOpen:j,onSetSettingsOpen:M})}),!F&&!me&&h.jsx("div",{className:"pane-resize-handle pane-resize-handle-rail",style:{left:Oe.rail},onPointerDown:Ee,onDoubleClick:We,role:"separator","aria-orientation":"vertical","aria-label":"Resize workspace rail","data-testid":"resize-handle-rail"}),h.jsxs("div",{className:"workspace-main",children:[!t&&h.jsx(E5,{}),Pe.consentSource==="default-silent"&&!((ma=e.settings)!=null&&ma.telemetryNoticeDismissed)&&h.jsx(TO,{onDismiss:()=>{e.updateSettings({telemetryNoticeDismissed:!0})},onOpenSettings:()=>M(!0)}),h.jsxs("div",{className:"app"+(W?" is-browsing":"")+(!W&&!me&&!ye?" canvas-animated":"")+(Ze?" canvas-sliding":"")+(Le?" canvas-dragging":""),style:{gridTemplateColumns:W||me||ye?"minmax(0, 1fr)":`minmax(${ac}px, 1fr) ${ae?Oe.canvas==null?"0fr":"0px":Oe.canvas==null?"1fr":`${Oe.canvas}px`}`},children:[W&&h.jsx(FO,{projectRoot:Lt||null,recentDirs:((va=e.settings)==null?void 0:va.recentDirs)??[],listDir:e.listDir,onExit:()=>Q(!1),onUse:Ys,listTemplates:e.listTemplates,getTemplate:e.getTemplate,openTemplateId:C}),h.jsxs("div",{className:"center-pane",children:[h.jsx(U5,{openedAgentName:ct,reviewTitle:J?J.title:null,composing:ye,onBack:xe?()=>m(!1):null,activeSession:fe||li?Qe:null,sessionName:Qe?mh(Qe,Pe.sessions,P):null,onRenameSession:H,boundWorkflowName:(Is==null?void 0:Is.name)??null,sessions:fe?sn:[],busySessionIds:e.busySessionIds,onSelectSession:oc,labelOf:Z=>mh(Z,Pe.sessions,P),busy:Qe!=null&&e.busySessionIds.has(Qe.id),onCloseSession:Z=>void e.closeSession(Z),onOpenInEditor:Co,editorLabel:Dw((gn=e.settings)==null?void 0:gn.editor),onToast:e.showToast,onExpandRail:F?()=>le(!1):null,onExpandRight:ae?Dt:null,subjectName:(Cs==null?void 0:Cs.name)??(Qe?Gn(Qe.cwd):null),newSessionPending:y,onNewSession:Qe?()=>et(Qe):null,actions:fe&&Qe&&Is?h.jsx(CO,{workflow:Is,activeSessionId:e.activeSessionId,sessionReady:Qe.ready===!0&&Qe.status!=="exited",macros:Pe.macros,onRunMacro:Z=>si(Is,Z),onRequestRun:(Z,Se)=>c({workflow:Is,target:Z,returnFocus:Se}),preview:e.previewBySession.get(Qe.id)??null,lastDeployError:e.lastDeployErrorFor(Is.path),authenticated:Pe.authenticated,directActionSettleSeq:e.directActionSettleSeq,runningTarget:Be}):null}),h.jsx("div",{className:"terminal-slot",children:Di&&J?h.jsx(P5,{summary:J,loadRecord:e.sessionRecord,onStart:()=>{const Z=J;ee(null),e.resumeFromHistory(Z)},onClose:()=>ee(null)}):li&&Qe?h.jsx(I5,{session:Qe,resumeMode:Ls,loadRecord:e.sessionRecord,onResume:()=>void e.resumeSession(Qe.id),onContinue:()=>void e.rehydrateSession({cwd:Qe.cwd,harness:Qe.harness,from:Qe.id}),onClose:()=>void e.closeSession(Qe.id)}):oe&&Cs?h.jsx(Zi,{className:"terminal-empty",testId:"open-agent-empty",icon:"Radio",title:`No running session for ${Cs.name}`,body:"Start a session to map, run, and inspect this agent.",cta:h.jsxs("button",{className:"btn-primary","data-testid":"open-agent-start-session",onClick:()=>dt(Cs),children:[h.jsx(de,{name:"Plus",size:14})," Start session"]})}):fe&&e.activeSessionId?h.jsx("div",{className:"agent-view","data-testid":"agent-view",children:h.jsx("div",{className:"agent-view-panel",id:"agent-panel-terminal",children:h.jsx(a$,{sessionId:e.activeSessionId,token:e.bootToken,cwd:(Qe==null?void 0:Qe.cwd)??null})})}):h.jsx(P$,{firstRun:Pe.firstRun===!0,onSubmitIdea:pn,onAttachmentError:e.showToast,onUseTemplate:ua,onBrowseTemplates:()=>Q(!0),listHarnesses:e.listHarnesses,listTemplates:e.listTemplates,telemetryOptIn:((_n=e.settings)==null?void 0:_n.telemetryOptIn)??Pe.telemetryOptIn,onToggleTelemetry:async Z=>{await e.updateSettings({telemetryOptIn:Z})},recentDirs:((No=e.settings)==null?void 0:No.recentDirs)??[],projectRoot:Lt||null,listDir:e.listDir,onConnect:async Z=>{await e.connectWorkflow(Z)},onScan:yi,onScaffold:ts,onSaveProjectRoot:Ns})})]}),!ae&&!me&&!ye&&h.jsx("div",{className:"pane-resize-handle pane-resize-handle-canvas",style:{right:Oe.canvas==null?"50%":`min(${Oe.canvas}px, calc(100% - ${ac}px))`},onPointerDown:qe,onDoubleClick:it,role:"separator","aria-orientation":"vertical","aria-label":"Resize canvas pane","data-testid":"resize-handle-canvas"}),me&&!ae&&h.jsx("div",{className:"shell-scrim","data-testid":"right-sheet-scrim","aria-hidden":"true",onClick:()=>X(!0)}),h.jsxs("div",{ref:xs,className:"right-pane"+(ae||ye?" is-collapsed":""),children:[h.jsxs("div",{className:"right-pane-tabs",role:"tablist","aria-label":"Right pane",children:[h.jsxs("button",{role:"tab","aria-selected":O==="canvas",className:"right-pane-tab"+(O==="canvas"?" is-active":""),onClick:()=>B("canvas"),"data-testid":"right-tab-canvas",children:[h.jsx(de,{name:"Workflow",size:14}),"Canvas"]}),h.jsxs("button",{role:"tab","aria-selected":O==="steps",className:"right-pane-tab"+(O==="steps"?" is-active":""),onClick:()=>B("steps"),"data-testid":"right-tab-steps",children:[h.jsx(de,{name:"List",size:14}),"Steps"]}),h.jsxs("button",{role:"tab","aria-selected":O==="code",className:"right-pane-tab"+(O==="code"?" is-active":""),onClick:()=>{B("code"),V(!0)},"data-testid":"right-tab-code",children:[h.jsx(de,{name:"Code",size:14}),"Code"]}),h.jsxs("div",{className:"right-pane-corner",children:[O==="canvas"&&(Te==null?void 0:Te.definitionId)!=null&&h.jsxs("a",{className:"status-tag status-tag-action workflow-deployed-tag right-pane-deployed","data-testid":"workflow-dashboard-link","data-deployment-state":Rt??void 0,href:xh(Te.definitionId),target:"_blank",rel:"noreferrer","aria-label":`${Rt} — open in the Sapiom dashboard`,"data-tooltip":"Open this agent in the Sapiom dashboard",children:[h.jsx(de,{name:"Cloud",size:12}),Rt==="ready"?"deployed":Rt==="building"?"building":Rt==="failed"?"deploy failed":"linked"]}),(O==="canvas"||O==="steps")&&h.jsx("button",{className:"theme-toggle","data-testid":"canvas-expand",hidden:te,"aria-label":O==="steps"?"Open Focus mode":"Expand canvas",title:O==="steps"?"Open Focus mode":"Expand canvas",onClick:()=>ue(Z=>!Z),children:h.jsx(de,{name:"Maximize2",size:15})}),h.jsx("button",{className:"theme-toggle right-pane-collapse","data-testid":"right-collapse","aria-label":"Collapse canvas panel",title:"Collapse canvas panel",onClick:()=>X(!0),children:h.jsx(de,{name:"PanelRightClose",size:15})})]})]}),h.jsx("div",{className:"right-pane-panel"+(O==="canvas"||O==="steps"?"":" is-hidden"),"data-testid":"right-panel-canvas",children:h.jsx(v4,{sessionId:e.activeSessionId,lastMessage:e.lastMessage,boundWorkflow:Te,noSessionAgent:ct,overviewActive:ye,sessionExited:li,onCanvasState:Z=>{var ze;if(me)return;const Se=((ze=Pe.sessions.find(Et=>Et.id===e.activeSessionId))==null?void 0:ze.status)==="exited";if(Z||Se){mt.current=null,X(!1);return}if(Mt.current){Mt.current=!1,Qt.current=e.activeSessionId??null;return}const Ne=Qt.current;Ne!=null&&Ne===e.activeSessionId||mt.current!==xt&&(mt.current=xt,X(!0))},onGraphChange:(Z,Se)=>{const Ne=bO(Se);Ne&&f.current.set(Z,Ne)},expanded:te,onToggleExpanded:()=>ue(Z=>!Z),macros:Pe.macros,tasks:e.tasks,surface:O==="steps"?"steps":"board",onOpenSteps:()=>B("steps"),run:(ve==null?void 0:ve.run)??null,runTarget:(ve==null?void 0:ve.target)??null,runs:$e,onSelectRun:Z=>{e.activeSessionId&&e.selectRun(e.activeSessionId,Z)},preview:e.activeSessionId?e.previewBySession.get(e.activeSessionId)??null:null,deployState:Te?e.deployStateByPath.get(Te.path)??null:null,onDismissDeploy:()=>{Te&&e.dismissDeployState(Te.path)},onOpenCode:()=>{B("code"),V(!0)},workflows:Pe.workflows,onOpenWorkflow:Z=>void ha(Z),onRunMacro:Z=>si(Is,Z),onInjectPrompt:Z=>{e.activeSessionId&&e.injectInput(e.activeSessionId,Z)},onDescribeWorkflow:cc})}),(O==="code"||q)&&h.jsx("div",{className:"right-pane-panel"+(O==="code"?"":" is-hidden"),"data-testid":"right-panel-code",children:h.jsx(N4,{boundWorkflow:Te,noSessionAgent:ct,agentsBaseUrl:Pe.agentsBaseUrl,lastDeployError:Te?e.lastDeployErrorFor(Te.path):null})})]})]})]}),ie&&h.jsx(B$,{firstRun:Pe.firstRun===!0,appVersion:((ga=Xn())==null?void 0:ga.appVersion)||"0.8.9",recentDirs:((Mo=e.settings)==null?void 0:Mo.recentDirs)??[],projectRoot:Lt||null,listDir:e.listDir,onConnect:async Z=>{await e.connectWorkflow(Z),I(!1)},onScan:yi,onBrowseTemplates:()=>{I(!1),Q(!0)},onDismiss:()=>I(!1)}),i&&h.jsx(w5,{sessions:Pe.sessions,workflows:Pe.workflows,recentDirs:((Jn=e.settings)==null?void 0:Jn.recentDirs)??[],history:e.history,sessionNames:P,activeSessionId:e.activeSessionId,listDir:e.listDir,listTemplates:e.listTemplates,onSelectSession:ti,onReviewSummary:lc,onOpenPath:Z=>void es(Z,"claude-code"),onOpenTemplate:Z=>{N(Z),Q(!0),I(!1)},actions:[{id:"browse-templates",label:"Browse templates",meta:"Gallery and starters",icon:"LayoutTemplate",run:()=>{Q(!0),I(!1)}},{id:"toggle-theme",label:"Toggle theme",meta:"Light and dark",icon:"Sun",run:Ww},{id:"toggle-rail",label:F?"Show workspace panel":"Hide workspace panel",meta:"Left pane",icon:"Menu",run:()=>le(Z=>!Z)},{id:"toggle-right",label:ae?"Show canvas panel":"Hide canvas panel",meta:"Right pane",icon:ae?"PanelRightOpen":"PanelRightClose",run:()=>X(Z=>!Z)},...Qe?[{id:"new-session-here",label:"New session in this folder",meta:Qe.cwd,icon:"Plus",run:()=>void es(Qe.cwd,"claude-code")}]:[]],onClose:()=>r(!1)}),k&&h.jsx(v6,{agentLabel:k.slug?`“${k.slug}”`:`Agent ${k.definitionId}`,onCancel:()=>A(null),onConfirm:()=>void da(k)}),o&&h.jsx(RO,{workflow:o.workflow,target:o.target,loadContract:l,returnFocus:o.returnFocus,onClose:()=>c(null),onRun:ko}),e.toast&&h.jsx(u$,{message:e.toast.message,tone:e.toast.tone,onDismiss:e.dismissToast}),h.jsx(d$,{})]})};function pL(e=document.documentElement,t=window){const i=c=>{e.dataset.windowFocused=c?"true":"false"};i(t.document.hasFocus());const r=()=>i(!0),o=()=>i(!1);return t.addEventListener("focus",r),t.addEventListener("blur",o),()=>{t.removeEventListener("focus",r),t.removeEventListener("blur",o)}}function mL(e=typeof window>"u"?"":window.location.search){return new URLSearchParams(e).get("frame")==="macos"?"macos":"web"}document.documentElement.dataset.windowFrame=mL();pL();window.addEventListener("scroll",()=>{(window.scrollX!==0||window.scrollY!==0)&&window.scrollTo(0,0)},{passive:!0});window.addEventListener("dragover",e=>{var t;(t=e.dataTransfer)!=null&&t.types.includes("Files")&&e.preventDefault()});window.addEventListener("drop",e=>{var t;(t=e.dataTransfer)!=null&&t.types.includes("Files")&&e.preventDefault()});eA.createRoot(document.getElementById("root")).render(h.jsx(z.StrictMode,{children:h.jsx(fL,{})}));
@@ -19,7 +19,7 @@
19
19
  document.documentElement.dataset.theme = theme;
20
20
  })();
21
21
  </script>
22
- <script type="module" crossorigin src="/assets/index-DrTPW10E.js"></script>
22
+ <script type="module" crossorigin src="/assets/index-B18B2y5o.js"></script>
23
23
  <link rel="stylesheet" crossorigin href="/assets/index-jGBbXx9R.css">
24
24
  </head>
25
25
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sapiom/harness",
3
- "version": "0.8.8",
3
+ "version": "0.8.9",
4
4
  "description": "Agent Studio — a CLI-launched local web app that runs your coding agent (Claude Code or Codex) in a Sapiom-configured environment: MCP pre-wired, agents tracked, one-click deploy/run, and a live canvas for previews.",
5
5
  "keywords": [
6
6
  "sapiom",
@@ -48,10 +48,10 @@
48
48
  "open": "^10.1.0",
49
49
  "ws": "^8.18.0",
50
50
  "zod": "^3.25.0",
51
- "@sapiom/agent": "^0.12.1",
52
- "@sapiom/agent-core": "^0.13.1",
51
+ "@sapiom/agent": "^0.12.2",
52
+ "@sapiom/agent-core": "^0.13.2",
53
53
  "@sapiom/analytics-core": "^0.2.1",
54
- "@sapiom/mcp": "^0.12.10"
54
+ "@sapiom/mcp": "^0.13.0"
55
55
  },
56
56
  "devDependencies": {
57
57
  "@playwright/test": "^1.61.0",