@fnmoa/cli 0.4.6 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/main.js CHANGED
@@ -1,18 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
3
- var fc=Object.defineProperty;var Te=(e,t)=>()=>(e&&(t=e(e=0)),t);var mc=(e,t)=>{for(var n in t)fc(e,n,{get:t[n],enumerable:!0})};function U(e,t=fetch){let n=e.url.replace(/\/+$/,""),o=async(s,a,c,i)=>{let l=async()=>t(`${n}${a}`,{method:s,headers:{authorization:`Bearer ${e.token}`,...c===void 0?{}:{"content-type":"application/json"},...i===void 0?{}:{"idempotency-key":i}},...c===void 0?{}:{body:JSON.stringify(c)}}),d;try{d=await l()}catch(u){if(i!==void 0)try{d=await l()}catch{throw ws(n,u)}else throw ws(n,u)}if(!d.ok){let u=await d.text(),f=u,p=d.headers.get("x-request-id")??void 0;try{let g=JSON.parse(u);f=g.error??u,p=g.requestId??p}catch{}throw new ae(d.status,f||`${s} ${a} failed`,p)}return d},r=async(s,a,c,i)=>{let l=await o(s,a,c,i);return l.status===204?void 0:await l.json()};return{url:n,get:s=>r("GET",s),post:(s,a,c)=>r("POST",s,a,c),patch:(s,a)=>r("PATCH",s,a),put:(s,a)=>r("PUT",s,a),del:async s=>{let a=await o("DELETE",s);if(a.status!==204)return await a.json().catch(()=>{})},stream:(s,a)=>t(`${n}${s}`,{headers:{authorization:`Bearer ${e.token}`,accept:"text/event-stream"},...a?{signal:a}:{}}),async rpc(s,a,c,i){let l=await t(s,{method:"POST",headers:{authorization:`Bearer ${a}`,"content-type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:c,...i?{params:i}:{}})}),d=await l.json().catch(()=>({}));if(!l.ok||d.error)throw new ae(l.status,d.error?.message??`the server said ${l.status}`);return d.result}}}var ae,Pt,ws,De=Te(()=>{"use strict";ae=class extends Error{status;requestId;constructor(t,n,o){super(n),this.name="ApiError",this.status=t,o&&(this.requestId=o)}},Pt=class extends Error{constructor(t,n){super(`cannot reach ${t}: ${n instanceof Error?n.message:String(n)}`),this.name="Unreachable"}},ws=(e,t)=>new Pt(e,t)});import{mkdir as gc,readFile as hc,writeFile as wc}from"node:fs/promises";import{homedir as kc}from"node:os";import{dirname as yc,join as ks}from"node:path";async function ve(e){try{let t=JSON.parse(await hc(bs(e),"utf8"));return{current:t.current??"default",profiles:t.profiles??{}}}catch{return bc()}}async function gt(e,t){let n=bs(t);await gc(yc(n),{recursive:!0}),await wc(n,`${JSON.stringify(e,null,2)}
4
- `,{mode:384})}async function te(e,t=process.env){if(t.MOA_URL&&t.MOA_TOKEN)return{name:"env",url:t.MOA_URL,token:t.MOA_TOKEN};let n;try{n=await ve(t)}catch(s){throw t.MOA_URL||t.MOA_TOKEN?new Error(ys(t)):s}let o=e??n.current,r=n.profiles[o];if(!r)throw t.MOA_URL||t.MOA_TOKEN?new Error(ys(t)):new Error(o==="default"&&Object.keys(n.profiles).length===0?"no workspace yet \u2014 run `moa login <url> --token <token>`":`no profile named ${o}`);return{name:t.MOA_URL||t.MOA_TOKEN?`${o}+env`:o,url:t.MOA_URL??r.url,token:t.MOA_TOKEN??r.token}}var bc,bs,ys,Ze=Te(()=>{"use strict";bc=()=>({current:"default",profiles:{}}),bs=(e=process.env)=>e.MOA_CONFIG??ks(e.MOA_HOME??ks(kc(),".moa"),"config.json");ys=e=>e.MOA_URL?"MOA_URL is set but MOA_TOKEN is not, and there is no saved profile to take one from":"MOA_TOKEN is set but MOA_URL is not, and there is no saved profile to take one from"});async function Nt(e,t,n,o,r){let s=Date.now()+n*1e3,a=250,c="",i=t,l;for(;;){let d=await e.get(`/v1/jobs/${i}`).catch(async u=>{if(u instanceof Pt){if(l??=Date.now()+sr,Date.now()<l&&Date.now()<s)return;throw u}let p=u instanceof ae&&u.status===404&&r!==void 0?await r():void 0;if(!p)throw u;return i=p.id,p});if(d===void 0){await new Promise(u=>setTimeout(u,500));continue}if(l=void 0,o&&d.progress){let{at:u,...f}=d.progress,p=JSON.stringify(f);p!==c&&(c=p,o(d.progress))}if(d.state!=="running"&&d.state!=="queued")return d;if(Date.now()>s)throw new zn(t,n);await new Promise(u=>setTimeout(u,a)),a=Math.min(a*1.5,1e3)}}function kn(e,t,n,o=(s,a)=>{process.on(s,a)},r=(s,a)=>{process.off(s,a)}){let s=!1,a=()=>{s&&(n("moa: leaving it running \u2014 see `moa jobs`"),process.exit(2)),s=!0,n(`moa: stopping ${t} \u2014 Ctrl-C again to leave it running`),e.post(`/v1/jobs/${t}/cancel`,{}).catch(()=>{n("moa: could not reach the workspace to stop it")})};return o("SIGINT",a),{stop:()=>r("SIGINT",a),asked:()=>s}}var zn,sr,yn=Te(()=>{"use strict";De();zn=class extends Error{jobId;constructor(t,n){super(`timed out after ${n}s \u2014 it is still going: ${t}`),this.name="StoppedWaiting",this.jobId=t}},sr=2e4});import{join as vo}from"node:path";function Ge(e,t,n,o={}){let r={...e.env};o.account&&(r.CLOUDFLARE_ACCOUNT_ID=o.account),r.WRANGLER_SEND_METRICS="false",r.NO_COLOR="1";let[s,...a]=e.root?["pnpm","exec","wrangler"]:["npx","--yes",fr];return e.exec(s,[...a,...n],{cwd:e.root?vo(t,"apps","workspace"):t,env:r,timeoutMs:o.timeoutMs??6e4})}function tn(e){let t=e.search(/[[{]/);if(t!==-1)try{return JSON.parse(e.slice(t))}catch{return}}async function aa(e,t){let n=await Ge(e,t,["whoami","--json"],{timeoutMs:3e4}),o=tn(n.stdout||n.stderr);if(!o)return{ok:!1,why:Qn(n.stderr||n.stdout)||"wrangler did not answer"};if(!o.loggedIn)return{ok:!1,why:"wrangler is not logged in",loggedOut:!0};let r=o.accounts??[],s=e.env.CLOUDFLARE_ACCOUNT_ID?.trim(),a=s?r.find(c=>c.id===s):r[0];return a?{ok:!0,account:a,others:r.length-1,...o.email?{email:o.email}:{}}:{ok:!1,why:s?`CLOUDFLARE_ACCOUNT_ID ${s} is not an account this login can use`:"this login has no account"}}async function ia(e,t){let n=t.split(".");for(let o=0;o<n.length-1;o++){let r=n.slice(o).join("."),s;try{s=await(await e.fetch(`${dl}?name=${encodeURIComponent(r)}&type=NS`,{headers:{accept:"application/dns-json"},signal:AbortSignal.timeout(1e4)})).json()}catch(c){return{onCloudflare:!1,why:`DNS did not answer: ${c instanceof Error?c.message:String(c)}`}}let a=(s.Answer??[]).filter(c=>c.type===2).map(c=>c.data);if(a.length!==0)return{zone:r,onCloudflare:a.every(c=>/\.ns\.cloudflare\.com\.?$/i.test(c))}}return{onCloudflare:!1,why:`no DNS zone holds ${t}`}}async function ca(e,t,n){let o=`https://api.cloudflare.com/client/v4/accounts/${encodeURIComponent(t)}`,r=s=>e.fetch(`${o}${s}`,{headers:{authorization:`Bearer ${n}`},signal:AbortSignal.timeout(15e3)});try{let s=await r("/d1/database?per_page=1");if(!s.ok){let d=(await s.json().catch(()=>({}))).errors?.[0]?.message??"";return{ok:!1,why:`${s.status} ${d}`.trim()}}let[a,c]=await Promise.all([r("/workers/account-settings"),r("/workers/scripts")]),i=c.ok?(await c.json().catch(()=>({}))).result?.length??0:0;return a.ok||i>0?{ok:!1,why:"it can reach Workers too \u2014 the container gets this token, so it must be D1 only"}:{ok:!0}}catch(s){return{ok:!1,why:s instanceof Error?s.message:String(s)}}}async function la(e,t,n){let o=async()=>{let c=await Ge(e,t,["d1","list","--json"],{account:n});return(tn(c.stdout)??[]).find(l=>l.name===ht)?.uuid},r=await o();if(r)return{ok:!0,id:r,made:!1};let s=await Ge(e,t,["d1","create",ht],{account:n});if(!s.ok)return{ok:!1,why:Qn(s.stderr||s.stdout)||"d1 create failed"};let a=await o();return a?{ok:!0,id:a,made:!0}:{ok:!1,why:`${ht} was made but is not listed`}}async function da(e,t,n){let o=await Ge(e,t,["r2","bucket","create",wt],{account:n}),r=`${o.stdout}
5
- ${o.stderr}`;return/already exists|already own/i.test(r)?{ok:!0,made:!1}:o.ok?{ok:!0,made:!0}:{ok:!1,why:Qn(r)||"r2 bucket create failed"}}async function mr(e,t,n){let o=await Ge(e,t,["containers","list","--json"],{account:n}),r=o.ok?tn(o.stdout):void 0;return Array.isArray(r)?{ok:!0,apps:r}:{ok:!1,why:Qn(o.stderr||o.stdout)||"wrangler did not answer"}}function gr(e){let t=e.filter(s=>s.name===je),n=t.length===1?t[0]:void 0;if(!n||typeof n.id!="string"||n.id==="")return;let o=typeof n.image=="string"?n.image.split("/").at(-1):void 0,r=o?.startsWith(`${je}:`)?o:void 0;return{id:n.id,...r?{image:r}:{}}}async function ua(e,t,n){let o=await mr(e,t,n);return o.ok?gr(o.apps):void 0}async function Xn(e,t,n){let o=await Ge(e,t,["containers","images","list","--json"],{account:n}),r=o.ok?tn(o.stdout):void 0;if(!Array.isArray(r))return{ok:!1,why:Qn(o.stderr||o.stdout)||"wrangler did not answer"};let s=r.filter(a=>typeof a.name=="string"&&a.name.split("/").at(-1)===je).flatMap(a=>Array.isArray(a.tags)?a.tags:[]).filter(a=>typeof a=="string"&&a!=="").map(a=>`${je}:${a}`);return{ok:!0,images:[...new Set(s)]}}function pa(e){let t=vo(e.root,"apps","workspace"),n=en(e.domain);return{name:We,account_id:e.account,main:e.worker??vo(t,"dist","worker.js"),compatibility_date:"2026-09-01",compatibility_flags:["nodejs_compat"],routes:[{pattern:n.workspace,custom_domain:!0},{pattern:n.console,custom_domain:!0}],d1_databases:[{binding:"DB",database_name:ht,database_id:e.databaseId}],r2_buckets:[{binding:"STATE",bucket_name:wt}],durable_objects:{bindings:[{name:"WORKSPACE",class_name:"WorkspaceBox"}]},migrations:[{tag:"v1",new_sqlite_classes:["WorkspaceBox"]}],containers:[{class_name:"WorkspaceBox",name:je,image:e.image??vo(t,"Dockerfile.cloudflare"),...e.image?{}:{image_build_context:e.root},instance_type:"standard-4",max_instances:1}],vars:e.vars}}var We,ht,wt,je,_t,pr,en,Yn,fr,dl,Qn,Zn=Te(()=>{"use strict";We="fnmoa-workspace",ht="fnmoa-workspace",wt="fnmoa-state",je=`${We}-workspacebox`,_t=6,pr=/^(?=.{4,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}$/,en=e=>({workspace:`workspace.${e}`,console:`console.${e}`}),Yn=e=>{let t=en(e);return{workspaceUrl:`https://${t.workspace}`,consoleUrl:`https://${t.console}`}},fr="wrangler@4";dl="https://cloudflare-dns.com/dns-query";Qn=e=>e.replace(/\u001B\[[0-9;]*m/g,"").trim().split(`
6
- `).filter(t=>t.trim()!=="").slice(-2).join(" \xB7 ").slice(0,240)});function fl(e){let t="";for(let n of e)t+=String.fromCharCode(n);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function So(e){let t=e.replace(/-/g,"+").replace(/_/g,"/"),n=atob(t+"=".repeat((4-t.length%4)%4)),o=new Uint8Array(n.length);for(let r=0;r<n.length;r++)o[r]=n.charCodeAt(r);return o}function ml(e){let t=e.replace(/-----BEGIN [^-]+-----/,"").replace(/-----END [^-]+-----/,"").replace(/\\n/g,"").replace(/\s+/g,"");return So(t.replace(/\+/g,"-").replace(/\//g,"_"))}async function gl(e){let t=e.trim();if(t.startsWith("{")){let n=JSON.parse(t),{kty:o,crv:r,x:s}=n;return crypto.subtle.importKey("jwk",{kty:o,crv:r,x:s},hr,!0,["verify"])}return crypto.subtle.importKey("spki",ml(t),hr,!0,["verify"])}async function hl(e){let t=await crypto.subtle.exportKey("raw",e),n=await crypto.subtle.digest("SHA-256",t);return fl(new Uint8Array(n).slice(0,8))}async function fa(e,t,n={}){let o=e.trim().split(".");if(o.length!==3)return{ok:!1,reason:"malformed"};let[r,s,a]=o,c,i,l;try{c=JSON.parse(new TextDecoder().decode(So(r))),i=JSON.parse(new TextDecoder().decode(So(s))),l=So(a)}catch{return{ok:!1,reason:"malformed"}}let d=c;if(d?.alg!=="EdDSA"||d?.typ!=="JWT")return{ok:!1,reason:"malformed"};if(d.kid!==void 0&&typeof d.kid!="string")return{ok:!1,reason:"malformed"};let u=await Promise.all((Array.isArray(t)?t:[t]).map(b=>typeof b=="string"?gl(b):b)),f;if(typeof d.kid=="string")for(let b of u)await hl(b)===d.kid&&(f=b);else u.length===1&&(f=u[0]);if(!f)return{ok:!1,reason:"unknown key"};if(!await crypto.subtle.verify(hr,f,l,new TextEncoder().encode(`${r}.${s}`)))return{ok:!1,reason:"bad signature"};if(!wl(i))return{ok:!1,reason:"malformed"};if(i.iss!==ul)return{ok:!1,reason:"wrong issuer"};if(n.install!==void 0&&i.install!==n.install)return{ok:!1,reason:"wrong install"};let g=Math.floor((n.now??new Date).getTime()/1e3);return i.iat>g+pl?{ok:!1,reason:"issued in the future"}:!n.allowExpired&&g>i.exp+(n.leewaySeconds??60)?{ok:!1,reason:"expired"}:{ok:!0,claims:i}}var ul,hr,pl,wl,wr=Te(()=>{"use strict";ul="fnmoa-licence",hr={name:"Ed25519"},pl=300;wl=e=>{if(!e||typeof e!="object")return!1;let t=e;return typeof t.iss=="string"&&typeof t.sub=="string"&&typeof t.key=="string"&&typeof t.install=="string"&&typeof t.plan=="string"&&(t.seats===null||typeof t.seats=="number")&&Array.isArray(t.targets)&&t.targets.every(n=>typeof n=="string")&&typeof t.iat=="number"&&typeof t.exp=="number"&&(t.lapsed===void 0||typeof t.lapsed=="boolean")&&(t.offline===void 0||typeof t.offline=="boolean")&&(t.grace_until===void 0||typeof t.grace_until=="number")}});function kl(e,t,n){switch(e){case"seats_full":return`All ${t??"available"} workspace seats are in use. Release a workspace on the account page or upgrade your plan.`;case"activation_released":return"This workspace was released. Run `moa setup licence` to activate it again.";case"unknown_activation":return"This install is not activated. Run `moa setup licence`.";case"key_replaced":return"Use the new key from your account page with `moa setup licence`.";case"lapsed":case"not_paid":return"Your subscription is unpaid. Renew it on your account page.";case"target_not_in_plan":return"This target is not included in your plan. Choose another target or upgrade.";case"licence_too_old":return"This licence expired over 30 days ago and can no longer renew. Run `moa setup licence` to activate again.";case"seat_lost":return"This workspace lost its seat. Run `moa setup licence` to take one again, or release another workspace on the account page.";case"bad_licence":return"The licence server did not accept this licence. Run `moa setup licence`.";case"unknown_key":return"The licence server does not know this key. Check it on your account page and run `moa setup licence`.";case"rate_limited":return"Too many licence requests. Wait a minute and try again.";case"not_set_up":return"The licence server is not set up yet. Try again later.";default:return n??`Licence request refused (${e}). Check your account page.`}}async function kr(e,t,n,o){let r=new URL(e);if(r.protocol!=="https:"&&!(r.protocol==="http:"&&["localhost","127.0.0.1","[::1]"].includes(r.hostname)))throw new Error("The licence server must use HTTPS.");let s=await o(new URL(`/v1/${t}`,r),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n),signal:AbortSignal.timeout(15e3),redirect:"error"}),a=await s.json();if(!s.ok){let c=typeof a.error=="string"?a.error:"request_failed";throw new xo(c,s.status,kl(c,typeof a.seats=="number"?a.seats:void 0,typeof a.message=="string"?a.message:void 0))}return a}async function ga(e,t,n,o=fetch){return ma(await kr(e,t,n,o))}async function ha(e,t,n=fetch){let o=await kr(e,"device",t,n),{device_code:r,user_code:s,verification_uri_complete:a,expires_in:c,interval:i}=o;if(typeof r!="string"||typeof s!="string"||typeof a!="string")throw new Error("The licence server did not start a sign-in.");return{deviceCode:r,userCode:s,url:a,expiresIn:typeof c=="number"?c:600,interval:typeof i=="number"?i:5}}async function wa(e,t,n=fetch){try{return ma(await kr(e,"device/token",{device_code:t},n))}catch(o){if(o instanceof xo&&o.code==="authorization_pending")return"pending";throw o}}async function eo(e,t,n,o){let r=await fa(e,t,{install:n});if(!r.ok)throw new Error(`Licence refused: ${r.reason}`);if(o&&!r.claims.targets.includes(o))throw new Error("Licence refused: target not in plan");return r.claims}var xo,ma,ka=Te(()=>{"use strict";wr();xo=class extends Error{constructor(n,o,r){super(r);this.code=n;this.status=o}};ma=e=>{if(typeof e.licence!="string")throw new Error("The licence server returned no signed licence.");return{licence:e.licence,pullToken:typeof e.pullToken=="string"?e.pullToken:null}}});var yl,vn,to,ya=Te(()=>{"use strict";yl=`-----BEGIN PUBLIC KEY-----
3
+ var yc=Object.defineProperty;var Oe=(e,t)=>()=>(e&&(t=e(e=0)),t);var bc=(e,t)=>{for(var n in t)yc(e,n,{get:t[n],enumerable:!0})};function N(e,t=fetch){let n=e.url.replace(/\/+$/,""),o=async(s,a,c,i)=>{let l=async()=>t(`${n}${a}`,{method:s,headers:{authorization:`Bearer ${e.token}`,...c===void 0?{}:{"content-type":"application/json"},...i===void 0?{}:{"idempotency-key":i}},...c===void 0?{}:{body:JSON.stringify(c)}}),d;try{d=await l()}catch(u){if(i!==void 0)try{d=await l()}catch{throw bs(n,u)}else throw bs(n,u)}if(!d.ok){let u=await d.text(),f=u,p=d.headers.get("x-request-id")??void 0;try{let g=JSON.parse(u);f=g.error??u,p=g.requestId??p}catch{}throw new ie(d.status,f||`${s} ${a} failed`,p)}return d},r=async(s,a,c,i)=>{let l=await o(s,a,c,i);return l.status===204?void 0:await l.json()};return{url:n,get:s=>r("GET",s),post:(s,a,c)=>r("POST",s,a,c),patch:(s,a)=>r("PATCH",s,a),put:(s,a)=>r("PUT",s,a),del:async s=>{let a=await o("DELETE",s);if(a.status!==204)return await a.json().catch(()=>{})},stream:(s,a)=>t(`${n}${s}`,{headers:{authorization:`Bearer ${e.token}`,accept:"text/event-stream"},...a?{signal:a}:{}}),async rpc(s,a,c,i){let l=await t(s,{method:"POST",headers:{authorization:`Bearer ${a}`,"content-type":"application/json"},body:JSON.stringify({jsonrpc:"2.0",id:1,method:c,...i?{params:i}:{}})}),d=await l.json().catch(()=>({}));if(!l.ok||d.error)throw new ie(l.status,d.error?.message??`the server said ${l.status}`);return d.result}}}var ie,Ot,bs,Ue=Oe(()=>{"use strict";ie=class extends Error{status;requestId;constructor(t,n,o){super(n),this.name="ApiError",this.status=t,o&&(this.requestId=o)}},Ot=class extends Error{constructor(t,n){super(`cannot reach ${t}: ${n instanceof Error?n.message:String(n)}`),this.name="Unreachable"}},bs=(e,t)=>new Ot(e,t)});import{mkdir as $c,readFile as vc,writeFile as Sc}from"node:fs/promises";import{homedir as xc}from"node:os";import{dirname as Ac,join as $s}from"node:path";async function xe(e){try{let t=JSON.parse(await vc(Ss(e),"utf8"));return{current:t.current??"default",profiles:t.profiles??{}}}catch{return Ec()}}async function ht(e,t){let n=Ss(t);await $c(Ac(n),{recursive:!0}),await Sc(n,`${JSON.stringify(e,null,2)}
4
+ `,{mode:384})}async function re(e,t=process.env){if(t.MOA_URL&&t.MOA_TOKEN)return{name:"env",url:t.MOA_URL,token:t.MOA_TOKEN};let n;try{n=await xe(t)}catch(s){throw t.MOA_URL||t.MOA_TOKEN?new Error(vs(t)):s}let o=e??n.current,r=n.profiles[o];if(!r)throw t.MOA_URL||t.MOA_TOKEN?new Error(vs(t)):new Error(o==="default"&&Object.keys(n.profiles).length===0?"no workspace yet \u2014 run `moa login <url> --token <token>`":`no profile named ${o}`);return{name:t.MOA_URL||t.MOA_TOKEN?`${o}+env`:o,url:t.MOA_URL??r.url,token:t.MOA_TOKEN??r.token}}var Ec,Ss,vs,Ye=Oe(()=>{"use strict";Ec=()=>({current:"default",profiles:{}}),Ss=(e=process.env)=>e.MOA_CONFIG??$s(e.MOA_HOME??$s(xc(),".moa"),"config.json");vs=e=>e.MOA_URL?"MOA_URL is set but MOA_TOKEN is not, and there is no saved profile to take one from":"MOA_TOKEN is set but MOA_URL is not, and there is no saved profile to take one from"});async function Ft(e,t,n,o,r){let s=Date.now()+n*1e3,a=250,c="",i=t,l;for(;;){let d=await e.get(`/v1/jobs/${i}`).catch(async u=>{if(u instanceof Ot){if(l??=Date.now()+rr,Date.now()<l&&Date.now()<s)return;throw u}let p=u instanceof ie&&u.status===404&&r!==void 0?await r():void 0;if(!p)throw u;return i=p.id,p});if(d===void 0){await new Promise(u=>setTimeout(u,500));continue}if(l=void 0,o&&d.progress){let{at:u,...f}=d.progress,p=JSON.stringify(f);p!==c&&(c=p,o(d.progress))}if(d.state!=="running"&&d.state!=="queued")return d;if(Date.now()>s)throw new Xn(t,n);await new Promise(u=>setTimeout(u,a)),a=Math.min(a*1.5,1e3)}}function vn(e,t,n,o=(s,a)=>{process.on(s,a)},r=(s,a)=>{process.off(s,a)}){let s=!1,a=()=>{s&&(n("moa: leaving it running \u2014 see `moa jobs`"),process.exit(2)),s=!0,n(`moa: stopping ${t} \u2014 Ctrl-C again to leave it running`),e.post(`/v1/jobs/${t}/cancel`,{}).catch(()=>{n("moa: could not reach the workspace to stop it")})};return o("SIGINT",a),{stop:()=>r("SIGINT",a),asked:()=>s}}var Xn,rr,Sn=Oe(()=>{"use strict";Ue();Xn=class extends Error{jobId;constructor(t,n){super(`timed out after ${n}s \u2014 it is still going: ${t}`),this.name="StoppedWaiting",this.jobId=t}},rr=2e4});import{join as $o}from"node:path";function Fe(e,t,n,o={}){let r={...e.env};o.account&&(r.CLOUDFLARE_ACCOUNT_ID=o.account),r.WRANGLER_SEND_METRICS="false",r.NO_COLOR="1";let[s,...a]=e.root?["pnpm","exec","wrangler"]:["npx","--yes",pr];return e.exec(s,[...a,...n],{cwd:e.root?$o(t,"apps","workspace"):t,env:r,timeoutMs:o.timeoutMs??6e4})}function rn(e){let t=e.search(/[[{]/);if(t!==-1)try{return JSON.parse(e.slice(t))}catch{return}}async function la(e,t){let n=await Fe(e,t,["whoami","--json"],{timeoutMs:3e4}),o=rn(n.stdout||n.stderr);if(!o)return{ok:!1,why:to(n.stderr||n.stdout)||"wrangler did not answer"};if(!o.loggedIn)return{ok:!1,why:"wrangler is not logged in",loggedOut:!0};let r=o.accounts??[],s=e.env.CLOUDFLARE_ACCOUNT_ID?.trim(),a=s?r.find(c=>c.id===s):r[0];return a?{ok:!0,account:a,others:r.length-1,...o.email?{email:o.email}:{}}:{ok:!1,why:s?`CLOUDFLARE_ACCOUNT_ID ${s} is not an account this login can use`:"this login has no account"}}async function da(e,t){let n=t.split(".");for(let o=0;o<n.length-1;o++){let r=n.slice(o).join("."),s;try{s=await(await e.fetch(`${hl}?name=${encodeURIComponent(r)}&type=NS`,{headers:{accept:"application/dns-json"},signal:AbortSignal.timeout(1e4)})).json()}catch(c){return{onCloudflare:!1,why:`DNS did not answer: ${c instanceof Error?c.message:String(c)}`}}let a=(s.Answer??[]).filter(c=>c.type===2).map(c=>c.data);if(a.length!==0)return{zone:r,onCloudflare:a.every(c=>/\.ns\.cloudflare\.com\.?$/i.test(c))}}return{onCloudflare:!1,why:`no DNS zone holds ${t}`}}async function ua(e,t,n){let o=`https://api.cloudflare.com/client/v4/accounts/${encodeURIComponent(t)}`,r=s=>e.fetch(`${o}${s}`,{headers:{authorization:`Bearer ${n}`},signal:AbortSignal.timeout(15e3)});try{let s=await r("/d1/database?per_page=1");if(!s.ok){let d=(await s.json().catch(()=>({}))).errors?.[0]?.message??"";return{ok:!1,why:`${s.status} ${d}`.trim()}}let[a,c]=await Promise.all([r("/workers/account-settings"),r("/workers/scripts")]),i=c.ok?(await c.json().catch(()=>({}))).result?.length??0:0;return a.ok||i>0?{ok:!1,why:"it can reach Workers too \u2014 the container gets this token, so it must be D1 only"}:{ok:!0}}catch(s){return{ok:!1,why:s instanceof Error?s.message:String(s)}}}async function pa(e,t,n){let o=async()=>{let c=await Fe(e,t,["d1","list","--json"],{account:n});return(rn(c.stdout)??[]).find(l=>l.name===wt)?.uuid},r=await o();if(r)return{ok:!0,id:r,made:!1};let s=await Fe(e,t,["d1","create",wt],{account:n});if(!s.ok)return{ok:!1,why:to(s.stderr||s.stdout)||"d1 create failed"};let a=await o();return a?{ok:!0,id:a,made:!0}:{ok:!1,why:`${wt} was made but is not listed`}}async function fa(e,t,n){let o=await Fe(e,t,["r2","bucket","create",kt],{account:n}),r=`${o.stdout}
5
+ ${o.stderr}`;return/already exists|already own/i.test(r)?{ok:!0,made:!1}:o.ok?{ok:!0,made:!0}:{ok:!1,why:to(r)||"r2 bucket create failed"}}async function fr(e,t,n){let o=await Fe(e,t,["containers","list","--json"],{account:n}),r=o.ok?rn(o.stdout):void 0;return Array.isArray(r)?{ok:!0,apps:r}:{ok:!1,why:to(o.stderr||o.stdout)||"wrangler did not answer"}}function mr(e){let t=e.filter(s=>s.name===He),n=t.length===1?t[0]:void 0;if(!n||typeof n.id!="string"||n.id==="")return;let o=typeof n.image=="string"?n.image.split("/").at(-1):void 0,r=o?.startsWith(`${He}:`)?o:void 0;return{id:n.id,...r?{image:r}:{}}}async function ma(e,t,n){let o=await fr(e,t,n);return o.ok?mr(o.apps):void 0}async function eo(e,t,n){let o=await Fe(e,t,["containers","images","list","--json"],{account:n}),r=o.ok?rn(o.stdout):void 0;if(!Array.isArray(r))return{ok:!1,why:to(o.stderr||o.stdout)||"wrangler did not answer"};let s=r.filter(a=>typeof a.name=="string"&&a.name.split("/").at(-1)===He).flatMap(a=>Array.isArray(a.tags)?a.tags:[]).filter(a=>typeof a=="string"&&a!=="").map(a=>`${He}:${a}`);return{ok:!0,images:[...new Set(s)]}}function ga(e){let t=$o(e.root,"apps","workspace"),n=on(e.domain);return{name:Je,account_id:e.account,main:e.worker??$o(t,"dist","worker.js"),compatibility_date:"2026-09-01",compatibility_flags:["nodejs_compat"],routes:[{pattern:n.workspace,custom_domain:!0},{pattern:n.console,custom_domain:!0}],d1_databases:[{binding:"DB",database_name:wt,database_id:e.databaseId}],r2_buckets:[{binding:"STATE",bucket_name:kt}],durable_objects:{bindings:[{name:"WORKSPACE",class_name:"WorkspaceBox"}]},migrations:[{tag:"v1",new_sqlite_classes:["WorkspaceBox"]}],containers:[{class_name:"WorkspaceBox",name:He,image:e.image??$o(t,"Dockerfile.cloudflare"),...e.image?{}:{image_build_context:e.root},instance_type:"standard-4",max_instances:1}],vars:e.vars}}var Je,wt,kt,He,Tt,ur,on,Zn,pr,hl,to,no=Oe(()=>{"use strict";Je="fnmoa-workspace",wt="fnmoa-workspace",kt="fnmoa-state",He=`${Je}-workspacebox`,Tt=6,ur=/^(?=.{4,253}$)(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}$/,on=e=>({workspace:`workspace.${e}`,console:`console.${e}`}),Zn=e=>{let t=on(e);return{workspaceUrl:`https://${t.workspace}`,consoleUrl:`https://${t.console}`}},pr="wrangler@4";hl="https://cloudflare-dns.com/dns-query";to=e=>e.replace(/\u001B\[[0-9;]*m/g,"").trim().split(`
6
+ `).filter(t=>t.trim()!=="").slice(-2).join(" \xB7 ").slice(0,240)});function yl(e){let t="";for(let n of e)t+=String.fromCharCode(n);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}function vo(e){let t=e.replace(/-/g,"+").replace(/_/g,"/"),n=atob(t+"=".repeat((4-t.length%4)%4)),o=new Uint8Array(n.length);for(let r=0;r<n.length;r++)o[r]=n.charCodeAt(r);return o}function bl(e){let t=e.replace(/-----BEGIN [^-]+-----/,"").replace(/-----END [^-]+-----/,"").replace(/\\n/g,"").replace(/\s+/g,"");return vo(t.replace(/\+/g,"-").replace(/\//g,"_"))}async function $l(e){let t=e.trim();if(t.startsWith("{")){let n=JSON.parse(t),{kty:o,crv:r,x:s}=n;return crypto.subtle.importKey("jwk",{kty:o,crv:r,x:s},gr,!0,["verify"])}return crypto.subtle.importKey("spki",bl(t),gr,!0,["verify"])}async function vl(e){let t=await crypto.subtle.exportKey("raw",e),n=await crypto.subtle.digest("SHA-256",t);return yl(new Uint8Array(n).slice(0,8))}async function ha(e,t,n={}){let o=e.trim().split(".");if(o.length!==3)return{ok:!1,reason:"malformed"};let[r,s,a]=o,c,i,l;try{c=JSON.parse(new TextDecoder().decode(vo(r))),i=JSON.parse(new TextDecoder().decode(vo(s))),l=vo(a)}catch{return{ok:!1,reason:"malformed"}}let d=c;if(d?.alg!=="EdDSA"||d?.typ!=="JWT")return{ok:!1,reason:"malformed"};if(d.kid!==void 0&&typeof d.kid!="string")return{ok:!1,reason:"malformed"};let u=await Promise.all((Array.isArray(t)?t:[t]).map(y=>typeof y=="string"?$l(y):y)),f;if(typeof d.kid=="string")for(let y of u)await vl(y)===d.kid&&(f=y);else u.length===1&&(f=u[0]);if(!f)return{ok:!1,reason:"unknown key"};if(!await crypto.subtle.verify(gr,f,l,new TextEncoder().encode(`${r}.${s}`)))return{ok:!1,reason:"bad signature"};if(!Sl(i))return{ok:!1,reason:"malformed"};if(i.iss!==wl)return{ok:!1,reason:"wrong issuer"};if(n.install!==void 0&&i.install!==n.install)return{ok:!1,reason:"wrong install"};let g=Math.floor((n.now??new Date).getTime()/1e3);return i.iat>g+kl?{ok:!1,reason:"issued in the future"}:!n.allowExpired&&g>i.exp+(n.leewaySeconds??60)?{ok:!1,reason:"expired"}:{ok:!0,claims:i}}var wl,gr,kl,Sl,hr=Oe(()=>{"use strict";wl="fnmoa-licence",gr={name:"Ed25519"},kl=300;Sl=e=>{if(!e||typeof e!="object")return!1;let t=e;return typeof t.iss=="string"&&typeof t.sub=="string"&&typeof t.key=="string"&&typeof t.install=="string"&&typeof t.plan=="string"&&(t.seats===null||typeof t.seats=="number")&&Array.isArray(t.targets)&&t.targets.every(n=>typeof n=="string")&&typeof t.iat=="number"&&typeof t.exp=="number"&&(t.lapsed===void 0||typeof t.lapsed=="boolean")&&(t.offline===void 0||typeof t.offline=="boolean")&&(t.grace_until===void 0||typeof t.grace_until=="number")}});function xl(e,t,n){switch(e){case"seats_full":return`All ${t??"available"} workspace seats are in use. Release a workspace on the account page or upgrade your plan.`;case"activation_released":return"This workspace was released. Run `moa setup licence` to activate it again.";case"unknown_activation":return"This install is not activated. Run `moa setup licence`.";case"key_replaced":return"Use the new key from your account page with `moa setup licence`.";case"lapsed":case"not_paid":return"Your subscription is unpaid. Renew it on your account page.";case"target_not_in_plan":return"This target is not included in your plan. Choose another target or upgrade.";case"licence_too_old":return"This licence expired over 30 days ago and can no longer renew. Run `moa setup licence` to activate again.";case"seat_lost":return"This workspace lost its seat. Run `moa setup licence` to take one again, or release another workspace on the account page.";case"bad_licence":return"The licence server did not accept this licence. Run `moa setup licence`.";case"unknown_key":return"The licence server does not know this key. Check it on your account page and run `moa setup licence`.";case"rate_limited":return"Too many licence requests. Wait a minute and try again.";case"not_set_up":return"The licence server is not set up yet. Try again later.";default:return n??`Licence request refused (${e}). Check your account page.`}}async function wr(e,t,n,o){let r=new URL(e);if(r.protocol!=="https:"&&!(r.protocol==="http:"&&["localhost","127.0.0.1","[::1]"].includes(r.hostname)))throw new Error("The licence server must use HTTPS.");let s=await o(new URL(`/v1/${t}`,r),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n),signal:AbortSignal.timeout(15e3),redirect:"error"}),a=await s.json();if(!s.ok){let c=typeof a.error=="string"?a.error:"request_failed";throw new So(c,s.status,xl(c,typeof a.seats=="number"?a.seats:void 0,typeof a.message=="string"?a.message:void 0))}return a}async function ka(e,t,n,o=fetch){return wa(await wr(e,t,n,o))}async function ya(e,t,n=fetch){let o=await wr(e,"device",t,n),{device_code:r,user_code:s,verification_uri_complete:a,expires_in:c,interval:i}=o;if(typeof r!="string"||typeof s!="string"||typeof a!="string")throw new Error("The licence server did not start a sign-in.");return{deviceCode:r,userCode:s,url:a,expiresIn:typeof c=="number"?c:600,interval:typeof i=="number"?i:5}}async function ba(e,t,n=fetch){try{return wa(await wr(e,"device/token",{device_code:t},n))}catch(o){if(o instanceof So&&o.code==="authorization_pending")return"pending";throw o}}async function oo(e,t,n,o){let r=await ha(e,t,{install:n});if(!r.ok)throw new Error(`Licence refused: ${r.reason}`);if(o&&!r.claims.targets.includes(o))throw new Error("Licence refused: target not in plan");return r.claims}var So,wa,$a=Oe(()=>{"use strict";hr();So=class extends Error{constructor(n,o,r){super(r);this.code=n;this.status=o}};wa=e=>{if(typeof e.licence!="string")throw new Error("The licence server returned no signed licence.");return{licence:e.licence,pullToken:typeof e.pullToken=="string"?e.pullToken:null}}});var Al,En,ro,va=Oe(()=>{"use strict";Al=`-----BEGIN PUBLIC KEY-----
7
7
  MCowBQYDK2VwAyEARMFG3IjOWjtjPhlxBemrNtNnN59FZNc3sDDipX1WKQA=
8
- -----END PUBLIC KEY-----`,vn=[yl,""].filter(Boolean),to="https://fnmoa.locusgraph.com"});var ba=Te(()=>{ka();ya();wr()});import{access as bl,mkdir as $l,readFile as vl,rename as Aa,writeFile as Sl}from"node:fs/promises";import{homedir as xl}from"node:os";import{dirname as Ea,join as Sn}from"node:path";function Ia(e){if(typeof e!="object"||e===null)return Eo();let t=e,n=typeof t.answers=="object"&&t.answers!==null?t.answers:{},o={version:1,screen:$a(t.screen)?t.screen:"where",answers:kt({source:st(n.source,["image","checkout"]),runner:st(n.runner,br),agentCli:st(n.agentCli,pe),tenant:q(n.tenant,64),owner:q(n.owner,64),repo:q(n.repo,140),workspacePort:va(n.workspacePort),consolePort:va(n.consolePort),appOrg:q(n.appOrg,39),githubApp:Pa(n.githubApp),people:Ta(n.people),removed:Cl(n.removed),loginsFor:st(n.loginsFor,br),loggedIn:Array.isArray(n.loggedIn)?[...new Set(n.loggedIn.map(m=>st(m,pe)).filter(m=>m!==void 0))]:void 0,domain:q(n.domain,253),cloudflareAccount:q(n.cloudflareAccount,64),locusgraphGraph:q(n.locusgraphGraph,100),vercelTeam:q(n.vercelTeam,100),vercelPlan:st(n.vercelPlan,["hobby","pro","enterprise"]),vercelScope:El(n.vercelScope),store:st(n.store,["postgres","sqlite"]),sandbox:_a(n.sandbox),githubToken:st(n.githubToken,["own","pasted"])}),passed:Array.isArray(t.passed)?[...new Set(t.passed.filter($a))]:[]},r=st(t.target,Tt);r&&(o.target=r);let s=kt({deployed:Oa(t.deployed),sandbox:o.answers.sandbox,cloudflare:xr(t.cloudflare),githubApp:o.answers.githubApp}),a=typeof t.deployments=="object"&&t.deployments!==null?t.deployments:{},c={};for(let m of Tt){let h=Ol(a[m]);h&&(m===r?Co(s)||(s=h):c[m]=h)}let i=(m,h)=>{let A=s[m];if(A===void 0||r===void 0||h===void 0||h===r)return;let E=c[h]??{};if(E[m]!==void 0)return;c[h]={...E,[m]:A};let{[m]:I,...W}=s;s=W},l=s.deployed?.runner,d=l==="vercel"?"vercel":l==="cloudflare"?"cloudflare":l&&"local",u=s.githubApp?.consoleUrl,f=u===void 0||u.startsWith("http://localhost:")?"local":u===s.sandbox?.consoleUrl?"vercel":u===s.deployed?.consoleUrl?d:void 0;i("githubApp",f),i("deployed",d),i("sandbox","vercel"),i("cloudflare","cloudflare"),s.deployed&&(o.deployed=s.deployed),s.cloudflare&&(o.cloudflare=s.cloudflare),o.answers=kt({...o.answers,sandbox:s.sandbox,githubApp:s.githubApp}),Object.keys(c).length>0&&(o.deployments=c);let p=typeof t.down=="object"&&t.down!==null?t.down:void 0,g=st(p?.target,Tt),b=m=>{if(!Array.isArray(m))return;let h=m.map(A=>q(A,300)).filter(A=>A!==void 0);return h.length>0?h:void 0};p&&g&&(o.down=kt({target:g,at:q(p.at)??new Date(0).toISOString(),removed:b(p.removed)??[],left:b(p.left)}));let $=q(t.updatedAt);return $&&(o.updatedAt=$),o}async function Il(e,t){let n=Sn(Ea(pt(t)),"local"),o=i=>bl(Sn(n,i)).then(()=>!0,()=>!1);if(!await o(vr))return;let r=new Map;for(let i of[e.answers.githubApp,...Tt.map(l=>e.deployments?.[l]?.githubApp)])i&&r.set(i.id,i);let s=[];for(let i of r.values())await o(Ao(i))||s.push(i);let[a,...c]=s;!a||c.length>0||await Aa(Sn(n,vr),Sn(n,Ao(a)))}async function An(e){let t;try{t=Ia(JSON.parse(await vl(pt(e),"utf8")))}catch{return Eo()}return await Il(t,e).catch(()=>{}),t}async function Ot(e,t,n=new Date){let o=pt(t);await $l(Ea(o),{recursive:!0});let r=`${JSON.stringify({...Ia(e),updatedAt:n.toISOString()},null,2)}
9
- `,s=`${o}.${process.pid}.tmp`;await Sl(s,r,{mode:384}),await Aa(s,o)}function at(e,t){if(t===e.target)return e;let{deployed:n,cloudflare:o,deployments:r,...s}=e,{sandbox:a,githubApp:c,...i}=e.answers,l=Ra(e),d=t?e.deployments?.[t]:void 0,u={};for(let b of Tt){let $=b===e.target?l:b===t?void 0:e.deployments?.[b];$&&(u[b]=$)}let f=e.answers.runner!=="cloudflare"?e.answers.runner:void 0,p=d?.deployed?.runner;return{...s,...t?{target:t}:{},answers:kt({...i,runner:t==="cloudflare"?"cloudflare":f??(p==="node"||p==="compose"?p:void 0),sandbox:d?.sandbox,githubApp:d?.githubApp}),...d?.deployed?{deployed:d.deployed}:{},...d?.cloudflare?{cloudflare:d.cloudflare}:{},...Object.keys(u).length>0?{deployments:u}:{}}}function Po(e,t){if(!t)return"";let{deployed:n}=t;if(e==="vercel"){let o=t.sandbox?.name;return n?`deployed, ${o??n.consoleUrl}`:o?`sandbox ${o} made, not deployed yet`:""}if(e==="cloudflare"){let o=t.cloudflare??n?.cloudflare;if(n)return`deployed, ${o?.worker??n.consoleUrl}`;if(!o)return"";let r=o.worker?`Worker ${o.worker}`:[o.d1?"D1":void 0,o.r2?"R2":void 0].filter(Boolean).join(" and ");return r?`${r} made, not deployed yet`:`account ${o.account} used, not deployed yet`}return n?`deployed, ${n.runner==="compose"?"docker compose":"node"} \u2014 ${n.consoleUrl}`:""}var ut,oo,Tt,br,Al,pe,Se,Sr,nn,xn,Eo,pt,$a,q,va,$r,st,Ca,Pa,_a,El,Ta,Cl,yr,Pl,_l,Tl,no,Sa,xa,xr,Oa,Co,Ol,kt,Ao,vr,Ra,ro,Ar,La,Er,Da,Ua,Ma,D,Je=Te(()=>{"use strict";ut=["where","checks","github","memory","logins","access","deploy"],oo={where:"Where should fnMoa run?",checks:"Checks & account",github:"GitHub",logins:"Agent logins (owner only)",memory:"Memory & database",access:"Console access",deploy:"Deploy & done"},Tt=["vercel","cloudflare","local"],br=["node","compose","cloudflare"],Al=[...br,"vercel","image"],pe=["claude","codex","cursor"],Se={claude:"ANTHROPIC_API_KEY",codex:"OPENAI_API_KEY",cursor:"CURSOR_API_KEY"},Sr=20,nn=50,xn=e=>e.answers.source??(e.deployed&&e.deployed.runner!=="image"?"checkout":"image"),Eo=()=>({version:1,screen:"where",answers:{},passed:[]}),pt=(e=process.env)=>Sn(e.MOA_HOME??Sn(xl(),".moa"),"setup.json"),$a=e=>typeof e=="string"&&ut.includes(e),q=(e,t=200)=>typeof e=="string"&&e.length>0&&e.length<=t?e:void 0,va=e=>typeof e=="number"&&Number.isInteger(e)&&e>0&&e<65536?e:void 0,$r=e=>typeof e=="number"&&Number.isInteger(e)&&e>0?e:void 0,st=(e,t)=>typeof e=="string"&&t.includes(e)?e:void 0,Ca=/^[a-z\d](?:[a-z\d-]{0,38})$/i,Pa=e=>{if(typeof e!="object"||e===null)return;let t=e,n=$r(t.id),o=q(t.slug,100),r=q(t.clientId,100),s=q(t.settingsUrl);if(!n||!o||!r||!s)return;let a=q(t.consoleUrl);return{id:n,slug:o,clientId:r,settingsUrl:s,...t.deviceFlow===!0?{deviceFlow:!0}:{},...a?{consoleUrl:a}:{}}},_a=e=>{if(typeof e!="object"||e===null)return;let t=e,n=q(t.name,63),o=q(t.workspaceUrl),r=q(t.consoleUrl);if(!(!n||!o||!r))return kt({name:n,workspaceUrl:o,consoleUrl:r,snapshotId:q(t.snapshotId,100),teamId:q(t.teamId,100),projectId:q(t.projectId,100),revision:q(t.revision,64)})},El=e=>{if(typeof e!="object"||e===null)return;let t=e,n=q(t.teamId,100),o=q(t.projectId,100);return n&&o?{teamId:n,projectId:o}:void 0},Ta=e=>{if(!Array.isArray(e))return;let t=new Map;for(let n of e){if(typeof n!="object"||n===null)continue;let o=n,r=typeof o.login=="string"&&Ca.test(o.login)?o.login:void 0,s=st(o.role,["member","viewer"]),a=o.dailyCapUsd;!r||!s||t.set(r.toLowerCase(),{login:r,role:s,dailyCapUsd:typeof a=="number"&&Number.isFinite(a)&&a>=0?a:Sr})}return t.size>0?[...t.values()]:void 0},Cl=e=>{if(!Array.isArray(e))return;let t=[...new Set(e.filter(n=>typeof n=="string"&&Ca.test(n)).map(n=>n.toLowerCase()))];return t.length>0?t:void 0},yr=/^[A-Za-z0-9][A-Za-z0-9-]{0,63}$/,Pl=/^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/,_l=/^[a-z0-9](?:[a-z0-9-]{1,61}[a-z0-9])$/,Tl=/^[a-z0-9]+(?:[._-][a-z0-9]+)*:[A-Za-z0-9_][A-Za-z0-9._-]{0,127}$/,no=(e,t)=>typeof e=="string"&&t.test(e)?e:void 0,Sa=(e,t,n)=>{if(typeof e!="object"||e===null)return;let o=e,r=no(o[t],n);if(!(!r||typeof o.made!="boolean"))return{[t]:r,made:o.made,...o.unsure===!0&&!o.made?{unsure:!0}:{}}},xa=e=>Array.isArray(e)?[...new Set(e.map(t=>no(t,Tl)).filter(t=>t!==void 0))]:[],xr=e=>{if(typeof e!="object"||e===null)return;let t=e,n=no(t.account,yr);if(!n)return;let o=xa(t.images),r=xa(t.unsureImages).filter(s=>!o.includes(s));return kt({account:n,worker:no(t.worker,Pl),containerId:no(t.containerId,yr),images:o.length>0?o:void 0,unsureImages:r.length>0?r:void 0,older:t.older===!0?!0:void 0,imagesUnlisted:t.imagesUnlisted===!0?!0:void 0,d1:Sa(t.d1,"id",yr),r2:Sa(t.r2,"name",_l)})},Oa=e=>{if(typeof e!="object"||e===null)return;let t=e,n=st(t.runner,Al),o=q(t.workspaceUrl),r=q(t.consoleUrl);if(!(!n||!o||!r))return kt({runner:n,workspaceUrl:o,consoleUrl:r,workspacePid:$r(t.workspacePid),consolePid:$r(t.consolePid),workspaceStarted:q(t.workspaceStarted,64),consoleStarted:q(t.consoleStarted,64),consoleFor:q(t.consoleFor),workspaceFor:q(t.workspaceFor),image:q(t.image),proofRunId:q(t.proofRunId),memory:q(t.memory),people:Ta(t.people),memoryKept:t.memoryKept===!0?!0:void 0,cloudflare:n==="cloudflare"?xr(t.cloudflare):void 0,at:q(t.at)??new Date(0).toISOString()})},Co=e=>e!==void 0&&(e.deployed!==void 0||e.sandbox!==void 0||e.cloudflare!==void 0||e.githubApp!==void 0),Ol=e=>{if(typeof e!="object"||e===null)return;let t=e,n=kt({deployed:Oa(t.deployed),sandbox:_a(t.sandbox),cloudflare:xr(t.cloudflare),githubApp:Pa(t.githubApp)});return Co(n)?n:void 0},kt=e=>Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0));Ao=e=>`github-app.${e.id}.json`,vr="github-app.json";Ra=e=>{let t=kt({deployed:e.deployed,sandbox:e.answers.sandbox,cloudflare:e.cloudflare,githubApp:e.answers.githubApp});return Co(t)?t:void 0},ro=(e,t)=>t===e.target?Ra(e):e.deployments?.[t],Ar=e=>Tt.filter(t=>Co(ro(e,t)));La=(e,t)=>{if(!t)return!1;if(e==="vercel")return t.sandbox!==void 0;if(e==="cloudflare"){let n=t.cloudflare??t.deployed?.cloudflare;return n!==void 0&&(n.worker!==void 0||n.containerId!==void 0||(n.images??[]).length>0||(n.unsureImages??[]).length>0||n.imagesUnlisted===!0||n.d1?.made===!0||n.d1?.unsure===!0||n.r2?.made===!0||n.r2?.unsure===!0)}return!1};Er=e=>ut.indexOf(e),Da=e=>ut[Math.min(Er(e)+1,ut.length-1)],Ua=e=>ut[Math.max(Er(e)-1,0)],Ma=e=>e==="where"?"":`${Er(e)}/${ut.length-1}`,D="\u2022\u2022\u2022"});import{randomUUID as Na}from"node:crypto";import{chmod as Rl,mkdir as Ll,readFile as Dl,rename as Ul,writeFile as Ml}from"node:fs/promises";import{hostname as Nl}from"node:os";import{dirname as ja,join as jl}from"node:path";import{readFileSync as Gl}from"node:fs";async function so(e,t){try{let n=JSON.parse(await Dl(Ga(e,t),"utf8"));if(!/^[A-Za-z0-9_-]{16,64}$/.test(n.install))throw new Error("Invalid install id");return n}catch(n){if(n.code==="ENOENT")return;throw n}}async function Cr(e,t,n){let o=Ga(e,t);await Ll(ja(o),{recursive:!0,mode:448});let r=`${o}.${Na()}.tmp`;await Ml(r,`${JSON.stringify(n)}
10
- `,{mode:384}),await Rl(r,384),await Ul(r,o)}async function Ha(e){if(!to||vn.length===0)throw new Error("This build has no licence-server URL or verification key. Ask the publisher for a configured release.");let t=e.state.target;if(!t)throw new Error("Choose a deployment target first.");let n=await so(e.sys.env,t),o=n??{install:Na()};return n||await Cr(e.sys.env,t,o),{target:t,saved:o}}async function Pr(e,t){let{target:n,saved:o}=await Ha(e),r=await ga(to,"activate",{key:t,install:o.install,version:Gt(),target:n},e.sys.fetch);if((await eo(r.licence,vn,o.install,n)).lapsed)throw new Error("The subscription is unpaid. Renew it before installing or updating.");let a={install:o.install,key:t,licence:r.licence};return await Cr(e.sys.env,n,a),a}async function _o(e,t,n){let{target:o,saved:r}=await Ha(e),s=await ha(to,{install:r.install,version:Gt(),target:o,machine:Nl().slice(0,64)},e.sys.fetch);t({url:s.url,code:s.userCode}),e.sys.exec(process.platform==="darwin"?"open":"xdg-open",[s.url]);let a=Date.now()+s.expiresIn*1e3;for(;Date.now()<a;){if(await e.sys.sleep(s.interval*1e3),n.aborted)throw new Error("Stopped before it was approved.");let c=await wa(to,s.deviceCode,e.sys.fetch);if(c==="pending")continue;if((await eo(c.licence,vn,r.install,o)).lapsed)throw new Error("The subscription is unpaid. Renew it before installing or updating.");let l={install:r.install,licence:c.licence};return await Cr(e.sys.env,o,l),l}throw new Error("The code ran out before it was approved. Press c to try again.")}function Gt(){return Hl}async function yt(e){if(Fa(e)&&!e.secrets.licence)return[];try{let t=e.state.target;if(!t)throw new Error("Choose a target first.");let n=await so(e.sys.env,t);if(!e.secrets.licence&&n?.licence){let a=await eo(n.licence,vn,n.install,t).then(c=>c.lapsed?void 0:c).catch(()=>{});if(a)return[{label:"licence",mark:"ok",detail:`${a.plan} - install ${n.install}`}]}let o=e.secrets.licence??n?.key;if(!o)throw new Error("Not connected: press c to connect your fnMoa account in the browser, or l to paste a licence key.");let r=await Pr(e,o);return[{label:"licence",mark:"ok",detail:`${(await eo(r.licence,vn,r.install,t)).plan} - install ${r.install}`}]}catch(t){return[{label:"licence",mark:"fail",detail:t instanceof Error?t.message:String(t),fix:"Check your account or run `moa setup licence`."}]}}async function Ht(e){if(!e.state.target)return{};let t=await so(e.sys.env,e.state.target);if(!t?.licence){if(Fa(e))return{};throw new Error("Activate this install with `moa setup licence`.")}return{MOA_LICENCE:t.licence,MOA_INSTALL_ID:t.install}}var Ga,Hl,Fa,It=Te(()=>{"use strict";ba();Je();Ga=(e,t)=>jl(ja(pt(e)),`licence-${t}.json`);Hl=JSON.parse(Gl(new URL(import.meta.url.endsWith("/main.js")?"../package.json":"../../package.json",import.meta.url),"utf8")).version,Fa=e=>!!e.sys.root&&xn(e.state)==="checkout"});import{join as Fl}from"node:path";import{parseEnv as Kl}from"node:util";async function Wa(e,t){let n=await e.exec("docker",Rt(t,"build","workspace"),{cwd:t,env:on(e),timeoutMs:12e5});return n.ok?{ok:!0}:{ok:!1,why:To(n.stderr||n.stdout)||"no answer"}}function on(e,t){let n={...e.env,MOA_TOKENS:"setup-check:setup"};for(let o of[...Ja,"MOA_CLI_HOME","LOCUSGRAPH_AGENT_SECRET"])delete n[o];return t&&(n.CLAUDE_CODE_OAUTH_TOKEN=t),n}async function _r(e,t,n){let o;if(n==="here"){let r={...e.env};for(let s of Ja)delete r[s];o=await e.exec("claude",["-p",En],{env:{...r,CLAUDE_CODE_OAUTH_TOKEN:t},timeoutMs:12e4})}else o=await e.exec("docker",Ba(n.container,"claude","-p",En),{cwd:n.container,env:on(e,t),timeoutMs:12e5});return o.ok&&/\bok\b/i.test(o.stdout)?{ok:!0}:{ok:!1,why:To(o.stdout||o.stderr)||"no answer"}}async function qa(e,t){let n=await e.exec("docker",Ba(t,"codex","login","status"),{cwd:t,env:on(e),timeoutMs:12e5}),o=`${n.stdout}
11
- ${n.stderr}`;return n.ok?{loggedIn:!0,says:Bl(n.stdout)||"logged in"}:/not logged in/i.test(o)?{loggedIn:!1,says:"not logged in"}:{loggedIn:!1,says:"",broken:To(o)||"the container did not start"}}function rn(e){let t=e.replace(Wl,""),n=/https:\/\/\S*(device|auth)\S*/i.exec(t);if(!n)return{};let o=t.slice(n.index+n[0].length),r=/\b[A-Z0-9]{4,}-[A-Z0-9]{4,}\b/.exec(o)?.[0];return{url:n[0].replace(/[).,]+$/,""),...r?{code:r}:{}}}function za(e,t,n){let o="",r=!1,s,a=on(e),c=()=>e.exec("docker",["rm","-f",Ka],{cwd:t,env:a,timeoutMs:3e4});return{done:c().then(()=>r?{ok:!1,stdout:"",stderr:"stopped"}:(s=e.run("docker",Rt(t,"run","--rm","--no-deps","-T","--name",Ka,"workspace","codex","login","--device-auth"),{cwd:t,env:a,timeoutMs:16*6e4},l=>{o+=l,n(rn(o))}),s.done)),cancel:()=>{r=!0,s?.cancel(),c()}}}async function Cn(e,t,n){let o={Authorization:`Bearer ${t.secret}`,"Content-Type":"application/json"},r=async(i,l,d=!1)=>{try{let u=await e.fetch(i,{...l,headers:o,signal:AbortSignal.timeout(15e3)});if(u.ok||d&&u.status===409)return{ok:!0};let f=(await u.text().catch(()=>"")).split(t.secret).join("\u2022\u2022\u2022");return{ok:!1,why:`${u.status} ${To(f)}`.trim()}}catch(u){return{ok:!1,why:u instanceof Error?u.message:String(u)}}},s=encodeURIComponent(t.graph),a=await r(`${t.server}/v1/contexts/${s}?type=workspace&page_size=1`,{method:"GET"});if(!a.ok)return{read:a,write:{ok:!1,why:"not tried"}};let c=await r(`${t.server}/v1/events`,{method:"POST",body:JSON.stringify({graph_id:t.graph,context_id:`workspace:${n}`,event_kind:"fact",source:"system",payload:{data:`The ${n} workspace`}})},!0);return{read:a,write:c}}function Ya(e){let t={};for(let[n,o]of Object.entries(Kl(e??"")))o&&(t[n]=o);return t}var we,Rt,Ba,En,Ja,To,Bl,Wl,Ka,Va,Ft=Te(()=>{"use strict";we="fnmoa-setup",Rt=(e,...t)=>["compose","--env-file","/dev/null","-f",Fl(e,"apps","workspace","compose.yaml"),"-p",we,...t],Ba=(e,...t)=>Rt(e,"run","--rm","--no-deps","-T","workspace",...t);En="Reply with the single word ok and nothing else.",Ja=["ANTHROPIC_API_KEY","ANTHROPIC_AUTH_TOKEN","CLAUDE_CODE_OAUTH_TOKEN"];To=e=>e.trim().split(`
12
- `).slice(-2).join(" \xB7 ").slice(0,200);Bl=e=>e.trim().split(`
13
- `)[0]?.trim()??"",Wl=new RegExp("\x1B\\[[0-9;?]*[A-Za-z]","g");Ka=`${we}-codex-login`;Va="https://api.locusgraph.com"});import{randomBytes as Jl}from"node:crypto";import{mkdir as ql,readFile as zl,rm as Tr,writeFile as Vl}from"node:fs/promises";import{dirname as Yl,join as Xl}from"node:path";async function Xa(e,t,n,o){let r=Oo(e,t);await ql(Yl(r),{recursive:!0}),await Tr(r,{force:!0}),await Vl(r,JSON.stringify({url:n,token:o}),{mode:384})}async function Qa(e,t,n){try{let o=JSON.parse(await zl(Oo(e,t),"utf8"));return o.url===n&&typeof o.token=="string"&&Ql.test(o.token)?o.token:void 0}catch{return}}async function Kt(e,t,n){let o=await ve(e.env),r=o.profiles[t],s=o.current,a=!!o.profiles[s],c=await Qa(e,t,n),i=r?.url===n?r.token:void 0;if(c&&i)return s!==t&&await gt({...o,current:t},e.env),{token:c,pending:!0,before:s,had:a};let l=c??i??Or();return(r?.token!==l||r?.url!==n||s!==t)&&await gt({current:t,profiles:{...o.profiles,[t]:{url:n,token:l}}},e.env),c&&await Tr(Oo(e,t),{force:!0}),{token:l,pending:!1,before:s,had:a}}async function Bt(e,t,n,o){if(await Qa(e,t,n)!==o)return;let r=await ve(e.env);await gt({...r,profiles:{...r.profiles,[t]:{url:n,token:o}}},e.env),await Tr(Oo(e,t),{force:!0})}var Ql,Or,Oo,Pn=Te(()=>{"use strict";Ze();qe();Ql=/^moa_[A-Za-z0-9_-]{16,128}$/,Or=()=>`moa_${Jl(24).toString("base64url")}`,Oo=(e,t)=>le(e,Xl("rotate",`${t}.json`))});import{Writable as Zl}from"node:stream";function $t(e){return e==="hobby"?{vcpus:4,memoryGb:8,sessionMs:45*6e4,maxRuns:1}:{vcpus:8,memoryGb:16,sessionMs:24*36e5,maxRuns:3}}function ni(e){let t=e.memoryGb*24*Io.memoryGbHour;return{idle:t,busy:t+e.vcpus*24*Io.cpuHour,perGb:Io.transferGb,storagePerGbMonth:Io.storageGbMonth}}async function si(e,t,n){let o=Object.entries(t).filter(a=>a[1]!==void 0),r={MOA_KEYS:o.map(([a])=>a).join(" "),MOA_DROP:n.join(" "),START:td};o.forEach(([,a],c)=>{r[`V_${c}`]=a});let s=await Ue(e,nd,r);return s.ok?{ok:!0,changed:s.stdout.trim().endsWith("1")}:{ok:!1,changed:!1,why:vt(s.stderr||s.stdout)}}async function Rr(e,t){if(t){let n=await Ue(e,`exec sh "${bt}/start.sh" stop`,{},12e4);if(!n.ok)throw new Error(vt(n.stderr||n.stdout)||"the servers did not stop")}await e.spawn("sh",["-c",`exec sh "${bt}/start.sh"${t?" restart":""}`])}async function ai(e){await Ue(e,`rm -f "${bt}/restart"`)}async function Do(e){let t=await Ue(e,`if [ -f "${bt}/start.sh" ]; then exec sh "${bt}/start.sh" stop; fi`,{},12e4);if(!t.ok)throw new Error(vt(t.stderr||t.stdout)||"the servers did not stop")}function ei(e){return{writeFiles:t=>e.writeFiles(t),name:e.name,status:e.status,...e.vcpus?{vcpus:e.vcpus}:{},domain:t=>e.domain(t),exec:async(t,n,o={})=>{try{let r=await e.runCommand({cmd:t,args:n,...o.env?{env:o.env}:{},...o.sudo?{sudo:!0}:{},signal:AbortSignal.timeout(o.timeoutMs??6e5)});return{ok:r.exitCode===0,stdout:await r.stdout(),stderr:await r.stderr()}}catch(r){return{ok:!1,stdout:"",stderr:Ir(r)}}},spawn:async(t,n)=>{await e.runCommand({cmd:t,args:n,detached:!0})},stream:(t,n,o)=>{let r="",s="",a=new AbortController;return{done:e.runCommand({cmd:t,args:n,stdout:Za(i=>{r+=i,o(i)}),stderr:Za(i=>{s+=i,o(i)}),signal:a.signal}).then(i=>({ok:i.exitCode===0,stdout:r,stderr:s}),i=>({ok:!1,stdout:r,stderr:s||Ir(i)})),cancel:()=>a.abort()}},snapshot:async()=>(await e.snapshot()).snapshotId,stop:async()=>{await e.stop()},delete:async()=>{await e.delete({deleteOrphanSnapshots:!0})}}}async function od(e,t,n){let o=await e(`https://api.vercel.com/v2/teams/${encodeURIComponent(n)}`,{headers:{Authorization:`Bearer ${t}`},signal:AbortSignal.timeout(15e3)});if(!o.ok)throw new Error(`Vercel answered ${o.status} for team ${n}`);let s=(await o.json()).billing?.plan;return s==="pro"||s==="enterprise"?s:"hobby"}function ci(e){let{env:t}=e,n=o=>({token:o.token,teamId:o.teamId,projectId:o.projectId});return{account:async(o,r)=>{let s=await e.exec("vercel",["whoami"]),a=t.VERCEL_TOKEN?.trim();if(!a){if(s.missing)throw new Error("the vercel CLI is not installed");if(!s.ok)throw new Error("not signed in to Vercel");let{getAuth:f}=await import("@vercel/sandbox/dist/auth/index.js");if(a=f()?.token,!a)throw new Error("no Vercel token found for the vercel CLI's login")}let{inferScope:c}=await import("@vercel/sandbox/dist/auth/index.js"),i=t.VERCEL_TEAM_ID?.trim(),l=t.VERCEL_PROJECT_ID?.trim(),d=o??i,u=r?{...r,teamSlug:o??r.teamId}:d&&l&&(!o||o===i)?{teamId:d,projectId:l,teamSlug:d}:await c({token:a,cwd:e.scratch,...d?{teamId:d}:{}});return{user:s.stdout.trim().split(`
14
- `).pop()?.trim()||"you",team:u.teamSlug??u.teamId,teamId:u.teamId,projectId:u.projectId,plan:await od(e.fetch,a,u.teamId),token:a}},get:async(o,r,s=!1)=>{let{Sandbox:a}=await import("@vercel/sandbox");try{return ei(await a.get({name:r,resume:s,...n(o)}))}catch(c){if(ti(c))return;throw c}},create:async(o,r)=>{let{Sandbox:s}=await import("@vercel/sandbox"),a={name:r.name,persistent:!0,ports:[ft,sn],resources:{vcpus:r.size.vcpus},timeout:r.size.sessionMs,...r.env?{env:r.env}:{},...n(o)};return ei(await s.create(r.snapshotId?{...a,source:{type:"snapshot",snapshotId:r.snapshotId}}:r.image?{...a,image:r.image}:a))},deleteSnapshot:async(o,r)=>{let{Snapshot:s}=await import("@vercel/sandbox");try{await(await s.get({snapshotId:r,...n(o)})).delete()}catch(a){if(!ti(a))throw a}}}}var ft,sn,ao,Io,Ro,oi,Lo,ri,bt,ed,td,nd,Ue,vt,_n,Uo,ii,Ir,Za,ti,an=Te(()=>{"use strict";ft=8787,sn=3100,ao=e=>`fnmoa-${e}`.slice(0,63);Io={cpuHour:.128,memoryGbHour:.0212,transferGb:.15,storageGbMonth:.08};Ro=e=>`$${e<10?e.toFixed(2):e.toFixed(0)}`,oi=(e,t)=>`${e==="hobby"?"Hobby":e==="pro"?"Pro":"Enterprise"} \u2014 ${t.vcpus} vCPU / ${t.memoryGb} GB, ${t.sessionMs>=36e5?`${t.sessionMs/36e5}h sessions`:`${t.sessionMs/6e4}-minute sessions`}, ${t.maxRuns===1?"one step at a time":`${t.maxRuns} steps side by side`}`,Lo=e=>{let t=ni(e);return`~${Ro(t.idle)} a day idle, ~${Ro(t.busy)} a day busy, + ${Ro(t.perGb)} per GB served from its URLs (downloads free) \u2014 list prices`},ri=e=>`+ ${Ro(ni(e).storagePerGbMonth)} per GB a month for its kept disk and its snapshot, stopped or not`,bt="$HOME/moa",ed=`set -eu
15
- M="${bt}"
8
+ -----END PUBLIC KEY-----`,En=[Al,""].filter(Boolean),ro="https://fnmoa.locusgraph.com"});var Sa=Oe(()=>{$a();va();hr()});import{access as El,mkdir as Cl,readFile as Pl,rename as Pa,writeFile as _l}from"node:fs/promises";import{homedir as Ol}from"node:os";import{dirname as _a,join as Cn}from"node:path";function Da(e){if(typeof e!="object"||e===null)return Ao();let t=e,n=typeof t.answers=="object"&&t.answers!==null?t.answers:{},o={version:1,screen:xa(t.screen)?t.screen:"where",answers:yt({source:Qe(n.source,["image","checkout"]),runner:Qe(n.runner,yr),agentCli:Qe(n.agentCli,pe),tenant:z(n.tenant,64),owner:z(n.owner,64),repo:z(n.repo,140),workspacePort:Aa(n.workspacePort),consolePort:Aa(n.consolePort),appOrg:z(n.appOrg,39),githubApp:Ta(n.githubApp),people:Ra(n.people),removed:Rl(n.removed),loginsFor:Qe(n.loginsFor,yr),loggedIn:Array.isArray(n.loggedIn)?[...new Set(n.loggedIn.map(m=>Qe(m,pe)).filter(m=>m!==void 0))]:void 0,domain:z(n.domain,253),cloudflareAccount:z(n.cloudflareAccount,64),locusgraphGraph:z(n.locusgraphGraph,100),consoleSignIn:Qe(n.consoleSignIn,["password","github"]),vercelTeam:z(n.vercelTeam,100),vercelPlan:Qe(n.vercelPlan,["hobby","pro","enterprise"]),vercelScope:Il(n.vercelScope),store:Qe(n.store,["postgres","sqlite"]),sandbox:Ia(n.sandbox),githubToken:Qe(n.githubToken,["own","pasted"])}),passed:Array.isArray(t.passed)?[...new Set(t.passed.filter(xa))]:[]},r=Qe(t.target,It);r&&(o.target=r);let s=yt({deployed:La(t.deployed),sandbox:o.answers.sandbox,cloudflare:Sr(t.cloudflare),githubApp:o.answers.githubApp}),a=typeof t.deployments=="object"&&t.deployments!==null?t.deployments:{},c={};for(let m of It){let w=Nl(a[m]);w&&(m===r?Eo(s)||(s=w):c[m]=w)}let i=(m,w)=>{let v=s[m];if(v===void 0||r===void 0||w===void 0||w===r)return;let _=c[w]??{};if(_[m]!==void 0)return;c[w]={..._,[m]:v};let{[m]:H,...W}=s;s=W},l=s.deployed?.runner,d=l==="vercel"?"vercel":l==="cloudflare"?"cloudflare":l&&"local",u=s.githubApp?.consoleUrl,f=u===void 0||u.startsWith("http://localhost:")?"local":u===s.sandbox?.consoleUrl?"vercel":u===s.deployed?.consoleUrl?d:void 0;i("githubApp",f),i("deployed",d),i("sandbox","vercel"),i("cloudflare","cloudflare"),s.deployed&&(o.deployed=s.deployed),s.cloudflare&&(o.cloudflare=s.cloudflare),o.answers=yt({...o.answers,sandbox:s.sandbox,githubApp:s.githubApp}),Object.keys(c).length>0&&(o.deployments=c);let p=typeof t.down=="object"&&t.down!==null?t.down:void 0,g=Qe(p?.target,It),y=m=>{if(!Array.isArray(m))return;let w=m.map(v=>z(v,300)).filter(v=>v!==void 0);return w.length>0?w:void 0};p&&g&&(o.down=yt({target:g,at:z(p.at)??new Date(0).toISOString(),removed:y(p.removed)??[],left:y(p.left)}));let b=z(t.updatedAt);return b&&(o.updatedAt=b),o}async function Ml(e,t){let n=Cn(_a(ut(t)),"local"),o=i=>El(Cn(n,i)).then(()=>!0,()=>!1);if(!await o($r))return;let r=new Map;for(let i of[e.answers.githubApp,...It.map(l=>e.deployments?.[l]?.githubApp)])i&&r.set(i.id,i);let s=[];for(let i of r.values())await o(xo(i))||s.push(i);let[a,...c]=s;!a||c.length>0||await Pa(Cn(n,$r),Cn(n,xo(a)))}async function _n(e){let t;try{t=Da(JSON.parse(await Pl(ut(e),"utf8")))}catch{return Ao()}return await Ml(t,e).catch(()=>{}),t}async function Rt(e,t,n=new Date){let o=ut(t);await Cl(_a(o),{recursive:!0});let r=`${JSON.stringify({...Da(e),updatedAt:n.toISOString()},null,2)}
9
+ `,s=`${o}.${process.pid}.tmp`;await _l(s,r,{mode:384}),await Pa(s,o)}function st(e,t){if(t===e.target)return e;let{deployed:n,cloudflare:o,deployments:r,...s}=e,{sandbox:a,githubApp:c,...i}=e.answers,l=Ua(e),d=t?e.deployments?.[t]:void 0,u={};for(let y of It){let b=y===e.target?l:y===t?void 0:e.deployments?.[y];b&&(u[y]=b)}let f=e.answers.runner!=="cloudflare"?e.answers.runner:void 0,p=d?.deployed?.runner;return{...s,...t?{target:t}:{},answers:yt({...i,runner:t==="cloudflare"?"cloudflare":f??(p==="node"||p==="compose"?p:void 0),sandbox:d?.sandbox,githubApp:d?.githubApp}),...d?.deployed?{deployed:d.deployed}:{},...d?.cloudflare?{cloudflare:d.cloudflare}:{},...Object.keys(u).length>0?{deployments:u}:{}}}function Co(e,t){if(!t)return"";let{deployed:n}=t;if(e==="vercel"){let o=t.sandbox?.name;return n?`deployed, ${o??n.consoleUrl}`:o?`sandbox ${o} made, not deployed yet`:""}if(e==="cloudflare"){let o=t.cloudflare??n?.cloudflare;if(n)return`deployed, ${o?.worker??n.consoleUrl}`;if(!o)return"";let r=o.worker?`Worker ${o.worker}`:[o.d1?"D1":void 0,o.r2?"R2":void 0].filter(Boolean).join(" and ");return r?`${r} made, not deployed yet`:`account ${o.account} used, not deployed yet`}return n?`deployed, ${n.runner==="compose"?"docker compose":"node"} \u2014 ${n.consoleUrl}`:""}var dt,ao,It,yr,Tl,pe,Ae,vr,sn,Pn,Ao,ut,xa,z,Aa,br,Qe,Oa,Ta,Ia,Il,Ra,Rl,kr,Ll,Dl,Ul,so,Ea,Ca,Sr,La,Eo,Nl,yt,xo,$r,Ua,io,xr,Na,Ar,Ma,Ga,ja,U,qe=Oe(()=>{"use strict";dt=["where","checks","github","memory","logins","access","deploy"],ao={where:"Where should fnMoa run?",checks:"Checks & account",github:"GitHub",logins:"Agent logins (owner only)",memory:"Memory & database",access:"Console access",deploy:"Deploy & done"},It=["vercel","cloudflare","local"],yr=["node","compose","cloudflare"],Tl=[...yr,"vercel","image"],pe=["claude","codex","cursor"],Ae={claude:"ANTHROPIC_API_KEY",codex:"OPENAI_API_KEY",cursor:"CURSOR_API_KEY"},vr=20,sn=50,Pn=e=>e.answers.source??(e.deployed&&e.deployed.runner!=="image"?"checkout":"image"),Ao=()=>({version:1,screen:"where",answers:{},passed:[]}),ut=(e=process.env)=>Cn(e.MOA_HOME??Cn(Ol(),".moa"),"setup.json"),xa=e=>typeof e=="string"&&dt.includes(e),z=(e,t=200)=>typeof e=="string"&&e.length>0&&e.length<=t?e:void 0,Aa=e=>typeof e=="number"&&Number.isInteger(e)&&e>0&&e<65536?e:void 0,br=e=>typeof e=="number"&&Number.isInteger(e)&&e>0?e:void 0,Qe=(e,t)=>typeof e=="string"&&t.includes(e)?e:void 0,Oa=/^[a-z\d](?:[a-z\d-]{0,38})$/i,Ta=e=>{if(typeof e!="object"||e===null)return;let t=e,n=br(t.id),o=z(t.slug,100),r=z(t.clientId,100),s=z(t.settingsUrl);if(!n||!o||!r||!s)return;let a=z(t.consoleUrl);return{id:n,slug:o,clientId:r,settingsUrl:s,...t.deviceFlow===!0?{deviceFlow:!0}:{},...a?{consoleUrl:a}:{}}},Ia=e=>{if(typeof e!="object"||e===null)return;let t=e,n=z(t.name,63),o=z(t.workspaceUrl),r=z(t.consoleUrl);if(!(!n||!o||!r))return yt({name:n,workspaceUrl:o,consoleUrl:r,snapshotId:z(t.snapshotId,100),teamId:z(t.teamId,100),projectId:z(t.projectId,100),revision:z(t.revision,64)})},Il=e=>{if(typeof e!="object"||e===null)return;let t=e,n=z(t.teamId,100),o=z(t.projectId,100);return n&&o?{teamId:n,projectId:o}:void 0},Ra=e=>{if(!Array.isArray(e))return;let t=new Map;for(let n of e){if(typeof n!="object"||n===null)continue;let o=n,r=typeof o.login=="string"&&Oa.test(o.login)?o.login:void 0,s=Qe(o.role,["member","viewer"]),a=o.dailyCapUsd;!r||!s||t.set(r.toLowerCase(),{login:r,role:s,dailyCapUsd:typeof a=="number"&&Number.isFinite(a)&&a>=0?a:vr})}return t.size>0?[...t.values()]:void 0},Rl=e=>{if(!Array.isArray(e))return;let t=[...new Set(e.filter(n=>typeof n=="string"&&Oa.test(n)).map(n=>n.toLowerCase()))];return t.length>0?t:void 0},kr=/^[A-Za-z0-9][A-Za-z0-9-]{0,63}$/,Ll=/^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/,Dl=/^[a-z0-9](?:[a-z0-9-]{1,61}[a-z0-9])$/,Ul=/^[a-z0-9]+(?:[._-][a-z0-9]+)*:[A-Za-z0-9_][A-Za-z0-9._-]{0,127}$/,so=(e,t)=>typeof e=="string"&&t.test(e)?e:void 0,Ea=(e,t,n)=>{if(typeof e!="object"||e===null)return;let o=e,r=so(o[t],n);if(!(!r||typeof o.made!="boolean"))return{[t]:r,made:o.made,...o.unsure===!0&&!o.made?{unsure:!0}:{}}},Ca=e=>Array.isArray(e)?[...new Set(e.map(t=>so(t,Ul)).filter(t=>t!==void 0))]:[],Sr=e=>{if(typeof e!="object"||e===null)return;let t=e,n=so(t.account,kr);if(!n)return;let o=Ca(t.images),r=Ca(t.unsureImages).filter(s=>!o.includes(s));return yt({account:n,worker:so(t.worker,Ll),containerId:so(t.containerId,kr),images:o.length>0?o:void 0,unsureImages:r.length>0?r:void 0,older:t.older===!0?!0:void 0,imagesUnlisted:t.imagesUnlisted===!0?!0:void 0,d1:Ea(t.d1,"id",kr),r2:Ea(t.r2,"name",Dl)})},La=e=>{if(typeof e!="object"||e===null)return;let t=e,n=Qe(t.runner,Tl),o=z(t.workspaceUrl),r=z(t.consoleUrl);if(!(!n||!o||!r))return yt({runner:n,workspaceUrl:o,consoleUrl:r,workspacePid:br(t.workspacePid),consolePid:br(t.consolePid),workspaceStarted:z(t.workspaceStarted,64),consoleStarted:z(t.consoleStarted,64),consoleFor:z(t.consoleFor),workspaceFor:z(t.workspaceFor),image:z(t.image),proofRunId:z(t.proofRunId),memory:z(t.memory),people:Ra(t.people),memoryKept:t.memoryKept===!0?!0:void 0,cloudflare:n==="cloudflare"?Sr(t.cloudflare):void 0,at:z(t.at)??new Date(0).toISOString()})},Eo=e=>e!==void 0&&(e.deployed!==void 0||e.sandbox!==void 0||e.cloudflare!==void 0||e.githubApp!==void 0),Nl=e=>{if(typeof e!="object"||e===null)return;let t=e,n=yt({deployed:La(t.deployed),sandbox:Ia(t.sandbox),cloudflare:Sr(t.cloudflare),githubApp:Ta(t.githubApp)});return Eo(n)?n:void 0},yt=e=>Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0));xo=e=>`github-app.${e.id}.json`,$r="github-app.json";Ua=e=>{let t=yt({deployed:e.deployed,sandbox:e.answers.sandbox,cloudflare:e.cloudflare,githubApp:e.answers.githubApp});return Eo(t)?t:void 0},io=(e,t)=>t===e.target?Ua(e):e.deployments?.[t],xr=e=>It.filter(t=>Eo(io(e,t)));Na=(e,t)=>{if(!t)return!1;if(e==="vercel")return t.sandbox!==void 0;if(e==="cloudflare"){let n=t.cloudflare??t.deployed?.cloudflare;return n!==void 0&&(n.worker!==void 0||n.containerId!==void 0||(n.images??[]).length>0||(n.unsureImages??[]).length>0||n.imagesUnlisted===!0||n.d1?.made===!0||n.d1?.unsure===!0||n.r2?.made===!0||n.r2?.unsure===!0)}return!1};Ar=e=>dt.indexOf(e),Ma=e=>dt[Math.min(Ar(e)+1,dt.length-1)],Ga=e=>dt[Math.max(Ar(e)-1,0)],ja=e=>e==="where"?"":`${Ar(e)}/${dt.length-1}`,U="\u2022\u2022\u2022"});import{randomUUID as Ha}from"node:crypto";import{chmod as Gl,mkdir as jl,readFile as Hl,rename as Fl,writeFile as Kl}from"node:fs/promises";import{hostname as Bl}from"node:os";import{dirname as Fa,join as Wl}from"node:path";import{readFileSync as Jl}from"node:fs";async function co(e,t){try{let n=JSON.parse(await Hl(Ka(e,t),"utf8"));if(!/^[A-Za-z0-9_-]{16,64}$/.test(n.install))throw new Error("Invalid install id");return n}catch(n){if(n.code==="ENOENT")return;throw n}}async function Er(e,t,n){let o=Ka(e,t);await jl(Fa(o),{recursive:!0,mode:448});let r=`${o}.${Ha()}.tmp`;await Kl(r,`${JSON.stringify(n)}
10
+ `,{mode:384}),await Gl(r,384),await Fl(r,o)}async function Ba(e){if(!ro||En.length===0)throw new Error("This build has no licence-server URL or verification key. Ask the publisher for a configured release.");let t=e.state.target;if(!t)throw new Error("Choose a deployment target first.");let n=await co(e.sys.env,t),o=n??{install:Ha()};return n||await Er(e.sys.env,t,o),{target:t,saved:o}}async function Cr(e,t){let{target:n,saved:o}=await Ba(e),r=await ka(ro,"activate",{key:t,install:o.install,version:Bt(),target:n},e.sys.fetch);if((await oo(r.licence,En,o.install,n)).lapsed)throw new Error("The subscription is unpaid. Renew it before installing or updating.");let a={install:o.install,key:t,licence:r.licence};return await Er(e.sys.env,n,a),a}async function Po(e,t,n){let{target:o,saved:r}=await Ba(e),s=await ya(ro,{install:r.install,version:Bt(),target:o,machine:Bl().slice(0,64)},e.sys.fetch);t({url:s.url,code:s.userCode}),e.sys.exec(process.platform==="darwin"?"open":"xdg-open",[s.url]);let a=Date.now()+s.expiresIn*1e3;for(;Date.now()<a;){if(await e.sys.sleep(s.interval*1e3),n.aborted)throw new Error("Stopped before it was approved.");let c=await ba(ro,s.deviceCode,e.sys.fetch);if(c==="pending")continue;if((await oo(c.licence,En,r.install,o)).lapsed)throw new Error("The subscription is unpaid. Renew it before installing or updating.");let l={install:r.install,licence:c.licence};return await Er(e.sys.env,o,l),l}throw new Error("The code ran out before it was approved. Press c to try again.")}function Bt(){return ql}async function bt(e){if(Wa(e)&&!e.secrets.licence)return[];try{let t=e.state.target;if(!t)throw new Error("Choose a target first.");let n=await co(e.sys.env,t);if(!e.secrets.licence&&n?.licence){let a=await oo(n.licence,En,n.install,t).then(c=>c.lapsed?void 0:c).catch(()=>{});if(a)return[{label:"licence",mark:"ok",detail:`${a.plan} - install ${n.install}`}]}let o=e.secrets.licence??n?.key;if(!o)throw new Error("Not connected: press c to connect your fnMoa account in the browser, or l to paste a licence key.");let r=await Cr(e,o);return[{label:"licence",mark:"ok",detail:`${(await oo(r.licence,En,r.install,t)).plan} - install ${r.install}`}]}catch(t){return[{label:"licence",mark:"fail",detail:t instanceof Error?t.message:String(t),fix:"Check your account or run `moa setup licence`."}]}}async function Wt(e){if(!e.state.target)return{};let t=await co(e.sys.env,e.state.target);if(!t?.licence){if(Wa(e))return{};throw new Error("Activate this install with `moa setup licence`.")}return{MOA_LICENCE:t.licence,MOA_INSTALL_ID:t.install}}var Ka,ql,Wa,Lt=Oe(()=>{"use strict";Sa();qe();Ka=(e,t)=>Wl(Fa(ut(e)),`licence-${t}.json`);ql=JSON.parse(Jl(new URL(import.meta.url.endsWith("/main.js")?"../package.json":"../../package.json",import.meta.url),"utf8")).version,Wa=e=>!!e.sys.root&&Pn(e.state)==="checkout"});import{join as zl}from"node:path";import{parseEnv as Vl}from"node:util";async function za(e,t){let n=await e.exec("docker",Dt(t,"build","workspace"),{cwd:t,env:an(e),timeoutMs:12e5});return n.ok?{ok:!0}:{ok:!1,why:_o(n.stderr||n.stdout)||"no answer"}}function an(e,t){let n={...e.env,MOA_TOKENS:"setup-check:setup"};for(let o of[...Va,"MOA_CLI_HOME","LOCUSGRAPH_AGENT_SECRET"])delete n[o];return t&&(n.CLAUDE_CODE_OAUTH_TOKEN=t),n}async function Pr(e,t,n){let o;if(n==="here"){let r={...e.env};for(let s of Va)delete r[s];o=await e.exec("claude",["-p",On],{env:{...r,CLAUDE_CODE_OAUTH_TOKEN:t},timeoutMs:12e4})}else o=await e.exec("docker",qa(n.container,"claude","-p",On),{cwd:n.container,env:an(e,t),timeoutMs:12e5});return o.ok&&/\bok\b/i.test(o.stdout)?{ok:!0}:{ok:!1,why:_o(o.stdout||o.stderr)||"no answer"}}async function Ya(e,t){let n=await e.exec("docker",qa(t,"codex","login","status"),{cwd:t,env:an(e),timeoutMs:12e5}),o=`${n.stdout}
11
+ ${n.stderr}`;return n.ok?{loggedIn:!0,says:Yl(n.stdout)||"logged in"}:/not logged in/i.test(o)?{loggedIn:!1,says:"not logged in"}:{loggedIn:!1,says:"",broken:_o(o)||"the container did not start"}}function cn(e){let t=e.replace(Xl,""),n=/https:\/\/\S*(device|auth)\S*/i.exec(t);if(!n)return{};let o=t.slice(n.index+n[0].length),r=/\b[A-Z0-9]{4,}-[A-Z0-9]{4,}\b/.exec(o)?.[0];return{url:n[0].replace(/[).,]+$/,""),...r?{code:r}:{}}}function Xa(e,t,n){let o="",r=!1,s,a=an(e),c=()=>e.exec("docker",["rm","-f",Ja],{cwd:t,env:a,timeoutMs:3e4});return{done:c().then(()=>r?{ok:!1,stdout:"",stderr:"stopped"}:(s=e.run("docker",Dt(t,"run","--rm","--no-deps","-T","--name",Ja,"workspace","codex","login","--device-auth"),{cwd:t,env:a,timeoutMs:16*6e4},l=>{o+=l,n(cn(o))}),s.done)),cancel:()=>{r=!0,s?.cancel(),c()}}}async function Tn(e,t,n){let o={Authorization:`Bearer ${t.secret}`,"Content-Type":"application/json"},r=async(i,l,d=!1)=>{try{let u=await e.fetch(i,{...l,headers:o,signal:AbortSignal.timeout(15e3)});if(u.ok||d&&u.status===409)return{ok:!0};let f=(await u.text().catch(()=>"")).split(t.secret).join("\u2022\u2022\u2022");return{ok:!1,why:`${u.status} ${_o(f)}`.trim()}}catch(u){return{ok:!1,why:u instanceof Error?u.message:String(u)}}},s=encodeURIComponent(t.graph),a=await r(`${t.server}/v1/contexts/${s}?type=workspace&page_size=1`,{method:"GET"});if(!a.ok)return{read:a,write:{ok:!1,why:"not tried"}};let c=await r(`${t.server}/v1/events`,{method:"POST",body:JSON.stringify({graph_id:t.graph,context_id:`workspace:${n}`,event_kind:"fact",source:"system",payload:{data:`The ${n} workspace`}})},!0);return{read:a,write:c}}function Za(e){let t={};for(let[n,o]of Object.entries(Vl(e??"")))o&&(t[n]=o);return t}var he,Dt,qa,On,Va,_o,Yl,Xl,Ja,Qa,Jt=Oe(()=>{"use strict";he="fnmoa-setup",Dt=(e,...t)=>["compose","--env-file","/dev/null","-f",zl(e,"apps","workspace","compose.yaml"),"-p",he,...t],qa=(e,...t)=>Dt(e,"run","--rm","--no-deps","-T","workspace",...t);On="Reply with the single word ok and nothing else.",Va=["ANTHROPIC_API_KEY","ANTHROPIC_AUTH_TOKEN","CLAUDE_CODE_OAUTH_TOKEN"];_o=e=>e.trim().split(`
12
+ `).slice(-2).join(" \xB7 ").slice(0,200);Yl=e=>e.trim().split(`
13
+ `)[0]?.trim()??"",Xl=new RegExp("\x1B\\[[0-9;?]*[A-Za-z]","g");Ja=`${he}-codex-login`;Qa="https://api.locusgraph.com"});import{randomBytes as Ql}from"node:crypto";import{mkdir as Zl,readFile as ed,rm as _r,writeFile as td}from"node:fs/promises";import{dirname as nd,join as od}from"node:path";async function ei(e,t,n,o){let r=Oo(e,t);await Zl(nd(r),{recursive:!0}),await _r(r,{force:!0}),await td(r,JSON.stringify({url:n,token:o}),{mode:384})}async function ti(e,t,n){try{let o=JSON.parse(await ed(Oo(e,t),"utf8"));return o.url===n&&typeof o.token=="string"&&rd.test(o.token)?o.token:void 0}catch{return}}async function qt(e,t,n){let o=await xe(e.env),r=o.profiles[t],s=o.current,a=!!o.profiles[s],c=await ti(e,t,n),i=r?.url===n?r.token:void 0;if(c&&i)return s!==t&&await ht({...o,current:t},e.env),{token:c,pending:!0,before:s,had:a};let l=c??i??Or();return(r?.token!==l||r?.url!==n||s!==t)&&await ht({current:t,profiles:{...o.profiles,[t]:{url:n,token:l}}},e.env),c&&await _r(Oo(e,t),{force:!0}),{token:l,pending:!1,before:s,had:a}}async function zt(e,t,n,o){if(await ti(e,t,n)!==o)return;let r=await xe(e.env);await ht({...r,profiles:{...r.profiles,[t]:{url:n,token:o}}},e.env),await _r(Oo(e,t),{force:!0})}var rd,Or,Oo,In=Oe(()=>{"use strict";Ye();ze();rd=/^moa_[A-Za-z0-9_-]{16,128}$/,Or=()=>`moa_${Ql(24).toString("base64url")}`,Oo=(e,t)=>ce(e,od("rotate",`${t}.json`))});import{Writable as sd}from"node:stream";function vt(e){return e==="hobby"?{vcpus:4,memoryGb:8,sessionMs:45*6e4,maxRuns:1}:{vcpus:8,memoryGb:16,sessionMs:24*36e5,maxRuns:3}}function si(e){let t=e.memoryGb*24*To.memoryGbHour;return{idle:t,busy:t+e.vcpus*24*To.cpuHour,perGb:To.transferGb,storagePerGbMonth:To.storageGbMonth}}async function ci(e,t,n){let o=Object.entries(t).filter(a=>a[1]!==void 0),r={MOA_KEYS:o.map(([a])=>a).join(" "),MOA_DROP:n.join(" "),START:id};o.forEach(([,a],c)=>{r[`V_${c}`]=a});let s=await Ne(e,cd,r);return s.ok?{ok:!0,changed:s.stdout.trim().endsWith("1")}:{ok:!1,changed:!1,why:St(s.stderr||s.stdout)}}async function Ir(e,t){if(t){let n=await Ne(e,`exec sh "${$t}/start.sh" stop`,{},12e4);if(!n.ok)throw new Error(St(n.stderr||n.stdout)||"the servers did not stop")}await e.spawn("sh",["-c",`exec sh "${$t}/start.sh"${t?" restart":""}`])}async function li(e){await Ne(e,`rm -f "${$t}/restart"`)}async function Lo(e){let t=await Ne(e,`if [ -f "${$t}/start.sh" ]; then exec sh "${$t}/start.sh" stop; fi`,{},12e4);if(!t.ok)throw new Error(St(t.stderr||t.stdout)||"the servers did not stop")}function oi(e){return{writeFiles:t=>e.writeFiles(t),name:e.name,status:e.status,...e.vcpus?{vcpus:e.vcpus}:{},domain:t=>e.domain(t),exec:async(t,n,o={})=>{try{let r=await e.runCommand({cmd:t,args:n,...o.env?{env:o.env}:{},...o.sudo?{sudo:!0}:{},signal:AbortSignal.timeout(o.timeoutMs??6e5)});return{ok:r.exitCode===0,stdout:await r.stdout(),stderr:await r.stderr()}}catch(r){return{ok:!1,stdout:"",stderr:Tr(r)}}},spawn:async(t,n)=>{await e.runCommand({cmd:t,args:n,detached:!0})},stream:(t,n,o)=>{let r="",s="",a=new AbortController;return{done:e.runCommand({cmd:t,args:n,stdout:ni(i=>{r+=i,o(i)}),stderr:ni(i=>{s+=i,o(i)}),signal:a.signal}).then(i=>({ok:i.exitCode===0,stdout:r,stderr:s}),i=>({ok:!1,stdout:r,stderr:s||Tr(i)})),cancel:()=>a.abort()}},snapshot:async()=>(await e.snapshot()).snapshotId,stop:async()=>{await e.stop()},delete:async()=>{await e.delete({deleteOrphanSnapshots:!0})}}}async function ld(e,t,n){let o=await e(`https://api.vercel.com/v2/teams/${encodeURIComponent(n)}`,{headers:{Authorization:`Bearer ${t}`},signal:AbortSignal.timeout(15e3)});if(!o.ok)throw new Error(`Vercel answered ${o.status} for team ${n}`);let s=(await o.json()).billing?.plan;return s==="pro"||s==="enterprise"?s:"hobby"}function ui(e){let{env:t}=e,n=o=>({token:o.token,teamId:o.teamId,projectId:o.projectId});return{account:async(o,r)=>{let s=await e.exec("vercel",["whoami"]),a=t.VERCEL_TOKEN?.trim();if(!a){if(s.missing)throw new Error("the vercel CLI is not installed");if(!s.ok)throw new Error("not signed in to Vercel");let{getAuth:f}=await import("@vercel/sandbox/dist/auth/index.js");if(a=f()?.token,!a)throw new Error("no Vercel token found for the vercel CLI's login")}let{inferScope:c}=await import("@vercel/sandbox/dist/auth/index.js"),i=t.VERCEL_TEAM_ID?.trim(),l=t.VERCEL_PROJECT_ID?.trim(),d=o??i,u=r?{...r,teamSlug:o??r.teamId}:d&&l&&(!o||o===i)?{teamId:d,projectId:l,teamSlug:d}:await c({token:a,cwd:e.scratch,...d?{teamId:d}:{}});return{user:s.stdout.trim().split(`
14
+ `).pop()?.trim()||"you",team:u.teamSlug??u.teamId,teamId:u.teamId,projectId:u.projectId,plan:await ld(e.fetch,a,u.teamId),token:a}},get:async(o,r,s=!1)=>{let{Sandbox:a}=await import("@vercel/sandbox");try{return oi(await a.get({name:r,resume:s,...n(o)}))}catch(c){if(ri(c))return;throw c}},create:async(o,r)=>{let{Sandbox:s}=await import("@vercel/sandbox"),a={name:r.name,persistent:!0,ports:[pt,ln],resources:{vcpus:r.size.vcpus},timeout:r.size.sessionMs,...r.env?{env:r.env}:{},...n(o)};return oi(await s.create(r.snapshotId?{...a,source:{type:"snapshot",snapshotId:r.snapshotId}}:r.image?{...a,image:r.image}:a))},deleteSnapshot:async(o,r)=>{let{Snapshot:s}=await import("@vercel/sandbox");try{await(await s.get({snapshotId:r,...n(o)})).delete()}catch(a){if(!ri(a))throw a}}}}var pt,ln,lo,To,Io,ai,Ro,ii,$t,ad,id,cd,Ne,St,Rn,Do,di,Tr,ni,ri,dn=Oe(()=>{"use strict";pt=8787,ln=3100,lo=e=>`fnmoa-${e}`.slice(0,63);To={cpuHour:.128,memoryGbHour:.0212,transferGb:.15,storageGbMonth:.08};Io=e=>`$${e<10?e.toFixed(2):e.toFixed(0)}`,ai=(e,t)=>`${e==="hobby"?"Hobby":e==="pro"?"Pro":"Enterprise"} \u2014 ${t.vcpus} vCPU / ${t.memoryGb} GB, ${t.sessionMs>=36e5?`${t.sessionMs/36e5}h sessions`:`${t.sessionMs/6e4}-minute sessions`}, ${t.maxRuns===1?"one step at a time":`${t.maxRuns} steps side by side`}`,Ro=e=>{let t=si(e);return`~${Io(t.idle)} a day idle, ~${Io(t.busy)} a day busy, + ${Io(t.perGb)} per GB served from its URLs (downloads free) \u2014 list prices`},ii=e=>`+ ${Io(si(e).storagePerGbMonth)} per GB a month for its kept disk and its snapshot, stopped or not`,$t="$HOME/moa",ad=`set -eu
15
+ M="${$t}"
16
16
  mkdir -p "$M"
17
17
  missing() { ! command -v "$1" > /dev/null 2>&1; }
18
18
  UPDATED=""
@@ -45,8 +45,8 @@ pnpm install --frozen-lockfile
45
45
  pnpm --filter "@fnmoa/workspace..." run build
46
46
  pnpm --filter @fnmoa/console run build
47
47
  printf %s "$MOA_REVISION" > "$M/image"
48
- `,td=`#!/bin/sh
49
- M="${bt}"
48
+ `,id=`#!/bin/sh
49
+ M="${$t}"
50
50
  R="$M/run/$(cat /proc/sys/kernel/random/boot_id 2>/dev/null || echo boot)"
51
51
  mkdir -p "$M/logs" "$R" "$M/data/worktrees"
52
52
  load() { for f in "$M/env/$1"/*; do if [ -f "$f" ]; then export "$(basename "$f")=$(cat "$f")"; fi; done; }
@@ -104,13 +104,13 @@ fi
104
104
  if ! running console; then
105
105
  (
106
106
  load console
107
- cd "$M/fnmoa/apps/console" && exec node node_modules/next/dist/bin/next start --hostname 0.0.0.0 --port ${sn}
107
+ cd "$M/fnmoa/apps/console" && exec node node_modules/next/dist/bin/next start --hostname 0.0.0.0 --port ${ln}
108
108
  ) >> "$M/logs/console.log" 2>&1 &
109
109
  echo $! > "$R/console.pid"
110
110
  fi
111
111
  wait
112
- `,nd=`set -eu
113
- M="${bt}"
112
+ `,cd=`set -eu
113
+ M="${$t}"
114
114
  umask 077
115
115
  changed=0
116
116
  i=0
@@ -133,37 +133,38 @@ if [ ! -f "$M/start.sh" ] || [ "$(cat "$M/start.sh")" != "$(printf %s "$START")"
133
133
  fi
134
134
  if [ "$changed" = 1 ]; then : > "$M/restart"; fi
135
135
  if [ -f "$M/restart" ]; then echo 1; else echo 0; fi
136
- `,Ue=(e,t,n={},o)=>e.exec("sh",["-c",t],{env:n,...o?{timeoutMs:o}:{}});vt=(e,t=2)=>e.trim().split(`
137
- `).slice(-t).join(" \xB7 ").slice(0,300);_n=async(e,t)=>{let n=await Ue(e,`tail -n 5 "${bt}/logs/${t}.log" 2> /dev/null`);return vt(n.stdout,3)},Uo=async e=>{let t=await Ue(e,`cat "${bt}/image" 2> /dev/null`);return t.ok&&t.stdout.trim()||void 0},ii=(e,t,n,o)=>Ue(e,ed,{MOA_SOURCE:t,MOA_REVISION:n,...o?{GH_TOKEN:o}:{}},18e5),Ir=e=>(e instanceof Error?e.message:String(e)).split(`
138
- `)[0]?.slice(0,300)??"",Za=e=>new Zl({write(t,n,o){e(String(t)),o()}});ti=e=>e.response?.status===404||/not.?found|404/i.test(Ir(e))});import{execFile as rd,execFileSync as li,spawn as di}from"node:child_process";import{existsSync as Lr,mkdirSync as sd,openSync as ad,readFileSync as id}from"node:fs";import{connect as cd}from"node:net";import{dirname as Dr,join as Ur,resolve as ld}from"node:path";import{fileURLToPath as dd}from"node:url";function Lt(e,t,n,o){let r=e.processOf(t);return r?n!==void 0?r.started===n:e.root!==void 0&&r.command.includes(e.root)?!0:r.command.startsWith("next-server")&&o!==void 0&&e.portsOf(t)?.includes(o)===!0:!1}function St(e){try{let t=Number(new URL(e).port);return Number.isInteger(t)&&t>0?t:void 0}catch{return}}function md(e=process.cwd()){let t=Dr(dd(import.meta.url));for(let n of[e,t]){let o=ld(n);for(;;){if(fd(o))return o;let r=Dr(o);if(r===o)break;o=r}}}function cn(e=process.env){let t={env:e,root:md(),exec:(n,o,r={})=>new Promise(s=>{rd(n,o,{cwd:r.cwd,env:r.env??e,timeout:r.timeoutMs??15e3,maxBuffer:16777216},(a,c,i)=>{let l=a?.code;s({ok:a===null,stdout:String(c),stderr:String(i),...l==="ENOENT"?{missing:!0}:{}})})}),run:(n,o,r,s)=>{let a="",c="",i=di(n,o,{cwd:r.cwd,env:r.env??e,stdio:["ignore","pipe","pipe"]}),l=setTimeout(()=>i.kill("SIGTERM"),r.timeoutMs??9e5);return i.stdout.on("data",u=>{a+=String(u),s(String(u))}),i.stderr.on("data",u=>{c+=String(u),s(String(u))}),{done:new Promise(u=>{i.once("error",f=>{clearTimeout(l),u({ok:!1,stdout:a,stderr:c||f.message,...f.code==="ENOENT"?{missing:!0}:{}})}),i.once("close",f=>{clearTimeout(l),u({ok:f===0,stdout:a,stderr:c})})}),cancel:()=>i.kill("SIGTERM")}},exists:Lr,read:n=>{try{return id(n,"utf8")}catch{return}},listening:n=>new Promise(o=>{let r=cd({host:"127.0.0.1",port:n}),s=a=>{r.destroy(),o(a)};r.once("connect",()=>s(!0)),r.once("error",()=>s(!1)),r.setTimeout(1e3,()=>s(!1))}),alive:n=>{try{return process.kill(n,0),!0}catch(o){return o.code==="EPERM"}},processOf:n=>{try{let o=li("ps",["-o","lstart=,command=","-p",String(n)],{env:{...e,LC_ALL:"C",TZ:"UTC"},encoding:"utf8",timeout:5e3,stdio:["ignore","pipe","ignore"]}),r=ud.exec(o.trim().split(`
139
- `)[0]??"");return r?.[1]&&r[2]!==void 0?{started:r[1],command:r[2]}:void 0}catch{return}},portsOf:n=>{try{let r=li("lsof",["-nP","-a","-p",String(n),"-iTCP","-sTCP:LISTEN","-Fn"],{env:e,encoding:"utf8",timeout:5e3,stdio:["ignore","pipe","ignore"]}).split(`
140
- `).map(s=>pd.exec(s)?.[1]).filter(s=>s!==void 0).map(Number);return[...new Set(r)]}catch(o){return o.status===1?[]:void 0}},start:(n,o,r)=>{sd(Dr(r.log),{recursive:!0});let s=ad(r.log,"a"),a=di(n,o,{cwd:r.cwd,env:r.env,detached:!0,stdio:["ignore",s,s]});if(a.unref(),a.pid===void 0)throw new Error(`could not start ${n}`);return a.pid},stop:(n,o)=>{for(let r of[-n,n])try{if(process.kill(r,o?"SIGKILL":"SIGTERM"),!o)return}catch{}},fetch:(...n)=>fetch(...n),sleep:n=>new Promise(o=>setTimeout(o,n))};return t.vercel=ci({env:e,exec:(n,o)=>t.exec(n,o),fetch:t.fetch,scratch:Ur(pt(e),"..","local")}),t}var ud,pd,fd,io=Te(()=>{"use strict";Je();an();ud=/^\s*(\w{3} \w{3} [ \d]\d \d\d:\d\d:\d\d \d{4})\s+(.*)$/,pd=/^n.*:(\d+)$/,fd=e=>Lr(Ur(e,"pnpm-workspace.yaml"))&&Lr(Ur(e,"apps","workspace","compose.yaml"))});import{createHash as gd}from"node:crypto";import{join as Tn}from"node:path";async function ui(e,t,n){let o=Date.now()+n*1e3;for(;Date.now()<o;){if(await e.fetch(t,{signal:AbortSignal.timeout(2e3)}).then(()=>!0).catch(()=>!1))return!0;await e.sleep(500)}return!1}async function hd(e,t,n){let o=Date.now()+n*1e3;for(;Date.now()<o;){if(!await e.listening(t))return!0;await e.sleep(500)}return!1}async function wd(e,t,n){let o=Date.now()+n*1e3;for(;Date.now()<o;){if(!e.alive(t))return!0;await e.sleep(500)}return!1}async function Mo(e,t,n=()=>{}){let{sys:o,state:r}=e,s=[],a=re=>{let _e=s.findIndex(ue=>ue.label===re.label);_e===-1?s.push(re):s[_e]=re,t([...s])},c,i=(re,_e,ue)=>(a({label:re,mark:"fail",detail:_e,fix:ue}),c?{ok:!1,deployed:c}:{ok:!1}),l=o.root;if(!l||Oe(e)||r.deployed?.runner==="image")return Nr(e,t,n);if(un(e))return i("memory","the last deploy kept memory in LocusGraph, and this run has no secret for it","Esc back to Memory & database and paste it again \u2014 or go on there without it");let d=r.answers.runner??"node",u=r.answers.agentCli??"claude",f=d==="compose"&&r.answers.loginsFor==="compose"?[...new Set([u,...r.answers.loggedIn??[]])]:[u],p=tt(e)?.token,g=xe(e),b=r.answers.tenant??Ie(r.answers.owner),$=Jt(r),m=Ut(r),h=`http://127.0.0.1:${$}`,A=`http://localhost:${m}`,E=r.answers.owner,I=r.answers.githubApp,W=I?He(o,I):void 0;if(I&&!W)return i("GitHub App",`the client secret for ${I.slug} is not on this machine`,"Esc back to Console access and press g to create a new app");let fe=I&&W?{AUTH_GITHUB_ID:I.clientId,AUTH_GITHUB_SECRET:W.clientSecret,AUTH_SECRET:W.authSecret,AUTH_URL:A}:{};if(d==="compose"&&f.includes("claude")&&!p)return i("claude token","none in this run \u2014 it is never saved","Esc back to Agent logins and press t (or choose codex there), then Enter");let M=Tn(l,"apps","workspace","dist","node.js"),z=Tn(l,"apps","console",".next"),R=o.exists(M),J=o.exists(Tn(z,"BUILD_ID"));if(R&&J)a({label:"build",mark:"ok",detail:"workspace and console are built"});else{if(!J&&o.exists(z))return i("build","apps/console/.next holds no build \u2014 `next dev` may be using it, and a build would write over it",`stop the console's dev server, then run \`pnpm --filter @fnmoa/console build\` in ${l}, then Enter`);let re=[...R?[]:[{what:"workspace",args:["--filter","@fnmoa/workspace...","run","build"]}],...J?[]:[{what:"console",args:["--filter","@fnmoa/console","run","build"]}]],_e=re.map(Qe=>Qe.what).join(" and ");a({label:"build",mark:"wait",detail:`building the ${_e} \u2014 a few minutes`});let ue=await o.exec("pnpm",["install"],{cwd:l,timeoutMs:6e5});if(!ue.ok)return i("build",`pnpm install: ${In(ue.stderr||ue.stdout)}`,`run \`pnpm install\` in ${l}, then Enter`);for(let Qe of re){let lt=await o.exec("pnpm",Qe.args,{cwd:l,timeoutMs:9e5});if(!lt.ok)return i("build",`${Qe.what}: ${In(lt.stderr||lt.stdout)}`,`run \`pnpm ${Qe.args.join(" ")}\` in ${l}, then Enter`)}a({label:"build",mark:"ok",detail:`${_e} built`})}let{token:V,pending:Ce,before:X,had:Fe}=await Kt(o,On,h);a({label:"owner token",mark:"ok",detail:`${D} \u2014 profile ${On} in ~/.moa/config.json${X===On?"":Fe?`; \`moa\` now talks to this workspace, not profile ${X} (\`moa use ${X}\` to go back)`:"; `moa` now talks to this workspace"}`});let me=U({url:h,token:V},o.fetch),k=r.deployed?Ln(o,r.deployed):void 0,Q=kd({runner:d,workspaceUrl:h,tenant:b,token:V,...r.answers.repo?{repo:r.answers.repo}:{},...E?{owner:E}:{},...I?{githubClientId:I.clientId}:{},...g?{locusgraph:g.secret,graph:g.graph,server:g.server}:{},...p?{claude:p}:{}}),O=k?.workspacePid!==void 0&&Lt(o,k.workspacePid,k.workspaceStarted,St(k.workspaceUrl))?k.workspacePid:void 0,N=O?k?.workspaceStarted:void 0,ne=k?.workspaceFor,ge=k?.consolePid!==void 0&&Lt(o,k.consolePid,k.consoleStarted,St(k.consoleUrl))?k.consolePid:void 0,oe=ge?k?.consoleStarted:void 0,ke=k?.consoleFor,Ve=k?.memoryKept,Pe=k?.workspaceUrl===h?k?.people:void 0,Me=()=>{c={runner:d,workspaceUrl:h,consoleUrl:A,...O?{workspacePid:O,...N?{workspaceStarted:N}:{}}:{},...ne?{workspaceFor:ne}:{},...ge?{consolePid:ge,...oe?{consoleStarted:oe}:{},...ke?{consoleFor:ke}:{}}:{},...Pe?{people:Pe}:{},...Ve?{memoryKept:Ve}:{},at:new Date().toISOString()},n(c)};if((O||ge)&&Me(),O!==void 0&&ne!==Q){if(a({label:"workspace",mark:"wait",detail:"restarting \u2014 it was started with other answers"}),o.stop(O),!await wd(o,O,15))return i("workspace",`the old workspace (pid ${O}) is still running`,`stop it (\`kill ${O}\`), then Enter`);O=void 0,N=void 0,ne=void 0,Me()}let Le=await me.get("/v1/whoami").then(()=>"ours",re=>re instanceof ae?"other":"down");if(Le==="other")return i("workspace",`something else answers on :${$} and refuses this token`,"stop it, or run `moa setup --workspace-port <port>`");if(Le==="ours"&&ne!==Q&&d==="node")return i("workspace",`the workspace on :${$} was not started with these answers`,k?.runner==="compose"?`run \`docker compose -p ${we} down\`, then Enter`:"stop it, then Enter");if(Le==="ours"&&ne===Q)a({label:"workspace",mark:"ok",detail:`${h} \u2014 already running`});else{a({label:"workspace",mark:"wait",detail:`starting on :${$}`});let re={...o.env,...await Ht(e),MOA_TOKENS:`${V}:${b}`,PORT:String($),MOA_PORT:String($),MOA_CONSOLE_PORT:String(m),...r.answers.repo?{MOA_REPO:r.answers.repo}:{},...E?{MOA_OWNER_LOGIN:E}:{},...I?{MOA_GITHUB_CLIENT_ID:I.clientId}:{},...g?{LOCUSGRAPH_AGENT_SECRET:g.secret,LOCUSGRAPH_GRAPH_ID:g.graph,LOCUSGRAPH_SERVER_URL:g.server}:{}};for(let ue of["MOA_DATABASE_URL","MOA_SQLITE_FILE","MOA_TOKEN_FILE","MOA_WORKSPACE_ROOT","MOA_SELF_URL",...E?[]:["MOA_OWNER_LOGIN"],...I?[]:["MOA_GITHUB_CLIENT_ID"]])delete re[ue];if(d==="compose"){for(let Qe of["MOA_CLI_HOME","CLAUDE_CODE_OAUTH_TOKEN","ANTHROPIC_API_KEY"])delete re[Qe];p&&(re.CLAUDE_CODE_OAUTH_TOKEN=p);let ue=await o.exec("docker",Rt(l,"up","-d","--build"),{cwd:l,env:re,timeoutMs:12e5});if(!ue.ok)return i("workspace",`docker compose: ${In(ue.stderr||ue.stdout)}`,"fix that, then Enter");O=void 0,N=void 0,ne=Q,Ve=!!g,Me()}else{let ue=le(o,"workspace.db");O=o.start(process.execPath,[M],{cwd:Tn(l,"apps","workspace"),env:{...re,...p?{CLAUDE_CODE_OAUTH_TOKEN:p}:{},MOA_DATABASE_URL:`sqlite:${ue}`,MOA_D1_ACCOUNT_ID:"",MOA_D1_DATABASE_ID:"",MOA_D1_API_TOKEN:"",MOA_SQLITE_FILE:ue,MOA_WORKSPACE_ROOT:le(o,"worktrees"),MOA_SELF_URL:h,MOA_PID_FILE:jr(o)},log:le(o,"workspace.log")}),N=o.processOf(O)?.started,ne=Q,Ve=!!g,Me()}if(!await ui(o,`${h}/health`,d==="compose"?120:60))return i("workspace",`did not answer on :${$}`,d==="compose"?`look at \`docker compose -p ${we} logs workspace\`, then Enter`:`look at ${le(o,"workspace.log")}, then Enter`);if(!await me.get("/v1/whoami").then(()=>!0,()=>!1))return i("workspace","it started but refuses the owner token","Enter to try again");a({label:"workspace",mark:"ok",detail:`${h}${O?` (pid ${O})`:""}`})}Ce&&await Bt(o,On,h,V);let ye=await Mr(o,h,a,d==="compose"?"postgres":"sqlite",d==="compose"?`look at \`docker compose -p ${we} logs\`, then Enter`:`look at ${le(o,"workspace.log")}, then Enter`);if(ye)return i(ye.label,ye.detail,ye.fix);let T=await ln(me,r,a,Pe);if(T)return i(T.label,T.detail,T.fix);let F=Pe;Pe=r.answers.people??[],JSON.stringify(Pe)!==JSON.stringify(F??[])&&Me();let Ye=yd(h,V,fe),Xe=ge!==void 0&&await o.listening(m);if(Xe&&ge!==void 0&&ke!==Ye){if(a({label:"console",mark:"wait",detail:"restarting \u2014 it points at another workspace"}),o.stop(ge),ge=void 0,oe=void 0,ke=void 0,Me(),!await hd(o,m,15))return i("console",`the old console still holds :${m}`,"stop it, then Enter");Xe=!1}if(Xe)a({label:"console",mark:"ok",detail:`${A} \u2014 already running`});else{if(await o.listening(m))return i("console",`something else is on :${m}`,"stop it, or run `moa setup --console-port <port>`");if(a({label:"console",mark:"wait",detail:`starting on :${m}`}),ge=o.start(process.execPath,[Tn(l,"apps","console","node_modules","next","dist","bin","next"),"start","--port",String(m),"--hostname","127.0.0.1"],{cwd:Tn(l,"apps","console"),env:{...bd(o.env),MOA_URL:h,MOA_TOKEN:V,...fe},log:le(o,"console.log")}),oe=o.processOf(ge)?.started,ke=Ye,Me(),!await ui(o,A,60))return i("console",`did not answer on :${m}`,`look at ${le(o,"console.log")}, then Enter`);a({label:"console",mark:"ok",detail:`${A} (pid ${ge})${I?" \u2014 Sign in with GitHub":""}`})}let ct=await Dt(me,f,d==="compose"?"in the container":"on this machine",re=>d==="compose"?"Esc back to Agent logins and log it in again, then Enter":`is ${re} logged in on this machine? Run \`${re}\` once and log in, then Enter`,a);if("label"in ct)return i(ct.label,ct.detail,ct.fix);let Et=ct.runs[u],ie=await dn(me,a);if("label"in ie)return i(ie.label,ie.detail,ie.fix);let Yt=ie.memory;return ie.live!==void 0&&(Ve=ie.live),a({label:"Console",mark:"ok",detail:A}),a({label:"Workspace",mark:"ok",detail:h}),a({label:"Next",mark:"skip",detail:`moa whoami \xB7 moa agent list \xB7 moa run ${Rn(u)} "\u2026"`}),{ok:!0,deployed:{runner:d,workspaceUrl:h,consoleUrl:A,...O?{workspacePid:O,...N?{workspaceStarted:N}:{}}:{},...ne?{workspaceFor:ne}:{},...ge?{consolePid:ge,...oe?{consoleStarted:oe}:{},...ke?{consoleFor:ke}:{}}:{},...Et?{proofRunId:Et}:{},memory:Yt,people:Pe,...Ve?{memoryKept:Ve}:{},at:new Date().toISOString()}}}async function Mr(e,t,n,o,r){let s=await e.fetch(`${t}/health`,{signal:AbortSignal.timeout(5e3)}).then(c=>c.json()).catch(c=>({ok:!1,error:String(c)})),a=s.database??o;if(s.ok!==!0)return{label:"database",detail:`${a} does not answer: ${In(String(s.error??"no answer"),1)}`,fix:r};n({label:"database",mark:"ok",detail:`${a} \u2014 migrated, and it answers`})}async function ln(e,t,n,o=[]){let r=t.answers.people??[],s=r.filter(i=>!o.some(l=>$d(l,i)));for(let i of s){n({label:"people",mark:"wait",detail:`adding ${i.login}`});try{await e.put(`/v1/access/people/${encodeURIComponent(i.login)}`,{role:i.role,dailyCapUsd:i.dailyCapUsd})}catch(l){let d=l instanceof Error?l.message:String(l);return{label:"people",detail:`${i.login}: ${d}`,fix:l instanceof ae&&l.status===404?"this workspace has no access list \u2014 `git pull`, then `pnpm run build`, then Enter":"Enter to try again"}}}let a=(t.answers.removed??[]).filter(i=>!r.some(l=>l.login.toLowerCase()===i));for(let i of a){n({label:"people",mark:"wait",detail:`removing ${i}`});try{await e.del(`/v1/access/people/${encodeURIComponent(i)}`)}catch(l){if(l instanceof ae&&l.status===404)continue;let d=l instanceof Error?l.message:String(l);return{label:"people",detail:`removing ${i}: ${d}`,fix:"Enter to try again"}}}let c=r.length-s.length;(r.length>0||a.length>0)&&n({label:"people",mark:"ok",detail:[...s.map(i=>`${i.login} (${i.role})`),...a.map(i=>`${i} removed`),...c>0?[`${c} as before \u2014 left as the Access page has them`]:[]].join(", ")})}async function Dt(e,t,n,o,r){let s={};for(let a of t){let c=`proof: ${a} run`,i=Rn(a);r({label:c,mark:"wait",detail:`${a} is answering ${n}`});try{if(!await e.post("/v1/agents",{name:i,cli:a,role:"Proves moa setup worked. Answers in one word."}).then(()=>!0,p=>{if(!(p instanceof ae&&p.status===409))throw p;return!1})){let p=await e.get(`/v1/agents/${i}`);if(p.cli!==a)return{label:c,detail:`agent ${i} already exists and runs ${p.cli??"another CLI"}`,fix:`run \`moa agent rm ${i}\`, then Enter`}}let d=await e.post(`/v1/agents/${i}/runs`,{prompt:En}),u=await Nt(e,d.id,300),f=u.result;if(u.state!=="done"||!f||!("runId"in f)||f.isError){let p=u.error??(f&&"result"in f?f.result:"no answer");return{label:c,detail:In(String(p),2),fix:o(a)}}s[a]=f.runId,r({label:c,mark:"ok",detail:`${a} answered "${In(f.result,1).slice(0,40)}" ${n} \u2014 moa logs ${f.runId}`})}catch(l){return{label:c,detail:l instanceof Error?l.message:String(l),fix:"Enter to try again"}}}return{runs:s}}async function dn(e,t){try{let n=await e.get("/v1/memory"),o=(n.types??[]).reduce((c,i)=>c+(i.items?.length??0),0),r=typeof n.live=="boolean"?n.live:void 0,a=`${o} memor${o===1?"y":"ies"}, ${r===void 0?"kept where this older workspace build cannot say":r?"kept in LocusGraph":"in the workspace process"}`;return t({label:"proof: memory read",mark:"ok",detail:a}),r===void 0?{memory:a}:{memory:a,live:r}}catch(n){return{label:"proof: memory read",detail:n instanceof Error?n.message:String(n),fix:"Enter to try again"}}}var On,Rn,In,pi,kd,yd,bd,$d,Wt=Te(()=>{"use strict";De();yn();qe();it();It();Ft();Pn();Je();io();On="local",Rn=e=>`setup-proof-${e}`,In=(e,t=3)=>e.trim().split(`
141
- `).slice(-t).join(" \xB7 ").slice(0,300);pi=e=>gd("sha256").update(e).digest("hex").slice(0,12),kd=e=>pi(JSON.stringify([e.runner,e.workspaceUrl,e.tenant,e.repo??"",e.token,e.locusgraph??"",e.owner??"",e.githubClientId??"",e.graph??"",e.server??"",e.claude??""])),yd=(e,t,n)=>`${e} ${pi(JSON.stringify([t,n.AUTH_GITHUB_ID??"",n.AUTH_GITHUB_SECRET??"",n.AUTH_SECRET??""]))}`,bd=e=>Object.fromEntries(Object.entries(e).filter(([t])=>!t.startsWith("AUTH_")));$d=(e,t)=>e.login.toLowerCase()===t.login.toLowerCase()&&e.role===t.role&&e.dailyCapUsd===t.dailyCapUsd});var Kr={};mc(Kr,{artifactRoot:()=>Dn,bundledWorker:()=>Gr,crashOf:()=>wi,cursorPrompt:()=>No,deployImage:()=>Nr,imageChecks:()=>Un,imageCompose:()=>nt,imageComposePath:()=>qt,imageConfig:()=>hi,loggedInImage:()=>zt,loginInImage:()=>Mn,logsInInContainer:()=>co,releaseImage:()=>Ae,waiting:()=>Nn,workerFromImage:()=>Hr});import{chmod as vd,mkdir as fi,readFile as Sd,writeFile as xd}from"node:fs/promises";import{dirname as mi,join as gi}from"node:path";import{fileURLToPath as Ad}from"node:url";async function Hr(e){let t=await e.exec("docker",["create","--platform","linux/amd64",Ae()]);if(!t.ok)return{ok:!1,why:de(t.stderr)||"docker create failed"};let n=de(t.stdout),o=le(e,gi("cloudflare","worker.js"));await fi(mi(o),{recursive:!0});let r=await e.exec("docker",["cp",`${n}:/repo/apps/workspace/dist/worker.js`,o]);return await e.exec("docker",["rm",n]),r.ok?{ok:!0,path:o}:{ok:!1,why:de(r.stderr)||"the image holds no worker.js"}}async function Un(e){let t=await e.sys.exec("docker",["info","--format","{{.ServerVersion}}"]);if(!t.ok)return[{label:"docker",mark:"fail",detail:`${t.missing?"not installed":"not running"} \u2014 it pulls the published image`,fix:"Start Docker, then check again."}];let n=await e.sys.exec("docker",["pull",...e.state.target==="local"?[]:["--platform","linux/amd64"],Ae()],{timeoutMs:6e5}),o=e.state.target==="cloudflare"?"pulls the published image, then pushes it to your Cloudflare registry":"pulls the published image; nothing is built here";return[{label:"docker",mark:"ok",detail:`${t.stdout.trim().split(`
142
- `)[0]} \u2014 ${o}`},{label:"image",mark:n.ok?"ok":"fail",detail:Ae(),...n.ok?{}:{fix:"Sign in to ghcr.io with your account's package pull token, then check again."}}]}function hi(e){let t=`fnmoa-${e.install}`;return{services:{workspace:{image:e.image,restart:"unless-stopped",ports:[`127.0.0.1:${e.workspacePort}:8787`,`127.0.0.1:${e.consolePort}:3100`],volumes:[`${t}:/data`,`${t}-home:/home/moa`],environment:{...e.env,MOA_PORT:"8787",MOA_SELF_URL:"http://127.0.0.1:8787",MOA_WORKSPACE_ROOT:"/data/worktrees",MOA_LICENCE_FILE:"/data/licence.json",MOA_DATABASE_URL:e.postgres?"postgres://moa@postgres:5432/moa":"sqlite:/data/workspace.db",MOA_SQLITE_FILE:"/data/workspace.db",MOA_LOCAL_CONTAINER:"1"},...e.postgres?{depends_on:{postgres:{condition:"service_healthy"}}}:{}},...e.postgres?{postgres:{image:"postgres:17-alpine",restart:"unless-stopped",environment:{POSTGRES_USER:"moa",POSTGRES_DB:"moa",POSTGRES_HOST_AUTH_METHOD:"trust"},volumes:[`${t}-pg:/var/lib/postgresql/data`],healthcheck:{test:["CMD-SHELL","pg_isready -U moa"],interval:"5s",timeout:"5s",retries:20}}}:{}},volumes:{[t]:{name:t},[`${t}-home`]:{name:`${t}-home`},...e.postgres?{[`${t}-pg`]:{name:`${t}-pg`}}:{}}}}function No(e){let t=/https:\/\/cursor\.com\/\S+/.exec(e);return t?{url:t[0]}:{}}async function zt(e,t){if(!e.exists(qt(e)))return!1;let n=Fr[t],o=await e.exec("docker",nt(e,"exec","-T","workspace",...n.status),{timeoutMs:6e4});return n.loggedIn(o)}function Mn(e,t,n){let o=Fr[t],r="";return e.run("docker",nt(e,"exec","-T",...o.env,"workspace",...o.login),{timeoutMs:16*6e4},s=>{r+=s,n(o.prompt(r))})}function wi(e){return e.split(`
143
- `).map(n=>n.trim()).reverse().find(n=>/^[A-Z]\w*(Error|Exception)\b.*:/.test(n))}async function Nr(e,t,n){let o=[],r=k=>{o.push(k),t([...o])},s=k=>(r({label:"image",mark:"fail",detail:k}),{ok:!1}),a=await yt(e);for(let k of a)r(k);if(a.some(k=>k.mark==="fail"))return{ok:!1};let c=await so(e.sys.env,"local");if(!c)return s("Activate the local install first.");for(let k of await Un(e))if(r(k),k.mark==="fail")return{ok:!1};let{sys:i,state:l}=e,d={};if(l.deployed?.runner==="image"){let k=JSON.parse(await Sd(qt(i),"utf8"));d=Object.fromEntries(Object.entries(k.services.workspace.environment).map(([Q,O])=>[Q,O.replaceAll("$$","$")]))}let u=`http://127.0.0.1:${Jt(l)}`,f=`http://localhost:${Ut(l)}`,{token:p}=await Kt(i,"local",u),g=l.answers.githubApp,b=g?He(i,g):void 0;if(g&&!b)return s("The GitHub App client secret is missing.");let $=await i.exec("gh",["auth","token"]),m={...d,...await Ht(e),MOA_TOKENS:`${p}:${l.answers.tenant??Ie(l.answers.owner)}`,...l.answers.owner?{MOA_OWNER_LOGIN:l.answers.owner}:{},...l.answers.repo?{MOA_REPO:l.answers.repo}:{},...$.ok?{GH_TOKEN:$.stdout.trim()}:{}},h=tt(e)?.token;h&&(m.CLAUDE_CODE_OAUTH_TOKEN=h);for(let k of pe){let Q=$e(e,k);Q&&(m[Se[k]]=Q)}let A=l.answers.loggedIn;if(A)for(let k of pe){if(A.includes(k)||$e(e,k))continue;let Q=[Se[k],...k==="claude"&&!h?["CLAUDE_CODE_OAUTH_TOKEN"]:[]];for(let O of Q)delete m[O]}let E=xe(e);E&&Object.assign(m,{LOCUSGRAPH_AGENT_SECRET:E.secret,LOCUSGRAPH_GRAPH_ID:E.graph,LOCUSGRAPH_SERVER_URL:E.server}),g&&b&&Object.assign(m,{MOA_GITHUB_CLIENT_ID:g.clientId,AUTH_GITHUB_ID:g.clientId,AUTH_GITHUB_SECRET:b.clientSecret,AUTH_SECRET:b.authSecret,AUTH_URL:f});let I=qt(i),W=k=>typeof k=="string"?k.replaceAll("$",()=>"$$"):Array.isArray(k)?k.map(W):k&&typeof k=="object"?Object.fromEntries(Object.entries(k).map(([Q,O])=>[Q,W(O)])):k,fe=hi({image:Ae(),install:c.install,workspacePort:Jt(l),consolePort:Ut(l),postgres:l.answers.runner==="compose",env:m});if(await fi(mi(I),{recursive:!0,mode:448}),await xd(I,JSON.stringify(W(fe)),{mode:384}),await vd(I,384),!(await i.exec("docker",nt(i,"up","-d","--wait"),{timeoutMs:6e5})).ok)return s("Docker Compose did not start the image. Run `moa setup logs` for details.");let z={runner:"image",workspaceUrl:u,consoleUrl:f,image:Ae(),at:new Date().toISOString()};n(z);let R=U({url:u,token:p},i.fetch),J=!1;for(let k=0;k<60;k++)try{await R.get("/v1/whoami"),J=!0;break}catch{await i.sleep(1e3)}if(!J){let k=await i.exec("docker",nt(i,"logs","--tail","40","workspace"),{timeoutMs:3e4}),Q=wi(`${k.stdout}
144
- ${k.stderr}`);return{...s(Q?`The workspace did not become ready: ${Q}. \`moa setup logs\` has the rest.`:"The workspace did not become ready. `moa setup logs` says why."),deployed:z}}await Bt(i,"local",u,p);let V=await ln(R,l,r,l.deployed?.people);if(V)return{...s(V.detail),deployed:z};let Ce=l.answers.agentCli??"claude",X=[...new Set([Ce,...l.answers.loggedIn??[]])];for(let k of X){if(!co(k)||$e(e,k)||await zt(i,k))continue;r({label:k,mark:"wait",detail:"starting its login inside the container\u2026"});let O=await Mn(i,k,N=>{let ne=Nn(N);ne&&r({label:k,mark:"wait",detail:ne})}).done;if(!O.ok||!await zt(i,k))return r({label:k,mark:"fail",detail:`the login did not finish: ${de(O.stderr)||"no answer"}`,fix:"Enter to log in again \u2014 or Esc back to Agent logins and \u2191 \u2193 to choose another agent"}),{ok:!1,deployed:z};r({label:k,mark:"ok",detail:"logged in inside the container \u2014 kept on its home volume"})}let Fe=await Dt(R,X,"in the image",k=>k==="claude"?"Esc back to Agent logins: t to connect your Claude subscription, or export ANTHROPIC_API_KEY and run setup again.":`\`moa setup login ${k}\` to log it in again, or export ${Se[k]} and run setup again.`,r);if("label"in Fe)return{...s(Fe.detail),deployed:z};let me=await dn(R,r);return"label"in me?{...s(me.detail),deployed:z}:(r({label:"console",mark:"ok",detail:f}),{ok:!0,deployed:{...z,people:l.answers.people,memory:me.memory,memoryKept:me.live}})}var Ae,Dn,Gr,qt,nt,Fr,co,Nn,it=Te(()=>{"use strict";De();qe();Wt();It();Ft();Pn();Je();Ae=()=>`ghcr.io/fnlog0/fnmoa:${Gt()}`,Dn=()=>Ad(new URL(import.meta.url.endsWith("/main.js")?"../":"../../",import.meta.url)),Gr=()=>gi(Dn(),"dist/assets/worker.js"),qt=e=>le(e,"image/compose.json"),nt=(e,...t)=>["compose","--project-name","fnmoa-image","--file",qt(e),...t];Fr={codex:{status:["codex","login","status"],login:["codex","login","--device-auth"],env:[],loggedIn:e=>e.ok,prompt:rn},cursor:{status:["cursor-agent","status"],login:["cursor-agent","login"],env:["-e","NO_OPEN_BROWSER=1"],loggedIn:e=>e.ok&&!/not logged in/i.test(`${e.stdout}${e.stderr}`),prompt:No}},co=e=>e in Fr;Nn=e=>e.url?e.code?`open ${e.url} and enter ${e.code} \u2014 waiting for you to approve it`:`open ${e.url} and sign in \u2014 waiting for you to approve it`:void 0});import{join as Wr}from"node:path";async function pn(e,t,n,o=["--version"]){let r=await e.exec(t,o);return r.ok?v(t,uo(r.stdout)):_(t,"not found",n)}function Pd(e=process){return e.platform==="darwin"&&e.env.MOA_KEEP_AWAKE!=="0"?v("Sleep","held off while a pipeline runs, as `caffeinate -i` does \u2014 a closed lid still sleeps, and work it cut short is run again"):v("Sleep",e.platform==="darwin"?"not held off, MOA_KEEP_AWAKE=0 \u2014 work a sleep cuts short is run again":"not held off on this system \u2014 work a sleep cuts short is run again")}function _d(e,t=process){switch(e.target){case"local":return{lines:[v("This machine","Docker or local, nothing in the cloud"),Pd(t)]};case"cloudflare":return{lines:[v("Cloudflare","a Worker and its container on D1, on your own domain \u2014 Workers Paid plan")]};case"vercel":return{lines:[v("Vercel Sandbox","one persistent VM, fnmoa-<tenant>, resumed by name \u2014 needs the vercel CLI, signed in")]};default:return{lines:[{label:"Pick one with \u2191 \u2193 and Enter",mark:"wait"}]}}}async function ki(e,t,n,o,r,s){return await e.sys.listening(n)?o!==void 0&&Lt(e.sys,o,r,n)?v(`port ${n}`,`the ${t} the last setup started`):_(`port ${n}`,"something else is listening there",`stop it, or run \`moa setup ${s} <port>\``):v(`port ${n}`,`free for the ${t}`)}async function yi(e){return[Number(process.versions.node.split(".")[0])>=22?v("node",process.versions.node):_("node",process.versions.node,"install node 22 or newer"),...await Promise.all([pn(e,"pnpm","install pnpm: `corepack enable`"),pn(e,"git","install git"),pn(e,"gh","install the GitHub CLI: https://cli.github.com")])]}function qr(e){if(e.secrets.cloudflare)return{token:e.secrets.cloudflare,from:"pasted in this run"};let t=e.sys.env.MOA_D1_API_TOKEN?.trim();return t?{token:t,from:"MOA_D1_API_TOKEN"}:void 0}function zr(e){if(e.secrets.github)return{token:e.secrets.github,from:"pasted in this run"};let t=e.sys.env.GH_TOKEN?.trim();return t?{token:t,from:"GH_TOKEN"}:void 0}async function Td(e){let{sys:t,state:n}=e,o=await yi(t);if(Oe(e)){let{imageChecks:u}=await Promise.resolve().then(()=>(it(),Kr));o.push(...await u(e))}else{let u=await t.exec("docker",["info","--format","{{.ServerVersion}}"]);o.push(u.ok?v("docker",`${de(u.stdout)} \u2014 builds the container image from this checkout`):_("docker",u.missing?"not installed":"not running","wrangler builds the container image with Docker: start it, then r"))}let s=t.root??Dn();o.push(v(t.root?"checkout":"release",s));let a=await Ge(t,s,["--version"],{timeoutMs:3e4});if(!a.ok)return o.push(t.root?_("wrangler","not installed in this checkout",`run \`pnpm install\` in ${s}, then r`):_("wrangler",`\`npx ${fr}\` did not run: ${de(a.stderr)||"no answer"}`,"check Node and npm can reach the npm registry, then r")),{lines:o};o.push(v("wrangler",uo(a.stdout)));let c=await aa(t,s),i;c.ok?(i=c.account.id,o.push(v("account",`${c.account.name} (${c.account.id})${c.email?` as ${c.email}`:""}${c.others>0?" \u2014 CLOUDFLARE_ACCOUNT_ID picks another":""}`))):o.push(_("account",c.why,c.loggedOut?`run \`pnpm --dir ${Wr(s,"apps","workspace")} exec wrangler login\`, then r`:"fix that, then r"));let l=n.answers.domain;if(!l)o.push(_("domain","none yet \u2014 the console and workspace need a name of yours","press d and type a domain on this Cloudflare account, like example.com"));else{let u=await ia(t,l),f=Yn(l);o.push(u.zone&&u.onCloudflare?v("domain",`${f.consoleUrl} and ${f.workspaceUrl} \u2014 zone ${u.zone}`):_("domain",u.why??`${u.zone} is not served by Cloudflare's name servers`,"add the domain to this Cloudflare account (its name servers must be Cloudflare's), or d for another"))}let d=qr(e);if(!d)o.push(Jr(n)?H("D1 token","kept \u2014 the deployed Worker has it (k to replace it)"):_("D1 token","none \u2014 the container reaches D1 over Cloudflare's API with it","make an API token with Account \xB7 D1 \xB7 Edit on this account, then press k and paste it"));else if(i){let u=await ca(t,i,d.token);o.push(u.ok?v("D1 token",`${D} (${d.from}) \u2014 D1 answers to it`):_("D1 token",`${D} (${d.from}) \u2014 D1 refused it: ${u.why}`,"make one with only Account \xB7 D1 \xB7 Edit on this account, then press k to paste it"))}return o.push(H("cost",`Workers Paid, plus the container (standard-4) while it runs \u2014 up to ${_t}h after the last request`)),{lines:o,...i?{answers:{cloudflareAccount:i}}:{}}}async function Od(e){let{sys:t,state:n}=e;if(Oe(e)&&n.target==="local"){let{imageChecks:a}=await Promise.resolve().then(()=>(it(),Kr));return{lines:await a(e)}}if(n.target==="cloudflare")return Td(e);let o=await yi(t),r=n.deployed?Ln(t,n.deployed):void 0,s=await t.exec("docker",["--version"]);return o.push(s.ok?v("docker",uo(s.stdout)):H("docker","not found \u2014 only needed for Postgres with docker compose")),o.push(t.root?v("checkout",t.root):_("checkout","not inside a fnMoa checkout","run moa setup from a clone of https://github.com/fnLog0/fnmoa")),o.push(await ki(e,"workspace",Jt(n),r?.workspacePid,r?.workspaceStarted,"--workspace-port"),await ki(e,"console",Ut(n),n.deployed?.consolePid,n.deployed?.consoleStarted,"--console-port"),H("account","this machine \u2014 no account needed")),{lines:o}}async function Id(e){let{sys:t,state:n}=e,o=n.target==="cloudflare"?{...t.env}:void 0;if(o)for(let i of["GH_TOKEN","GITHUB_TOKEN"])delete o[i];let r=await t.exec("gh",["api","user","--jq",".login"],o?{env:o}:{}),s=de(r.stdout);if(!r.ok||!s)return{lines:[_("gh login",r.missing?"gh is not installed":"gh has no login on this machine","run `gh auth login`, then press r to check again")]};if(n.target==="cloudflare")return Ld(e,s);let a=[v("gh login",`${s} \u2014 on this machine the workspace uses your own login`)],c=n.answers.repo;if(!c)a.push(H("repo","none \u2014 a pipeline can name any repository later (e to set one)"));else{let i=await t.exec("gh",["repo","view",c,"--json","viewerPermission","--jq",".viewerPermission"]),l=de(i.stdout);a.push(i.ok&&["ADMIN","MAINTAIN","WRITE"].includes(l)?v("repo",`${c} \u2014 ${l.toLowerCase()}`):_("repo",i.ok?`${s} cannot push to ${c}`:`${c} is not a repository ${s} can see`,"press e to change it, or clear it to skip"))}return{lines:a,answers:{owner:s}}}async function Rd(e,t,n,o){let r=await e.exec("gh",["repo","view",t,"--json","viewerPermission","--jq",".viewerPermission"],o?{env:o}:{}),s=de(r.stdout);return r.ok&&["ADMIN","MAINTAIN","WRITE"].includes(s)?v("repo",`${t} \u2014 ${s.toLowerCase()} for ${n}`):_("repo",r.ok?`${n} cannot push to ${t}`:`${t} is not a repository ${n} can see`,"press e to change it, or clear it to skip")}async function Ld(e,t){let{sys:n,state:o}=e,r=[v("gh login",`${t} \u2014 you, the first owner`)],s=zr(e),a;if(!s)r.push(Jr(o)?H("token","kept \u2014 the deployed Worker has it (k to replace it)"):_("token","none \u2014 the container works on GitHub with a token of its own","make a fine-grained token (contents, pull requests, issues: read/write; checks, actions: read) \u2014 a bot account's, preferably \u2014 then press k"));else{let c={...n.env,GH_TOKEN:s.token};for(let d of["GITHUB_TOKEN"])delete c[d];let i=await n.exec("gh",["api","user","--jq",".login"],{env:c});a=de(i.stdout)||void 0,r.push(i.ok&&a?v("token",`${D} (${s.from}) \u2014 GitHub sees ${a}`):_("token",`${D} (${s.from}) \u2014 GitHub refused it`,"press k to paste another"));let l=o.answers.repo;l&&a&&r.push(await Rd(n,l,a,c))}return o.answers.repo||r.push(H("repo","none \u2014 a pipeline can name any repository later (e to set one)")),{lines:r,answers:{owner:t}}}function tt(e){if(e.secrets.claude)return{token:e.secrets.claude,from:"pasted in this run"};let t=e.sys.env.CLAUDE_CODE_OAUTH_TOKEN?.trim();return t?{token:t,from:"your environment"}:void 0}async function Ud(e){let{sys:t,state:n}=e;if(Oe(e)&&n.target==="local")return Md(e);if(n.target==="cloudflare")return jd(e);let o=Dd(n),[r,s]=await Promise.all([t.exec("claude",["--version"]),t.exec("codex",["--version"])]),a=tt(e),c={claude:r.ok,codex:s.ok,cursor:!1},i=[o?v("agents run","in the container \u2014 only what is carried in here reaches it"):H("agents run","on this machine, on your logins \u2014 Postgres on Memory & database would move them into a container")],l,d=o&&t.root?await Wa(t,t.root):void 0;if(d&&!d.ok)c.codex=!1,l=_("codex",`the image did not build: ${d.why}`,"start Docker, or fix the build, then press r");else if(o&&t.root){let g=await qa(t,t.root);c.codex=g.loggedIn,l=g.loggedIn?v("codex",`${g.says} \u2014 its own session in the container (l to log in again)`):g.broken?_("codex",`the container did not run: ${g.broken}`,"start Docker, then press r"):H("codex","not logged in inside the container \u2014 l to log in with a code")}else{let g=s.ok?await t.exec("codex",["login","status"]):void 0;c.codex=s.ok&&g?.ok===!0,l=s.ok?g?.ok?v("codex",`${uo(s.stdout)} \u2014 ${de(g.stdout)||"logged in"}`):H("codex","not logged in \u2014 run `codex login`, then press r"):H("codex","not found")}let u;if(a){let g=await _r(t,a.token,o&&t.root?{container:t.root}:"here");c.claude=g.ok,u=g.ok?v("claude",`token ${D} (${a.from}) \u2014 "reply ok" ${o?"in the container":"on it alone"}`):_("claude",`the token did not answer: ${g.why}`,"press t to make a new one with `claude setup-token`, or e to paste it again")}else o?(c.claude=!1,u=H("claude",r.ok?"no token carried in \u2014 t to make one with `claude setup-token`":"no token \u2014 install claude here to make one: npm i -g @anthropic-ai/claude-code")):u=r.ok?v("claude",`${uo(r.stdout)} \u2014 your existing login (t to carry a token instead)`):H("claude","not found");i.push(u,l);let f=e.state.answers.agentCli??(c.claude?"claude":c.codex?"codex":void 0);f?i.push(c[f]?v("proof run",`uses ${f} (\u2191 \u2193 to change)`):_("proof run",`${f} is not ready ${o?"in the container":"here"}`,f==="claude"?o?"press t to carry a token in \u2014 or \u2191 \u2193 to choose codex":"install claude and log in \u2014 or \u2191 \u2193 to choose codex":o?"press l to log codex in \u2014 or \u2191 \u2193 to choose claude":"install codex and run `codex login` \u2014 or \u2191 \u2193 to choose claude")):i.push(_("agent",o?"neither claude nor codex is logged in inside the container":"neither claude nor codex is ready",o?"press t to carry a claude token in, or l to log codex in":"install one and log in, then press r")),i.push(H("note","owner only: your subscriptions; teammates use them, never see them (moa setup login)"));let p=["claude","codex"].filter(g=>c[g]);return{lines:i,answers:{...f?{agentCli:f}:{},loggedIn:p,...po(i)?{loginsFor:o?"compose":"node"}:{}}}}async function Md(e){let{sys:t,state:n}=e,o=n.deployed?.runner==="image",r=tt(e),s=new Set,a=[v("agents run","in the image's container \u2014 only what is carried in reaches it")];r?(s.add("claude"),a.push(v("claude",`token ${D} (${r.from}) \u2014 Deploy proves it in the image`))):$e(e,"claude")?(s.add("claude"),a.push(v("claude",`ANTHROPIC_API_KEY ${D} (${lo(e,"claude")})`))):o&&n.answers.loggedIn?.includes("claude")?(s.add("claude"),a.push(H("claude","kept \u2014 the running container has its login (t to replace it)"))):a.push(H("claude","not connected \u2014 t for your Claude subscription (`claude setup-token`), or export ANTHROPIC_API_KEY"));let c={codex:"ChatGPT",cursor:"Cursor"};for(let l of["codex","cursor"])$e(e,l)?(s.add(l),a.push(v(l,`${Se[l]} ${D} (${lo(e,l)})`))):o&&await zt(t,l)?(s.add(l),a.push(v(l,"logged in inside the container \u2014 kept on its home volume"))):a.push(H(l,`logs in at Deploy when chosen \u2014 or later, \`moa setup login ${l}\` with your ${c[l]} account`));let i=n.answers.agentCli??(s.has("claude")?"claude":s.values().next().value??"codex");return a.push(i!=="claude"||s.has("claude")?v("proof run",`uses ${i} (\u2191 \u2193 to change)`):_("proof run","claude has no login for the image","press t to connect your Claude subscription \u2014 or \u2191 \u2193 to choose codex or cursor")),{lines:a,answers:{agentCli:i,loggedIn:pe.filter(l=>s.has(l))}}}async function Nd(e){let t=e.state.deployed;if(t?.runner!=="cloudflare")return;let n=await ve(e.sys.env),o=Object.values(n.profiles).find(r=>r.url===t.workspaceUrl);if(o)try{let r=await e.sys.fetch(`${t.workspaceUrl}/_moa/codex`,{headers:{authorization:`Bearer ${o.token}`},signal:AbortSignal.timeout(12e4)});return r.ok?(await r.json()).loggedIn===!0:void 0}catch{return}}async function jd(e){let{sys:t,state:n}=e,o=tt(e),r=[v("agents run","in the Cloudflare container \u2014 only what is carried in reaches it")],s={claude:!1,codex:!0,cursor:!1};if(o){let d=await _r(t,o.token,"here");s.claude=d.ok,r.push(d.ok?v("claude",`token ${D} (${o.from}) \u2014 "reply ok" on it alone; a Worker secret`):_("claude",`the token did not answer: ${d.why}`,"press c to make a new one with `claude setup-token`, or k for an API key"))}else $e(e,"claude")?(s.claude=!0,r.push(v("claude",`ANTHROPIC_API_KEY ${D} (${lo(e,"claude")}) \u2014 a Worker secret`))):Jr(n)&&n.answers.loggedIn?.includes("claude")?(s.claude=!0,r.push(H("claude","kept \u2014 the deployed Worker has the token (c to replace it)"))):r.push(H("claude","not connected \u2014 c for your Claude subscription, or k for an API key"));let a=$e(e,"codex"),c=a?void 0:await Nd(e);r.push(a?v("codex",`OPENAI_API_KEY ${D} (${lo(e,"codex")}) \u2014 a Worker secret`):c===!0?v("codex","logged in inside the container \u2014 its login is kept in R2 across restarts"):H("codex",c===!1?"not logged in inside the container \u2014 Deploy shows a link and a code (or k for an API key)":"logs in inside the container at Deploy \u2014 a link and a code (or k for an API key)")),s.cursor=$e(e,"cursor")!==void 0,r.push(s.cursor?v("cursor",`CURSOR_API_KEY ${D} (${lo(e,"cursor")}) \u2014 a Worker secret`):H("cursor","not connected \u2014 on Cloudflare cursor runs on an API key: k"));let i=n.answers.agentCli??(s.claude?"claude":"codex");r.push(s[i]?v("proof run",`uses ${i} (\u2191 \u2193 to change)`):_("proof run",`${i} is not connected`,"press c to connect it or k for its API key \u2014 or \u2191 \u2193 to another agent"),H("note","owner only: your subscriptions; teammates use them, never see them (moa setup login)"));let l=pe.filter(d=>s[d]&&(d!=="codex"||a!==void 0||c===!0));return{lines:r,answers:{agentCli:i,loggedIn:l,...po(r)?{loginsFor:"cloudflare"}:{}}}}function bi(e){let{sys:t,state:n,secrets:o}=e,r=Gd(e),s=t.env.LOCUSGRAPH_AGENT_SECRET,a=s?.trim(),c=o.locusgraph||(s!==void 0?a:r.LOCUSGRAPH_AGENT_SECRET?.trim()),i=o.locusgraph?"pasted in this run":a?"your environment":"apps/workspace/.env";return{...c?{secret:c,from:i}:{},graph:n.answers.locusgraphGraph||t.env.LOCUSGRAPH_GRAPH_ID?.trim()||r.LOCUSGRAPH_GRAPH_ID?.trim()||void 0,server:t.env.LOCUSGRAPH_SERVER_URL?.trim()||r.LOCUSGRAPH_SERVER_URL||Va}}function xe(e){let{secret:t,from:n,graph:o,server:r}=bi(e);return t&&n&&o?{secret:t,from:n,graph:o,server:r}:void 0}function Vr(e){let{secret:t,from:n,graph:o}=bi(e);if(t&&!o){let r=e.state.answers.tenant??Ie(e.state.answers.owner);return _("LocusGraph",`secret ${D} (${n}), but no graph ID`,e.state.deployed?.memoryKept?`press g to type the graph ID this secret belongs to \u2014 the last deploy used fnmoa-${r}`:"press g to type the graph ID this secret belongs to")}if(!t&&e.state.answers.locusgraphGraph)return _("LocusGraph",`graph ${e.state.answers.locusgraphGraph}, but no secret`,"press e to paste its agent secret \u2014 or g, then Enter on nothing, to go on without LocusGraph")}async function Hd(e){let{sys:t,state:n}=e,o=xe(e),r=[],s=Vr(e);if(s)r.push(s);else if(!o)r.push(un(e)?_("LocusGraph","the last deploy kept memory in LocusGraph, and this run has no secret for it","press e to paste it again \u2014 or e, then Enter on nothing, to let memory stay in the workspace process"):e.secrets.noLocusgraph&&n.deployed?.memoryKept?H("LocusGraph","no secret \u2014 memory will not be kept in LocusGraph; it stays in the workspace process"):H("LocusGraph","not connected \u2014 memory stays in the workspace process (g for the graph ID, e for its secret)"));else{let i=n.answers.tenant??Ie(n.answers.owner),l=await Cn(t,o,i),d=`secret ${D} (${o.from}), graph ${o.graph}`;r.push(l.read.ok&&l.write.ok?v("LocusGraph",`${d} \u2014 one graph read, one event written`):_("LocusGraph",`${d} \u2014 ${l.read.ok?`the write failed: ${l.write.why}`:`the read failed: ${l.read.why}`}`,"e to paste the secret again, or g to check the graph ID \u2014 then r"))}if(n.target==="cloudflare")return r.push(v("database",`D1 \u2014 ${ht} on your account, made at deploy; the container reaches it over HTTP`)),{lines:r,answers:{runner:"cloudflare"}};let a=n.answers.runner??"node";if(a==="node")return r.push(v("database",`SQLite, ${le(t,"workspace.db")} \u2014 migrated at deploy (\u2191 \u2193 for Postgres)`)),{lines:r,answers:{runner:a}};let c=await t.exec("docker",["info","--format","{{.ServerVersion}}"]);return r.push(c.ok?v("database","Postgres, with docker compose \u2014 migrated at deploy (\u2191 \u2193 for SQLite)"):_("database",c.missing?"docker is not installed":"docker is not running","start Docker, or \u2191 \u2193 to choose SQLite")),r.push(H("agent logins","in the container \u2014 Agent logins, next, carries them in and proves them")),{lines:r,answers:{runner:a}}}function He(e,t){try{let n=JSON.parse(e.read(Go(e,t))??"");if(n.clientSecret&&n.authSecret)return{clientSecret:n.clientSecret,authSecret:n.authSecret}}catch{}}function Yr(e){let{state:t,sys:n}=e,o=t.answers.owner,r=t.answers.tenant??Ie(o),s=t.answers.githubApp,a=[];s?t.target!=="vercel"&&(s.consoleUrl??Br(t))!==jo(t)?a.push(_("GitHub App",`${s.slug} signs people in at ${s.consoleUrl??Br(t)}, not ${jo(t)}`,"press g to create one for this console")):a.push(He(n,s)?v("GitHub App",`${s.slug} (id ${s.id}) \u2014 client secret ${D} kept beside setup`):_("GitHub App",`the client secret for ${s.slug} is not on this machine`,"press g to create a new app \u2014 GitHub shows a secret only once"),s.deviceFlow?v("device flow","on \u2014 teammates run `moa login <url> --github`"):{label:"device flow",mark:"wait",detail:`GitHub cannot switch it on for us: tick "Enable Device Flow" on ${s.settingsUrl}, Save, then press d`}):a.push(t.target==="local"?H("GitHub App","none \u2014 the console stays on localhost, never exposed (g to create one anyway)"):_("GitHub App","none yet \u2014 teammates sign in with it","press g: GitHub opens with the app filled in, and you click Create")),a.push(o?v("owner",`${o} (you)`):_("owner","no GitHub login yet","Esc back to GitHub"),v("tenant",`${r} (e to change)`),v("owner token",`${D} \u2014 made at deploy, kept in ~/.moa/config.json`));let c=t.answers.people??[];c.length===0&&a.push(H("people","only you \u2014 a to add a teammate"));for(let i of c)a.push(v(i.login,`${Fd(i.role)} \xB7 cap $${i.dailyCapUsd}/day \u2014 added at deploy`));return{lines:a,answers:{tenant:r}}}function Ln(e,t){if(t.runner!=="node")return t;let n=t.workspacePid;if(n!==void 0&&Lt(e,n,t.workspaceStarted,St(t.workspaceUrl)))return t;let[o="",r=""]=(e.read(jr(e))??"").split(`
145
- `),s=Number(o.trim()),a=r.trim();if(!Number.isSafeInteger(s)||s<=1||a===""||e.processOf(s)?.started!==a)return t;let c=St(t.workspaceUrl);if(c===void 0)return t;let i=e.portsOf(s);return i!==void 0&&!i.includes(c)?t:{...t,workspacePid:s,workspaceStarted:a}}var $e,lo,Oe,Ed,Cd,Jt,Ut,Br,jo,Ie,po,v,_,H,de,uo,Jr,Dd,Gd,un,Go,Fd,le,jr,Ho,qe=Te(()=>{"use strict";Ze();Zn();it();Ft();Je();io();$e=(e,t)=>e.secrets.keys?.[t]?.trim()||e.sys.env[Se[t]]?.trim()||void 0,lo=(e,t)=>e.secrets.keys?.[t]?.trim()?"typed in this run":"your environment",Oe=({sys:e,state:t})=>!e.root||xn(t)==="image",Ed=8787,Cd=3100,Jt=e=>e.answers.workspacePort??Ed,Ut=e=>e.answers.consolePort??Cd,Br=e=>`http://localhost:${Ut(e)}`,jo=e=>e.target==="vercel"&&e.answers.sandbox?e.answers.sandbox.consoleUrl:e.target==="cloudflare"&&e.answers.domain?Yn(e.answers.domain).consoleUrl:Br(e),Ie=e=>(e??"").toLowerCase().replace(/[^a-z0-9-]+/g,"-").replace(/^-+|-+$/g,"")||"local",po=e=>e.length>0&&e.every(t=>t.mark==="ok"||t.mark==="skip"),v=(e,t)=>({label:e,mark:"ok",...t?{detail:t}:{}}),_=(e,t,n)=>({label:e,mark:"fail",detail:t,fix:n}),H=(e,t)=>({label:e,mark:"skip",detail:t}),de=e=>e.trim().split(`
146
- `)[0]?.trim()??"",uo=e=>de(e).match(/\d+(\.\d+)+/)?.[0]??de(e);Jr=e=>e.deployed?.runner==="cloudflare";Dd=e=>e.answers.runner==="compose";Gd=e=>e.sys.root?Ya(e.sys.read(Wr(e.sys.root,"apps","workspace",".env"))):{};un=e=>e.state.deployed?.memoryKept===!0&&!e.secrets.noLocusgraph&&xe(e)===void 0;Go=(e,t)=>le(e,Ao(t));Fd=e=>`${e[0]?.toUpperCase()??""}${e.slice(1)}`;le=(e,t)=>Wr(pt(e.env),"..","local",t),jr=e=>le(e,"workspace.pid");Ho={where:e=>_d(e.state,{platform:process.platform,env:e.sys.env}),checks:Od,github:Id,logins:Ud,memory:Hd,access:Yr}});import{readFileSync as kp,realpathSync as yp}from"node:fs";import{fileURLToPath as bp}from"node:url";function hs(e){let t=[],n=new Map;for(let o=0;o<e.length;o++){let r=e[o];if(!r.startsWith("-")){t.push(r);continue}if(r==="--"){t.push(...e.slice(o+1));break}let s=r.indexOf("=");if(s!==-1){n.set(r.slice(0,s).replace(/^--?/,""),r.slice(s+1));continue}let a=r.replace(/^--?/,""),c=e[o+1];c!==void 0&&!c.startsWith("-")?(n.set(a,c),o+=1):n.set(a,!0)}return{positional:t,flags:n}}var P=(e,t)=>{let n=e.flags.get(t);return typeof n=="string"?n:void 0},C=(e,t)=>e.flags.has(t);function ce(e,t){let n=P(e,t);if(n===void 0)return;let o=Number(n);if(!Number.isFinite(o))throw new x(`--${t} must be a number`);return o}var x=class extends Error{constructor(t){super(t),this.name="Misuse"}};De();Ze();De();yn();var y={ok:0,failed:1,halted:2,misuse:3};function G(e,t=process.stdout,n=process.stderr){return{line(o){e||t.write(`${o}
136
+ `,Ne=(e,t,n={},o)=>e.exec("sh",["-c",t],{env:n,...o?{timeoutMs:o}:{}});St=(e,t=2)=>e.trim().split(`
137
+ `).slice(-t).join(" \xB7 ").slice(0,300);Rn=async(e,t)=>{let n=await Ne(e,`tail -n 5 "${$t}/logs/${t}.log" 2> /dev/null`);return St(n.stdout,3)},Do=async e=>{let t=await Ne(e,`cat "${$t}/image" 2> /dev/null`);return t.ok&&t.stdout.trim()||void 0},di=(e,t,n,o)=>Ne(e,ad,{MOA_SOURCE:t,MOA_REVISION:n,...o?{GH_TOKEN:o}:{}},18e5),Tr=e=>(e instanceof Error?e.message:String(e)).split(`
138
+ `)[0]?.slice(0,300)??"",ni=e=>new sd({write(t,n,o){e(String(t)),o()}});ri=e=>e.response?.status===404||/not.?found|404/i.test(Tr(e))});import{execFile as dd,execFileSync as pi,spawn as fi}from"node:child_process";import{existsSync as Rr,mkdirSync as ud,openSync as pd,readFileSync as fd}from"node:fs";import{connect as md}from"node:net";import{dirname as Lr,join as Dr,resolve as gd}from"node:path";import{fileURLToPath as hd}from"node:url";function Ut(e,t,n,o){let r=e.processOf(t);return r?n!==void 0?r.started===n:e.root!==void 0&&r.command.includes(e.root)?!0:r.command.startsWith("next-server")&&o!==void 0&&e.portsOf(t)?.includes(o)===!0:!1}function xt(e){try{let t=Number(new URL(e).port);return Number.isInteger(t)&&t>0?t:void 0}catch{return}}function bd(e=process.cwd()){let t=Lr(hd(import.meta.url));for(let n of[e,t]){let o=gd(n);for(;;){if(yd(o))return o;let r=Lr(o);if(r===o)break;o=r}}}function un(e=process.env){let t={env:e,root:bd(),exec:(n,o,r={})=>new Promise(s=>{dd(n,o,{cwd:r.cwd,env:r.env??e,timeout:r.timeoutMs??15e3,maxBuffer:16777216},(a,c,i)=>{let l=a?.code;s({ok:a===null,stdout:String(c),stderr:String(i),...l==="ENOENT"?{missing:!0}:{}})})}),run:(n,o,r,s)=>{let a="",c="",i=fi(n,o,{cwd:r.cwd,env:r.env??e,stdio:["ignore","pipe","pipe"]}),l=setTimeout(()=>i.kill("SIGTERM"),r.timeoutMs??9e5);return i.stdout.on("data",u=>{a+=String(u),s(String(u))}),i.stderr.on("data",u=>{c+=String(u),s(String(u))}),{done:new Promise(u=>{i.once("error",f=>{clearTimeout(l),u({ok:!1,stdout:a,stderr:c||f.message,...f.code==="ENOENT"?{missing:!0}:{}})}),i.once("close",f=>{clearTimeout(l),u({ok:f===0,stdout:a,stderr:c})})}),cancel:()=>i.kill("SIGTERM")}},exists:Rr,read:n=>{try{return fd(n,"utf8")}catch{return}},listening:n=>new Promise(o=>{let r=md({host:"127.0.0.1",port:n}),s=a=>{r.destroy(),o(a)};r.once("connect",()=>s(!0)),r.once("error",()=>s(!1)),r.setTimeout(1e3,()=>s(!1))}),alive:n=>{try{return process.kill(n,0),!0}catch(o){return o.code==="EPERM"}},processOf:n=>{try{let o=pi("ps",["-o","lstart=,command=","-p",String(n)],{env:{...e,LC_ALL:"C",TZ:"UTC"},encoding:"utf8",timeout:5e3,stdio:["ignore","pipe","ignore"]}),r=wd.exec(o.trim().split(`
139
+ `)[0]??"");return r?.[1]&&r[2]!==void 0?{started:r[1],command:r[2]}:void 0}catch{return}},portsOf:n=>{try{let r=pi("lsof",["-nP","-a","-p",String(n),"-iTCP","-sTCP:LISTEN","-Fn"],{env:e,encoding:"utf8",timeout:5e3,stdio:["ignore","pipe","ignore"]}).split(`
140
+ `).map(s=>kd.exec(s)?.[1]).filter(s=>s!==void 0).map(Number);return[...new Set(r)]}catch(o){return o.status===1?[]:void 0}},start:(n,o,r)=>{ud(Lr(r.log),{recursive:!0});let s=pd(r.log,"a"),a=fi(n,o,{cwd:r.cwd,env:r.env,detached:!0,stdio:["ignore",s,s]});if(a.unref(),a.pid===void 0)throw new Error(`could not start ${n}`);return a.pid},stop:(n,o)=>{for(let r of[-n,n])try{if(process.kill(r,o?"SIGKILL":"SIGTERM"),!o)return}catch{}},fetch:(...n)=>fetch(...n),sleep:n=>new Promise(o=>setTimeout(o,n))};return t.vercel=ui({env:e,exec:(n,o)=>t.exec(n,o),fetch:t.fetch,scratch:Dr(ut(e),"..","local")}),t}var wd,kd,yd,uo=Oe(()=>{"use strict";qe();dn();wd=/^\s*(\w{3} \w{3} [ \d]\d \d\d:\d\d:\d\d \d{4})\s+(.*)$/,kd=/^n.*:(\d+)$/,yd=e=>Rr(Dr(e,"pnpm-workspace.yaml"))&&Rr(Dr(e,"apps","workspace","compose.yaml"))});import{createHash as $d}from"node:crypto";import{join as Ln}from"node:path";async function mi(e,t,n){let o=Date.now()+n*1e3;for(;Date.now()<o;){if(await e.fetch(t,{signal:AbortSignal.timeout(2e3)}).then(()=>!0).catch(()=>!1))return!0;await e.sleep(500)}return!1}async function vd(e,t,n){let o=Date.now()+n*1e3;for(;Date.now()<o;){if(!await e.listening(t))return!0;await e.sleep(500)}return!1}async function Sd(e,t,n){let o=Date.now()+n*1e3;for(;Date.now()<o;){if(!e.alive(t))return!0;await e.sleep(500)}return!1}async function Uo(e,t,n=()=>{}){let{sys:o,state:r}=e,s=[],a=Q=>{let Le=s.findIndex(ue=>ue.label===Q.label);Le===-1?s.push(Q):s[Le]=Q,t([...s])},c,i=(Q,Le,ue)=>(a({label:Q,mark:"fail",detail:Le,fix:ue}),c?{ok:!1,deployed:c}:{ok:!1}),l=o.root;if(!l||Te(e)||r.deployed?.runner==="image")return Nr(e,t,n);if(mn(e))return i("memory","the last deploy kept memory in LocusGraph, and this run has no secret for it","Esc back to Memory & database and paste it again \u2014 or go on there without it");let d=r.answers.runner??"node",u=r.answers.agentCli??"claude",f=d==="compose"&&r.answers.loginsFor==="compose"?[...new Set([u,...r.answers.loggedIn??[]])]:[u],p=Ze(e)?.token,g=Ee(e),y=r.answers.tenant??Ie(r.answers.owner),b=Yt(r),m=Mt(r),w=`http://127.0.0.1:${b}`,v=`http://localhost:${m}`,_=r.answers.owner,H=await Xt(e);if("why"in H)return i("console sign-in",H.why,H.fix);let W=H.mode==="github"?r.answers.githubApp:void 0,le=H.mode==="none"?{}:{...H.vars,...H.secrets,AUTH_URL:v};if(d==="compose"&&f.includes("claude")&&!p)return i("claude token","none in this run \u2014 it is never saved","Esc back to Agent logins and press t (or choose codex there), then Enter");let L=Ln(l,"apps","workspace","dist","node.js"),X=Ln(l,"apps","console",".next"),D=o.exists(L),B=o.exists(Ln(X,"BUILD_ID"));if(D&&B)a({label:"build",mark:"ok",detail:"workspace and console are built"});else{if(!B&&o.exists(X))return i("build","apps/console/.next holds no build \u2014 `next dev` may be using it, and a build would write over it",`stop the console's dev server, then run \`pnpm --filter @fnmoa/console build\` in ${l}, then Enter`);let Q=[...D?[]:[{what:"workspace",args:["--filter","@fnmoa/workspace...","run","build"]}],...B?[]:[{what:"console",args:["--filter","@fnmoa/console","run","build"]}]],Le=Q.map(Be=>Be.what).join(" and ");a({label:"build",mark:"wait",detail:`building the ${Le} \u2014 a few minutes`});let ue=await o.exec("pnpm",["install"],{cwd:l,timeoutMs:6e5});if(!ue.ok)return i("build",`pnpm install: ${Un(ue.stderr||ue.stdout)}`,`run \`pnpm install\` in ${l}, then Enter`);for(let Be of Q){let gt=await o.exec("pnpm",Be.args,{cwd:l,timeoutMs:9e5});if(!gt.ok)return i("build",`${Be.what}: ${Un(gt.stderr||gt.stdout)}`,`run \`pnpm ${Be.args.join(" ")}\` in ${l}, then Enter`)}a({label:"build",mark:"ok",detail:`${Le} built`})}let{token:ne,pending:ge,before:ee,had:$e}=await qt(o,Dn,w);a({label:"owner token",mark:"ok",detail:`${U} \u2014 profile ${Dn} in ~/.moa/config.json${ee===Dn?"":$e?`; \`moa\` now talks to this workspace, not profile ${ee} (\`moa use ${ee}\` to go back)`:"; `moa` now talks to this workspace"}`});let $=N({url:w,token:ne},o.fetch),I=r.deployed?Mn(o,r.deployed):void 0,oe=xd({runner:d,workspaceUrl:w,tenant:y,token:ne,...r.answers.repo?{repo:r.answers.repo}:{},..._?{owner:_}:{},...W?{githubClientId:W.clientId}:{},...g?{locusgraph:g.secret,graph:g.graph,server:g.server}:{},...p?{claude:p}:{}}),O=I?.workspacePid!==void 0&&Ut(o,I.workspacePid,I.workspaceStarted,xt(I.workspaceUrl))?I.workspacePid:void 0,V=O?I?.workspaceStarted:void 0,fe=I?.workspaceFor,te=I?.consolePid!==void 0&&Ut(o,I.consolePid,I.consoleStarted,xt(I.consoleUrl))?I.consolePid:void 0,ve=te?I?.consoleStarted:void 0,Se=I?.consoleFor,Me=I?.memoryKept,Re=I?.workspaceUrl===w?I?.people:void 0,Ke=()=>{c={runner:d,workspaceUrl:w,consoleUrl:v,...O?{workspacePid:O,...V?{workspaceStarted:V}:{}}:{},...fe?{workspaceFor:fe}:{},...te?{consolePid:te,...ve?{consoleStarted:ve}:{},...Se?{consoleFor:Se}:{}}:{},...Re?{people:Re}:{},...Me?{memoryKept:Me}:{},at:new Date().toISOString()},n(c)};if((O||te)&&Ke(),O!==void 0&&fe!==oe){if(a({label:"workspace",mark:"wait",detail:"restarting \u2014 it was started with other answers"}),o.stop(O),!await Sd(o,O,15))return i("workspace",`the old workspace (pid ${O}) is still running`,`stop it (\`kill ${O}\`), then Enter`);O=void 0,V=void 0,fe=void 0,Ke()}let we=await $.get("/v1/whoami").then(()=>"ours",Q=>Q instanceof ie?"other":"down");if(we==="other")return i("workspace",`something else answers on :${b} and refuses this token`,"stop it, or run `moa setup --workspace-port <port>`");if(we==="ours"&&fe!==oe&&d==="node")return i("workspace",`the workspace on :${b} was not started with these answers`,I?.runner==="compose"?`run \`docker compose -p ${he} down\`, then Enter`:"stop it, then Enter");if(we==="ours"&&fe===oe)a({label:"workspace",mark:"ok",detail:`${w} \u2014 already running`});else{a({label:"workspace",mark:"wait",detail:`starting on :${b}`});let Q={...o.env,...await Wt(e),MOA_TOKENS:`${ne}:${y}`,PORT:String(b),MOA_PORT:String(b),MOA_CONSOLE_PORT:String(m),...r.answers.repo?{MOA_REPO:r.answers.repo}:{},..._?{MOA_OWNER_LOGIN:_}:{},...W?{MOA_GITHUB_CLIENT_ID:W.clientId}:{},...g?{LOCUSGRAPH_AGENT_SECRET:g.secret,LOCUSGRAPH_GRAPH_ID:g.graph,LOCUSGRAPH_SERVER_URL:g.server}:{}};for(let ue of["MOA_DATABASE_URL","MOA_SQLITE_FILE","MOA_TOKEN_FILE","MOA_WORKSPACE_ROOT","MOA_SELF_URL",..._?[]:["MOA_OWNER_LOGIN"],...W?[]:["MOA_GITHUB_CLIENT_ID"]])delete Q[ue];if(d==="compose"){for(let Be of["MOA_CLI_HOME","CLAUDE_CODE_OAUTH_TOKEN","ANTHROPIC_API_KEY"])delete Q[Be];p&&(Q.CLAUDE_CODE_OAUTH_TOKEN=p);let ue=await o.exec("docker",Dt(l,"up","-d","--build"),{cwd:l,env:Q,timeoutMs:12e5});if(!ue.ok)return i("workspace",`docker compose: ${Un(ue.stderr||ue.stdout)}`,"fix that, then Enter");O=void 0,V=void 0,fe=oe,Me=!!g,Ke()}else{let ue=ce(o,"workspace.db");O=o.start(process.execPath,[L],{cwd:Ln(l,"apps","workspace"),env:{...Q,...p?{CLAUDE_CODE_OAUTH_TOKEN:p}:{},MOA_DATABASE_URL:`sqlite:${ue}`,MOA_D1_ACCOUNT_ID:"",MOA_D1_DATABASE_ID:"",MOA_D1_API_TOKEN:"",MOA_SQLITE_FILE:ue,MOA_WORKSPACE_ROOT:ce(o,"worktrees"),MOA_SELF_URL:w,MOA_PID_FILE:Mr(o)},log:ce(o,"workspace.log")}),V=o.processOf(O)?.started,fe=oe,Me=!!g,Ke()}if(!await mi(o,`${w}/health`,d==="compose"?120:60))return i("workspace",`did not answer on :${b}`,d==="compose"?`look at \`docker compose -p ${he} logs workspace\`, then Enter`:`look at ${ce(o,"workspace.log")}, then Enter`);if(!await $.get("/v1/whoami").then(()=>!0,()=>!1))return i("workspace","it started but refuses the owner token","Enter to try again");a({label:"workspace",mark:"ok",detail:`${w}${O?` (pid ${O})`:""}`})}ge&&await zt(o,Dn,w,ne);let _e=await Ur(o,w,a,d==="compose"?"postgres":"sqlite",d==="compose"?`look at \`docker compose -p ${he} logs\`, then Enter`:`look at ${ce(o,"workspace.log")}, then Enter`);if(_e)return i(_e.label,_e.detail,_e.fix);let T=await pn($,r,a,Re);if(T)return i(T.label,T.detail,T.fix);let F=Re;Re=r.answers.people??[],JSON.stringify(Re)!==JSON.stringify(F??[])&&Ke();let Ge=Ad(w,ne,le),nt=te!==void 0&&await o.listening(m);if(nt&&te!==void 0&&Se!==Ge){if(a({label:"console",mark:"wait",detail:"restarting \u2014 it points at another workspace"}),o.stop(te),te=void 0,ve=void 0,Se=void 0,Ke(),!await vd(o,m,15))return i("console",`the old console still holds :${m}`,"stop it, then Enter");nt=!1}if(nt)a({label:"console",mark:"ok",detail:`${v} \u2014 already running`});else{if(await o.listening(m))return i("console",`something else is on :${m}`,"stop it, or run `moa setup --console-port <port>`");if(a({label:"console",mark:"wait",detail:`starting on :${m}`}),te=o.start(process.execPath,[Ln(l,"apps","console","node_modules","next","dist","bin","next"),"start","--port",String(m),"--hostname","127.0.0.1"],{cwd:Ln(l,"apps","console"),env:{...Ed(o.env),MOA_URL:w,MOA_TOKEN:ne,...le},log:ce(o,"console.log")}),ve=o.processOf(te)?.started,Se=Ge,Ke(),!await mi(o,v,60))return i("console",`did not answer on :${m}`,`look at ${ce(o,"console.log")}, then Enter`);a({label:"console",mark:"ok",detail:`${v} (pid ${te})${W?" \u2014 Sign in with GitHub":""}`})}let ot=await Nt($,f,d==="compose"?"in the container":"on this machine",Q=>d==="compose"?"Esc back to Agent logins and log it in again, then Enter":`is ${Q} logged in on this machine? Run \`${Q}\` once and log in, then Enter`,a);if("label"in ot)return i(ot.label,ot.detail,ot.fix);let mt=ot.runs[u],me=await fn($,a);if("label"in me)return i(me.label,me.detail,me.fix);let bn=me.memory;return me.live!==void 0&&(Me=me.live),a({label:"Console",mark:"ok",detail:v}),a({label:"Workspace",mark:"ok",detail:w}),a({label:"Next",mark:"skip",detail:`moa whoami \xB7 moa agent list \xB7 moa run ${Nn(u)} "\u2026"`}),{ok:!0,deployed:{runner:d,workspaceUrl:w,consoleUrl:v,...O?{workspacePid:O,...V?{workspaceStarted:V}:{}}:{},...fe?{workspaceFor:fe}:{},...te?{consolePid:te,...ve?{consoleStarted:ve}:{},...Se?{consoleFor:Se}:{}}:{},...mt?{proofRunId:mt}:{},memory:bn,people:Re,...Me?{memoryKept:Me}:{},at:new Date().toISOString()}}}async function Ur(e,t,n,o,r){let s=await e.fetch(`${t}/health`,{signal:AbortSignal.timeout(5e3)}).then(c=>c.json()).catch(c=>({ok:!1,error:String(c)})),a=s.database??o;if(s.ok!==!0)return{label:"database",detail:`${a} does not answer: ${Un(String(s.error??"no answer"),1)}`,fix:r};n({label:"database",mark:"ok",detail:`${a} \u2014 migrated, and it answers`})}async function pn(e,t,n,o=[]){let r=t.answers.people??[],s=r.filter(i=>!o.some(l=>Cd(l,i)));for(let i of s){n({label:"people",mark:"wait",detail:`adding ${i.login}`});try{await e.put(`/v1/access/people/${encodeURIComponent(i.login)}`,{role:i.role,dailyCapUsd:i.dailyCapUsd})}catch(l){let d=l instanceof Error?l.message:String(l);return{label:"people",detail:`${i.login}: ${d}`,fix:l instanceof ie&&l.status===404?"this workspace has no access list \u2014 `git pull`, then `pnpm run build`, then Enter":"Enter to try again"}}}let a=(t.answers.removed??[]).filter(i=>!r.some(l=>l.login.toLowerCase()===i));for(let i of a){n({label:"people",mark:"wait",detail:`removing ${i}`});try{await e.del(`/v1/access/people/${encodeURIComponent(i)}`)}catch(l){if(l instanceof ie&&l.status===404)continue;let d=l instanceof Error?l.message:String(l);return{label:"people",detail:`removing ${i}: ${d}`,fix:"Enter to try again"}}}let c=r.length-s.length;(r.length>0||a.length>0)&&n({label:"people",mark:"ok",detail:[...s.map(i=>`${i.login} (${i.role})`),...a.map(i=>`${i} removed`),...c>0?[`${c} as before \u2014 left as the Access page has them`]:[]].join(", ")})}async function Nt(e,t,n,o,r){let s={};for(let a of t){let c=`proof: ${a} run`,i=Nn(a);r({label:c,mark:"wait",detail:`${a} is answering ${n}`});try{if(!await e.post("/v1/agents",{name:i,cli:a,role:"Proves moa setup worked. Answers in one word."}).then(()=>!0,p=>{if(!(p instanceof ie&&p.status===409))throw p;return!1})){let p=await e.get(`/v1/agents/${i}`);if(p.cli!==a)return{label:c,detail:`agent ${i} already exists and runs ${p.cli??"another CLI"}`,fix:`run \`moa agent rm ${i}\`, then Enter`}}let d=await e.post(`/v1/agents/${i}/runs`,{prompt:On}),u=await Ft(e,d.id,300),f=u.result;if(u.state!=="done"||!f||!("runId"in f)||f.isError){let p=u.error??(f&&"result"in f?f.result:"no answer");return{label:c,detail:Un(String(p),2),fix:o(a)}}s[a]=f.runId,r({label:c,mark:"ok",detail:`${a} answered "${Un(f.result,1).slice(0,40)}" ${n} \u2014 moa logs ${f.runId}`})}catch(l){return{label:c,detail:l instanceof Error?l.message:String(l),fix:"Enter to try again"}}}return{runs:s}}async function fn(e,t){try{let n=await e.get("/v1/memory"),o=(n.types??[]).reduce((c,i)=>c+(i.items?.length??0),0),r=typeof n.live=="boolean"?n.live:void 0,a=`${o} memor${o===1?"y":"ies"}, ${r===void 0?"kept where this older workspace build cannot say":r?"kept in LocusGraph":"in the workspace process"}`;return t({label:"proof: memory read",mark:"ok",detail:a}),r===void 0?{memory:a}:{memory:a,live:r}}catch(n){return{label:"proof: memory read",detail:n instanceof Error?n.message:String(n),fix:"Enter to try again"}}}var Dn,Nn,Un,gi,xd,Ad,Ed,Cd,Vt=Oe(()=>{"use strict";Ue();Sn();ze();at();Lt();Jt();In();qe();uo();Dn="local",Nn=e=>`setup-proof-${e}`,Un=(e,t=3)=>e.trim().split(`
141
+ `).slice(-t).join(" \xB7 ").slice(0,300);gi=e=>$d("sha256").update(e).digest("hex").slice(0,12),xd=e=>gi(JSON.stringify([e.runner,e.workspaceUrl,e.tenant,e.repo??"",e.token,e.locusgraph??"",e.owner??"",e.githubClientId??"",e.graph??"",e.server??"",e.claude??""])),Ad=(e,t,n)=>`${e} ${gi(JSON.stringify([t,n.AUTH_GITHUB_ID??"",n.AUTH_GITHUB_SECRET??"",n.AUTH_SECRET??"",n.MOA_CONSOLE_PASSWORD_HASH??""]))}`,Ed=e=>Object.fromEntries(Object.entries(e).filter(([t])=>!t.startsWith("AUTH_")&&!t.startsWith("MOA_CONSOLE_")));Cd=(e,t)=>e.login.toLowerCase()===t.login.toLowerCase()&&e.role===t.role&&e.dailyCapUsd===t.dailyCapUsd});var Fr={};bc(Fr,{artifactRoot:()=>Gn,bundledWorker:()=>Gr,crashOf:()=>bi,cursorPrompt:()=>No,deployImage:()=>Nr,imageChecks:()=>jn,imageCompose:()=>et,imageComposePath:()=>Qt,imageConfig:()=>yi,loggedInImage:()=>Zt,loginInImage:()=>Hn,logsInInContainer:()=>po,releaseImage:()=>Ce,waiting:()=>Fn,workerFromImage:()=>jr});import{chmod as Pd,mkdir as hi,readFile as _d,writeFile as Od}from"node:fs/promises";import{dirname as wi,join as ki}from"node:path";import{fileURLToPath as Td}from"node:url";async function jr(e){let t=await e.exec("docker",["create","--platform","linux/amd64",Ce()]);if(!t.ok)return{ok:!1,why:ae(t.stderr)||"docker create failed"};let n=ae(t.stdout),o=ce(e,ki("cloudflare","worker.js"));await hi(wi(o),{recursive:!0});let r=await e.exec("docker",["cp",`${n}:/repo/apps/workspace/dist/worker.js`,o]);return await e.exec("docker",["rm",n]),r.ok?{ok:!0,path:o}:{ok:!1,why:ae(r.stderr)||"the image holds no worker.js"}}async function jn(e){let t=await e.sys.exec("docker",["info","--format","{{.ServerVersion}}"]);if(!t.ok)return[{label:"docker",mark:"fail",detail:`${t.missing?"not installed":"not running"} \u2014 it pulls the published image`,fix:"Start Docker, then check again."}];let n=await e.sys.exec("docker",["pull",...e.state.target==="local"?[]:["--platform","linux/amd64"],Ce()],{timeoutMs:6e5}),o=e.state.target==="cloudflare"?"pulls the published image, then pushes it to your Cloudflare registry":"pulls the published image; nothing is built here";return[{label:"docker",mark:"ok",detail:`${t.stdout.trim().split(`
142
+ `)[0]} \u2014 ${o}`},{label:"image",mark:n.ok?"ok":"fail",detail:Ce(),...n.ok?{}:{fix:"Sign in to ghcr.io with your account's package pull token, then check again."}}]}function yi(e){let t=`fnmoa-${e.install}`;return{services:{workspace:{image:e.image,restart:"unless-stopped",ports:[`127.0.0.1:${e.workspacePort}:8787`,`127.0.0.1:${e.consolePort}:3100`],volumes:[`${t}:/data`,`${t}-home:/home/moa`],environment:{...e.env,MOA_PORT:"8787",MOA_SELF_URL:"http://127.0.0.1:8787",MOA_WORKSPACE_ROOT:"/data/worktrees",MOA_LICENCE_FILE:"/data/licence.json",MOA_DATABASE_URL:e.postgres?"postgres://moa@postgres:5432/moa":"sqlite:/data/workspace.db",MOA_SQLITE_FILE:"/data/workspace.db",MOA_LOCAL_CONTAINER:"1"},...e.postgres?{depends_on:{postgres:{condition:"service_healthy"}}}:{}},...e.postgres?{postgres:{image:"postgres:17-alpine",restart:"unless-stopped",environment:{POSTGRES_USER:"moa",POSTGRES_DB:"moa",POSTGRES_HOST_AUTH_METHOD:"trust"},volumes:[`${t}-pg:/var/lib/postgresql/data`],healthcheck:{test:["CMD-SHELL","pg_isready -U moa"],interval:"5s",timeout:"5s",retries:20}}}:{}},volumes:{[t]:{name:t},[`${t}-home`]:{name:`${t}-home`},...e.postgres?{[`${t}-pg`]:{name:`${t}-pg`}}:{}}}}function No(e){let t=/https:\/\/cursor\.com\/\S+/.exec(e);return t?{url:t[0]}:{}}async function Zt(e,t){if(!e.exists(Qt(e)))return!1;let n=Hr[t],o=await e.exec("docker",et(e,"exec","-T","workspace",...n.status),{timeoutMs:6e4});return n.loggedIn(o)}function Hn(e,t,n){let o=Hr[t],r="";return e.run("docker",et(e,"exec","-T",...o.env,"workspace",...o.login),{timeoutMs:16*6e4},s=>{r+=s,n(o.prompt(r))})}function bi(e){return e.split(`
143
+ `).map(n=>n.trim()).reverse().find(n=>/^[A-Z]\w*(Error|Exception)\b.*:/.test(n))}async function Nr(e,t,n){let o=[],r=$=>{o.push($),t([...o])},s=$=>(r({label:"image",mark:"fail",detail:$}),{ok:!1}),a=await bt(e);for(let $ of a)r($);if(a.some($=>$.mark==="fail"))return{ok:!1};let c=await co(e.sys.env,"local");if(!c)return s("Activate the local install first.");for(let $ of await jn(e))if(r($),$.mark==="fail")return{ok:!1};let{sys:i,state:l}=e,d={};if(l.deployed?.runner==="image"){let $=JSON.parse(await _d(Qt(i),"utf8"));d=Object.fromEntries(Object.entries($.services.workspace.environment).map(([I,oe])=>[I,oe.replaceAll("$$","$")]))}let u=`http://127.0.0.1:${Yt(l)}`,f=`http://localhost:${Mt(l)}`,{token:p}=await qt(i,"local",u),g=await Xt(e);if("why"in g)return s(`The console cannot sign anyone in: ${g.why}. ${g.fix}.`);let y=await i.exec("gh",["auth","token"]),b={...d,...await Wt(e),MOA_TOKENS:`${p}:${l.answers.tenant??Ie(l.answers.owner)}`,...l.answers.owner?{MOA_OWNER_LOGIN:l.answers.owner}:{},...l.answers.repo?{MOA_REPO:l.answers.repo}:{},...y.ok?{GH_TOKEN:y.stdout.trim()}:{}},m=Ze(e)?.token;m&&(b.CLAUDE_CODE_OAUTH_TOKEN=m);for(let $ of pe){let I=ye(e,$);I&&(b[Ae[$]]=I)}let w=l.answers.loggedIn;if(w)for(let $ of pe){if(w.includes($)||ye(e,$))continue;let I=[Ae[$],...$==="claude"&&!m?["CLAUDE_CODE_OAUTH_TOKEN"]:[]];for(let oe of I)delete b[oe]}let v=Ee(e);v&&Object.assign(b,{LOCUSGRAPH_AGENT_SECRET:v.secret,LOCUSGRAPH_GRAPH_ID:v.graph,LOCUSGRAPH_SERVER_URL:v.server});for(let $ of $i)delete b[$];g.mode!=="none"&&Object.assign(b,g.vars,g.secrets,{AUTH_URL:f});let _=Qt(i),H=$=>typeof $=="string"?$.replaceAll("$",()=>"$$"):Array.isArray($)?$.map(H):$&&typeof $=="object"?Object.fromEntries(Object.entries($).map(([I,oe])=>[I,H(oe)])):$,W=yi({image:Ce(),install:c.install,workspacePort:Yt(l),consolePort:Mt(l),postgres:l.answers.runner==="compose",env:b});if(await hi(wi(_),{recursive:!0,mode:448}),await Od(_,JSON.stringify(H(W)),{mode:384}),await Pd(_,384),!(await i.exec("docker",et(i,"up","-d","--wait"),{timeoutMs:6e5})).ok)return s("Docker Compose did not start the image. Run `moa setup logs` for details.");let L={runner:"image",workspaceUrl:u,consoleUrl:f,image:Ce(),at:new Date().toISOString()};n(L);let X=N({url:u,token:p},i.fetch),D=!1;for(let $=0;$<60;$++)try{await X.get("/v1/whoami"),D=!0;break}catch{await i.sleep(1e3)}if(!D){let $=await i.exec("docker",et(i,"logs","--tail","40","workspace"),{timeoutMs:3e4}),I=bi(`${$.stdout}
144
+ ${$.stderr}`);return{...s(I?`The workspace did not become ready: ${I}. \`moa setup logs\` has the rest.`:"The workspace did not become ready. `moa setup logs` says why."),deployed:L}}await zt(i,"local",u,p);let B=await pn(X,l,r,l.deployed?.people);if(B)return{...s(B.detail),deployed:L};let ne=l.answers.agentCli??"claude",ge=[...new Set([ne,...l.answers.loggedIn??[]])];for(let $ of ge){if(!po($)||ye(e,$)||await Zt(i,$))continue;r({label:$,mark:"wait",detail:"starting its login inside the container\u2026"});let oe=await Hn(i,$,O=>{let V=Fn(O);V&&r({label:$,mark:"wait",detail:V})}).done;if(!oe.ok||!await Zt(i,$))return r({label:$,mark:"fail",detail:`the login did not finish: ${ae(oe.stderr)||"no answer"}`,fix:"Enter to log in again \u2014 or Esc back to Agent logins and \u2191 \u2193 to choose another agent"}),{ok:!1,deployed:L};r({label:$,mark:"ok",detail:"logged in inside the container \u2014 kept on its home volume"})}let ee=await Nt(X,ge,"in the image",$=>$==="claude"?"Esc back to Agent logins: t to connect your Claude subscription, or export ANTHROPIC_API_KEY and run setup again.":`\`moa setup login ${$}\` to log it in again, or export ${Ae[$]} and run setup again.`,r);if("label"in ee)return{...s(ee.detail),deployed:L};let $e=await fn(X,r);return"label"in $e?{...s($e.detail),deployed:L}:(r({label:"console",mark:"ok",detail:f}),{ok:!0,deployed:{...L,people:l.answers.people,memory:$e.memory,memoryKept:$e.live}})}var Ce,Gn,Gr,Qt,et,Hr,po,Fn,at=Oe(()=>{"use strict";Ue();ze();Vt();Lt();Jt();In();qe();Ce=()=>`ghcr.io/fnlog0/fnmoa:${Bt()}`,Gn=()=>Td(new URL(import.meta.url.endsWith("/main.js")?"../":"../../",import.meta.url)),Gr=()=>ki(Gn(),"dist/assets/worker.js"),Qt=e=>ce(e,"image/compose.json"),et=(e,...t)=>["compose","--project-name","fnmoa-image","--file",Qt(e),...t];Hr={codex:{status:["codex","login","status"],login:["codex","login","--device-auth"],env:[],loggedIn:e=>e.ok,prompt:cn},cursor:{status:["cursor-agent","status"],login:["cursor-agent","login"],env:["-e","NO_OPEN_BROWSER=1"],loggedIn:e=>e.ok&&!/not logged in/i.test(`${e.stdout}${e.stderr}`),prompt:No}},po=e=>e in Hr;Fn=e=>e.url?e.code?`open ${e.url} and enter ${e.code} \u2014 waiting for you to approve it`:`open ${e.url} and sign in \u2014 waiting for you to approve it`:void 0});import{pbkdf2Sync as Id,randomBytes as Si}from"node:crypto";import{chmod as Rd,mkdir as Ld,writeFile as Dd}from"node:fs/promises";import{dirname as Ud,join as Br}from"node:path";async function gn(e,t,n,o=["--version"]){let r=await e.exec(t,o);return r.ok?S(t,mo(r.stdout)):C(t,"not found",n)}function Gd(e=process){return e.platform==="darwin"&&e.env.MOA_KEEP_AWAKE!=="0"?S("Sleep","held off while a pipeline runs, as `caffeinate -i` does \u2014 a closed lid still sleeps, and work it cut short is run again"):S("Sleep",e.platform==="darwin"?"not held off, MOA_KEEP_AWAKE=0 \u2014 work a sleep cuts short is run again":"not held off on this system \u2014 work a sleep cuts short is run again")}function jd(e,t=process){switch(e.target){case"local":return{lines:[S("This machine","Docker or local, nothing in the cloud"),Gd(t)]};case"cloudflare":return{lines:[S("Cloudflare","a Worker and its container on D1, on your own domain \u2014 Workers Paid plan")]};case"vercel":return{lines:[S("Vercel Sandbox","one persistent VM, fnmoa-<tenant>, resumed by name \u2014 needs the vercel CLI, signed in")]};default:return{lines:[{label:"Pick one with \u2191 \u2193 and Enter",mark:"wait"}]}}}async function vi(e,t,n,o,r,s){return await e.sys.listening(n)?o!==void 0&&Ut(e.sys,o,r,n)?S(`port ${n}`,`the ${t} the last setup started`):C(`port ${n}`,"something else is listening there",`stop it, or run \`moa setup ${s} <port>\``):S(`port ${n}`,`free for the ${t}`)}async function xi(e){return[Number(process.versions.node.split(".")[0])>=22?S("node",process.versions.node):C("node",process.versions.node,"install node 22 or newer"),...await Promise.all([gn(e,"pnpm","install pnpm: `corepack enable`"),gn(e,"git","install git"),gn(e,"gh","install the GitHub CLI: https://cli.github.com")])]}function Jr(e){if(e.secrets.cloudflare)return{token:e.secrets.cloudflare,from:"pasted in this run"};let t=e.sys.env.MOA_D1_API_TOKEN?.trim();return t?{token:t,from:"MOA_D1_API_TOKEN"}:void 0}function qr(e){if(e.secrets.github)return{token:e.secrets.github,from:"pasted in this run"};let t=e.sys.env.GH_TOKEN?.trim();return t?{token:t,from:"GH_TOKEN"}:void 0}async function Hd(e){let{sys:t,state:n}=e,o=await xi(t);if(Te(e)){let{imageChecks:u}=await Promise.resolve().then(()=>(at(),Fr));o.push(...await u(e))}else{let u=await t.exec("docker",["info","--format","{{.ServerVersion}}"]);o.push(u.ok?S("docker",`${ae(u.stdout)} \u2014 builds the container image from this checkout`):C("docker",u.missing?"not installed":"not running","wrangler builds the container image with Docker: start it, then r"))}let s=t.root??Gn();o.push(S(t.root?"checkout":"release",s));let a=await Fe(t,s,["--version"],{timeoutMs:3e4});if(!a.ok)return o.push(t.root?C("wrangler","not installed in this checkout",`run \`pnpm install\` in ${s}, then r`):C("wrangler",`\`npx ${pr}\` did not run: ${ae(a.stderr)||"no answer"}`,"check Node and npm can reach the npm registry, then r")),{lines:o};o.push(S("wrangler",mo(a.stdout)));let c=await la(t,s),i;c.ok?(i=c.account.id,o.push(S("account",`${c.account.name} (${c.account.id})${c.email?` as ${c.email}`:""}${c.others>0?" \u2014 CLOUDFLARE_ACCOUNT_ID picks another":""}`))):o.push(C("account",c.why,c.loggedOut?`run \`pnpm --dir ${Br(s,"apps","workspace")} exec wrangler login\`, then r`:"fix that, then r"));let l=n.answers.domain;if(!l)o.push(C("domain","none yet \u2014 the console and workspace need a name of yours","press d and type a domain on this Cloudflare account, like example.com"));else{let u=await da(t,l),f=Zn(l);o.push(u.zone&&u.onCloudflare?S("domain",`${f.consoleUrl} and ${f.workspaceUrl} \u2014 zone ${u.zone}`):C("domain",u.why??`${u.zone} is not served by Cloudflare's name servers`,"add the domain to this Cloudflare account (its name servers must be Cloudflare's), or d for another"))}let d=Jr(e);if(!d)o.push(Wr(n)?j("D1 token","kept \u2014 the deployed Worker has it (k to replace it)"):C("D1 token","none \u2014 the container reaches D1 over Cloudflare's API with it","make an API token with Account \xB7 D1 \xB7 Edit on this account, then press k and paste it"));else if(i){let u=await ua(t,i,d.token);o.push(u.ok?S("D1 token",`${U} (${d.from}) \u2014 D1 answers to it`):C("D1 token",`${U} (${d.from}) \u2014 D1 refused it: ${u.why}`,"make one with only Account \xB7 D1 \xB7 Edit on this account, then press k to paste it"))}return o.push(j("cost",`Workers Paid, plus the container (standard-4) while it runs \u2014 up to ${Tt}h after the last request`)),{lines:o,...i?{answers:{cloudflareAccount:i}}:{}}}async function Fd(e){let{sys:t,state:n}=e;if(Te(e)&&n.target==="local"){let{imageChecks:a}=await Promise.resolve().then(()=>(at(),Fr));return{lines:await a(e)}}if(n.target==="cloudflare")return Hd(e);let o=await xi(t),r=n.deployed?Mn(t,n.deployed):void 0,s=await t.exec("docker",["--version"]);return o.push(s.ok?S("docker",mo(s.stdout)):j("docker","not found \u2014 only needed for Postgres with docker compose")),o.push(t.root?S("checkout",t.root):C("checkout","not inside a fnMoa checkout","run moa setup from a clone of https://github.com/fnLog0/fnmoa")),o.push(await vi(e,"workspace",Yt(n),r?.workspacePid,r?.workspaceStarted,"--workspace-port"),await vi(e,"console",Mt(n),n.deployed?.consolePid,n.deployed?.consoleStarted,"--console-port"),j("account","this machine \u2014 no account needed")),{lines:o}}async function Kd(e){let{sys:t,state:n}=e,o=n.target==="cloudflare"?{...t.env}:void 0;if(o)for(let i of["GH_TOKEN","GITHUB_TOKEN"])delete o[i];let r=await t.exec("gh",["api","user","--jq",".login"],o?{env:o}:{}),s=ae(r.stdout);if(!r.ok||!s)return{lines:[C("gh login",r.missing?"gh is not installed":"gh has no login on this machine","run `gh auth login`, then press r to check again")]};if(n.target==="cloudflare")return Wd(e,s);let a=[S("gh login",`${s} \u2014 on this machine the workspace uses your own login`)],c=n.answers.repo;if(!c)a.push(j("repo","none \u2014 a pipeline can name any repository later (e to set one)"));else{let i=await t.exec("gh",["repo","view",c,"--json","viewerPermission","--jq",".viewerPermission"]),l=ae(i.stdout);a.push(i.ok&&["ADMIN","MAINTAIN","WRITE"].includes(l)?S("repo",`${c} \u2014 ${l.toLowerCase()}`):C("repo",i.ok?`${s} cannot push to ${c}`:`${c} is not a repository ${s} can see`,"press e to change it, or clear it to skip"))}return{lines:a,answers:{owner:s}}}async function Bd(e,t,n,o){let r=await e.exec("gh",["repo","view",t,"--json","viewerPermission","--jq",".viewerPermission"],o?{env:o}:{}),s=ae(r.stdout);return r.ok&&["ADMIN","MAINTAIN","WRITE"].includes(s)?S("repo",`${t} \u2014 ${s.toLowerCase()} for ${n}`):C("repo",r.ok?`${n} cannot push to ${t}`:`${t} is not a repository ${n} can see`,"press e to change it, or clear it to skip")}async function Wd(e,t){let{sys:n,state:o}=e,r=[S("gh login",`${t} \u2014 you, the first owner`)],s=qr(e),a;if(!s)r.push(Wr(o)?j("token","kept \u2014 the deployed Worker has it (k to replace it)"):C("token","none \u2014 the container works on GitHub with a token of its own","make a fine-grained token (contents, pull requests, issues: read/write; checks, actions: read) \u2014 a bot account's, preferably \u2014 then press k"));else{let c={...n.env,GH_TOKEN:s.token};for(let d of["GITHUB_TOKEN"])delete c[d];let i=await n.exec("gh",["api","user","--jq",".login"],{env:c});a=ae(i.stdout)||void 0,r.push(i.ok&&a?S("token",`${U} (${s.from}) \u2014 GitHub sees ${a}`):C("token",`${U} (${s.from}) \u2014 GitHub refused it`,"press k to paste another"));let l=o.answers.repo;l&&a&&r.push(await Bd(n,l,a,c))}return o.answers.repo||r.push(j("repo","none \u2014 a pipeline can name any repository later (e to set one)")),{lines:r,answers:{owner:t}}}function Ze(e){if(e.secrets.claude)return{token:e.secrets.claude,from:"pasted in this run"};let t=e.sys.env.CLAUDE_CODE_OAUTH_TOKEN?.trim();return t?{token:t,from:"your environment"}:void 0}async function qd(e){let{sys:t,state:n}=e;if(Te(e)&&n.target==="local")return zd(e);if(n.target==="cloudflare")return Yd(e);let o=Jd(n),[r,s]=await Promise.all([t.exec("claude",["--version"]),t.exec("codex",["--version"])]),a=Ze(e),c={claude:r.ok,codex:s.ok,cursor:!1},i=[o?S("agents run","in the container \u2014 only what is carried in here reaches it"):j("agents run","on this machine, on your logins \u2014 Postgres on Memory & database would move them into a container")],l,d=o&&t.root?await za(t,t.root):void 0;if(d&&!d.ok)c.codex=!1,l=C("codex",`the image did not build: ${d.why}`,"start Docker, or fix the build, then press r");else if(o&&t.root){let g=await Ya(t,t.root);c.codex=g.loggedIn,l=g.loggedIn?S("codex",`${g.says} \u2014 its own session in the container (l to log in again)`):g.broken?C("codex",`the container did not run: ${g.broken}`,"start Docker, then press r"):j("codex","not logged in inside the container \u2014 l to log in with a code")}else{let g=s.ok?await t.exec("codex",["login","status"]):void 0;c.codex=s.ok&&g?.ok===!0,l=s.ok?g?.ok?S("codex",`${mo(s.stdout)} \u2014 ${ae(g.stdout)||"logged in"}`):j("codex","not logged in \u2014 run `codex login`, then press r"):j("codex","not found")}let u;if(a){let g=await Pr(t,a.token,o&&t.root?{container:t.root}:"here");c.claude=g.ok,u=g.ok?S("claude",`token ${U} (${a.from}) \u2014 "reply ok" ${o?"in the container":"on it alone"}`):C("claude",`the token did not answer: ${g.why}`,"press t to make a new one with `claude setup-token`, or e to paste it again")}else o?(c.claude=!1,u=j("claude",r.ok?"no token carried in \u2014 t to make one with `claude setup-token`":"no token \u2014 install claude here to make one: npm i -g @anthropic-ai/claude-code")):u=r.ok?S("claude",`${mo(r.stdout)} \u2014 your existing login (t to carry a token instead)`):j("claude","not found");i.push(u,l);let f=e.state.answers.agentCli??(c.claude?"claude":c.codex?"codex":void 0);f?i.push(c[f]?S("proof run",`uses ${f} (\u2191 \u2193 to change)`):C("proof run",`${f} is not ready ${o?"in the container":"here"}`,f==="claude"?o?"press t to carry a token in \u2014 or \u2191 \u2193 to choose codex":"install claude and log in \u2014 or \u2191 \u2193 to choose codex":o?"press l to log codex in \u2014 or \u2191 \u2193 to choose claude":"install codex and run `codex login` \u2014 or \u2191 \u2193 to choose claude")):i.push(C("agent",o?"neither claude nor codex is logged in inside the container":"neither claude nor codex is ready",o?"press t to carry a claude token in, or l to log codex in":"install one and log in, then press r")),i.push(j("note","owner only: your subscriptions; teammates use them, never see them (moa setup login)"));let p=["claude","codex"].filter(g=>c[g]);return{lines:i,answers:{...f?{agentCli:f}:{},loggedIn:p,...go(i)?{loginsFor:o?"compose":"node"}:{}}}}async function zd(e){let{sys:t,state:n}=e,o=n.deployed?.runner==="image",r=Ze(e),s=new Set,a=[S("agents run","in the image's container \u2014 only what is carried in reaches it")];r?(s.add("claude"),a.push(S("claude",`token ${U} (${r.from}) \u2014 Deploy proves it in the image`))):ye(e,"claude")?(s.add("claude"),a.push(S("claude",`ANTHROPIC_API_KEY ${U} (${fo(e,"claude")})`))):o&&n.answers.loggedIn?.includes("claude")?(s.add("claude"),a.push(j("claude","kept \u2014 the running container has its login (t to replace it)"))):a.push(j("claude","not connected \u2014 t for your Claude subscription (`claude setup-token`), or export ANTHROPIC_API_KEY"));let c={codex:"ChatGPT",cursor:"Cursor"};for(let l of["codex","cursor"])ye(e,l)?(s.add(l),a.push(S(l,`${Ae[l]} ${U} (${fo(e,l)})`))):o&&await Zt(t,l)?(s.add(l),a.push(S(l,"logged in inside the container \u2014 kept on its home volume"))):a.push(j(l,`logs in at Deploy when chosen \u2014 or later, \`moa setup login ${l}\` with your ${c[l]} account`));let i=n.answers.agentCli??(s.has("claude")?"claude":s.values().next().value??"codex");return a.push(i!=="claude"||s.has("claude")?S("proof run",`uses ${i} (\u2191 \u2193 to change)`):C("proof run","claude has no login for the image","press t to connect your Claude subscription \u2014 or \u2191 \u2193 to choose codex or cursor")),{lines:a,answers:{agentCli:i,loggedIn:pe.filter(l=>s.has(l))}}}async function Vd(e){let t=e.state.deployed;if(t?.runner!=="cloudflare")return;let n=await xe(e.sys.env),o=Object.values(n.profiles).find(r=>r.url===t.workspaceUrl);if(o)try{let r=await e.sys.fetch(`${t.workspaceUrl}/_moa/codex`,{headers:{authorization:`Bearer ${o.token}`},signal:AbortSignal.timeout(12e4)});return r.ok?(await r.json()).loggedIn===!0:void 0}catch{return}}async function Yd(e){let{sys:t,state:n}=e,o=Ze(e),r=[S("agents run","in the Cloudflare container \u2014 only what is carried in reaches it")],s={claude:!1,codex:!0,cursor:!1};if(o){let d=await Pr(t,o.token,"here");s.claude=d.ok,r.push(d.ok?S("claude",`token ${U} (${o.from}) \u2014 "reply ok" on it alone; a Worker secret`):C("claude",`the token did not answer: ${d.why}`,"press c to make a new one with `claude setup-token`, or k for an API key"))}else ye(e,"claude")?(s.claude=!0,r.push(S("claude",`ANTHROPIC_API_KEY ${U} (${fo(e,"claude")}) \u2014 a Worker secret`))):Wr(n)&&n.answers.loggedIn?.includes("claude")?(s.claude=!0,r.push(j("claude","kept \u2014 the deployed Worker has the token (c to replace it)"))):r.push(j("claude","not connected \u2014 c for your Claude subscription, or k for an API key"));let a=ye(e,"codex"),c=a?void 0:await Vd(e);r.push(a?S("codex",`OPENAI_API_KEY ${U} (${fo(e,"codex")}) \u2014 a Worker secret`):c===!0?S("codex","logged in inside the container \u2014 its login is kept in R2 across restarts"):j("codex",c===!1?"not logged in inside the container \u2014 Deploy shows a link and a code (or k for an API key)":"logs in inside the container at Deploy \u2014 a link and a code (or k for an API key)")),s.cursor=ye(e,"cursor")!==void 0,r.push(s.cursor?S("cursor",`CURSOR_API_KEY ${U} (${fo(e,"cursor")}) \u2014 a Worker secret`):j("cursor","not connected \u2014 on Cloudflare cursor runs on an API key: k"));let i=n.answers.agentCli??(s.claude?"claude":"codex");r.push(s[i]?S("proof run",`uses ${i} (\u2191 \u2193 to change)`):C("proof run",`${i} is not connected`,"press c to connect it or k for its API key \u2014 or \u2191 \u2193 to another agent"),j("note","owner only: your subscriptions; teammates use them, never see them (moa setup login)"));let l=pe.filter(d=>s[d]&&(d!=="codex"||a!==void 0||c===!0));return{lines:r,answers:{agentCli:i,loggedIn:l,...go(r)?{loginsFor:"cloudflare"}:{}}}}function Ai(e){let{sys:t,state:n,secrets:o}=e,r=Xd(e),s=t.env.LOCUSGRAPH_AGENT_SECRET,a=s?.trim(),c=o.locusgraph||(s!==void 0?a:r.LOCUSGRAPH_AGENT_SECRET?.trim()),i=o.locusgraph?"pasted in this run":a?"your environment":"apps/workspace/.env";return{...c?{secret:c,from:i}:{},graph:n.answers.locusgraphGraph||t.env.LOCUSGRAPH_GRAPH_ID?.trim()||r.LOCUSGRAPH_GRAPH_ID?.trim()||void 0,server:t.env.LOCUSGRAPH_SERVER_URL?.trim()||r.LOCUSGRAPH_SERVER_URL||Qa}}function Ee(e){let{secret:t,from:n,graph:o,server:r}=Ai(e);return t&&n&&o?{secret:t,from:n,graph:o,server:r}:void 0}function zr(e){let{secret:t,from:n,graph:o}=Ai(e);if(t&&!o){let r=e.state.answers.tenant??Ie(e.state.answers.owner);return C("LocusGraph",`secret ${U} (${n}), but no graph ID`,e.state.deployed?.memoryKept?`press g to type the graph ID this secret belongs to \u2014 the last deploy used fnmoa-${r}`:"press g to type the graph ID this secret belongs to")}if(!t&&e.state.answers.locusgraphGraph)return C("LocusGraph",`graph ${e.state.answers.locusgraphGraph}, but no secret`,"press e to paste its agent secret \u2014 or g, then Enter on nothing, to go on without LocusGraph")}async function Qd(e){let{sys:t,state:n}=e,o=Ee(e),r=[],s=zr(e);if(s)r.push(s);else if(!o)r.push(mn(e)?C("LocusGraph","the last deploy kept memory in LocusGraph, and this run has no secret for it","press e to paste it again \u2014 or e, then Enter on nothing, to let memory stay in the workspace process"):e.secrets.noLocusgraph&&n.deployed?.memoryKept?j("LocusGraph","no secret \u2014 memory will not be kept in LocusGraph; it stays in the workspace process"):j("LocusGraph","not connected \u2014 memory stays in the workspace process (g for the graph ID, e for its secret)"));else{let i=n.answers.tenant??Ie(n.answers.owner),l=await Tn(t,o,i),d=`secret ${U} (${o.from}), graph ${o.graph}`;r.push(l.read.ok&&l.write.ok?S("LocusGraph",`${d} \u2014 one graph read, one event written`):C("LocusGraph",`${d} \u2014 ${l.read.ok?`the write failed: ${l.write.why}`:`the read failed: ${l.read.why}`}`,"e to paste the secret again, or g to check the graph ID \u2014 then r"))}if(n.target==="cloudflare")return r.push(S("database",`D1 \u2014 ${wt} on your account, made at deploy; the container reaches it over HTTP`)),{lines:r,answers:{runner:"cloudflare"}};let a=n.answers.runner??"node";if(a==="node")return r.push(S("database",`SQLite, ${ce(t,"workspace.db")} \u2014 migrated at deploy (\u2191 \u2193 for Postgres)`)),{lines:r,answers:{runner:a}};let c=await t.exec("docker",["info","--format","{{.ServerVersion}}"]);return r.push(c.ok?S("database","Postgres, with docker compose \u2014 migrated at deploy (\u2191 \u2193 for SQLite)"):C("database",c.missing?"docker is not installed":"docker is not running","start Docker, or \u2191 \u2193 to choose SQLite")),r.push(j("agent logins","in the container \u2014 Agent logins, next, carries them in and proves them")),{lines:r,answers:{runner:a}}}function en(e,t){try{let n=JSON.parse(e.read(Go(e,t))??"");if(n.clientSecret&&n.authSecret)return{clientSecret:n.clientSecret,authSecret:n.authSecret}}catch{}}function Vr(e,t){try{let n=JSON.parse(e.read(Ei(e,t))??"");if(n.hash&&n.authSecret)return{hash:n.hash,authSecret:n.authSecret}}catch{}}function Zd(e,t=21e4){let n=Si(16),o=Id(e,n,t,32,"sha256");return`pbkdf2-sha256$${t}$${n.toString("base64url")}$${o.toString("base64url")}`}async function eu(e,t,n){let o={hash:Zd(n),authSecret:Vr(e,t)?.authSecret??Si(32).toString("base64url")},r=Ei(e,t);return await Ld(Ud(r),{recursive:!0,mode:448}),await Dd(r,`${JSON.stringify(o)}
145
+ `,{mode:384}),await Rd(r,384),o}async function Xt(e){let{state:t,sys:n,secrets:o}=e,r=hn(t),s=t.target??"local";if(r==="password"){let i=t.answers.owner;if(!i)return{why:"no GitHub login to sign in as",fix:"Esc back to GitHub"};let l=o.consolePassword?await eu(n,s,o.consolePassword):Vr(n,s);return l?{mode:r,vars:{MOA_CONSOLE_LOGIN:i},secrets:{MOA_CONSOLE_PASSWORD_HASH:l.hash,AUTH_SECRET:l.authSecret}}:{why:"no console password yet",fix:"Esc back to Console access and press p to choose one"}}let a=t.answers.githubApp;if(r===void 0||!a)return{mode:"none",vars:{},secrets:{}};let c=en(n,a);return c?{mode:"github",vars:{AUTH_GITHUB_ID:a.clientId,MOA_GITHUB_CLIENT_ID:a.clientId},secrets:{AUTH_GITHUB_SECRET:c.clientSecret,AUTH_SECRET:c.authSecret}}:{why:`the client secret for ${a.slug} is not on this machine`,fix:"Esc back to Console access and press g to create a new app"}}function Yr(e){let{state:t,sys:n}=e,o=t.answers.owner,r=t.answers.tenant??Ie(o),s=t.answers.githubApp,a=[];if(hn(t)==="password"){let l=Vr(n,t.target??"local");a.push(e.secrets.consolePassword||l?S("sign-in",`password \u2014 you sign in as ${o??"your GitHub login"} with it, ${e.secrets.consolePassword?"set in this run":"kept as a hash"} (p to change; \u2191 \u2193 for a GitHub App)`):C("sign-in","password \u2014 none chosen yet","press p and type one, 12 characters or more (or \u2191 \u2193 for a GitHub App)"),j("GitHub App","not needed \u2014 only you sign in, with the password")),(t.answers.people??[]).length>0&&a.push(C("people","teammates sign in with GitHub, and the password is yours alone","\u2191 \u2193 to GitHub App \u2014 or take them off with -login"))}else s?t.target!=="vercel"&&(s.consoleUrl??Kr(t))!==Mo(t)?a.push(C("GitHub App",`${s.slug} signs people in at ${s.consoleUrl??Kr(t)}, not ${Mo(t)}`,"press g to create one for this console")):a.push(en(n,s)?S("GitHub App",`${s.slug} (id ${s.id}) \u2014 client secret ${U} kept beside setup`):C("GitHub App",`the client secret for ${s.slug} is not on this machine`,"press g to create a new app \u2014 GitHub shows a secret only once"),s.deviceFlow?S("device flow","on \u2014 teammates run `moa login <url> --github`"):{label:"device flow",mark:"wait",detail:`GitHub cannot switch it on for us: tick "Enable Device Flow" on ${s.settingsUrl}, Save, then press d`}):a.push(t.target==="local"?j("GitHub App","none \u2014 the console stays on localhost, never exposed (g to create one anyway)"):C("GitHub App","none yet \u2014 teammates sign in with it","press g: GitHub opens with the app filled in, and you click Create"));a.push(o?S("owner",`${o} (you)`):C("owner","no GitHub login yet","Esc back to GitHub"),S("tenant",`${r} (e to change)`),S("owner token",`${U} \u2014 made at deploy, kept in ~/.moa/config.json`));let i=t.answers.people??[];i.length===0&&a.push(j("people","only you \u2014 a to add a teammate"));for(let l of i)a.push(S(l.login,`${tu(l.role)} \xB7 cap $${l.dailyCapUsd}/day \u2014 added at deploy`));return{lines:a,answers:{tenant:r}}}function Mn(e,t){if(t.runner!=="node")return t;let n=t.workspacePid;if(n!==void 0&&Ut(e,n,t.workspaceStarted,xt(t.workspaceUrl)))return t;let[o="",r=""]=(e.read(Mr(e))??"").split(`
146
+ `),s=Number(o.trim()),a=r.trim();if(!Number.isSafeInteger(s)||s<=1||a===""||e.processOf(s)?.started!==a)return t;let c=xt(t.workspaceUrl);if(c===void 0)return t;let i=e.portsOf(s);return i!==void 0&&!i.includes(c)?t:{...t,workspacePid:s,workspaceStarted:a}}var ye,fo,Te,Nd,Md,Yt,Mt,Kr,Mo,Ie,go,S,C,j,ae,mo,Wr,Jd,Xd,mn,Go,hn,Ei,$i,tu,ce,Mr,jo,ze=Oe(()=>{"use strict";Ye();no();at();Jt();qe();uo();ye=(e,t)=>e.secrets.keys?.[t]?.trim()||e.sys.env[Ae[t]]?.trim()||void 0,fo=(e,t)=>e.secrets.keys?.[t]?.trim()?"typed in this run":"your environment",Te=({sys:e,state:t})=>!e.root||Pn(t)==="image",Nd=8787,Md=3100,Yt=e=>e.answers.workspacePort??Nd,Mt=e=>e.answers.consolePort??Md,Kr=e=>`http://localhost:${Mt(e)}`,Mo=e=>e.target==="vercel"&&e.answers.sandbox?e.answers.sandbox.consoleUrl:e.target==="cloudflare"&&e.answers.domain?Zn(e.answers.domain).consoleUrl:Kr(e),Ie=e=>(e??"").toLowerCase().replace(/[^a-z0-9-]+/g,"-").replace(/^-+|-+$/g,"")||"local",go=e=>e.length>0&&e.every(t=>t.mark==="ok"||t.mark==="skip"),S=(e,t)=>({label:e,mark:"ok",...t?{detail:t}:{}}),C=(e,t,n)=>({label:e,mark:"fail",detail:t,fix:n}),j=(e,t)=>({label:e,mark:"skip",detail:t}),ae=e=>e.trim().split(`
147
+ `)[0]?.trim()??"",mo=e=>ae(e).match(/\d+(\.\d+)+/)?.[0]??ae(e);Wr=e=>e.deployed?.runner==="cloudflare";Jd=e=>e.answers.runner==="compose";Xd=e=>e.sys.root?Za(e.sys.read(Br(e.sys.root,"apps","workspace",".env"))):{};mn=e=>e.state.deployed?.memoryKept===!0&&!e.secrets.noLocusgraph&&Ee(e)===void 0;Go=(e,t)=>ce(e,xo(t));hn=e=>e.answers.consoleSignIn??(e.answers.githubApp?"github":e.target==="local"?void 0:"password"),Ei=(e,t)=>ce(e,`console-password-${t}.json`);$i=["AUTH_GITHUB_ID","AUTH_GITHUB_SECRET","MOA_GITHUB_CLIENT_ID","MOA_CONSOLE_PASSWORD_HASH","MOA_CONSOLE_LOGIN","AUTH_SECRET"];tu=e=>`${e[0]?.toUpperCase()??""}${e.slice(1)}`;ce=(e,t)=>Br(ut(e.env),"..","local",t),Mr=e=>ce(e,"workspace.pid");jo={where:e=>jd(e.state,{platform:process.platform,env:e.sys.env}),checks:Fd,github:Kd,logins:qd,memory:Qd,access:Yr}});import{readFileSync as Ip,realpathSync as Rp}from"node:fs";import{fileURLToPath as Lp}from"node:url";function ys(e){let t=[],n=new Map;for(let o=0;o<e.length;o++){let r=e[o];if(!r.startsWith("-")){t.push(r);continue}if(r==="--"){t.push(...e.slice(o+1));break}let s=r.indexOf("=");if(s!==-1){n.set(r.slice(0,s).replace(/^--?/,""),r.slice(s+1));continue}let a=r.replace(/^--?/,""),c=e[o+1];c!==void 0&&!c.startsWith("-")?(n.set(a,c),o+=1):n.set(a,!0)}return{positional:t,flags:n}}var P=(e,t)=>{let n=e.flags.get(t);return typeof n=="string"?n:void 0},E=(e,t)=>e.flags.has(t);function de(e,t){let n=P(e,t);if(n===void 0)return;let o=Number(n);if(!Number.isFinite(o))throw new A(`--${t} must be a number`);return o}var A=class extends Error{constructor(t){super(t),this.name="Misuse"}};Ue();Ye();Ue();Sn();var k={ok:0,failed:1,halted:2,misuse:3};function G(e,t=process.stdout,n=process.stderr){return{line(o){e||t.write(`${o}
147
148
  `)},data(o){e&&t.write(`${JSON.stringify(o,null,2)}
148
149
  `)},warn(o){n.write(`${o}
149
- `)}}}function $s(e){if(e instanceof x)return{message:e.message,code:y.misuse};if(e instanceof zn)return{message:e.message,code:y.halted};if(e instanceof ae){let t=e.status>=500&&e.requestId?` (request ${e.requestId})`:"";if(e.status===503)return{message:`the workspace is up and cannot work \u2014 ${e.message}. Look at the database it was started with, not the process.${t}`,code:y.failed};if(e.status===429)return{message:e.message,code:y.halted};let n=e.status===401||e.status===403||e.status===400?y.misuse:y.failed;return{message:`${e.message}${t}`,code:n}}return{message:e instanceof Error?e.message:String(e),code:y.failed}}function be(e){if(e.length===0)return"";let t=[];for(let n of e)n.forEach((o,r)=>{t[r]=Math.max(t[r]??0,o.length)});return e.map(n=>n.map((o,r)=>r===n.length-1?o:o.padEnd(t[r]??0)).join(" ").trimEnd()).join(`
150
- `)}var et=(e,t)=>`${e.padEnd(10)}${t}`,Y=(e,t=60)=>e.length>t?`${e.slice(0,t-1)}\u2026`:e,ar=e=>{let t=e.split(/\n\s*\n/).filter(n=>n.trim().length>0);return(t[t.length-1]??e).trim()};import{hostname as $c}from"node:os";De();Ze();var vc="usage: moa login <url> --token <token> or moa login <url> --github";async function xs(e,t=process.env,n={}){let o=C(e,"json"),r=G(o),s=e.flags.get("github"),a=e.positional[1]??(typeof s=="string"?s:void 0);if(!a)throw new x(vc);if(s!==void 0&&e.flags.has("token"))throw new x("--token and --github are two ways in \u2014 use one");let c=a.replace(/\/+$/,""),i=n.fetch??fetch;if(s!==void 0){let b=await Sc(c,h=>o?r.warn(h):r.line(h),{...n,fetch:i}),$=await vs(t,P(e,"profile"),{url:c,token:b.token}),m=b.role==="viewer"?", read-only: you may look and nothing else":"";return r.line(`logged in to ${c} as ${b.login}, ${b.role} on ${b.tenant} (profile ${$}${m})`),r.data({url:c,tenant:b.tenant,profile:$,login:b.login,role:b.role}),y.ok}let l=P(e,"token")??t.MOA_TOKEN;if(!l)throw new x("--token is required (or set MOA_TOKEN), or sign in with --github");let d={url:c,token:l},u=await U(d,i).get("/v1/whoami"),f=await vs(t,P(e,"profile"),d),p=u.scope==="read"?", read-only: it may look and nothing else":"";return r.line(`logged in to ${d.url} as ${u.tenant} (profile ${f}${p})`),r.data({url:d.url,tenant:u.tenant,profile:f,...u.scope===void 0?{}:{scope:u.scope}}),0}async function vs(e,t,n){let o=t??"default",r=await ve(e);return r.profiles[o]=n,r.current=o,await gt(r,e),o}var Ss=async e=>{let t=await e.text().catch(()=>"");try{return JSON.parse(t).error??t}catch{return t}};async function Sc(e,t,n){let o=n.sleep??(d=>new Promise(u=>setTimeout(u,d))),r=async(d,u)=>{try{return await n.fetch(`${e}${d}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(u??{})})}catch(f){throw new Pt(e,f)}},s=await r("/v1/access/device");if(!s.ok){let d=await Ss(s);throw new Error(s.status===503||s.status===404?`${e} has no GitHub sign-in${d?` (${d})`:""} \u2014 ask its owner to create the GitHub App in \`moa setup\`, or log in with --token`:`${e} would not start a GitHub sign-in: ${d||s.status}`)}let a=await s.json();t(`open ${a.verificationUri} and enter ${a.userCode}`),t("waiting for GitHub\u2026");let c=`${(n.hostname??$c)()} cli`,i=Math.max(a.interval??5,1),l=(a.expiresIn??900)+30;for(;;){await o(i*1e3),l-=i;let d=await r("/v1/access/device/token",{deviceCode:a.deviceCode,name:c});if(d.status===201)return await d.json();if(d.status===202){let f=await d.json().catch(()=>({}));if(i=Math.max(i,f.interval??i),l<=0)throw new Error("the code expired before it was entered \u2014 run moa login again");continue}if(d.status===429){if(i=Math.min(i*2,60),l<=0)throw new Error("the code expired before it was entered \u2014 run moa login again");continue}let u=await Ss(d)||`the workspace said ${d.status}`;throw d.status===403?new ae(403,`${u} \u2014 ask an owner to add your GitHub login on Access`):d.status===410?new ae(410,`${u} \u2014 run moa login again for a new code`):new ae(d.status,u)}}function rt(e,t=new Date){if(!e)return;let n=Date.parse(e);if(Number.isNaN(n))return;let o=Math.max(0,Math.round((t.getTime()-n)/1e3));if(o<60)return`${o}s`;let r=Math.floor(o/60);if(r<60)return`${r}m`;let s=Math.floor(r/60);return s<24?`${s}h ${r%60}m`:`${Math.floor(s/24)}d ${s%24}h`}function ir(e,t=new Date){if(!e)return;let n=Date.parse(e);if(!(Number.isNaN(n)||n<=t.getTime()))return rt(t.toISOString(),new Date(n))}async function As(e,t=process.env){let n=G(C(e,"json")),o=await te(P(e,"profile"),t),r=await U(o).get("/v1/whoami"),s=r.scope==="read"?", read-only":"";return n.line(`${r.tenant} at ${o.url} (profile ${o.name}${s})`),n.data({tenant:r.tenant,url:o.url,profile:o.name,...r.scope===void 0?{}:{scope:r.scope}}),0}async function Es(e,t=process.env){let n=G(C(e,"json")),o=e.positional[1]??P(e,"url"),r=o?{url:o,token:""}:await te(P(e,"profile"),t);try{let s=await U(r).get("/health"),a=rt(s.startedAt);return n.line(`${r.url} ${s.ok?"ok":"not ok"} (${s.database}, v${s.version}${a?`, up ${a}`:""})`),n.data(s),s.ok?y.ok:y.failed}catch(s){if(s instanceof ae&&s.status===503)return n.warn(`moa: ${r.url} is up and cannot work \u2014 ${s.message}`),n.data({ok:!1,url:r.url,status:503,error:s.message}),y.failed;throw s}}function xc(e,t,n){let o=e.missingTools??[],r=t.filter(s=>s.installed===!1).map(s=>s.cli);return[{name:"this token",ok:n!=="read",detail:n==="read"?"read-only: it may look, and every run, message and grant is refused":`${e.tenant}, and it may start work`},{name:"runs agents",ok:e.runsAgents,detail:e.runsAgents?`${e.database}, v${e.version}${rt(e.startedAt)?`, up ${rt(e.startedAt)}`:""}`:"a Worker: it serves the store, and the runs belong to the container beside it"},{name:"last restart",ok:!0,detail:(()=>{let s=rt(e.restart?.at??e.startedAt),a=e.restart?.cutShort??0;return s?a===0?`${s} ago, and nothing was cut short by it`:`${s} ago; ${a} run${a===1?"":"s"} did not survive it`:"this workspace has not said when it started"})()},{name:"seat capacity",ok:!t.every(s=>s.full===!0),detail:(()=>{let s=t.filter(a=>a.full===!0).map(a=>a.cli);return s.length===0?"room on every seat":s.length===t.length?"every seat is spent \u2014 nothing runs until a window resets":`${s.join(", ")} spent; room on the rest`})()},{name:"whose login",ok:!0,detail:t.length===0?"no seats: this tenant cannot run anything":t.every(s=>s.hasCredential)?"your own credential on every CLI":t.some(s=>s.hasCredential)?`your own on ${t.filter(s=>s.hasCredential===!0).map(s=>s.cli).join(", ")}; the machine's login on the rest`:"the machine's login, shared with every tenant on this workspace"},{name:"run ceiling",ok:!0,detail:e.runTimeoutMinutes===void 0?"this workspace does not say":e.runTimeoutMinutes===0?"no cap: a run that hangs holds its agent until somebody stops it":`a run is stopped after ${e.runTimeoutMinutes} minute(s)`},{name:"agent CLIs",ok:r.length<t.length,detail:(()=>{let s=t.filter(a=>a.installed!==!1).map(a=>a.cli);return r.length===0?s.join(", "):s.length===0?`none: missing ${r.join(", ")}`:`${s.join(", ")} \u2014 missing ${r.join(", ")}`})()},...e.agentBudget?[{name:"agent budget",ok:e.agentBudget.ok,detail:e.agentBudget.ok?`$${e.agentBudget.spentUsd.toFixed(4)} of today's $${e.agentBudget.limitUsd.toFixed(2)} spent asking each other`:e.agentBudget.reason??"today's budget is spent"}]:[],...e.agentTools?[{name:"agent tools",ok:e.agentTools.reachable,detail:e.agentTools.reachable?`${e.agentTools.tools?.length??0} at ${e.agentTools.url}`+(e.agentTools.unwired.length>0?` \u2014 not on ${e.agentTools.unwired.join(", ")}`:""):`${e.agentTools.url}: ${e.agentTools.problem??"no answer"}`}]:[],{name:"repository",ok:!!e.repo,detail:e.repo??"none configured \u2014 pipelines need MOA_REPO"},{name:"checkout",ok:e.hasCheckout,detail:e.checkoutProblem??"a git checkout the pipeline can work in"},{name:"git and gh",ok:o.length===0,detail:o.length===0?"both on its PATH":`missing ${o.join(", ")}`},{name:"github login",ok:e.githubAuthenticated!==!1,detail:e.githubAuthenticated===!1?"gh has no token there \u2014 run `gh auth login` where the workspace runs":"gh has a token"}]}async function Cs(e,t=process.env){let n=G(C(e,"json")),o=U(await te(P(e,"profile"),t)),[r,s,a]=await Promise.all([o.get("/v1/workspace"),o.get("/v1/seats"),o.get("/v1/whoami").catch(()=>({scope:void 0}))]),c=xc(r,s.seats.map(l=>({...l,full:l.limit!==void 0&&(l.used??0)>=l.limit})),a.scope);for(let l of c)n.line(`${l.ok?"ok ":"NO "}${l.name.padEnd(14)}${l.detail}`);let i=c.filter(l=>!l.ok);return n.data({tenant:r.tenant,checks:c}),i.length===0?y.ok:y.halted}async function Ps(e,t=process.env){let n=G(C(e,"json")),o=U(await te(P(e,"profile"),t)),{seats:r}=await o.get("/v1/seats");if(r.length===0)return n.warn("no seats \u2014 this tenant cannot run anything"),n.data({seats:[]}),1;for(let s of r){let a=s.limit?`${s.used}/${s.limit}`:`${s.used}`,c=ir(s.resetsAt),i=s.limit!==void 0&&s.used>=s.limit,l=s.resetsAt?`${i?" \xB7 full":""}, resets${c?` in ${c}`:" shortly"}`:"",d=s.installed===!1?" \xB7 not installed":"";n.line(`${s.cli.padEnd(8)} ${a.padEnd(8)} ${Ac(s)}${l}${d}`)}return n.data({seats:r}),0}var Ac=e=>e.hasCredential?"your own credential":"the machine's login, shared with every tenant here";async function _s(e,t=process.env){let n=G(C(e,"json")),o=await ve(t),r=Object.keys(o.profiles);r.length===0&&n.line("no workspace yet \u2014 run `moa login <url> --token <token>`");for(let s of r)n.line(`${s===o.current?"*":" "} ${s} ${o.profiles[s]?.url}`);return n.data({current:o.current,profiles:r.map(s=>({name:s,url:o.profiles[s]?.url}))}),0}async function Ts(e,t=process.env){let n=G(C(e,"json")),o=await ve(t),r=e.positional[1]??o.current;if(!o.profiles[r]){let a=Object.keys(o.profiles);throw new x(a.length===0?"no workspace is saved":`no profile named ${r} \u2014 there is ${a.join(", ")}`)}delete o.profiles[r];let s=Object.keys(o.profiles);return o.current===r&&(o.current=s[0]??"default"),await gt(o,t),n.data({forgot:r,current:o.current,profiles:s}),n.line(`forgot ${r} \u2014 its token is no longer on this machine`),s.length===0?n.line("no workspace left \u2014 `moa login <url> --token <token>`"):r!==o.current?n.line(`now using ${o.current}`):n.line(`now using ${o.current}`),y.ok}async function Os(e,t=process.env){let n=e.positional[1];if(!n)throw new x("usage: moa use <profile>");let o=G(C(e,"json")),r=await ve(t),s=r.profiles[n];if(!s){let c=Object.keys(r.profiles);throw new x(c.length===0?`no profile named ${n} \u2014 run \`moa login <url> --token <token>\` first`:`no profile named ${n} \u2014 there is ${c.join(", ")}`)}r.current=n,await gt(r,t);let a=await U(s).get("/v1/whoami").catch(()=>{});return o.line(`now using ${n} \u2014 ${s.url}${a?` as ${a.tenant}`:""}`),o.data({profile:n,url:s.url,...a?{tenant:a.tenant}:{}}),y.ok}function Ec(e,t=new Date){let n=/^(\d+)([hd])$/.exec(e.trim());if(!n?.[1])return e;let o=Number(n[1])*(n[2]==="d"?24:1);return new Date(t.getTime()-o*36e5).toISOString()}async function Is(e,t=process.env){let n=G(C(e,"json")),o=U(await te(P(e,"profile"),t)),r=P(e,"since"),s=r===void 0?void 0:Ec(r),a=s===void 0?"/v1/spend":`/v1/spend?since=${encodeURIComponent(s)}`,[c,i]=await Promise.all([o.get(a),o.get("/v1/workspace").catch(()=>{})]);n.data({...c,...i?.agentBudget?{agentBudget:i.agentBudget}:{}});let l=d=>`$${d.toFixed(4)}`;if(n.line(`${l(c.costUsd)} over ${c.runs} ${c.runs===1?"run":"runs"}`+(s===void 0?"":`, since ${s}`)),n.line("notional \u2014 what the CLIs reported, not a bill"),i?.agentBudget){let d=i.agentBudget;n.line(d.ok?`today, agents have spent $${d.spentUsd.toFixed(4)} of $${d.limitUsd.toFixed(2)} asking each other`:`agents are at today's ceiling: $${d.spentUsd.toFixed(4)} of $${d.limitUsd.toFixed(2)} \u2014 calls are refused until UTC midnight`)}return c.runs===0?y.ok:(n.line(""),n.line(be([["AGENT","RUNS","COST"],...c.byAgent.map(d=>[d.agent,String(d.runs),l(d.costUsd)])])),n.line(""),n.line(be([["WHAT ASKED","RUNS","COST"],...c.byCause.map(d=>[d.cause,String(d.runs),l(d.costUsd)])])),y.ok)}async function Ls(e,t=process.env){let n=e.positional[1],o=U(await te(P(e,"profile"),t)),r=G(C(e,"json"));switch(n){case"create":return Cc(o,e,r);case"list":case"ls":return Pc(o,r);case"show":return _c(o,e,r);case"role":return Tc(o,e,r);case"grant":return Rs(o,e,r,"grant");case"revoke":return Rs(o,e,r,"revoke");case"rm":case"remove":return Oc(o,e,r);default:throw new x(`usage: moa agent <create|list|show|role|grant|revoke|rm> \u2026
151
- moa agent create reviewer --cli codex --role "\u2026" --peers builder,planner`)}}async function Cc(e,t,n){let o=t.positional[2],r=P(t,"cli");if(!o)throw new x("usage: moa agent create <name> --cli <cli> [--role \u2026] [--peers a,b]");if(!r)throw new x("--cli is required (claude, codex, cursor, amp, gemini, crush)");let s=(P(t,"peers")??"").split(",").map(c=>c.trim()).filter(Boolean),a=await e.post("/v1/agents",{name:o,cli:r,...P(t,"role")===void 0?{}:{role:P(t,"role")},...s.length===0?{}:{peers:s}});return n.line(`created ${a.name} (${a.cli})`),s.length>0&&n.line(` may open a thread with: ${s.join(", ")}`),n.data(a),0}async function Pc(e,t){let[{agents:n},o]=await Promise.all([e.get("/v1/agents"),e.get("/v1/mail").catch(()=>{})]),r=new Map((o?.waiting??[]).map(s=>[s.to,s]));return n.length===0?t.line("no agents yet \u2014 moa agent create <name> --cli claude"):t.line(be([["NAME","CLI","STATUS","MAIL","ROLE"],...n.map(s=>{let a=r.get(s.name);return[s.name,s.cli,s.status,a?`${a.unread} \xB7${rt(a.oldest)??"?"}`:"\u2014",Y(s.role??"\u2014",40)]})])),t.data({agents:n,waiting:o?.waiting??[]}),0}async function _c(e,t,n){let o=t.positional[2];if(!o)throw new x("usage: moa agent show <name>");let[r,s]=await Promise.all([e.get(`/v1/agents/${o}`),e.get(`/v1/agents/${o}/history`)]);n.line(et("name",r.name)),n.line(et("cli",r.cli)),n.line(et("status",r.status)),n.line(et("role",r.role??"\u2014"));let a=s.peers.filter(i=>!i.revokedAt).map(i=>i.to),c=s.peers.filter(i=>i.revokedAt).map(i=>`${i.to} (revoked)`);return n.line(et("peers",[...a,...c].join(", ")||"\u2014")),s.history.length>0&&(n.line(""),n.line(be(s.history.map(i=>[i.at.slice(0,19).replace("T"," "),i.kind,i.actor,Y(i.detail??"",40)])))),n.data({agent:r,...s}),0}async function Tc(e,t,n){let o=t.positional[2],r=t.positional[3]??P(t,"role");if(!o||!r)throw new x('usage: moa agent role <name> "what it is for"');let s=await e.patch(`/v1/agents/${o}`,{role:r});return n.line(`${s.name} is now: ${Y(s.role??"",60)}`),n.data(s),0}async function Rs(e,t,n,o){let r=t.positional[2],s=t.positional[3];if(!r||!s)throw new x(`usage: moa agent ${o} <from> <to>`);return o==="grant"?(await e.post(`/v1/agents/${r}/peers`,{to:s}),n.line(`${r} may now open a thread with ${s}`)):(await e.del(`/v1/agents/${r}/peers/${s}`),n.line(`${r} may no longer open a thread with ${s}`)),n.data({from:r,to:s,granted:o==="grant"}),0}async function Oc(e,t,n){let o=t.positional[2];if(!o)throw new x("usage: moa agent rm <name>");return await e.del(`/v1/agents/${o}`),n.line(`released ${o}'s workspace \u2014 its runs, mail and edges remain`),n.data({released:o}),0}async function Ds(e,t=process.env){let n=U(await te(P(e,"profile"),t)),o=G(C(e,"json")),r=C(e,"all"),{peers:s}=await n.get("/v1/peers"),a=r?s:s.filter(i=>!i.revokedAt);if(o.data({peers:a}),a.length===0)return o.line(r?"no edges have ever been granted":"no edges \u2014 mail bounces, and only a team loop's own replies move"),y.ok;let c=new Set(s.filter(i=>!i.revokedAt).map(i=>`${i.from}\0${i.to}`));return o.line(be([["FROM","TO","GRANTED","BY","NOTE"],...a.map(i=>[i.from,i.to,i.grantedAt.slice(0,19).replace("T"," "),i.grantedBy,i.revokedAt?`revoked ${i.revokedAt.slice(0,19).replace("T"," ")}`:c.has(`${i.to}\0${i.from}`)?"":"one way"])])),y.ok}De();Ze();var jt=async(e,t)=>U(await te(P(e,"profile"),t)),cr="mesh";function Us(e){let t=/^(\S+) may not open a thread with (.+)$/.exec(e);return t?.[1]&&t[2]?{say:"Nobody granted that edge:",run:t[2].split(",").map(n=>`moa agent grant ${t[1]} ${n.trim()}`)}:/^fanout of \d+ exceeds/.test(e)?{say:"Too many recipients at once. Send to fewer, or send twice.",run:[]}:/^body of \d+ exceeds/.test(e)?{say:"The message is too long for the bus. Say less, or link to it.",run:[]}:/hit maxHops/.test(e)?{say:"This conversation is over its budget. Start a new thread.",run:[]}:/exceeds maxDepth/.test(e)?{say:"Delegations are nested too deep. Hand this one back up.",run:[]}:/cannot address itself/.test(e)?{say:"An agent cannot send itself mail. Give it work instead.",run:[]}:e==="no recipient"?{say:"Nobody was named.",run:[]}:{say:"The bus refused it. Nothing was delivered.",run:[]}}function yo(e){if(e.from===cr)return/^undelivered:\s*(.+)$/s.exec(e.body)?.[1]?.trim()}async function Ms(e,t=process.env){let[,n,o,r]=e.positional;if(!n||!o||!r)throw new x('usage: moa send <from> <a,b,c> "<body>"');let s=o.split(",").map(i=>i.trim()).filter(Boolean);if(s.length===0)throw new x("name at least one recipient");let a=G(C(e,"json")),c=await(await jt(e,t)).post("/v1/messages",{from:n,to:s.length===1?s[0]:s,body:r,...P(e,"thread")===void 0?{}:{thread:P(e,"thread")}});return lr(c,a,`${n} \u2192 ${s.join(", ")}`)}async function Ns(e,t=process.env){let n=e.positional[1];if(!n)return Ic(e,t);let o=G(C(e,"json")),{messages:r}=await(await jt(e,t)).get(`/v1/agents/${n}/inbox`);if(r.length===0)o.line(`${n} has no unread mail`);else{o.line(be([["FROM","KIND","BODY"],...r.map(s=>{let a=yo(s);return[s.from,a?"undelivered":s.kind??"status",Y(bn(a??s.body),60)]})]));for(let s of r){let a=yo(s);if(!a)continue;let c=Us(a);o.line(""),o.line(c.say);for(let i of c.run)o.line(` ${i}`)}}return o.data({messages:r}),0}async function Ic(e,t){let n=G(C(e,"json")),{waiting:o}=await(await jt(e,t)).get("/v1/mail");return n.data({waiting:o}),o.length===0?(n.line("nobody has unread mail"),y.ok):(n.line(be([["AGENT","UNREAD","WAITING","FROM"],...o.map(r=>[r.to,String(r.unread),rt(r.oldest)??"\u2014",r.from])])),o.some(r=>r.from===cr)&&(n.line(""),n.line(`${cr} is the bus: that mail never arrived. moa inbox <name> says why.`)),y.ok)}async function js(e,t=process.env){let n=e.positional[1];if(!n)throw new x("usage: moa mail <name> [--limit n]");let o=G(C(e,"json")),r=ce(e,"limit")??20,{messages:s}=await(await jt(e,t)).get(`/v1/agents/${n}/messages?limit=${r}`);return o.data({messages:s}),s.length===0?(o.line(`nothing has been said to ${n} yet`),y.ok):(o.line(be([["WHEN","WITH","KIND","BODY"],...s.map(a=>[a.createdAt.slice(0,19).replace("T"," "),a.from===n?`\u2192 ${a.to}`:`\u2190 ${a.from}`,(yo(a)?"undelivered":a.kind??"status")+(a.deliveredAt?"":" \xB7unread"),Y(bn(yo(a)??a.body),56)])])),y.ok)}async function Gs(e,t=process.env){let[,n,o,r]=e.positional;if(!n||!o||!r)throw new x('usage: moa delegate <from> <to> "<task>"');let s=G(C(e,"json")),a=await(await jt(e,t)).post("/v1/delegations",{from:n,to:o,task:r,...P(e,"parent")===void 0?{}:{parent:P(e,"parent")}});return a.delivered?(s.line(`${n} handed "${Y(r,50)}" to ${o}`),s.line(` thread ${a.thread}`),s.line(` ${n} answers for it until ${o} says done`),s.data(a),y.ok):lr(a,s,`${n} \u2192 ${o}`)}async function Hs(e,t=process.env){let n=G(C(e,"json")),o=await(await jt(e,t)).get("/v1/delegations"),r=C(e,"blocked")?o.delegations.filter(s=>s.blockedBy):o.delegations;if(r.length===0)n.line(C(e,"blocked")?"nothing is blocked":"nothing is open");else{n.line(be([["FROM","TO","STATE","TASK"],...r.map(s=>[s.from,s.to,s.blockedBy?"BLOCKED":"open",Y(bn(s.task),44)])]));for(let s of r.filter(a=>a.blockedBy))n.line(""),n.line(`${s.to} is waiting on an answer:`),n.line(` "${Y(bn(s.blockedBy?.body??""),70)}"`),n.line(` moa reply ${s.thread} ${s.from} --kind answer "\u2026"`)}return n.data(o),0}async function Fs(e,t=process.env){let n=e.positional[1];if(!n)throw new x("usage: moa thread <thread>");let o=G(C(e,"json")),r=await(await jt(e,t)).get(`/v1/delegations/${n}`),{delegation:s}=r;if(o.line(et("task",Y(bn(s.task),60))),o.line(et("from",s.from)),o.line(et("to",s.to)),o.line(et("state",s.closedAt?"closed":s.blockedBy?"BLOCKED":"open")),s.hops!==void 0&&s.maxHops!==void 0){let a=s.hops>=s.maxHops;o.line(et("hops",a?`${s.hops}/${s.maxHops} \u2014 spent, nothing more can be said in it`:`${s.hops}/${s.maxHops}`))}if(s.depth!==void 0&&s.maxDepth!==void 0){let a=s.depth>=s.maxDepth;o.line(et("depth",a?`${s.depth}/${s.maxDepth} \u2014 it cannot be handed on again`:`${s.depth}/${s.maxDepth}`))}o.line("");for(let a of r.messages)o.line(`${a.from} \xB7 ${a.kind??"status"}`),o.line(` ${bn(a.body)}`);return o.data(r),0}async function Ks(e,t=process.env){let[,n,o,r]=e.positional,s=P(e,"kind");if(!n||!o||!r||!s)throw new x('usage: moa reply <thread> <from> --kind <question|answer|finding|done> "<body>"');let a=G(C(e,"json")),c=await(await jt(e,t)).post(`/v1/delegations/${n}/messages`,{from:o,kind:s,body:r});if(!c.delivered)return lr(c,a,`${o} \u2192 thread`);let i=c.delegation?.closedAt?"closed":c.delegation?.blockedBy?"BLOCKED":"open",l=s==="done"?"finished":`sent ${/^[aeiou]/.test(s)?"an":"a"} ${s}`;return a.line(`${o} ${l} \u2014 the delegation is ${i}`),a.data(c),y.ok}function lr(e,t,n){if(e.delivered)return t.line(`${n}: delivered`),t.data(e),y.ok;let o=e.reason??"the bus refused it";t.warn(`moa: not delivered \u2014 ${o}`);let r=Us(o);t.warn(` ${r.say}`);for(let s of r.run)t.warn(` ${s}`);return t.data(e),y.halted}var bn=e=>e.replace(/\s+/g," ").trim();De();Ze();yn();var Rc=`usage: moa manager say "<text>" [--timeout s]
150
+ `)}}}function xs(e){if(e instanceof A)return{message:e.message,code:k.misuse};if(e instanceof Xn)return{message:e.message,code:k.halted};if(e instanceof ie){let t=e.status>=500&&e.requestId?` (request ${e.requestId})`:"";if(e.status===503)return{message:`the workspace is up and cannot work \u2014 ${e.message}. Look at the database it was started with, not the process.${t}`,code:k.failed};if(e.status===429)return{message:e.message,code:k.halted};let n=e.status===401||e.status===403||e.status===400?k.misuse:k.failed;return{message:`${e.message}${t}`,code:n}}return{message:e instanceof Error?e.message:String(e),code:k.failed}}function ke(e){if(e.length===0)return"";let t=[];for(let n of e)n.forEach((o,r)=>{t[r]=Math.max(t[r]??0,o.length)});return e.map(n=>n.map((o,r)=>r===n.length-1?o:o.padEnd(t[r]??0)).join(" ").trimEnd()).join(`
151
+ `)}var Xe=(e,t)=>`${e.padEnd(10)}${t}`,Y=(e,t=60)=>e.length>t?`${e.slice(0,t-1)}\u2026`:e,sr=e=>{let t=e.split(/\n\s*\n/).filter(n=>n.trim().length>0);return(t[t.length-1]??e).trim()};import{hostname as Cc}from"node:os";Ue();Ye();var Pc="usage: moa login <url> --token <token> or moa login <url> --github";async function Cs(e,t=process.env,n={}){let o=E(e,"json"),r=G(o),s=e.flags.get("github"),a=e.positional[1]??(typeof s=="string"?s:void 0);if(!a)throw new A(Pc);if(s!==void 0&&e.flags.has("token"))throw new A("--token and --github are two ways in \u2014 use one");let c=a.replace(/\/+$/,""),i=n.fetch??fetch;if(s!==void 0){let y=await _c(c,w=>o?r.warn(w):r.line(w),{...n,fetch:i}),b=await As(t,P(e,"profile"),{url:c,token:y.token}),m=y.role==="viewer"?", read-only: you may look and nothing else":"";return r.line(`logged in to ${c} as ${y.login}, ${y.role} on ${y.tenant} (profile ${b}${m})`),r.data({url:c,tenant:y.tenant,profile:b,login:y.login,role:y.role}),k.ok}let l=P(e,"token")??t.MOA_TOKEN;if(!l)throw new A("--token is required (or set MOA_TOKEN), or sign in with --github");let d={url:c,token:l},u=await N(d,i).get("/v1/whoami"),f=await As(t,P(e,"profile"),d),p=u.scope==="read"?", read-only: it may look and nothing else":"";return r.line(`logged in to ${d.url} as ${u.tenant} (profile ${f}${p})`),r.data({url:d.url,tenant:u.tenant,profile:f,...u.scope===void 0?{}:{scope:u.scope}}),0}async function As(e,t,n){let o=t??"default",r=await xe(e);return r.profiles[o]=n,r.current=o,await ht(r,e),o}var Es=async e=>{let t=await e.text().catch(()=>"");try{return JSON.parse(t).error??t}catch{return t}};async function _c(e,t,n){let o=n.sleep??(d=>new Promise(u=>setTimeout(u,d))),r=async(d,u)=>{try{return await n.fetch(`${e}${d}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(u??{})})}catch(f){throw new Ot(e,f)}},s=await r("/v1/access/device");if(!s.ok){let d=await Es(s);throw new Error(s.status===503||s.status===404?`${e} has no GitHub sign-in${d?` (${d})`:""} \u2014 ask its owner to create the GitHub App in \`moa setup\`, or log in with --token`:`${e} would not start a GitHub sign-in: ${d||s.status}`)}let a=await s.json();t(`open ${a.verificationUri} and enter ${a.userCode}`),t("waiting for GitHub\u2026");let c=`${(n.hostname??Cc)()} cli`,i=Math.max(a.interval??5,1),l=(a.expiresIn??900)+30;for(;;){await o(i*1e3),l-=i;let d=await r("/v1/access/device/token",{deviceCode:a.deviceCode,name:c});if(d.status===201)return await d.json();if(d.status===202){let f=await d.json().catch(()=>({}));if(i=Math.max(i,f.interval??i),l<=0)throw new Error("the code expired before it was entered \u2014 run moa login again");continue}if(d.status===429){if(i=Math.min(i*2,60),l<=0)throw new Error("the code expired before it was entered \u2014 run moa login again");continue}let u=await Es(d)||`the workspace said ${d.status}`;throw d.status===403?new ie(403,`${u} \u2014 ask an owner to add your GitHub login on Access`):d.status===410?new ie(410,`${u} \u2014 run moa login again for a new code`):new ie(d.status,u)}}function rt(e,t=new Date){if(!e)return;let n=Date.parse(e);if(Number.isNaN(n))return;let o=Math.max(0,Math.round((t.getTime()-n)/1e3));if(o<60)return`${o}s`;let r=Math.floor(o/60);if(r<60)return`${r}m`;let s=Math.floor(r/60);return s<24?`${s}h ${r%60}m`:`${Math.floor(s/24)}d ${s%24}h`}function ar(e,t=new Date){if(!e)return;let n=Date.parse(e);if(!(Number.isNaN(n)||n<=t.getTime()))return rt(t.toISOString(),new Date(n))}async function Ps(e,t=process.env){let n=G(E(e,"json")),o=await re(P(e,"profile"),t),r=await N(o).get("/v1/whoami"),s=r.scope==="read"?", read-only":"";return n.line(`${r.tenant} at ${o.url} (profile ${o.name}${s})`),n.data({tenant:r.tenant,url:o.url,profile:o.name,...r.scope===void 0?{}:{scope:r.scope}}),0}async function _s(e,t=process.env){let n=G(E(e,"json")),o=e.positional[1]??P(e,"url"),r=o?{url:o,token:""}:await re(P(e,"profile"),t);try{let s=await N(r).get("/health"),a=rt(s.startedAt);return n.line(`${r.url} ${s.ok?"ok":"not ok"} (${s.database}, v${s.version}${a?`, up ${a}`:""})`),n.data(s),s.ok?k.ok:k.failed}catch(s){if(s instanceof ie&&s.status===503)return n.warn(`moa: ${r.url} is up and cannot work \u2014 ${s.message}`),n.data({ok:!1,url:r.url,status:503,error:s.message}),k.failed;throw s}}function Oc(e,t,n){let o=e.missingTools??[],r=t.filter(s=>s.installed===!1).map(s=>s.cli);return[{name:"this token",ok:n!=="read",detail:n==="read"?"read-only: it may look, and every run, message and grant is refused":`${e.tenant}, and it may start work`},{name:"runs agents",ok:e.runsAgents,detail:e.runsAgents?`${e.database}, v${e.version}${rt(e.startedAt)?`, up ${rt(e.startedAt)}`:""}`:"a Worker: it serves the store, and the runs belong to the container beside it"},{name:"last restart",ok:!0,detail:(()=>{let s=rt(e.restart?.at??e.startedAt),a=e.restart?.cutShort??0;return s?a===0?`${s} ago, and nothing was cut short by it`:`${s} ago; ${a} run${a===1?"":"s"} did not survive it`:"this workspace has not said when it started"})()},{name:"seat capacity",ok:!t.every(s=>s.full===!0),detail:(()=>{let s=t.filter(a=>a.full===!0).map(a=>a.cli);return s.length===0?"room on every seat":s.length===t.length?"every seat is spent \u2014 nothing runs until a window resets":`${s.join(", ")} spent; room on the rest`})()},{name:"whose login",ok:!0,detail:t.length===0?"no seats: this tenant cannot run anything":t.every(s=>s.hasCredential)?"your own credential on every CLI":t.some(s=>s.hasCredential)?`your own on ${t.filter(s=>s.hasCredential===!0).map(s=>s.cli).join(", ")}; the machine's login on the rest`:"the machine's login, shared with every tenant on this workspace"},{name:"run ceiling",ok:!0,detail:e.runTimeoutMinutes===void 0?"this workspace does not say":e.runTimeoutMinutes===0?"no cap: a run that hangs holds its agent until somebody stops it":`a run is stopped after ${e.runTimeoutMinutes} minute(s)`},{name:"agent CLIs",ok:r.length<t.length,detail:(()=>{let s=t.filter(a=>a.installed!==!1).map(a=>a.cli);return r.length===0?s.join(", "):s.length===0?`none: missing ${r.join(", ")}`:`${s.join(", ")} \u2014 missing ${r.join(", ")}`})()},...e.agentBudget?[{name:"agent budget",ok:e.agentBudget.ok,detail:e.agentBudget.ok?`$${e.agentBudget.spentUsd.toFixed(4)} of today's $${e.agentBudget.limitUsd.toFixed(2)} spent asking each other`:e.agentBudget.reason??"today's budget is spent"}]:[],...e.agentTools?[{name:"agent tools",ok:e.agentTools.reachable,detail:e.agentTools.reachable?`${e.agentTools.tools?.length??0} at ${e.agentTools.url}`+(e.agentTools.unwired.length>0?` \u2014 not on ${e.agentTools.unwired.join(", ")}`:""):`${e.agentTools.url}: ${e.agentTools.problem??"no answer"}`}]:[],{name:"repository",ok:!!e.repo,detail:e.repo??"none configured \u2014 pipelines need MOA_REPO"},{name:"checkout",ok:e.hasCheckout,detail:e.checkoutProblem??"a git checkout the pipeline can work in"},{name:"git and gh",ok:o.length===0,detail:o.length===0?"both on its PATH":`missing ${o.join(", ")}`},{name:"github login",ok:e.githubAuthenticated!==!1,detail:e.githubAuthenticated===!1?"gh has no token there \u2014 run `gh auth login` where the workspace runs":"gh has a token"}]}async function Os(e,t=process.env){let n=G(E(e,"json")),o=N(await re(P(e,"profile"),t)),[r,s,a]=await Promise.all([o.get("/v1/workspace"),o.get("/v1/seats"),o.get("/v1/whoami").catch(()=>({scope:void 0}))]),c=Oc(r,s.seats.map(l=>({...l,full:l.limit!==void 0&&(l.used??0)>=l.limit})),a.scope);for(let l of c)n.line(`${l.ok?"ok ":"NO "}${l.name.padEnd(14)}${l.detail}`);let i=c.filter(l=>!l.ok);return n.data({tenant:r.tenant,checks:c}),i.length===0?k.ok:k.halted}async function Ts(e,t=process.env){let n=G(E(e,"json")),o=N(await re(P(e,"profile"),t)),{seats:r}=await o.get("/v1/seats");if(r.length===0)return n.warn("no seats \u2014 this tenant cannot run anything"),n.data({seats:[]}),1;for(let s of r){let a=s.limit?`${s.used}/${s.limit}`:`${s.used}`,c=ar(s.resetsAt),i=s.limit!==void 0&&s.used>=s.limit,l=s.resetsAt?`${i?" \xB7 full":""}, resets${c?` in ${c}`:" shortly"}`:"",d=s.installed===!1?" \xB7 not installed":"";n.line(`${s.cli.padEnd(8)} ${a.padEnd(8)} ${Tc(s)}${l}${d}`)}return n.data({seats:r}),0}var Tc=e=>e.hasCredential?"your own credential":"the machine's login, shared with every tenant here";async function Is(e,t=process.env){let n=G(E(e,"json")),o=await xe(t),r=Object.keys(o.profiles);r.length===0&&n.line("no workspace yet \u2014 run `moa login <url> --token <token>`");for(let s of r)n.line(`${s===o.current?"*":" "} ${s} ${o.profiles[s]?.url}`);return n.data({current:o.current,profiles:r.map(s=>({name:s,url:o.profiles[s]?.url}))}),0}async function Rs(e,t=process.env){let n=G(E(e,"json")),o=await xe(t),r=e.positional[1]??o.current;if(!o.profiles[r]){let a=Object.keys(o.profiles);throw new A(a.length===0?"no workspace is saved":`no profile named ${r} \u2014 there is ${a.join(", ")}`)}delete o.profiles[r];let s=Object.keys(o.profiles);return o.current===r&&(o.current=s[0]??"default"),await ht(o,t),n.data({forgot:r,current:o.current,profiles:s}),n.line(`forgot ${r} \u2014 its token is no longer on this machine`),s.length===0?n.line("no workspace left \u2014 `moa login <url> --token <token>`"):r!==o.current?n.line(`now using ${o.current}`):n.line(`now using ${o.current}`),k.ok}async function Ls(e,t=process.env){let n=e.positional[1];if(!n)throw new A("usage: moa use <profile>");let o=G(E(e,"json")),r=await xe(t),s=r.profiles[n];if(!s){let c=Object.keys(r.profiles);throw new A(c.length===0?`no profile named ${n} \u2014 run \`moa login <url> --token <token>\` first`:`no profile named ${n} \u2014 there is ${c.join(", ")}`)}r.current=n,await ht(r,t);let a=await N(s).get("/v1/whoami").catch(()=>{});return o.line(`now using ${n} \u2014 ${s.url}${a?` as ${a.tenant}`:""}`),o.data({profile:n,url:s.url,...a?{tenant:a.tenant}:{}}),k.ok}function Ic(e,t=new Date){let n=/^(\d+)([hd])$/.exec(e.trim());if(!n?.[1])return e;let o=Number(n[1])*(n[2]==="d"?24:1);return new Date(t.getTime()-o*36e5).toISOString()}async function Ds(e,t=process.env){let n=G(E(e,"json")),o=N(await re(P(e,"profile"),t)),r=P(e,"since"),s=r===void 0?void 0:Ic(r),a=s===void 0?"/v1/spend":`/v1/spend?since=${encodeURIComponent(s)}`,[c,i]=await Promise.all([o.get(a),o.get("/v1/workspace").catch(()=>{})]);n.data({...c,...i?.agentBudget?{agentBudget:i.agentBudget}:{}});let l=d=>`$${d.toFixed(4)}`;if(n.line(`${l(c.costUsd)} over ${c.runs} ${c.runs===1?"run":"runs"}`+(s===void 0?"":`, since ${s}`)),n.line("notional \u2014 what the CLIs reported, not a bill"),i?.agentBudget){let d=i.agentBudget;n.line(d.ok?`today, agents have spent $${d.spentUsd.toFixed(4)} of $${d.limitUsd.toFixed(2)} asking each other`:`agents are at today's ceiling: $${d.spentUsd.toFixed(4)} of $${d.limitUsd.toFixed(2)} \u2014 calls are refused until UTC midnight`)}return c.runs===0?k.ok:(n.line(""),n.line(ke([["AGENT","RUNS","COST"],...c.byAgent.map(d=>[d.agent,String(d.runs),l(d.costUsd)])])),n.line(""),n.line(ke([["WHAT ASKED","RUNS","COST"],...c.byCause.map(d=>[d.cause,String(d.runs),l(d.costUsd)])])),k.ok)}async function Ns(e,t=process.env){let n=e.positional[1],o=N(await re(P(e,"profile"),t)),r=G(E(e,"json"));switch(n){case"create":return Rc(o,e,r);case"list":case"ls":return Lc(o,r);case"show":return Dc(o,e,r);case"role":return Uc(o,e,r);case"grant":return Us(o,e,r,"grant");case"revoke":return Us(o,e,r,"revoke");case"rm":case"remove":return Nc(o,e,r);default:throw new A(`usage: moa agent <create|list|show|role|grant|revoke|rm> \u2026
152
+ moa agent create reviewer --cli codex --role "\u2026" --peers builder,planner`)}}async function Rc(e,t,n){let o=t.positional[2],r=P(t,"cli");if(!o)throw new A("usage: moa agent create <name> --cli <cli> [--role \u2026] [--peers a,b]");if(!r)throw new A("--cli is required (claude, codex, cursor, amp, gemini, crush)");let s=(P(t,"peers")??"").split(",").map(c=>c.trim()).filter(Boolean),a=await e.post("/v1/agents",{name:o,cli:r,...P(t,"role")===void 0?{}:{role:P(t,"role")},...s.length===0?{}:{peers:s}});return n.line(`created ${a.name} (${a.cli})`),s.length>0&&n.line(` may open a thread with: ${s.join(", ")}`),n.data(a),0}async function Lc(e,t){let[{agents:n},o]=await Promise.all([e.get("/v1/agents"),e.get("/v1/mail").catch(()=>{})]),r=new Map((o?.waiting??[]).map(s=>[s.to,s]));return n.length===0?t.line("no agents yet \u2014 moa agent create <name> --cli claude"):t.line(ke([["NAME","CLI","STATUS","MAIL","ROLE"],...n.map(s=>{let a=r.get(s.name);return[s.name,s.cli,s.status,a?`${a.unread} \xB7${rt(a.oldest)??"?"}`:"\u2014",Y(s.role??"\u2014",40)]})])),t.data({agents:n,waiting:o?.waiting??[]}),0}async function Dc(e,t,n){let o=t.positional[2];if(!o)throw new A("usage: moa agent show <name>");let[r,s]=await Promise.all([e.get(`/v1/agents/${o}`),e.get(`/v1/agents/${o}/history`)]);n.line(Xe("name",r.name)),n.line(Xe("cli",r.cli)),n.line(Xe("status",r.status)),n.line(Xe("role",r.role??"\u2014"));let a=s.peers.filter(i=>!i.revokedAt).map(i=>i.to),c=s.peers.filter(i=>i.revokedAt).map(i=>`${i.to} (revoked)`);return n.line(Xe("peers",[...a,...c].join(", ")||"\u2014")),s.history.length>0&&(n.line(""),n.line(ke(s.history.map(i=>[i.at.slice(0,19).replace("T"," "),i.kind,i.actor,Y(i.detail??"",40)])))),n.data({agent:r,...s}),0}async function Uc(e,t,n){let o=t.positional[2],r=t.positional[3]??P(t,"role");if(!o||!r)throw new A('usage: moa agent role <name> "what it is for"');let s=await e.patch(`/v1/agents/${o}`,{role:r});return n.line(`${s.name} is now: ${Y(s.role??"",60)}`),n.data(s),0}async function Us(e,t,n,o){let r=t.positional[2],s=t.positional[3];if(!r||!s)throw new A(`usage: moa agent ${o} <from> <to>`);return o==="grant"?(await e.post(`/v1/agents/${r}/peers`,{to:s}),n.line(`${r} may now open a thread with ${s}`)):(await e.del(`/v1/agents/${r}/peers/${s}`),n.line(`${r} may no longer open a thread with ${s}`)),n.data({from:r,to:s,granted:o==="grant"}),0}async function Nc(e,t,n){let o=t.positional[2];if(!o)throw new A("usage: moa agent rm <name>");return await e.del(`/v1/agents/${o}`),n.line(`released ${o}'s workspace \u2014 its runs, mail and edges remain`),n.data({released:o}),0}async function Ms(e,t=process.env){let n=N(await re(P(e,"profile"),t)),o=G(E(e,"json")),r=E(e,"all"),{peers:s}=await n.get("/v1/peers"),a=r?s:s.filter(i=>!i.revokedAt);if(o.data({peers:a}),a.length===0)return o.line(r?"no edges have ever been granted":"no edges \u2014 mail bounces, and only a team loop's own replies move"),k.ok;let c=new Set(s.filter(i=>!i.revokedAt).map(i=>`${i.from}\0${i.to}`));return o.line(ke([["FROM","TO","GRANTED","BY","NOTE"],...a.map(i=>[i.from,i.to,i.grantedAt.slice(0,19).replace("T"," "),i.grantedBy,i.revokedAt?`revoked ${i.revokedAt.slice(0,19).replace("T"," ")}`:c.has(`${i.to}\0${i.from}`)?"":"one way"])])),k.ok}Ue();Ye();var Kt=async(e,t)=>N(await re(P(e,"profile"),t)),ir="mesh";function Gs(e){let t=/^(\S+) may not open a thread with (.+)$/.exec(e);return t?.[1]&&t[2]?{say:"Nobody granted that edge:",run:t[2].split(",").map(n=>`moa agent grant ${t[1]} ${n.trim()}`)}:/^fanout of \d+ exceeds/.test(e)?{say:"Too many recipients at once. Send to fewer, or send twice.",run:[]}:/^body of \d+ exceeds/.test(e)?{say:"The message is too long for the bus. Say less, or link to it.",run:[]}:/hit maxHops/.test(e)?{say:"This conversation is over its budget. Start a new thread.",run:[]}:/exceeds maxDepth/.test(e)?{say:"Delegations are nested too deep. Hand this one back up.",run:[]}:/cannot address itself/.test(e)?{say:"An agent cannot send itself mail. Give it work instead.",run:[]}:e==="no recipient"?{say:"Nobody was named.",run:[]}:{say:"The bus refused it. Nothing was delivered.",run:[]}}function ko(e){if(e.from===ir)return/^undelivered:\s*(.+)$/s.exec(e.body)?.[1]?.trim()}async function js(e,t=process.env){let[,n,o,r]=e.positional;if(!n||!o||!r)throw new A('usage: moa send <from> <a,b,c> "<body>"');let s=o.split(",").map(i=>i.trim()).filter(Boolean);if(s.length===0)throw new A("name at least one recipient");let a=G(E(e,"json")),c=await(await Kt(e,t)).post("/v1/messages",{from:n,to:s.length===1?s[0]:s,body:r,...P(e,"thread")===void 0?{}:{thread:P(e,"thread")}});return cr(c,a,`${n} \u2192 ${s.join(", ")}`)}async function Hs(e,t=process.env){let n=e.positional[1];if(!n)return Mc(e,t);let o=G(E(e,"json")),{messages:r}=await(await Kt(e,t)).get(`/v1/agents/${n}/inbox`);if(r.length===0)o.line(`${n} has no unread mail`);else{o.line(ke([["FROM","KIND","BODY"],...r.map(s=>{let a=ko(s);return[s.from,a?"undelivered":s.kind??"status",Y(xn(a??s.body),60)]})]));for(let s of r){let a=ko(s);if(!a)continue;let c=Gs(a);o.line(""),o.line(c.say);for(let i of c.run)o.line(` ${i}`)}}return o.data({messages:r}),0}async function Mc(e,t){let n=G(E(e,"json")),{waiting:o}=await(await Kt(e,t)).get("/v1/mail");return n.data({waiting:o}),o.length===0?(n.line("nobody has unread mail"),k.ok):(n.line(ke([["AGENT","UNREAD","WAITING","FROM"],...o.map(r=>[r.to,String(r.unread),rt(r.oldest)??"\u2014",r.from])])),o.some(r=>r.from===ir)&&(n.line(""),n.line(`${ir} is the bus: that mail never arrived. moa inbox <name> says why.`)),k.ok)}async function Fs(e,t=process.env){let n=e.positional[1];if(!n)throw new A("usage: moa mail <name> [--limit n]");let o=G(E(e,"json")),r=de(e,"limit")??20,{messages:s}=await(await Kt(e,t)).get(`/v1/agents/${n}/messages?limit=${r}`);return o.data({messages:s}),s.length===0?(o.line(`nothing has been said to ${n} yet`),k.ok):(o.line(ke([["WHEN","WITH","KIND","BODY"],...s.map(a=>[a.createdAt.slice(0,19).replace("T"," "),a.from===n?`\u2192 ${a.to}`:`\u2190 ${a.from}`,(ko(a)?"undelivered":a.kind??"status")+(a.deliveredAt?"":" \xB7unread"),Y(xn(ko(a)??a.body),56)])])),k.ok)}async function Ks(e,t=process.env){let[,n,o,r]=e.positional;if(!n||!o||!r)throw new A('usage: moa delegate <from> <to> "<task>"');let s=G(E(e,"json")),a=await(await Kt(e,t)).post("/v1/delegations",{from:n,to:o,task:r,...P(e,"parent")===void 0?{}:{parent:P(e,"parent")}});return a.delivered?(s.line(`${n} handed "${Y(r,50)}" to ${o}`),s.line(` thread ${a.thread}`),s.line(` ${n} answers for it until ${o} says done`),s.data(a),k.ok):cr(a,s,`${n} \u2192 ${o}`)}async function Bs(e,t=process.env){let n=G(E(e,"json")),o=await(await Kt(e,t)).get("/v1/delegations"),r=E(e,"blocked")?o.delegations.filter(s=>s.blockedBy):o.delegations;if(r.length===0)n.line(E(e,"blocked")?"nothing is blocked":"nothing is open");else{n.line(ke([["FROM","TO","STATE","TASK"],...r.map(s=>[s.from,s.to,s.blockedBy?"BLOCKED":"open",Y(xn(s.task),44)])]));for(let s of r.filter(a=>a.blockedBy))n.line(""),n.line(`${s.to} is waiting on an answer:`),n.line(` "${Y(xn(s.blockedBy?.body??""),70)}"`),n.line(` moa reply ${s.thread} ${s.from} --kind answer "\u2026"`)}return n.data(o),0}async function Ws(e,t=process.env){let n=e.positional[1];if(!n)throw new A("usage: moa thread <thread>");let o=G(E(e,"json")),r=await(await Kt(e,t)).get(`/v1/delegations/${n}`),{delegation:s}=r;if(o.line(Xe("task",Y(xn(s.task),60))),o.line(Xe("from",s.from)),o.line(Xe("to",s.to)),o.line(Xe("state",s.closedAt?"closed":s.blockedBy?"BLOCKED":"open")),s.hops!==void 0&&s.maxHops!==void 0){let a=s.hops>=s.maxHops;o.line(Xe("hops",a?`${s.hops}/${s.maxHops} \u2014 spent, nothing more can be said in it`:`${s.hops}/${s.maxHops}`))}if(s.depth!==void 0&&s.maxDepth!==void 0){let a=s.depth>=s.maxDepth;o.line(Xe("depth",a?`${s.depth}/${s.maxDepth} \u2014 it cannot be handed on again`:`${s.depth}/${s.maxDepth}`))}o.line("");for(let a of r.messages)o.line(`${a.from} \xB7 ${a.kind??"status"}`),o.line(` ${xn(a.body)}`);return o.data(r),0}async function Js(e,t=process.env){let[,n,o,r]=e.positional,s=P(e,"kind");if(!n||!o||!r||!s)throw new A('usage: moa reply <thread> <from> --kind <question|answer|finding|done> "<body>"');let a=G(E(e,"json")),c=await(await Kt(e,t)).post(`/v1/delegations/${n}/messages`,{from:o,kind:s,body:r});if(!c.delivered)return cr(c,a,`${o} \u2192 thread`);let i=c.delegation?.closedAt?"closed":c.delegation?.blockedBy?"BLOCKED":"open",l=s==="done"?"finished":`sent ${/^[aeiou]/.test(s)?"an":"a"} ${s}`;return a.line(`${o} ${l} \u2014 the delegation is ${i}`),a.data(c),k.ok}function cr(e,t,n){if(e.delivered)return t.line(`${n}: delivered`),t.data(e),k.ok;let o=e.reason??"the bus refused it";t.warn(`moa: not delivered \u2014 ${o}`);let r=Gs(o);t.warn(` ${r.say}`);for(let s of r.run)t.warn(` ${s}`);return t.data(e),k.halted}var xn=e=>e.replace(/\s+/g," ").trim();Ue();Ye();Sn();var Gc=`usage: moa manager say "<text>" [--timeout s]
152
153
  moa manager proposals
153
154
  moa manager approve <id>
154
155
  moa manager dismiss <id>
155
- moa manager watch`;async function Ws(e,t=process.env){let n=e.positional[1],o={say:Lc,proposals:Nc,approve:(a,c,i)=>Bs(a,c,i,"approve"),dismiss:(a,c,i)=>Bs(a,c,i,"dismiss"),watch:Fc},r=n!==void 0&&Object.hasOwn(o,n)?o[n]:void 0;if(!r)throw new x(Rc);if(n!=="say"&&e.flags.has("timeout"))throw new x(`moa manager ${n} has no --timeout`);let s=U(await te(P(e,"profile"),t));return r(s,G(C(e,"json")),e)}async function Lc(e,t,n){let o=n.positional.slice(2).join(" ").trim();if(!o)throw new x('usage: moa manager say "<text>" [--timeout s]');let r=ce(n,"timeout");if(n.flags.has("timeout")&&(r===void 0||r<0))throw new x("--timeout takes a number of seconds, zero or more");let s=r??600,a=new Set((await e.get("/v1/manager/messages")).messages.map(u=>u.id)),{id:c}=await e.post("/v1/manager/messages",{body:o}),i=Date.now()+s*1e3,l=250,d;for(;;){let u=await e.get("/v1/manager/messages").then(p=>p.messages).catch(p=>{if(!(p instanceof Pt))throw p;if(d??=Date.now()+sr,!(Date.now()<d&&Date.now()<i))throw p});u!==void 0&&(d=void 0);let f=u===void 0?void 0:typeof c=="string"?Dc(u,c):Uc(u,a,o);if(f)return Mc(e,t,f);if(u!==void 0&&Date.now()>i)return t.warn(`moa: the Manager has not answered after ${s}s \u2014 it is still thinking, and its answer will be in the console's chat`),y.halted;await new Promise(p=>setTimeout(p,l)),l=Math.min(l*1.5,2e3)}}function Dc(e,t){return e.find(n=>n.from==="manager"&&n.answers===t)}function Uc(e,t,n){let o=e.filter(s=>!t.has(s.id)),r=o.findIndex(s=>s.from==="you"&&s.body.trim()===n);if(r!==-1)return o.slice(r+1).find(s=>s.from==="manager")}async function Mc(e,t,n){let o=n.proposals??[],r=o.length===0?[]:await e.get("/v1/manager/proposals").then(l=>l.proposals).catch(()=>[]),s=o.map(l=>r.find(d=>d.id===l)??{id:l}),a=s.filter(l=>l.state==="waiting"),c=s.filter(l=>l.state===void 0||l.state==="open"),i=l=>l.title??l.kind??"a proposal";if(n.failed?t.warn(`moa: ${n.body}`):t.line(n.body),c.length>0){n.failed||t.line(""),t.line(n.failed?"Before it failed, it proposed:":"It proposes:");for(let l of c)t.line(` ${i(l)}`),t.line(` moa manager approve ${l.id}`)}if(a.length>0){t.line(""),t.line("Set up for later:");for(let l of a)t.line(` ${i(l)}`),t.line(` moa manager dismiss ${l.id}`)}return t.data({message:n,proposals:s}),n.failed?y.failed:y.ok}async function Nc(e,t){let n=await e.get("/v1/manager/proposals?state=open");return t.data(n),n.proposals.length===0?(t.line("nothing is waiting for you"),y.ok):(t.line(be([["KIND","WHERE","WHAT","WHY","ID"],...n.proposals.map(o=>[o.kind,jc(o),Y(o.title,50),Y(o.why.replace(/\s+/g," "),50),o.id])])),y.ok)}var jc=e=>e.repo?`${e.repo}${e.issue?`#${e.issue}`:""}`:"";async function Bs(e,t,n,o){let r=n.positional[2];if(!r)throw new x(`usage: moa manager ${o} <id>`);let s=await Hc(e,r,o);if(o==="dismiss"){let c=await e.post(`/v1/manager/proposals/${encodeURIComponent(s)}/dismiss`,{});return t.line(`dismissed: ${c.title}`),t.data(c),y.ok}let a;try{a=await e.post(`/v1/manager/proposals/${encodeURIComponent(s)}/approve`,{})}catch(c){let i=c instanceof ae&&c.status===502?Gc(c):void 0;if(!i)throw c;return t.warn(`moa: ${i.title} failed${i.result?` \u2014 ${i.result}`:""}`),t.data(i),y.failed}return t.line(`${a.state==="waiting"?"approved, for later":"approved"}: ${a.title}`),a.result&&t.line(` ${a.result}`),t.data(a),y.ok}function Gc(e){try{let t=JSON.parse(e.message);return typeof t.id=="string"&&typeof t.title=="string"?t:void 0}catch{return}}async function Hc(e,t,n){let o=n==="dismiss"?["open","waiting"]:["open"],s=(await Promise.all(o.map(c=>e.get(`/v1/manager/proposals?state=${c}`)))).flatMap(c=>c.proposals.map(i=>i.id));if(s.includes(t))return t;let a=s.filter(c=>c.startsWith(t));if(a.length>1)throw new x(`${t} could be ${a.length} proposals \u2014 type more of the id`);if(a[0])return a[0];if(!/^[A-Za-z0-9_-]+$/.test(t))throw new x(`${t} is not a proposal's id`);return t}async function Fc(e,t){let n=await e.get("/v1/manager/watch");if(t.data(n),n.watching.length===0)return t.line("nothing is running"),y.ok;t.line(be([["HEALTH","KIND","WHAT","WHO","DOING","COST","JOB"],...n.watching.map(o=>[o.held?`${o.health} (held)`:o.health,o.kind,o.ref||Y(o.title,30),o.worker??"",Y(o.doing,40),`$${o.costUsd.toFixed(3)}`,o.job])]));for(let o of n.watching.filter(r=>r.health!=="ok"))t.line(""),t.line(`${o.ref||o.job}: ${o.note}`),o.suggest&&t.line(` it would say: ${o.suggest}`);return y.ok}import{chmod as Kc,writeFile as Bc}from"node:fs/promises";import{resolve as Wc}from"node:path";De();Ze();async function Js(e,t=process.env){let n=e.positional[1];if(!n)throw new x("usage: moa mcp <agent> [--file <path>]");let o=U(await te(P(e,"profile"),t)),r=G(C(e,"json"));if(C(e,"revoke")){let{revoked:f}=await o.del(`/v1/agents/${n}/mcp-token`);return r.data({revoked:f}),r.line(f===0?`${n} had no tokens out`:`took back ${f} token(s) \u2014 any config file holding one is now dead`),y.ok}let s=await o.get(`/v1/agents/${n}/mcp-token`),a=await o.post(`/v1/agents/${n}/mcp-token`,{}),i=(await o.rpc(a.url,a.token,"tools/list")).tools??[];r.data({url:a.url,expiresAt:a.expiresAt,tools:i.map(f=>f.name),outstanding:s.tokens.length}),r.line(`${n} reaches ${a.url}`);for(let f of i)r.line(` ${f.name.padEnd(12)}${f.description??""}`);i.length===0&&r.warn("moa: it answered, and offered no tools");let l=P(e,"file");if(!l)return await o.del(`/v1/agents/${n}/mcp-token/${a.id}`).catch(()=>{}),r.line(""),s.tokens.length>0&&r.line(`${s.tokens.length} token(s) already out, the last until ${s.tokens[s.tokens.length-1]?.expiresAt} \u2014 moa mcp ${n} --revoke takes them back`),r.line("--file <path> writes the config a CLI can load, with a token for this agent"),y.ok;let d={mcpServers:{fnmoa:{type:"http",url:a.url,headers:{Authorization:`Bearer ${a.token}`}}}},u=Wc(l);return await Bc(u,`${JSON.stringify(d,null,2)}
156
- `,{mode:384}),await Kc(u,384),r.line(""),r.line(`wrote ${u} \u2014 mode 0600, and it expires ${a.expiresAt}`),r.line(` claude --mcp-config ${u} --strict-mcp-config --allowedTools mcp__fnmoa`),y.ok}De();Ze();yn();async function*Vn(e,t){let n=e.body;if(!n)return;let o=n.getReader(),r=new TextDecoder,s="";try{for(;!t?.aborted;){let{value:a,done:c}=await o.read();if(c)break;s+=r.decode(a,{stream:!0});let i=s.indexOf(`
156
+ moa manager watch`;async function zs(e,t=process.env){let n=e.positional[1],o={say:jc,proposals:Bc,approve:(a,c,i)=>qs(a,c,i,"approve"),dismiss:(a,c,i)=>qs(a,c,i,"dismiss"),watch:zc},r=n!==void 0&&Object.hasOwn(o,n)?o[n]:void 0;if(!r)throw new A(Gc);if(n!=="say"&&e.flags.has("timeout"))throw new A(`moa manager ${n} has no --timeout`);let s=N(await re(P(e,"profile"),t));return r(s,G(E(e,"json")),e)}async function jc(e,t,n){let o=n.positional.slice(2).join(" ").trim();if(!o)throw new A('usage: moa manager say "<text>" [--timeout s]');let r=de(n,"timeout");if(n.flags.has("timeout")&&(r===void 0||r<0))throw new A("--timeout takes a number of seconds, zero or more");let s=r??600,a=new Set((await e.get("/v1/manager/messages")).messages.map(u=>u.id)),{id:c}=await e.post("/v1/manager/messages",{body:o}),i=Date.now()+s*1e3,l=250,d;for(;;){let u=await e.get("/v1/manager/messages").then(p=>p.messages).catch(p=>{if(!(p instanceof Ot))throw p;if(d??=Date.now()+rr,!(Date.now()<d&&Date.now()<i))throw p});u!==void 0&&(d=void 0);let f=u===void 0?void 0:typeof c=="string"?Hc(u,c):Fc(u,a,o);if(f)return Kc(e,t,f);if(u!==void 0&&Date.now()>i)return t.warn(`moa: the Manager has not answered after ${s}s \u2014 it is still thinking, and its answer will be in the console's chat`),k.halted;await new Promise(p=>setTimeout(p,l)),l=Math.min(l*1.5,2e3)}}function Hc(e,t){return e.find(n=>n.from==="manager"&&n.answers===t)}function Fc(e,t,n){let o=e.filter(s=>!t.has(s.id)),r=o.findIndex(s=>s.from==="you"&&s.body.trim()===n);if(r!==-1)return o.slice(r+1).find(s=>s.from==="manager")}async function Kc(e,t,n){let o=n.proposals??[],r=o.length===0?[]:await e.get("/v1/manager/proposals").then(l=>l.proposals).catch(()=>[]),s=o.map(l=>r.find(d=>d.id===l)??{id:l}),a=s.filter(l=>l.state==="waiting"),c=s.filter(l=>l.state===void 0||l.state==="open"),i=l=>l.title??l.kind??"a proposal";if(n.failed?t.warn(`moa: ${n.body}`):t.line(n.body),c.length>0){n.failed||t.line(""),t.line(n.failed?"Before it failed, it proposed:":"It proposes:");for(let l of c)t.line(` ${i(l)}`),t.line(` moa manager approve ${l.id}`)}if(a.length>0){t.line(""),t.line("Set up for later:");for(let l of a)t.line(` ${i(l)}`),t.line(` moa manager dismiss ${l.id}`)}return t.data({message:n,proposals:s}),n.failed?k.failed:k.ok}async function Bc(e,t){let n=await e.get("/v1/manager/proposals?state=open");return t.data(n),n.proposals.length===0?(t.line("nothing is waiting for you"),k.ok):(t.line(ke([["KIND","WHERE","WHAT","WHY","ID"],...n.proposals.map(o=>[o.kind,Wc(o),Y(o.title,50),Y(o.why.replace(/\s+/g," "),50),o.id])])),k.ok)}var Wc=e=>e.repo?`${e.repo}${e.issue?`#${e.issue}`:""}`:"";async function qs(e,t,n,o){let r=n.positional[2];if(!r)throw new A(`usage: moa manager ${o} <id>`);let s=await qc(e,r,o);if(o==="dismiss"){let c=await e.post(`/v1/manager/proposals/${encodeURIComponent(s)}/dismiss`,{});return t.line(`dismissed: ${c.title}`),t.data(c),k.ok}let a;try{a=await e.post(`/v1/manager/proposals/${encodeURIComponent(s)}/approve`,{})}catch(c){let i=c instanceof ie&&c.status===502?Jc(c):void 0;if(!i)throw c;return t.warn(`moa: ${i.title} failed${i.result?` \u2014 ${i.result}`:""}`),t.data(i),k.failed}return t.line(`${a.state==="waiting"?"approved, for later":"approved"}: ${a.title}`),a.result&&t.line(` ${a.result}`),t.data(a),k.ok}function Jc(e){try{let t=JSON.parse(e.message);return typeof t.id=="string"&&typeof t.title=="string"?t:void 0}catch{return}}async function qc(e,t,n){let o=n==="dismiss"?["open","waiting"]:["open"],s=(await Promise.all(o.map(c=>e.get(`/v1/manager/proposals?state=${c}`)))).flatMap(c=>c.proposals.map(i=>i.id));if(s.includes(t))return t;let a=s.filter(c=>c.startsWith(t));if(a.length>1)throw new A(`${t} could be ${a.length} proposals \u2014 type more of the id`);if(a[0])return a[0];if(!/^[A-Za-z0-9_-]+$/.test(t))throw new A(`${t} is not a proposal's id`);return t}async function zc(e,t){let n=await e.get("/v1/manager/watch");if(t.data(n),n.watching.length===0)return t.line("nothing is running"),k.ok;t.line(ke([["HEALTH","KIND","WHAT","WHO","DOING","COST","JOB"],...n.watching.map(o=>[o.held?`${o.health} (held)`:o.health,o.kind,o.ref||Y(o.title,30),o.worker??"",Y(o.doing,40),`$${o.costUsd.toFixed(3)}`,o.job])]));for(let o of n.watching.filter(r=>r.health!=="ok"))t.line(""),t.line(`${o.ref||o.job}: ${o.note}`),o.suggest&&t.line(` it would say: ${o.suggest}`);return k.ok}import{chmod as Vc,writeFile as Yc}from"node:fs/promises";import{resolve as Xc}from"node:path";Ue();Ye();async function Vs(e,t=process.env){let n=e.positional[1];if(!n)throw new A("usage: moa mcp <agent> [--file <path>]");let o=N(await re(P(e,"profile"),t)),r=G(E(e,"json"));if(E(e,"revoke")){let{revoked:f}=await o.del(`/v1/agents/${n}/mcp-token`);return r.data({revoked:f}),r.line(f===0?`${n} had no tokens out`:`took back ${f} token(s) \u2014 any config file holding one is now dead`),k.ok}let s=await o.get(`/v1/agents/${n}/mcp-token`),a=await o.post(`/v1/agents/${n}/mcp-token`,{}),i=(await o.rpc(a.url,a.token,"tools/list")).tools??[];r.data({url:a.url,expiresAt:a.expiresAt,tools:i.map(f=>f.name),outstanding:s.tokens.length}),r.line(`${n} reaches ${a.url}`);for(let f of i)r.line(` ${f.name.padEnd(12)}${f.description??""}`);i.length===0&&r.warn("moa: it answered, and offered no tools");let l=P(e,"file");if(!l)return await o.del(`/v1/agents/${n}/mcp-token/${a.id}`).catch(()=>{}),r.line(""),s.tokens.length>0&&r.line(`${s.tokens.length} token(s) already out, the last until ${s.tokens[s.tokens.length-1]?.expiresAt} \u2014 moa mcp ${n} --revoke takes them back`),r.line("--file <path> writes the config a CLI can load, with a token for this agent"),k.ok;let d={mcpServers:{fnmoa:{type:"http",url:a.url,headers:{Authorization:`Bearer ${a.token}`}}}},u=Xc(l);return await Yc(u,`${JSON.stringify(d,null,2)}
157
+ `,{mode:384}),await Vc(u,384),r.line(""),r.line(`wrote ${u} \u2014 mode 0600, and it expires ${a.expiresAt}`),r.line(` claude --mcp-config ${u} --strict-mcp-config --allowedTools mcp__fnmoa`),k.ok}Ue();Ye();Sn();async function*Qn(e,t){let n=e.body;if(!n)return;let o=n.getReader(),r=new TextDecoder,s="";try{for(;!t?.aborted;){let{value:a,done:c}=await o.read();if(c)break;s+=r.decode(a,{stream:!0});let i=s.indexOf(`
157
158
 
158
- `);for(;i!==-1;){let l=s.slice(0,i);s=s.slice(i+2);let d=Jc(l);d&&(yield d),i=s.indexOf(`
159
+ `);for(;i!==-1;){let l=s.slice(0,i);s=s.slice(i+2);let d=Qc(l);d&&(yield d),i=s.indexOf(`
159
160
 
160
- `)}}}finally{await o.cancel().catch(()=>{})}}function Jc(e){let t="message",n,o=[];for(let r of e.split(`
161
+ `)}}}finally{await o.cancel().catch(()=>{})}}function Qc(e){let t="message",n,o=[];for(let r of e.split(`
161
162
  `)){if(r.startsWith(":")||r.trim()==="")continue;let s=r.indexOf(":"),a=s===-1?r:r.slice(0,s),c=s===-1?"":r.slice(s+1).replace(/^ /,"");a==="event"?t=c:a==="data"?o.push(c):a==="id"&&(n=c)}if(!(o.length===0&&t==="message"))return{event:t,data:o.join(`
162
- `),...n===void 0?{}:{id:n}}}De();Ze();yn();async function qs(e,t=process.env){if(e.positional[1]!=="work")throw new x('usage: moa team work <a,b,c> [--watch] [--max-turns n] [--nudge "\u2026"]');let n=(e.positional[2]??"").split(",").map(u=>u.trim()).filter(Boolean);if(n.length===0)throw new x("usage: moa team work <a,b,c>");let o=U(await te(P(e,"profile"),t)),r=G(C(e,"json")),s=new AbortController,a=C(e,"watch")?n.map(async u=>{let f=await o.stream(`/v1/agents/${u}/events`,s.signal);await Vc(f,s,r,u)}):[],c;try{c=await o.post("/v1/team/work",{agents:n,...ce(e,"max-turns")===void 0?{}:{maxTurns:ce(e,"max-turns")},...ce(e,"max-cost")===void 0?{}:{maxCostUsd:ce(e,"max-cost")},...P(e,"nudge")===void 0?{}:{nudge:P(e,"nudge")},...C(e,"route-replies")?{routeReplies:!0}:{}},$n(e))}catch(u){throw s.abort(),u}let i=kn(o,c.id,u=>r.warn(u)),l;try{l=await Nt(o,c.id,ce(e,"timeout")??3600,C(e,"watch")?u=>r.line(`\xB7 ${dr(u)}`):void 0)}finally{i.stop()}if(s.abort(),await Promise.allSettled(a),l.state==="failed")return r.warn(`moa: ${l.error??"the team loop failed"}`),r.data(l),y.failed;let d=l.result;r.line(`${d.outcome}: ${d.reason}`),r.line(` ${d.turns} turn(s), $${d.costUsd.toFixed(3)} notional`);for(let u of d.open)r.line(` still open: ${u.from} \u2192 ${u.to} ${Y(u.task,40)}`+(u.blockedBy?` BLOCKED: "${Y(u.blockedBy.body,40)}"`:""));return r.data(l),d.outcome==="settled"?y.ok:y.halted}async function zs(e,t=process.env){let n=Number(e.positional[1]);if(!Number.isInteger(n)||n<1)throw new x("usage: moa ship <issue>");let o=U(await te(P(e,"profile"),t)),r=G(C(e,"json")),s=C(e,"watch"),a=await o.post("/v1/pipelines",{issue:n,...P(e,"repo")===void 0?{}:{repo:P(e,"repo")},...ce(e,"max-steps")===void 0?{}:{maxSteps:ce(e,"max-steps")},...ce(e,"max-cost")===void 0?{}:{maxCostUsd:ce(e,"max-cost")}},$n(e));r.line(`shipping #${n} \u2014 ${a.id}`);let c=kn(o,a.id,d=>r.warn(d)),i;try{i=await Nt(o,a.id,ce(e,"timeout")??7200,s?d=>r.line(` ${dr(d)}`):void 0)}finally{c.stop()}if(i.state==="failed")return r.warn(`moa: ${i.error??"the pipeline failed"}`),r.data(i),y.failed;let l=i.result;return r.line(`${l.outcome}: ${l.reason}`),r.line(` ${l.steps} step(s), $${l.costUsd.toFixed(3)} notional`),r.data(i),l.outcome==="merged"?y.ok:y.halted}function dr(e){let t=[];return e.step&&t.push(e.step),e.steps!==void 0&&t.push(`${e.steps} step(s)`),e.costUsd!==void 0&&t.push(`$${e.costUsd.toFixed(3)}`),e.note&&t.push(e.note),t.join(" \xB7 ")}async function Vs(e,t=process.env){let n=U(await te(P(e,"profile"),t)),o=G(C(e,"json")),[r,s]=await Promise.all([n.get("/v1/jobs"),n.get("/v1/workspace").catch(()=>({runSlots:void 0}))]);o.data({...r,...s.runSlots?{runSlots:s.runSlots}:{}});let a=bo(s.runSlots);if(r.jobs.length===0)return o.line("nothing has run yet"),a&&o.line(a),y.ok;let c=r.jobs.some(i=>(i.issue?.pipelines??0)>1);return o.line(be([["STATE","KIND","WHAT","WHERE",...c?["ISSUE IN ALL"]:[],"JOB"],...r.jobs.map(i=>[i.state,i.kind,i.subject??i.agent??"",Y(zc(i),44),...c?[qc(i)]:[],i.id])])),a&&(o.line(""),o.line(a)),y.ok}function qc(e){let t=e.issue;if(!t)return"";let n=`${t.pipelines} pipeline${t.pipelines===1?"":"s"}`;return`$${t.costUsd.toFixed(2)} \xB7 ${t.steps} step${t.steps===1?"":"s"} \xB7 ${n}`}function bo(e){if(!e||e.ceiling===0||e.waiting===0&&e.running<e.ceiling)return;let t=e.waiting===0?"":`, ${e.waiting} ${e.waiting===1?"agent is":"agents are"} waiting for a slot`;return`${e.running} of ${e.ceiling} run slots in use${t}`}function zc(e){if(e.error)return e.error;if(e.state==="running")return e.progress?dr(e.progress):"";let t=e.result;return t?t.outcome?t.reason?`${t.outcome}: ${t.reason}`:t.outcome:t.reason?t.reason:t.answered?"answered":t.isError?"the agent reported an error":"":""}async function Ys(e,t=process.env){let n=e.positional[1];if(!n)throw new x("usage: moa stop <jobId>");let o=U(await te(P(e,"profile"),t)),r=G(C(e,"json")),s=await o.post(`/v1/jobs/${n}/cancel`,{});return r.line(s.cancelled?`stopping ${n} \u2014 after whatever it is doing now`:`${n} had already ${s.job.state==="running"?"gone":s.job.state}`),r.data(s),y.ok}async function Vc(e,t,n,o){try{for await(let r of Vn(e,t.signal)){if(r.event!=="activity")continue;let s=JSON.parse(r.data);n.line(` ${o}: ${s.tool?`${s.tool} `:""}${Y(String(s.text??""),80)}`)}}catch{}}var $n=e=>P(e,"key")??crypto.randomUUID();function $o(e){if(!e)return;let t=/^`(\S+)` exceeded its (\d+)ms timeout$/.exec(e.trim());if(!t?.[1]||!t[2])return;let n=Number(t[2])/6e4,o=n>=1?`${Number(n.toFixed(1))} minute(s)`:`${Number(t[2])/1e3} second(s)`;return`${t[1]} ran for ${o} without finishing, and the workspace stopped it`}async function Yc(e,t,n,o,r){let s=await e.post(`/v1/agents/${t}/runs`,{prompt:n},o).catch(()=>{});if(s)return r(s.state==="done"||s.state==="failed"?"the workspace restarted; this is what became of the run it had already started":"the workspace restarted, and nothing had been recorded \u2014 asking again"),s}async function Qs(e,t=process.env){let n=e.positional[1],o=e.positional[2];if(!n||!o)throw new x('usage: moa run <name> "<prompt>" [--watch]');let r=U(await te(P(e,"profile"),t)),s=G(C(e,"json")),a=C(e,"watch"),c=new AbortController,i=a?await r.stream(`/v1/agents/${n}/events?from=next`,c.signal):void 0,l;try{l=await r.post(`/v1/agents/${n}/runs`,{prompt:o},$n(e))}catch(g){throw c.abort(),g}if(C(e,"detach"))return c.abort(),s.line(`started ${l.id}`),s.data(l),y.ok;let d=i?ea(i,c,s,r):void 0,u=ol(r,c.signal,g=>s.line(g)),f=kn(r,l.id,g=>s.warn(g)),p;try{p=await Nt(r,l.id,ce(e,"timeout")??3600,void 0,()=>Yc(r,n,o,$n(e),g=>s.warn(g)))}finally{f.stop()}return c.abort(),await d,await u,f.asked()?(s.data(p),y.halted):rl(p,s)}var Zs="the workspace stopped while this run was going",Xc=e=>e===Zs||$o(e)!==void 0;async function Qc(e,t,n=new Date,o){if(!t)return"nothing yet \u2014 it has not said anything";if(Xc(o))return;let r=await e.get("/v1/workspace").then(c=>c.keepActivityDays??0).catch(()=>0),s=Date.parse(t),a=Number.isNaN(s)?0:(n.getTime()-s)/864e5;return r>0&&a>r?`no lines \u2014 this workspace keeps them for ${r} day(s), and this run ended ${Math.floor(a)} day(s) ago`:"no lines \u2014 the CLI backing this agent does not stream, or it said nothing"}async function Zc(e,t){let n=U(await te(P(e,"profile"),t)),o=G(C(e,"json")),r=(ce(e,"every")??2)*1e3,s=new AbortController,a=()=>s.abort();process.on("SIGINT",a);try{await el(n,o,r,s.signal)}finally{process.off("SIGINT",a)}return y.ok}async function el(e,t,n,o){let r=new Map,s,a=!0;for(;!o.aborted;){let[c,i]=await Promise.all([e.get("/v1/jobs").catch(()=>({jobs:[]})),e.get("/v1/workspace").catch(()=>({runSlots:void 0}))]);for(let d of[...c.jobs].reverse()){let u=r.get(d.id);if(u===d.state)continue;r.set(d.id,d.state);let f=u===void 0?a?"":"new":`was ${u}`,p=d.subject??d.agent??d.kind;t.line(`${d.state.padEnd(8)} ${p.padEnd(16)} ${f.padEnd(12)} ${tl(d)}`.trimEnd()),t.data({job:d.id,kind:d.kind,state:d.state,was:u})}a=!1;let l=bo(i.runSlots);if(l!==s&&(l&&t.line(` ${l}`),s=l),o.aborted)return;await new Promise(d=>{let u=setTimeout(d,n);o.addEventListener("abort",()=>{clearTimeout(u),d()},{once:!0})})}}var tl=e=>{if(e.error)return Y(e.error,60);let t=e.result;if(!t)return"";let n=t.outcome??t.result??"",o=t.costUsd?` $${t.costUsd.toFixed(4)}`:"";return`${Y(String(n).replace(/\s+/g," "),52)}${o}`.trim()};async function nl(e){let t="waiting for a rate-limit window";if(!e)return t;let o=(await e.get("/v1/seats").catch(()=>({seats:[]}))).seats.find(s=>s.limit!==void 0&&s.used>=s.limit);if(!o)return t;let r=ir(o.resetsAt);return`waiting for a window \u2014 ${o.cli} ${o.used}/${o.limit}${r?`, resets in ${r}`:""}`}async function ol(e,t,n,o=2500){if(await new Promise(a=>{let c=setTimeout(a,o);t.addEventListener("abort",()=>{clearTimeout(c),a()},{once:!0})}),t.aborted)return;let r=await e.get("/v1/workspace").catch(()=>({runSlots:void 0}));if(t.aborted)return;let s=bo(r.runSlots);s&&n(` \xB7 ${s}`)}async function ea(e,t,n,o){let r=!1;try{for await(let s of Vn(e,t.signal)){let a=JSON.parse(s.data);if(s.event==="activity"){let c=typeof a.tool=="string"?a.tool:"";n.line(` ${c?`${c} `:""}${Y(String(a.text??""),100)}`)}else s.event==="status"&&a.status==="rate-limited"&&!r&&(r=!0,n.line(` \xB7 ${await nl(o)}`))}}catch{}}function rl(e,t){if(e.state==="failed"){let o=e.result&&"result"in e.result?e.result.result:void 0;return t.warn(`moa: ${e.error??(o?$o(o)??o:"the run failed")}`),t.data(e),y.failed}let n=e.result;return t.data(e),n&&"stopped"in n?(t.warn(`moa: ${n.reason}`),y.halted):(n?.result&&t.line($o(n.result)??n.result),n?.isError?y.failed:y.ok)}async function ta(e,t=process.env){let n=e.positional[1];if(!n)throw new x("usage: moa logs <runId> [--tail n] [--since seq]");let o=U(await te(P(e,"profile"),t)),r=G(C(e,"json")),s=ce(e,"tail"),a=ce(e,"since");if(s!==void 0&&a!==void 0)throw new x("moa logs takes --tail or --since, not both");let[c,i]=await Promise.all([o.get(`/v1/runs/${n}`),o.get(s!==void 0?`/v1/runs/${n}/activity?tail=${s}`:a===void 0?`/v1/runs/${n}/activity`:`/v1/runs/${n}/activity?since=${a}`)]),l=i.activity,d=i.total??l.length;if(r.line(`${c.agent}: ${Y(ar(c.prompt).split(`
163
- `)[0]??"",80)}`),l.length<d){let p=d-l.length;r.line(` \u2026 ${p} earlier ${p===1?"line":"lines"}, moa logs ${n} for all`)}for(let p of l)r.line(` ${p.tool?`${p.tool} `:""}${Y(p.text,100)}`);let u=C(e,"watch")&&!c.endedAt;if(d===0&&!u){let p=await Qc(o,c.endedAt,new Date,c.result);p&&r.line(` ${p}`)}let f=u?await sl(o,n,l[l.length-1]?.seq??-1,r,e):c;return f.result&&(r.line(""),r.line($o(f.result)??f.result)),r.data({run:f,activity:l}),f.isError?y.failed:y.ok}async function sl(e,t,n,o,r){let s=(ce(r,"every")??1)*1e3,a=new AbortController,c=()=>a.abort();process.on("SIGINT",c);let i=n;try{for(;;){let l=await e.get(i<0?`/v1/runs/${t}/activity`:`/v1/runs/${t}/activity?since=${i}`);for(let d of l.activity)i=d.seq,o.line(` ${d.tool?`${d.tool} `:""}${Y(d.text,100)}`);if(l.endedAt||a.signal.aborted)return l;if(await new Promise(d=>{let u=setTimeout(d,s);a.signal.addEventListener("abort",()=>{clearTimeout(u),d()},{once:!0})}),a.signal.aborted)return{}}}finally{process.off("SIGINT",c)}}async function na(e,t=process.env){let n=e.positional[1],o=e.positional[2],r=e.positional[3];if(!n||!o||!r)throw new x('usage: moa ask <from> <to> "<question>" [--watch]');let s=U(await te(P(e,"profile"),t)),a=G(C(e,"json")),c=ce(e,"timeout"),i=new AbortController,l=C(e,"watch")?await s.stream(`/v1/agents/${o}/events?from=next`,i.signal):void 0,d;try{d=await s.post("/v1/calls",{from:n,to:o,question:r,...c===void 0?{}:{timeoutMs:c*1e3}},$n(e))}catch(b){throw i.abort(),b}if(C(e,"detach"))return i.abort(),a.line(`started ${d.id}`),a.data(d),y.ok;let u=l?ea(l,i,a,s):void 0,f=kn(s,d.id,b=>a.warn(b)),p;try{p=await Nt(s,d.id,c??3600)}finally{f.stop()}if(i.abort(),await u,a.data(p),p.state==="failed")return a.warn(`moa: ${p.error??"the call failed"}`),y.failed;let g=p.result;return g?.answered?(a.line(g.answer),y.ok):(a.warn(`moa: ${g?.reason??"no answer"}`),y.halted)}var ur=e=>e.endedAt===void 0?"running":e.isError?e.result===Zs?"cut short":"failed":"done";async function al(e){let t=await e.get("/v1/workspace").catch(()=>{}),n=rt(t?.restart?.at),o=t?.restart?.cutShort??0;if(!(!n||o===0))return`the last restart was ${n} ago, and cut short ${o} ${o===1?"run":"runs"}`}var Xs=["running","done","failed","interrupted"];function il(e){let t=P(e,"state");if(t!==void 0){if(!Xs.includes(t))throw new x(`--state must be one of ${Xs.join(", ")}`);return t}return C(e,"failed")?"failed":void 0}var cl=(e,t,n,o)=>["moa runs",e,t===void 0?void 0:`--state ${t}`,n===10?void 0:`--limit ${n}`,`--before ${o}`].filter(r=>r!==void 0).join(" ");async function oa(e,t=process.env){let n=e.positional[1],o=il(e),r=U(await te(P(e,"profile"),t)),s=G(C(e,"json")),a=ce(e,"limit")??10,c=P(e,"before"),i=`limit=${a}${o===void 0?"":`&state=${o}`}${c===void 0?"":`&before=${encodeURIComponent(c)}`}`,l=n?(await r.get(`/v1/agents/${n}/runs?${i}`)).runs:(await r.get(`/v1/runs?${i}`)).runs;if(s.data({runs:l}),l.length===0){if(c!==void 0)return s.line(n?`nothing ${n} ran before that one`:"nothing ran before that one"),y.ok;if(o!==void 0){let g=o==="failed"?"ended with an error":o==="interrupted"?"was cut short by a restart":o==="running"?"is running":"has";return s.line(n?`nothing ${n} ran ${g}`:`nothing ${g}`),y.ok}return s.line(n?`${n} has not run yet`:"nothing has run yet"),y.ok}s.line(be([["AGE","STATE",...n?[]:["AGENT"],"CAUSE","COST","TASK","RUN"],...l.map(g=>[rt(g.startedAt)??"\u2014",ur(g),...n?[]:[g.agent??""],g.cause??"\u2014",g.costUsd===void 0?"\u2014":`$${g.costUsd.toFixed(4)}`,Y(ar(g.prompt).split(`
164
- `)[0]??"",44),g.id])]));let d=l.filter(g=>ur(g)==="failed").length,u=l.filter(g=>ur(g)==="cut short").length,f=u>0?await al(r):void 0;o===void 0&&d+u>0&&(s.line(`
163
+ `),...n===void 0?{}:{id:n}}}Ue();Ye();Sn();async function Ys(e,t=process.env){if(e.positional[1]!=="work")throw new A('usage: moa team work <a,b,c> [--watch] [--max-turns n] [--nudge "\u2026"]');let n=(e.positional[2]??"").split(",").map(u=>u.trim()).filter(Boolean);if(n.length===0)throw new A("usage: moa team work <a,b,c>");let o=N(await re(P(e,"profile"),t)),r=G(E(e,"json")),s=new AbortController,a=E(e,"watch")?n.map(async u=>{let f=await o.stream(`/v1/agents/${u}/events`,s.signal);await tl(f,s,r,u)}):[],c;try{c=await o.post("/v1/team/work",{agents:n,...de(e,"max-turns")===void 0?{}:{maxTurns:de(e,"max-turns")},...de(e,"max-cost")===void 0?{}:{maxCostUsd:de(e,"max-cost")},...P(e,"nudge")===void 0?{}:{nudge:P(e,"nudge")},...E(e,"route-replies")?{routeReplies:!0}:{}},An(e))}catch(u){throw s.abort(),u}let i=vn(o,c.id,u=>r.warn(u)),l;try{l=await Ft(o,c.id,de(e,"timeout")??3600,E(e,"watch")?u=>r.line(`\xB7 ${lr(u)}`):void 0)}finally{i.stop()}if(s.abort(),await Promise.allSettled(a),l.state==="failed")return r.warn(`moa: ${l.error??"the team loop failed"}`),r.data(l),k.failed;let d=l.result;r.line(`${d.outcome}: ${d.reason}`),r.line(` ${d.turns} turn(s), $${d.costUsd.toFixed(3)} notional`);for(let u of d.open)r.line(` still open: ${u.from} \u2192 ${u.to} ${Y(u.task,40)}`+(u.blockedBy?` BLOCKED: "${Y(u.blockedBy.body,40)}"`:""));return r.data(l),d.outcome==="settled"?k.ok:k.halted}async function Xs(e,t=process.env){let n=Number(e.positional[1]);if(!Number.isInteger(n)||n<1)throw new A("usage: moa ship <issue>");let o=N(await re(P(e,"profile"),t)),r=G(E(e,"json")),s=E(e,"watch"),a=await o.post("/v1/pipelines",{issue:n,...P(e,"repo")===void 0?{}:{repo:P(e,"repo")},...de(e,"max-steps")===void 0?{}:{maxSteps:de(e,"max-steps")},...de(e,"max-cost")===void 0?{}:{maxCostUsd:de(e,"max-cost")}},An(e));r.line(`shipping #${n} \u2014 ${a.id}`);let c=vn(o,a.id,d=>r.warn(d)),i;try{i=await Ft(o,a.id,de(e,"timeout")??7200,s?d=>r.line(` ${lr(d)}`):void 0)}finally{c.stop()}if(i.state==="failed")return r.warn(`moa: ${i.error??"the pipeline failed"}`),r.data(i),k.failed;let l=i.result;return r.line(`${l.outcome}: ${l.reason}`),r.line(` ${l.steps} step(s), $${l.costUsd.toFixed(3)} notional`),r.data(i),l.outcome==="merged"?k.ok:k.halted}function lr(e){let t=[];return e.step&&t.push(e.step),e.steps!==void 0&&t.push(`${e.steps} step(s)`),e.costUsd!==void 0&&t.push(`$${e.costUsd.toFixed(3)}`),e.note&&t.push(e.note),t.join(" \xB7 ")}async function Qs(e,t=process.env){let n=N(await re(P(e,"profile"),t)),o=G(E(e,"json")),[r,s]=await Promise.all([n.get("/v1/jobs"),n.get("/v1/workspace").catch(()=>({runSlots:void 0}))]);o.data({...r,...s.runSlots?{runSlots:s.runSlots}:{}});let a=yo(s.runSlots);if(r.jobs.length===0)return o.line("nothing has run yet"),a&&o.line(a),k.ok;let c=r.jobs.some(i=>(i.issue?.pipelines??0)>1);return o.line(ke([["STATE","KIND","WHAT","WHERE",...c?["ISSUE IN ALL"]:[],"JOB"],...r.jobs.map(i=>[i.state,i.kind,i.subject??i.agent??"",Y(el(i),44),...c?[Zc(i)]:[],i.id])])),a&&(o.line(""),o.line(a)),k.ok}function Zc(e){let t=e.issue;if(!t)return"";let n=`${t.pipelines} pipeline${t.pipelines===1?"":"s"}`;return`$${t.costUsd.toFixed(2)} \xB7 ${t.steps} step${t.steps===1?"":"s"} \xB7 ${n}`}function yo(e){if(!e||e.ceiling===0||e.waiting===0&&e.running<e.ceiling)return;let t=e.waiting===0?"":`, ${e.waiting} ${e.waiting===1?"agent is":"agents are"} waiting for a slot`;return`${e.running} of ${e.ceiling} run slots in use${t}`}function el(e){if(e.error)return e.error;if(e.state==="running")return e.progress?lr(e.progress):"";let t=e.result;return t?t.outcome?t.reason?`${t.outcome}: ${t.reason}`:t.outcome:t.reason?t.reason:t.answered?"answered":t.isError?"the agent reported an error":"":""}async function Zs(e,t=process.env){let n=e.positional[1];if(!n)throw new A("usage: moa stop <jobId>");let o=N(await re(P(e,"profile"),t)),r=G(E(e,"json")),s=await o.post(`/v1/jobs/${n}/cancel`,{});return r.line(s.cancelled?`stopping ${n} \u2014 after whatever it is doing now`:`${n} had already ${s.job.state==="running"?"gone":s.job.state}`),r.data(s),k.ok}async function tl(e,t,n,o){try{for await(let r of Qn(e,t.signal)){if(r.event!=="activity")continue;let s=JSON.parse(r.data);n.line(` ${o}: ${s.tool?`${s.tool} `:""}${Y(String(s.text??""),80)}`)}}catch{}}var An=e=>P(e,"key")??crypto.randomUUID();function bo(e){if(!e)return;let t=/^`(\S+)` exceeded its (\d+)ms timeout$/.exec(e.trim());if(!t?.[1]||!t[2])return;let n=Number(t[2])/6e4,o=n>=1?`${Number(n.toFixed(1))} minute(s)`:`${Number(t[2])/1e3} second(s)`;return`${t[1]} ran for ${o} without finishing, and the workspace stopped it`}async function nl(e,t,n,o,r){let s=await e.post(`/v1/agents/${t}/runs`,{prompt:n},o).catch(()=>{});if(s)return r(s.state==="done"||s.state==="failed"?"the workspace restarted; this is what became of the run it had already started":"the workspace restarted, and nothing had been recorded \u2014 asking again"),s}async function ta(e,t=process.env){let n=e.positional[1],o=e.positional[2];if(!n||!o)throw new A('usage: moa run <name> "<prompt>" [--watch]');let r=N(await re(P(e,"profile"),t)),s=G(E(e,"json")),a=E(e,"watch"),c=new AbortController,i=a?await r.stream(`/v1/agents/${n}/events?from=next`,c.signal):void 0,l;try{l=await r.post(`/v1/agents/${n}/runs`,{prompt:o},An(e))}catch(g){throw c.abort(),g}if(E(e,"detach"))return c.abort(),s.line(`started ${l.id}`),s.data(l),k.ok;let d=i?oa(i,c,s,r):void 0,u=ll(r,c.signal,g=>s.line(g)),f=vn(r,l.id,g=>s.warn(g)),p;try{p=await Ft(r,l.id,de(e,"timeout")??3600,void 0,()=>nl(r,n,o,An(e),g=>s.warn(g)))}finally{f.stop()}return c.abort(),await d,await u,f.asked()?(s.data(p),k.halted):dl(p,s)}var na="the workspace stopped while this run was going",ol=e=>e===na||bo(e)!==void 0;async function rl(e,t,n=new Date,o){if(!t)return"nothing yet \u2014 it has not said anything";if(ol(o))return;let r=await e.get("/v1/workspace").then(c=>c.keepActivityDays??0).catch(()=>0),s=Date.parse(t),a=Number.isNaN(s)?0:(n.getTime()-s)/864e5;return r>0&&a>r?`no lines \u2014 this workspace keeps them for ${r} day(s), and this run ended ${Math.floor(a)} day(s) ago`:"no lines \u2014 the CLI backing this agent does not stream, or it said nothing"}async function sl(e,t){let n=N(await re(P(e,"profile"),t)),o=G(E(e,"json")),r=(de(e,"every")??2)*1e3,s=new AbortController,a=()=>s.abort();process.on("SIGINT",a);try{await al(n,o,r,s.signal)}finally{process.off("SIGINT",a)}return k.ok}async function al(e,t,n,o){let r=new Map,s,a=!0;for(;!o.aborted;){let[c,i]=await Promise.all([e.get("/v1/jobs").catch(()=>({jobs:[]})),e.get("/v1/workspace").catch(()=>({runSlots:void 0}))]);for(let d of[...c.jobs].reverse()){let u=r.get(d.id);if(u===d.state)continue;r.set(d.id,d.state);let f=u===void 0?a?"":"new":`was ${u}`,p=d.subject??d.agent??d.kind;t.line(`${d.state.padEnd(8)} ${p.padEnd(16)} ${f.padEnd(12)} ${il(d)}`.trimEnd()),t.data({job:d.id,kind:d.kind,state:d.state,was:u})}a=!1;let l=yo(i.runSlots);if(l!==s&&(l&&t.line(` ${l}`),s=l),o.aborted)return;await new Promise(d=>{let u=setTimeout(d,n);o.addEventListener("abort",()=>{clearTimeout(u),d()},{once:!0})})}}var il=e=>{if(e.error)return Y(e.error,60);let t=e.result;if(!t)return"";let n=t.outcome??t.result??"",o=t.costUsd?` $${t.costUsd.toFixed(4)}`:"";return`${Y(String(n).replace(/\s+/g," "),52)}${o}`.trim()};async function cl(e){let t="waiting for a rate-limit window";if(!e)return t;let o=(await e.get("/v1/seats").catch(()=>({seats:[]}))).seats.find(s=>s.limit!==void 0&&s.used>=s.limit);if(!o)return t;let r=ar(o.resetsAt);return`waiting for a window \u2014 ${o.cli} ${o.used}/${o.limit}${r?`, resets in ${r}`:""}`}async function ll(e,t,n,o=2500){if(await new Promise(a=>{let c=setTimeout(a,o);t.addEventListener("abort",()=>{clearTimeout(c),a()},{once:!0})}),t.aborted)return;let r=await e.get("/v1/workspace").catch(()=>({runSlots:void 0}));if(t.aborted)return;let s=yo(r.runSlots);s&&n(` \xB7 ${s}`)}async function oa(e,t,n,o){let r=!1;try{for await(let s of Qn(e,t.signal)){let a=JSON.parse(s.data);if(s.event==="activity"){let c=typeof a.tool=="string"?a.tool:"";n.line(` ${c?`${c} `:""}${Y(String(a.text??""),100)}`)}else s.event==="status"&&a.status==="rate-limited"&&!r&&(r=!0,n.line(` \xB7 ${await cl(o)}`))}}catch{}}function dl(e,t){if(e.state==="failed"){let o=e.result&&"result"in e.result?e.result.result:void 0;return t.warn(`moa: ${e.error??(o?bo(o)??o:"the run failed")}`),t.data(e),k.failed}let n=e.result;return t.data(e),n&&"stopped"in n?(t.warn(`moa: ${n.reason}`),k.halted):(n?.result&&t.line(bo(n.result)??n.result),n?.isError?k.failed:k.ok)}async function ra(e,t=process.env){let n=e.positional[1];if(!n)throw new A("usage: moa logs <runId> [--tail n] [--since seq]");let o=N(await re(P(e,"profile"),t)),r=G(E(e,"json")),s=de(e,"tail"),a=de(e,"since");if(s!==void 0&&a!==void 0)throw new A("moa logs takes --tail or --since, not both");let[c,i]=await Promise.all([o.get(`/v1/runs/${n}`),o.get(s!==void 0?`/v1/runs/${n}/activity?tail=${s}`:a===void 0?`/v1/runs/${n}/activity`:`/v1/runs/${n}/activity?since=${a}`)]),l=i.activity,d=i.total??l.length;if(r.line(`${c.agent}: ${Y(sr(c.prompt).split(`
164
+ `)[0]??"",80)}`),l.length<d){let p=d-l.length;r.line(` \u2026 ${p} earlier ${p===1?"line":"lines"}, moa logs ${n} for all`)}for(let p of l)r.line(` ${p.tool?`${p.tool} `:""}${Y(p.text,100)}`);let u=E(e,"watch")&&!c.endedAt;if(d===0&&!u){let p=await rl(o,c.endedAt,new Date,c.result);p&&r.line(` ${p}`)}let f=u?await ul(o,n,l[l.length-1]?.seq??-1,r,e):c;return f.result&&(r.line(""),r.line(bo(f.result)??f.result)),r.data({run:f,activity:l}),f.isError?k.failed:k.ok}async function ul(e,t,n,o,r){let s=(de(r,"every")??1)*1e3,a=new AbortController,c=()=>a.abort();process.on("SIGINT",c);let i=n;try{for(;;){let l=await e.get(i<0?`/v1/runs/${t}/activity`:`/v1/runs/${t}/activity?since=${i}`);for(let d of l.activity)i=d.seq,o.line(` ${d.tool?`${d.tool} `:""}${Y(d.text,100)}`);if(l.endedAt||a.signal.aborted)return l;if(await new Promise(d=>{let u=setTimeout(d,s);a.signal.addEventListener("abort",()=>{clearTimeout(u),d()},{once:!0})}),a.signal.aborted)return{}}}finally{process.off("SIGINT",c)}}async function sa(e,t=process.env){let n=e.positional[1],o=e.positional[2],r=e.positional[3];if(!n||!o||!r)throw new A('usage: moa ask <from> <to> "<question>" [--watch]');let s=N(await re(P(e,"profile"),t)),a=G(E(e,"json")),c=de(e,"timeout"),i=new AbortController,l=E(e,"watch")?await s.stream(`/v1/agents/${o}/events?from=next`,i.signal):void 0,d;try{d=await s.post("/v1/calls",{from:n,to:o,question:r,...c===void 0?{}:{timeoutMs:c*1e3}},An(e))}catch(y){throw i.abort(),y}if(E(e,"detach"))return i.abort(),a.line(`started ${d.id}`),a.data(d),k.ok;let u=l?oa(l,i,a,s):void 0,f=vn(s,d.id,y=>a.warn(y)),p;try{p=await Ft(s,d.id,c??3600)}finally{f.stop()}if(i.abort(),await u,a.data(p),p.state==="failed")return a.warn(`moa: ${p.error??"the call failed"}`),k.failed;let g=p.result;return g?.answered?(a.line(g.answer),k.ok):(a.warn(`moa: ${g?.reason??"no answer"}`),k.halted)}var dr=e=>e.endedAt===void 0?"running":e.isError?e.result===na?"cut short":"failed":"done";async function pl(e){let t=await e.get("/v1/workspace").catch(()=>{}),n=rt(t?.restart?.at),o=t?.restart?.cutShort??0;if(!(!n||o===0))return`the last restart was ${n} ago, and cut short ${o} ${o===1?"run":"runs"}`}var ea=["running","done","failed","interrupted"];function fl(e){let t=P(e,"state");if(t!==void 0){if(!ea.includes(t))throw new A(`--state must be one of ${ea.join(", ")}`);return t}return E(e,"failed")?"failed":void 0}var ml=(e,t,n,o)=>["moa runs",e,t===void 0?void 0:`--state ${t}`,n===10?void 0:`--limit ${n}`,`--before ${o}`].filter(r=>r!==void 0).join(" ");async function aa(e,t=process.env){let n=e.positional[1],o=fl(e),r=N(await re(P(e,"profile"),t)),s=G(E(e,"json")),a=de(e,"limit")??10,c=P(e,"before"),i=`limit=${a}${o===void 0?"":`&state=${o}`}${c===void 0?"":`&before=${encodeURIComponent(c)}`}`,l=n?(await r.get(`/v1/agents/${n}/runs?${i}`)).runs:(await r.get(`/v1/runs?${i}`)).runs;if(s.data({runs:l}),l.length===0){if(c!==void 0)return s.line(n?`nothing ${n} ran before that one`:"nothing ran before that one"),k.ok;if(o!==void 0){let g=o==="failed"?"ended with an error":o==="interrupted"?"was cut short by a restart":o==="running"?"is running":"has";return s.line(n?`nothing ${n} ran ${g}`:`nothing ${g}`),k.ok}return s.line(n?`${n} has not run yet`:"nothing has run yet"),k.ok}s.line(ke([["AGE","STATE",...n?[]:["AGENT"],"CAUSE","COST","TASK","RUN"],...l.map(g=>[rt(g.startedAt)??"\u2014",dr(g),...n?[]:[g.agent??""],g.cause??"\u2014",g.costUsd===void 0?"\u2014":`$${g.costUsd.toFixed(4)}`,Y(sr(g.prompt).split(`
165
+ `)[0]??"",44),g.id])]));let d=l.filter(g=>dr(g)==="failed").length,u=l.filter(g=>dr(g)==="cut short").length,f=u>0?await pl(r):void 0;o===void 0&&d+u>0&&(s.line(`
165
166
  ${[d>0?`${d} of them ended with an error`:"",u>0?`${u} ${u===1?"was":"were"} cut short by a restart`:""].filter(Boolean).join(", ")}`),f&&s.line(f));let p=l[l.length-1]?.id;return l.length===a&&p!==void 0&&s.line(`
166
- older: ${cl(n,o,a,p)}`),y.ok}async function ra(e,t=process.env){let n=e.positional[1];if(!n)return Zc(e,t);let o=U(await te(P(e,"profile"),t)),r=G(C(e,"json")),s=new AbortController,a=()=>s.abort();process.on("SIGINT",a);let c=await o.stream(`/v1/agents/${n}/events`,s.signal);try{for await(let i of Vn(c,s.signal)){let l=JSON.parse(i.data);if(i.event==="run")r.line(`\u2014 ${String(l.runId??"")} started ${String(l.startedAt??"")}`);else if(i.event==="activity"){let d=typeof l.tool=="string"?l.tool:"";r.line(` ${d?`${d} `:""}${Y(String(l.text??""),100)}`)}else i.event==="status"?r.line(` \xB7 ${String(l.status??"")}`):i.event==="end"?r.line(` = ${Y(String(l.result??""),100)}`):i.event==="closing"&&r.warn("moa: the workspace is shutting down");r.data({event:i.event,data:l})}}catch{}finally{process.off("SIGINT",a)}return y.ok}var ll=["--json","--watch","--detach","--all","--limit","--since","--timeout","--nudge","--route-replies","--profile","--file","--revoke","--token","--github","--help"];function sa(e,t){let n=[...t].sort().join(" "),o=ll.join(" ");if(e==="bash")return`# moa completion for bash \u2014 eval "$(moa completion bash)"
167
+ older: ${ml(n,o,a,p)}`),k.ok}async function ia(e,t=process.env){let n=e.positional[1];if(!n)return sl(e,t);let o=N(await re(P(e,"profile"),t)),r=G(E(e,"json")),s=new AbortController,a=()=>s.abort();process.on("SIGINT",a);let c=await o.stream(`/v1/agents/${n}/events`,s.signal);try{for await(let i of Qn(c,s.signal)){let l=JSON.parse(i.data);if(i.event==="run")r.line(`\u2014 ${String(l.runId??"")} started ${String(l.startedAt??"")}`);else if(i.event==="activity"){let d=typeof l.tool=="string"?l.tool:"";r.line(` ${d?`${d} `:""}${Y(String(l.text??""),100)}`)}else i.event==="status"?r.line(` \xB7 ${String(l.status??"")}`):i.event==="end"?r.line(` = ${Y(String(l.result??""),100)}`):i.event==="closing"&&r.warn("moa: the workspace is shutting down");r.data({event:i.event,data:l})}}catch{}finally{process.off("SIGINT",a)}return k.ok}var gl=["--json","--watch","--detach","--all","--limit","--since","--timeout","--nudge","--route-replies","--profile","--file","--revoke","--token","--github","--help"];function ca(e,t){let n=[...t].sort().join(" "),o=gl.join(" ");if(e==="bash")return`# moa completion for bash \u2014 eval "$(moa completion bash)"
167
168
  _moa() {
168
169
  local commands="${n}"
169
170
  local flags="${o}"
@@ -186,56 +187,58 @@ _moa() {
186
187
  fi
187
188
  }
188
189
  compdef _moa moa
189
- `;throw new x(`moa completion takes bash or zsh, not ${JSON.stringify(e)}`)}import{spawnSync as dp}from"node:child_process";import{createInterface as ms}from"node:readline/promises";import{Writable as up}from"node:stream";import{render as pp}from"ink";import{createElement as fp}from"react";De();Ze();qe();Wt();it();Je();import{readFile as Kd,writeFile as Bd}from"node:fs/promises";var $i=e=>pe.includes(e);async function vi(e,t){let n=qt(e.sys),o=JSON.parse(await Kd(n,"utf8")),r=o.services.workspace.environment;for(let[a,c]of Object.entries(t))c===void 0?delete r[a]:r[a]=c.replaceAll("$",()=>"$$");await Bd(n,JSON.stringify(o),{mode:384});let s=await e.sys.exec("docker",nt(e.sys,"up","-d","--wait"),{timeoutMs:6e5});return s.ok?{ok:!0}:{ok:!1,why:de(s.stderr)||"compose up failed"}}async function Wd(e,t,n){let o=e.state.deployed?.workspaceUrl,r=await ve(e.sys.env),s=Object.values(r.profiles).find(i=>i.url===o);if(!o||!s)return n({label:"proof",mark:"fail",detail:"no profile on this machine for the workspace",fix:"run `moa setup` and Deploy"}),!1;let a=U({url:o,token:s.token},e.sys.fetch);for(let i=0;i<60;i++)try{await a.get("/v1/whoami");break}catch{await e.sys.sleep(1e3)}return!("label"in await Dt(a,[t],"in the image",()=>`run \`moa setup login ${t}\` again`,n))}var Si=(e,t,n)=>{let o=new Set(e.answers.loggedIn??[]);return n?o.add(t):o.delete(t),{...e,answers:{...e.answers,loggedIn:pe.filter(r=>o.has(r))}}};function xi(e,t){return e.state.deployed?.runner==="image"&&e.sys.exists(qt(e.sys))?!0:(t({label:"agent login",mark:"fail",detail:e.state.deployed===void 0?"nothing is deployed yet":"one agent at a time works on the published image on this machine for now",fix:"run `moa setup login` and use Agent logins, then Deploy"}),!1)}async function Ai(e,t,n,o){let{print:r}=o;if(!xi(e,r))return{ok:!1};if(n||!co(t)){n||await o.setupToken();let a=n?Se[t]:"CLAUDE_CODE_OAUTH_TOKEN",c=(await o.secret(n?`${a}: `:"Paste the token `claude setup-token` printed: ")).trim();if(!c||/\s/.test(c))return r({label:t,mark:"fail",detail:"nothing pasted \u2014 nothing was changed",fix:`run \`moa setup login ${t}${n?" --key":""}\` again`}),{ok:!1};r({label:t,mark:"wait",detail:"restarting the workspace on it \u2014 data kept"});let i=t==="claude"?n?"CLAUDE_CODE_OAUTH_TOKEN":Se.claude:void 0,l=await vi(e,{[a]:c,...i?{[i]:void 0}:{}});if(!l.ok)return r({label:t,mark:"fail",detail:l.why,fix:"`moa setup logs` says why"}),{ok:!1}}else if(await zt(e.sys,t))r({label:t,mark:"ok",detail:"already logged in inside the container"});else{r({label:t,mark:"wait",detail:"starting its login inside the container\u2026"});let a=!1,i=await Mn(e.sys,t,l=>{let d=Nn(l);d&&!a&&(a=!0,r({label:t,mark:"wait",detail:d}))}).done;if(!i.ok||!await zt(e.sys,t))return r({label:t,mark:"fail",detail:`the login did not finish: ${de(i.stderr)||"no answer"}`,fix:`run \`moa setup login ${t}\` again`}),{ok:!1};r({label:t,mark:"ok",detail:"logged in inside the container \u2014 kept on its home volume"})}let s=await Wd(e,t,r);return{ok:s,state:Si(e.state,t,s)}}var Xr={codex:["codex","logout"],cursor:["cursor-agent","logout"]};async function Ei(e,t,n){if(!xi(e,n))return{ok:!1};co(t)&&await e.sys.exec("docker",nt(e.sys,"exec","-T","workspace",...Xr[t]),{timeoutMs:6e4});let o=await vi(e,t==="claude"?{CLAUDE_CODE_OAUTH_TOKEN:void 0,ANTHROPIC_API_KEY:void 0}:{[Se[t]]:void 0});if(!o.ok)return n({label:t,mark:"fail",detail:o.why,fix:"`moa setup logs` says why"}),{ok:!1};n({label:t,mark:"ok",detail:`disconnected \u2014 \`moa setup login ${t}\` connects it again`});let r=Si(e.state,t,!1);return r.answers.agentCli===t&&(r.answers={...r.answers,agentCli:r.answers.loggedIn?.[0]}),{ok:!0,state:r}}import{Box as ze,Text as se,useApp as xu,useInput as Au,usePaste as Eu}from"ink";import{useEffect as Fi,useMemo as Cu,useRef as xt,useState as mt}from"react";qe();Wt();De();qe();Zn();Wt();it();It();Ft();Pn();Je();import{createHash as Jd}from"node:crypto";import{mkdir as qd,readFile as zd,rm as Vd,writeFile as Qr}from"node:fs/promises";import{dirname as Yd,join as Fo}from"node:path";var jn="cloudflare",fo=(e,t=2)=>e.replace(/\u001B\[[0-9;]*m/g,"").trim().split(`
190
- `).filter(n=>n.trim()!=="").slice(-t).join(" \xB7 ").slice(0,300),Ci=e=>Jd("sha256").update(e).digest("hex").slice(0,12);async function Zr(e,t,n){let o=Date.now()+t*1e3;for(;Date.now()<o;){if(await n().catch(()=>!1))return!0;await e.sleep(2e3)}return!1}async function Xd(e,t,n,o){o({label:"codex",mark:"wait",detail:"asking codex for a code inside the container\u2026"});let r=await e.fetch(`${t}/_moa/codex/login`,{method:"POST",headers:{authorization:`Bearer ${n}`},signal:AbortSignal.timeout(16*6e4)});if(!r.ok||!r.body)return{ok:!1,why:`${r.status} ${fo(await r.text().catch(()=>""))}`};let s="",a=r.body.getReader(),c=new TextDecoder;for(;;){let{done:l,value:d}=await a.read();if(l)break;s+=c.decode(d,{stream:!0});let u=rn(s);u.url&&u.code&&o({label:"codex",mark:"wait",detail:`open ${u.url} and enter ${u.code} \u2014 waiting for you to approve it`})}return/\[moa\] codex login exited (\d+)/.exec(s)?.[1]==="0"?{ok:!0}:{ok:!1,why:fo(s.replace(/\[moa\].*$/m,""))||"codex login did not finish"}}async function Ko(e,t,n=()=>{},o=()=>{}){let{sys:r,state:s}=e,a=[],c=K=>{let Z=a.findIndex(Be=>Be.label===K.label);Z===-1?a.push(K):a[Z]=K,t([...a])},i,l=(K,Z,Be)=>(c({label:K,mark:"fail",detail:Z,fix:Be}),i?{ok:!1,deployed:i}:{ok:!1}),d=r.root??Dn(),u=s.answers.domain,f=s.answers.cloudflareAccount;if(!u||!f)return l("account","no Cloudflare account or domain yet","Esc back to Checks & account, then Enter");if(un(e))return l("memory","the last deploy kept memory in LocusGraph, and this run has no secret for it","Esc back to Memory & database and paste it again \u2014 or go on there without it");let p=s.deployed?.runner==="cloudflare"?s.deployed:void 0,g=qr(e)?.token,b=zr(e)?.token,$=tt(e)?.token,m=s.answers.agentCli??"claude";if(!g&&!p)return l("D1 token","none in this run \u2014 it is never saved","Esc back to Checks & account and press k");if(!b&&!p)return l("GitHub token","none in this run \u2014 it is never saved","Esc back to GitHub and press k");if(m==="claude"&&!$&&!$e(e,"claude")&&!p)return l("claude token","none in this run \u2014 it is never saved","Esc back to Agent logins and press c (or k for an API key, or choose another agent), then Enter");let h=s.answers.githubApp,A=h?He(r,h):void 0;if(!h||!A)return l("GitHub App",h?`the client secret for ${h.slug} is not on this machine`:"none yet","Esc back to Console access and press g \u2014 on a domain, people sign in with it");let{workspaceUrl:E,consoleUrl:I}=Yn(u),W=s.answers.tenant??Ie(s.answers.owner),fe=s.answers.owner,M=xe(e),z=Fo(d,"apps","workspace"),R,J;if(Oe(e)){for(let he of await yt(e))if(c(he),he.mark==="fail")return{ok:!1};for(let he of await Un(e))if(c(he),he.mark==="fail")return{ok:!1};let K=`fnmoa:${Gt()}`;if(!(await r.exec("docker",["tag",Ae(),K])).ok)return l("image","Could not tag the release image","Check Docker and retry");if(!(await Ge(r,d,["containers","push",K],{account:f,timeoutMs:9e5})).ok)return l("image","Could not push to the Cloudflare registry","Check your Cloudflare login and retry");if(R=`registry.cloudflare.com/${f}/${K}`,r.root){let he=await Hr(r);if(!he.ok)return l("worker",`Could not copy the Worker out of ${Ae()}: ${he.why}`,"Check Docker and retry");J=he.path}else J=Gr();c({label:"image",mark:"ok",detail:`${Ae()} \u2014 the Worker and the container`})}else{c({label:"build",mark:"wait",detail:"building the Worker"});let K=await r.exec("pnpm",["install"],{cwd:d,timeoutMs:6e5}),Z=K.ok?await r.exec("pnpm",["--filter","@fnmoa/workspace...","run","build"],{cwd:d,timeoutMs:9e5}):K;if(!Z.ok)return l("build",fo(Z.stderr||Z.stdout),`run \`pnpm install && pnpm --filter @fnmoa/workspace... run build\` in ${d}, then Enter`);c({label:"build",mark:"ok",detail:"the Worker is built from this checkout"})}let{token:V,pending:Ce,before:X,had:Fe}=await Kt(r,jn,E);c({label:"owner token",mark:"ok",detail:`${D} \u2014 profile ${jn} in ~/.moa/config.json${X===jn||!Fe?"":`; \`moa\` now talks to this workspace, not profile ${X} (\`moa use ${X}\` to go back)`}`});let me=s.cloudflare??p?.cloudflare,k=me?.account===f?me:void 0,Q=k!==void 0&&k.older!==!0&&(k.d1?.unsure===!0||k.r2?.unsure===!0),O=p!==void 0&&me===void 0||k?.older===!0||Q,N={...k,account:f,...O?{older:!0}:{}},ne=K=>{N={...N,...K},o(N)},ge=async K=>{let Z=await ua(r,d,f),Be=Z?.image&&!(N.unsureImages??[]).includes(Z.image)?[Z.image]:[],he=[...new Set([...N.images??[],...Be])];ne({...K?{worker:We}:{},...Z?{containerId:Z.id}:{},...he.length>0?{images:he}:{}})};if(O&&(k===void 0||Q||k.imagesUnlisted)){let K=await Xn(r,d,f);if(!K.ok)ne({imagesUnlisted:!0}),c({label:"images",mark:"skip",detail:`could not list Cloudflare's registry \u2014 ${K.why}; the next deploy, or \`down\`, lists it again for the tags an older moa pushed`});else{let{imagesUnlisted:Z,...Be}=N,he=[...new Set([...N.unsureImages??[],...K.images.filter(or=>!(N.images??[]).includes(or))])];N={...Be,...he.length>0?{unsureImages:he}:{}},o(N),he.length>0&&c({label:"images",mark:"ok",detail:`${he.length} tag${he.length===1?"":"s"} of ${je} already in Cloudflare's registry \u2014 an older moa pushed them, so \`down\` asks before deleting them`})}}c({label:"D1",mark:"wait",detail:"finding the database, or making it"});let oe=await la(r,d,f);if(!oe.ok)return l("D1",oe.why,"fix that, then Enter");let ke=oe.made||k?.d1?.id===oe.id&&k.d1.made,Ve=!ke&&(O||k?.d1?.id===oe.id&&k.d1.unsure===!0);ne({d1:{id:oe.id,made:ke,...Ve?{unsure:!0}:{}}}),c({label:"D1",mark:"ok",detail:`${oe.made?"made":"found"} fnmoa-workspace (${oe.id})`});let Pe=await da(r,d,f);if(!Pe.ok)return l("R2",Pe.why,"R2 must be enabled on the account (dashboard \u2192 R2), then Enter");let Me=Pe.made||k?.r2?.name===wt&&k.r2.made,Le=!Me&&(O||k?.r2?.name===wt&&k.r2.unsure===!0);ne({r2:{name:wt,made:Me,...Le?{unsure:!0}:{}}}),c({label:"R2",mark:"ok",detail:"fnmoa-state \u2014 codex's login, kept across restarts"});let ye=en(u),T={MOA_D1_ACCOUNT_ID:f,MOA_D1_DATABASE_ID:oe.id,MOA_CONSOLE_HOST:ye.console,MOA_PUBLIC_URL:E,MOA_IDLE_HOURS:String(_t),AUTH_GITHUB_ID:h.clientId,AUTH_URL:I,MOA_GITHUB_CLIENT_ID:h.clientId,...fe?{MOA_OWNER_LOGIN:fe}:{},...s.answers.repo?{MOA_REPO:s.answers.repo}:{},...M?{LOCUSGRAPH_GRAPH_ID:M.graph,LOCUSGRAPH_SERVER_URL:M.server}:{}},F={...await Ht(e),MOA_TOKENS:`${V}:${W}`,AUTH_GITHUB_SECRET:A.clientSecret,AUTH_SECRET:A.authSecret,...g?{MOA_D1_API_TOKEN:g}:{},...b?{GH_TOKEN:b}:{},...$?{CLAUDE_CODE_OAUTH_TOKEN:$}:{},...Object.fromEntries(pe.map(K=>[Se[K],$e(e,K)??""])),LOCUSGRAPH_AGENT_SECRET:M?M.secret:""},Ye=await r.exec("git",["rev-parse","HEAD"],{cwd:d}),Xe=Ci(JSON.stringify([T,Ye.stdout.trim()])),ct=Ci(JSON.stringify(F)),Et=le(r,Fo("cloudflare","wrangler.json")),ie=le(r,Fo("cloudflare","secrets.json")),Yt=le(r,Fo("cloudflare","secrets.fingerprint")),re=(await zd(Yt,"utf8").catch(()=>"")).trim();await qd(Yd(Et),{recursive:!0}),await Qr(Et,`${JSON.stringify(pa({root:d,account:f,databaseId:oe.id,domain:u,vars:T,...R?{image:R,worker:J}:{}}),null,2)}
191
- `),c({label:"deploy",mark:"wait",detail:"the Worker, the container image and your two names \u2014 the first build takes several minutes"});let _e;try{await Qr(ie,JSON.stringify(F),{mode:384}),_e=await Ge(r,d,["deploy","--config",Et,"--secrets-file",ie],{account:f,timeoutMs:24e5})}finally{await Vd(ie,{force:!0})}if(!_e.ok){let K=N.worker!==void 0||(await Ge(r,d,["deployments","list","--name",We,"--json"],{account:f})).ok;await ge(K);let Z=`${_e.stdout}
192
- ${_e.stderr}`;return l("deploy",fo(Z.split(ie).join("secrets.json")),/containers?.*(plan|paid|not enabled|entitle)/i.test(Z)?"containers need the Workers Paid plan: upgrade the account, then Enter":/docker/i.test(Z)?"start Docker, then Enter":"fix that, then Enter")}await ge(!0);let ue=!!M,Qe=s.deployed?.workspaceUrl===E?s.deployed.people:void 0;i={runner:"cloudflare",workspaceUrl:E,consoleUrl:I,...Qe?{people:Qe}:{},...p?.workspaceFor?{workspaceFor:p.workspaceFor}:{},...ue?{memoryKept:ue}:{},cloudflare:N,at:new Date().toISOString()},n(i),c({label:"deploy",mark:"ok",detail:`Worker ${We} \u2014 ${ye.workspace}, ${ye.console}`});let lt=U({url:E,token:V},r.fetch),Jn=(K,Z={})=>r.fetch(`${E}${K}`,{...Z,headers:{authorization:`Bearer ${V}`},signal:AbortSignal.timeout(3e4)});if(c({label:"container",mark:"wait",detail:`waiting for ${ye.workspace} to answer`}),!await Zr(r,600,async()=>(await Jn("/_moa/box")).ok))return l("container",`${E} did not answer the owner token in 10 minutes`,"a new name can take a while for its certificate: Enter to try again");(p?.workspaceFor!==Xe||re!==ct)&&await Jn("/_moa/restart",{method:"POST"}).catch(()=>{}),c({label:"container",mark:"wait",detail:"starting the workspace and console in it"});let hn={};if(!await Zr(r,600,async()=>(hn=await(await r.fetch(`${E}/health`,{signal:AbortSignal.timeout(13e4)})).json().catch(()=>({})),hn.ok===!0)))return l("container",`the workspace did not come up: ${fo(String(hn.error??"no answer"),1)}`,`look at \`pnpm --dir ${z} exec wrangler tail ${We}\`, then Enter`);if(await Qr(Yt,`${ct}
193
- `,{mode:384}),i={...i,workspaceFor:Xe},n(i),c({label:"container",mark:"ok",detail:`${E} \u2014 kept up ${_t}h after the last request`}),c({label:"database",mark:"ok",detail:`${hn.database??"d1"} \u2014 migrated, and it answers`}),!await lt.get("/v1/whoami").then(()=>!0,()=>!1))return l("workspace","it answers but refuses the owner token","Enter to try again");Ce&&await Bt(r,jn,E,V);let Xt=await ln(lt,s,c,Qe);if(Xt)return l(Xt.label,Xt.detail,Xt.fix);i={...i,people:s.answers.people??[]},n(i);let ho=[...new Set([m,...s.answers.loggedIn??[]])];if(ho.includes("codex")&&!$e(e,"codex"))if((await Jn("/_moa/codex").then(Z=>Z.json()).catch(()=>({}))).loggedIn)c({label:"codex",mark:"ok",detail:"logged in inside the container \u2014 kept in R2"});else{let Z=await Xd(r,E,V,c).catch(Be=>({ok:!1,why:Be instanceof Error?Be.message:String(Be)}));if(!Z.ok)return l("codex",Z.why,"Enter to log in again");c({label:"codex",mark:"ok",detail:"logged in inside the container \u2014 saved to R2"})}let Qt=await Dt(lt,ho,"in the Cloudflare container",K=>K==="claude"?"Esc back to Agent logins and press t for a new token, then Enter":"Enter to log codex in again",c);if("label"in Qt)return l(Qt.label,Qt.detail,Qt.fix);let Ke=await dn(lt,c);if("label"in Ke)return l(Ke.label,Ke.detail,Ke.fix);let ko=Ke.live??ue;if(!await Zr(r,180,async()=>(await r.fetch(I,{redirect:"manual",signal:AbortSignal.timeout(13e4)})).status<500))return l("console",`${I} did not answer`,`look at \`pnpm --dir ${z} exec wrangler tail ${We}\`, then Enter`);c({label:"Console",mark:"ok",detail:`${I} \u2014 Sign in with GitHub`}),c({label:"Workspace",mark:"ok",detail:E}),c({label:"Next",mark:"skip",detail:`moa whoami \xB7 moa agent list \xB7 moa run ${Rn(m)} "\u2026"`});let Zt=Qt.runs[m];return{ok:!0,deployed:{runner:"cloudflare",workspaceUrl:E,consoleUrl:I,workspaceFor:Xe,...Zt?{proofRunId:Zt}:{},memory:Ke.memory,people:s.answers.people??[],...ko?{memoryKept:!0}:{},cloudflare:N,at:new Date().toISOString()}}}qe();import{randomBytes as Pi}from"node:crypto";import{chmod as Qd,mkdir as Zd,rm as eu,writeFile as tu}from"node:fs/promises";import{createServer as nu}from"node:http";import{dirname as ou}from"node:path";function ru(e,t,n){let o=e.replace(/\/+$/,"");return{name:t,url:o,redirect_url:n,callback_urls:[`${o}/api/auth/callback/github`],request_oauth_on_install:!1,public:!1,hook_attributes:{active:!1}}}var su=(e,t)=>`https://github.com${e?`/organizations/${encodeURIComponent(e)}`:""}/settings/apps/new?state=${encodeURIComponent(t)}`,au=(e,t)=>t?`https://github.com/organizations/${encodeURIComponent(t)}/settings/apps/${e}`:`https://github.com/settings/apps/${e}`,es=e=>e.replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t]),iu=(e,t)=>`<!doctype html>
190
+ `;throw new A(`moa completion takes bash or zsh, not ${JSON.stringify(e)}`)}import{spawnSync as xp}from"node:child_process";import{createInterface as ms}from"node:readline/promises";import{Writable as Ap}from"node:stream";import{render as Ep}from"ink";import{createElement as Cp}from"react";Ue();Ye();ze();Vt();at();qe();import{readFile as nu,writeFile as ou}from"node:fs/promises";var Ci=e=>pe.includes(e);async function Pi(e,t){let n=Qt(e.sys),o=JSON.parse(await nu(n,"utf8")),r=o.services.workspace.environment;for(let[a,c]of Object.entries(t))c===void 0?delete r[a]:r[a]=c.replaceAll("$",()=>"$$");await ou(n,JSON.stringify(o),{mode:384});let s=await e.sys.exec("docker",et(e.sys,"up","-d","--wait"),{timeoutMs:6e5});return s.ok?{ok:!0}:{ok:!1,why:ae(s.stderr)||"compose up failed"}}async function ru(e,t,n){let o=e.state.deployed?.workspaceUrl,r=await xe(e.sys.env),s=Object.values(r.profiles).find(i=>i.url===o);if(!o||!s)return n({label:"proof",mark:"fail",detail:"no profile on this machine for the workspace",fix:"run `moa setup` and Deploy"}),!1;let a=N({url:o,token:s.token},e.sys.fetch);for(let i=0;i<60;i++)try{await a.get("/v1/whoami");break}catch{await e.sys.sleep(1e3)}return!("label"in await Nt(a,[t],"in the image",()=>`run \`moa setup login ${t}\` again`,n))}var _i=(e,t,n)=>{let o=new Set(e.answers.loggedIn??[]);return n?o.add(t):o.delete(t),{...e,answers:{...e.answers,loggedIn:pe.filter(r=>o.has(r))}}};function Oi(e,t){return e.state.deployed?.runner==="image"&&e.sys.exists(Qt(e.sys))?!0:(t({label:"agent login",mark:"fail",detail:e.state.deployed===void 0?"nothing is deployed yet":"one agent at a time works on the published image on this machine for now",fix:"run `moa setup login` and use Agent logins, then Deploy"}),!1)}async function Ti(e,t,n,o){let{print:r}=o;if(!Oi(e,r))return{ok:!1};if(n||!po(t)){n||await o.setupToken();let a=n?Ae[t]:"CLAUDE_CODE_OAUTH_TOKEN",c=(await o.secret(n?`${a}: `:"Paste the token `claude setup-token` printed: ")).trim();if(!c||/\s/.test(c))return r({label:t,mark:"fail",detail:"nothing pasted \u2014 nothing was changed",fix:`run \`moa setup login ${t}${n?" --key":""}\` again`}),{ok:!1};r({label:t,mark:"wait",detail:"restarting the workspace on it \u2014 data kept"});let i=t==="claude"?n?"CLAUDE_CODE_OAUTH_TOKEN":Ae.claude:void 0,l=await Pi(e,{[a]:c,...i?{[i]:void 0}:{}});if(!l.ok)return r({label:t,mark:"fail",detail:l.why,fix:"`moa setup logs` says why"}),{ok:!1}}else if(await Zt(e.sys,t))r({label:t,mark:"ok",detail:"already logged in inside the container"});else{r({label:t,mark:"wait",detail:"starting its login inside the container\u2026"});let a=!1,i=await Hn(e.sys,t,l=>{let d=Fn(l);d&&!a&&(a=!0,r({label:t,mark:"wait",detail:d}))}).done;if(!i.ok||!await Zt(e.sys,t))return r({label:t,mark:"fail",detail:`the login did not finish: ${ae(i.stderr)||"no answer"}`,fix:`run \`moa setup login ${t}\` again`}),{ok:!1};r({label:t,mark:"ok",detail:"logged in inside the container \u2014 kept on its home volume"})}let s=await ru(e,t,r);return{ok:s,state:_i(e.state,t,s)}}var Xr={codex:["codex","logout"],cursor:["cursor-agent","logout"]};async function Ii(e,t,n){if(!Oi(e,n))return{ok:!1};po(t)&&await e.sys.exec("docker",et(e.sys,"exec","-T","workspace",...Xr[t]),{timeoutMs:6e4});let o=await Pi(e,t==="claude"?{CLAUDE_CODE_OAUTH_TOKEN:void 0,ANTHROPIC_API_KEY:void 0}:{[Ae[t]]:void 0});if(!o.ok)return n({label:t,mark:"fail",detail:o.why,fix:"`moa setup logs` says why"}),{ok:!1};n({label:t,mark:"ok",detail:`disconnected \u2014 \`moa setup login ${t}\` connects it again`});let r=_i(e.state,t,!1);return r.answers.agentCli===t&&(r.answers={...r.answers,agentCli:r.answers.loggedIn?.[0]}),{ok:!0,state:r}}import{Box as Ve,Text as se,useApp as Mu,useInput as Gu,usePaste as ju}from"ink";import{useEffect as zi,useMemo as Hu,useRef as At,useState as ft}from"react";ze();Vt();Ue();ze();no();Vt();at();Lt();Jt();In();qe();import{createHash as su}from"node:crypto";import{mkdir as au,readFile as iu,rm as cu,writeFile as Qr}from"node:fs/promises";import{dirname as lu,join as Ho}from"node:path";var Kn="cloudflare",ho=(e,t=2)=>e.replace(/\u001B\[[0-9;]*m/g,"").trim().split(`
191
+ `).filter(n=>n.trim()!=="").slice(-t).join(" \xB7 ").slice(0,300),Ri=e=>su("sha256").update(e).digest("hex").slice(0,12);async function Zr(e,t,n){let o=Date.now()+t*1e3;for(;Date.now()<o;){if(await n().catch(()=>!1))return!0;await e.sleep(2e3)}return!1}async function du(e,t,n,o){o({label:"codex",mark:"wait",detail:"asking codex for a code inside the container\u2026"});let r=await e.fetch(`${t}/_moa/codex/login`,{method:"POST",headers:{authorization:`Bearer ${n}`},signal:AbortSignal.timeout(16*6e4)});if(!r.ok||!r.body)return{ok:!1,why:`${r.status} ${ho(await r.text().catch(()=>""))}`};let s="",a=r.body.getReader(),c=new TextDecoder;for(;;){let{done:l,value:d}=await a.read();if(l)break;s+=c.decode(d,{stream:!0});let u=cn(s);u.url&&u.code&&o({label:"codex",mark:"wait",detail:`open ${u.url} and enter ${u.code} \u2014 waiting for you to approve it`})}return/\[moa\] codex login exited (\d+)/.exec(s)?.[1]==="0"?{ok:!0}:{ok:!1,why:ho(s.replace(/\[moa\].*$/m,""))||"codex login did not finish"}}async function uu(e,t){let n=t.match(/^ghcr\.io\/([^:]+):(.+)$/);if(!n)return{why:`not a ghcr.io image: ${t}`};let[,o,r]=n;try{let s=await(await e.fetch(`https://ghcr.io/token?scope=repository:${o}:pull`)).json(),c=(await(await e.fetch(`https://ghcr.io/v2/${o}/manifests/${r}`,{headers:{authorization:`Bearer ${s.token??""}`,accept:"application/vnd.oci.image.index.v1+json, application/vnd.docker.distribution.manifest.list.v2+json"}})).json()).manifests?.find(i=>i.platform?.os==="linux"&&i.platform?.architecture==="amd64");return c?{image:`ghcr.io/${o}@${c.digest}`}:{why:`${t} has no linux/amd64 image`}}catch(s){return{why:s instanceof Error?s.message:String(s)}}}async function Fo(e,t,n=()=>{},o=()=>{}){let{sys:r,state:s}=e,a=[],c=K=>{let J=a.findIndex(De=>De.label===K.label);J===-1?a.push(K):a[J]=K,t([...a])},i,l=(K,J,De)=>(c({label:K,mark:"fail",detail:J,fix:De}),i?{ok:!1,deployed:i}:{ok:!1}),d=r.root??Gn(),u=s.answers.domain,f=s.answers.cloudflareAccount;if(!u||!f)return l("account","no Cloudflare account or domain yet","Esc back to Checks & account, then Enter");if(mn(e))return l("memory","the last deploy kept memory in LocusGraph, and this run has no secret for it","Esc back to Memory & database and paste it again \u2014 or go on there without it");let p=s.deployed?.runner==="cloudflare"?s.deployed:void 0,g=Jr(e)?.token,y=qr(e)?.token,b=Ze(e)?.token,m=s.answers.agentCli??"claude";if(!g&&!p)return l("D1 token","none in this run \u2014 it is never saved","Esc back to Checks & account and press k");if(!y&&!p)return l("GitHub token","none in this run \u2014 it is never saved","Esc back to GitHub and press k");if(m==="claude"&&!b&&!ye(e,"claude")&&!p)return l("claude token","none in this run \u2014 it is never saved","Esc back to Agent logins and press c (or k for an API key, or choose another agent), then Enter");let w=await Xt(e);if("why"in w)return l("console sign-in",w.why,w.fix);if(w.mode==="none")return l("console sign-in","none \u2014 a console on a domain needs somebody to sign in","Esc back to Console access: \u2191 \u2193 to password, or press g for a GitHub App");let{workspaceUrl:v,consoleUrl:_}=Zn(u),H=s.answers.tenant??Ie(s.answers.owner),W=s.answers.owner,le=Ee(e),L=Ho(d,"apps","workspace"),X,D;if(Te(e)){for(let We of await bt(e))if(c(We),We.mark==="fail")return{ok:!1};for(let We of await jn(e))if(c(We),We.mark==="fail")return{ok:!1};let K=`fnmoa:${Bt()}`,J=await uu(r,Ce());if("why"in J)return l("image",`no linux/amd64 image: ${J.why}`,"Check your network and retry");let De=await r.exec("docker",["pull","--platform","linux/amd64",J.image],{timeoutMs:9e5});if(!De.ok)return l("image",`could not pull ${J.image}: ${ae(De.stderr)}`,"Check Docker and retry");if(!(await r.exec("docker",["tag",J.image,K])).ok)return l("image","Could not tag the release image","Check Docker and retry");let nn=await Fe(r,d,["containers","push",K],{account:f,timeoutMs:9e5});if(!nn.ok){let We=`${nn.stderr}
192
+ ${nn.stdout}`.split(`
193
+ `).map(h=>h.replace(/\[[0-9;]*m/g,"").trim()).find(h=>/ERROR|✘/.test(h));return l("image",`Could not push to the Cloudflare registry${We?`: ${We.replace(/^✘\s*\[ERROR\]\s*/,"")}`:""}`,"Check your Cloudflare login and retry")}if(X=`registry.cloudflare.com/${f}/${K}`,r.root){let We=await jr(r);if(!We.ok)return l("worker",`Could not copy the Worker out of ${Ce()}: ${We.why}`,"Check Docker and retry");D=We.path}else D=Gr();c({label:"image",mark:"ok",detail:`${Ce()} \u2014 the Worker and the container`})}else{c({label:"build",mark:"wait",detail:"building the Worker"});let K=await r.exec("pnpm",["install"],{cwd:d,timeoutMs:6e5}),J=K.ok?await r.exec("pnpm",["--filter","@fnmoa/workspace...","run","build"],{cwd:d,timeoutMs:9e5}):K;if(!J.ok)return l("build",ho(J.stderr||J.stdout),`run \`pnpm install && pnpm --filter @fnmoa/workspace... run build\` in ${d}, then Enter`);c({label:"build",mark:"ok",detail:"the Worker is built from this checkout"})}let{token:B,pending:ne,before:ge,had:ee}=await qt(r,Kn,v);c({label:"owner token",mark:"ok",detail:`${U} \u2014 profile ${Kn} in ~/.moa/config.json${ge===Kn||!ee?"":`; \`moa\` now talks to this workspace, not profile ${ge} (\`moa use ${ge}\` to go back)`}`});let $e=s.cloudflare??p?.cloudflare,$=$e?.account===f?$e:void 0,I=$!==void 0&&$.older!==!0&&($.d1?.unsure===!0||$.r2?.unsure===!0),oe=p!==void 0&&$e===void 0||$?.older===!0||I,O={...$,account:f,...oe?{older:!0}:{}},V=K=>{O={...O,...K},o(O)},fe=async K=>{let J=await ma(r,d,f),De=J?.image&&!(O.unsureImages??[]).includes(J.image)?[J.image]:[],ct=[...new Set([...O.images??[],...De])];V({...K?{worker:Je}:{},...J?{containerId:J.id}:{},...ct.length>0?{images:ct}:{}})};if(oe&&($===void 0||I||$.imagesUnlisted)){let K=await eo(r,d,f);if(!K.ok)V({imagesUnlisted:!0}),c({label:"images",mark:"skip",detail:`could not list Cloudflare's registry \u2014 ${K.why}; the next deploy, or \`down\`, lists it again for the tags an older moa pushed`});else{let{imagesUnlisted:J,...De}=O,ct=[...new Set([...O.unsureImages??[],...K.images.filter(nn=>!(O.images??[]).includes(nn))])];O={...De,...ct.length>0?{unsureImages:ct}:{}},o(O),ct.length>0&&c({label:"images",mark:"ok",detail:`${ct.length} tag${ct.length===1?"":"s"} of ${He} already in Cloudflare's registry \u2014 an older moa pushed them, so \`down\` asks before deleting them`})}}c({label:"D1",mark:"wait",detail:"finding the database, or making it"});let te=await pa(r,d,f);if(!te.ok)return l("D1",te.why,"fix that, then Enter");let ve=te.made||$?.d1?.id===te.id&&$.d1.made,Se=!ve&&(oe||$?.d1?.id===te.id&&$.d1.unsure===!0);V({d1:{id:te.id,made:ve,...Se?{unsure:!0}:{}}}),c({label:"D1",mark:"ok",detail:`${te.made?"made":"found"} fnmoa-workspace (${te.id})`});let Me=await fa(r,d,f);if(!Me.ok)return l("R2",Me.why,"R2 must be enabled on the account (dashboard \u2192 R2), then Enter");let Re=Me.made||$?.r2?.name===kt&&$.r2.made,Ke=!Re&&(oe||$?.r2?.name===kt&&$.r2.unsure===!0);V({r2:{name:kt,made:Re,...Ke?{unsure:!0}:{}}}),c({label:"R2",mark:"ok",detail:"fnmoa-state \u2014 codex's login, kept across restarts"});let we=on(u),_e={MOA_D1_ACCOUNT_ID:f,MOA_D1_DATABASE_ID:te.id,MOA_CONSOLE_HOST:we.console,MOA_PUBLIC_URL:v,MOA_IDLE_HOURS:String(Tt),...w.vars,AUTH_URL:_,...W?{MOA_OWNER_LOGIN:W}:{},...s.answers.repo?{MOA_REPO:s.answers.repo}:{},...le?{LOCUSGRAPH_GRAPH_ID:le.graph,LOCUSGRAPH_SERVER_URL:le.server}:{}},T={...await Wt(e),MOA_TOKENS:`${B}:${H}`,AUTH_GITHUB_SECRET:"",MOA_CONSOLE_PASSWORD_HASH:"",...w.secrets,...g?{MOA_D1_API_TOKEN:g}:{},...y?{GH_TOKEN:y}:{},...b?{CLAUDE_CODE_OAUTH_TOKEN:b}:{},...Object.fromEntries(pe.map(K=>[Ae[K],ye(e,K)??""])),LOCUSGRAPH_AGENT_SECRET:le?le.secret:""},F=await r.exec("git",["rev-parse","HEAD"],{cwd:d}),Ge=Ri(JSON.stringify([_e,F.stdout.trim()])),nt=Ri(JSON.stringify(T)),ot=ce(r,Ho("cloudflare","wrangler.json")),mt=ce(r,Ho("cloudflare","secrets.json")),me=ce(r,Ho("cloudflare","secrets.fingerprint")),bn=(await iu(me,"utf8").catch(()=>"")).trim();await au(lu(ot),{recursive:!0}),await Qr(ot,`${JSON.stringify(ga({root:d,account:f,databaseId:te.id,domain:u,vars:_e,...X?{image:X,worker:D}:{}}),null,2)}
194
+ `),c({label:"deploy",mark:"wait",detail:"the Worker, the container image and your two names \u2014 the first build takes several minutes"});let Q;try{await Qr(mt,JSON.stringify(T),{mode:384}),Q=await Fe(r,d,["deploy","--config",ot,"--secrets-file",mt],{account:f,timeoutMs:24e5})}finally{await cu(mt,{force:!0})}if(!Q.ok){let K=O.worker!==void 0||(await Fe(r,d,["deployments","list","--name",Je,"--json"],{account:f})).ok;await fe(K);let J=`${Q.stdout}
195
+ ${Q.stderr}`;return l("deploy",ho(J.split(mt).join("secrets.json")),/containers?.*(plan|paid|not enabled|entitle)/i.test(J)?"containers need the Workers Paid plan: upgrade the account, then Enter":/docker/i.test(J)?"start Docker, then Enter":"fix that, then Enter")}await fe(!0);let Le=!!le,ue=s.deployed?.workspaceUrl===v?s.deployed.people:void 0;i={runner:"cloudflare",workspaceUrl:v,consoleUrl:_,...ue?{people:ue}:{},...p?.workspaceFor?{workspaceFor:p.workspaceFor}:{},...Le?{memoryKept:Le}:{},cloudflare:O,at:new Date().toISOString()},n(i),c({label:"deploy",mark:"ok",detail:`Worker ${Je} \u2014 ${we.workspace}, ${we.console}`});let Be=N({url:v,token:B},r.fetch),gt=(K,J={})=>r.fetch(`${v}${K}`,{...J,headers:{authorization:`Bearer ${B}`},signal:AbortSignal.timeout(3e4)});if(c({label:"container",mark:"wait",detail:`waiting for ${we.workspace} to answer`}),!await Zr(r,600,async()=>(await gt("/_moa/box")).ok))return l("container",`${v} did not answer the owner token in 10 minutes`,"a new name can take a while for its certificate: Enter to try again");(p?.workspaceFor!==Ge||bn!==nt)&&await gt("/_moa/restart",{method:"POST"}).catch(()=>{}),c({label:"container",mark:"wait",detail:"starting the workspace and console in it"});let Ct={};if(!await Zr(r,600,async()=>(Ct=await(await r.fetch(`${v}/health`,{signal:AbortSignal.timeout(13e4)})).json().catch(()=>({})),Ct.ok===!0)))return l("container",`the workspace did not come up: ${ho(String(Ct.error??"no answer"),1)}`,`look at \`pnpm --dir ${L} exec wrangler tail ${Je}\`, then Enter`);if(await Qr(me,`${nt}
196
+ `,{mode:384}),i={...i,workspaceFor:Ge},n(i),c({label:"container",mark:"ok",detail:`${v} \u2014 kept up ${Tt}h after the last request`}),c({label:"database",mark:"ok",detail:`${Ct.database??"d1"} \u2014 migrated, and it answers`}),!await Be.get("/v1/whoami").then(()=>!0,()=>!1))return l("workspace","it answers but refuses the owner token","Enter to try again");ne&&await zt(r,Kn,v,B);let jt=await pn(Be,s,c,ue);if(jt)return l(jt.label,jt.detail,jt.fix);i={...i,people:s.answers.people??[]},n(i);let Yn=[...new Set([m,...s.answers.loggedIn??[]])];if(Yn.includes("codex")&&!ye(e,"codex"))if((await gt("/_moa/codex").then(J=>J.json()).catch(()=>({}))).loggedIn)c({label:"codex",mark:"ok",detail:"logged in inside the container \u2014 kept in R2"});else{let J=await du(r,v,B,c).catch(De=>({ok:!1,why:De instanceof Error?De.message:String(De)}));if(!J.ok)return l("codex",J.why,"Enter to log in again");c({label:"codex",mark:"ok",detail:"logged in inside the container \u2014 saved to R2"})}let Pt=await Nt(Be,Yn,"in the Cloudflare container",K=>K==="claude"?"Esc back to Agent logins and press t for a new token, then Enter":"Enter to log codex in again",c);if("label"in Pt)return l(Pt.label,Pt.detail,Pt.fix);let Ht=await fn(Be,c);if("label"in Ht)return l(Ht.label,Ht.detail,Ht.fix);let _t=Ht.live??Le;if(!await Zr(r,180,async()=>(await r.fetch(_,{redirect:"manual",signal:AbortSignal.timeout(13e4)})).status<500))return l("console",`${_} did not answer`,`look at \`pnpm --dir ${L} exec wrangler tail ${Je}\`, then Enter`);c({label:"Console",mark:"ok",detail:`${_} \u2014 Sign in with GitHub`}),c({label:"Workspace",mark:"ok",detail:v}),c({label:"Next",mark:"skip",detail:`moa whoami \xB7 moa agent list \xB7 moa run ${Nn(m)} "\u2026"`});let it=Pt.runs[m];return{ok:!0,deployed:{runner:"cloudflare",workspaceUrl:v,consoleUrl:_,workspaceFor:Ge,...it?{proofRunId:it}:{},memory:Ht.memory,people:s.answers.people??[],..._t?{memoryKept:!0}:{},cloudflare:O,at:new Date().toISOString()}}}ze();import{randomBytes as Li}from"node:crypto";import{chmod as pu,mkdir as fu,rm as mu,writeFile as gu}from"node:fs/promises";import{createServer as hu}from"node:http";import{dirname as wu}from"node:path";function ku(e,t,n){let o=e.replace(/\/+$/,"");return{name:t,url:o,redirect_url:n,callback_urls:[`${o}/api/auth/callback/github`],request_oauth_on_install:!1,public:!1,hook_attributes:{url:`${o}/api/github/webhook`,active:!1}}}var yu=(e,t)=>`https://github.com${e?`/organizations/${encodeURIComponent(e)}`:""}/settings/apps/new?state=${encodeURIComponent(t)}`,bu=(e,t)=>t?`https://github.com/organizations/${encodeURIComponent(t)}/settings/apps/${e}`:`https://github.com/settings/apps/${e}`,es=e=>e.replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t]),$u=(e,t)=>`<!doctype html>
194
197
  <meta charset="utf-8"><title>moa setup \u2014 GitHub App</title>
195
198
  <form id="f" method="post" action="${es(e)}">
196
199
  <input type="hidden" name="manifest" value="${es(JSON.stringify(t))}">
197
200
  <p>Taking you to GitHub to create the app\u2026 <button type="submit">Go</button></p>
198
201
  </form>
199
202
  <script>document.getElementById("f").submit()</script>
200
- `,Bo=e=>`<!doctype html><meta charset="utf-8"><title>moa setup</title><p>${es(e)}</p>`;async function cu(e){let t=Pi(16).toString("hex"),n,o=new Promise((i,l)=>{n={ok:i,no:l}}),r=nu((i,l)=>{let d=new URL(i.url??"/","http://127.0.0.1"),u=(p,g,b)=>{l.writeHead(p,{"content-type":"text/html; charset=utf-8"}),l.end(g,b)};if(d.pathname==="/"){let p=r.address().port,g=ru(e.consoleUrl,e.name,`http://127.0.0.1:${p}/created`);return u(200,iu(su(e.org,t),g))}if(d.pathname!=="/created")return u(404,Bo("Nothing here."));let f=d.searchParams.get("code");if(!f||d.searchParams.get("state")!==t)return u(400,Bo("That is not the app moa setup asked for. Try again from setup."));lu(e.fetch,f).then(p=>u(200,Bo(`Created ${p.slug}. Back to the terminal.`),()=>n?.ok(p)),p=>u(502,Bo(`GitHub would not hand the app over: ${p.message}`),()=>n?.no(p)))});await new Promise((i,l)=>{r.once("error",l),r.listen(0,"127.0.0.1",()=>i())});let s=`http://127.0.0.1:${r.address().port}/`,a=setTimeout(()=>n?.no(new Error("no app came back from GitHub \u2014 press g to try again")),e.timeoutMs??15*6e4),c=()=>n?.no(new Error("stopped"));e.signal?.addEventListener("abort",c,{once:!0});try{return e.onPage?.(s),await e.open(s),await o}finally{clearTimeout(a),e.signal?.removeEventListener("abort",c),r.closeAllConnections(),r.close()}}async function lu(e,t){let n=await e(`https://api.github.com/app-manifests/${encodeURIComponent(t)}/conversions`,{method:"POST",headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}}),o=await n.json().catch(()=>({}));if(!n.ok)throw new Error(String(o.message??`GitHub said ${n.status}`));let{id:r,slug:s,client_id:a,client_secret:c,html_url:i,owner:l}=o;if(typeof r!="number"||!s||!a||!c)throw new Error("GitHub's answer had no app in it");return{id:r,slug:s,clientId:a,clientSecret:c,htmlUrl:i??`https://github.com/apps/${s}`,...l?{owner:l}:{}}}async function du(e,t){let[n,o]=process.platform==="darwin"?["open",[t]]:process.platform==="win32"?["cmd",["/c","start","",t]]:["xdg-open",[t]];await e.exec(n,o)}async function ts(e,t,n){let o=Go(e,t);await Zd(ou(o),{recursive:!0}),await tu(o,`${JSON.stringify(n,null,2)}
201
- `,{mode:384}),await Qd(o,384)}async function ns(e,t){await eu(Go(e,t),{force:!0})}async function _i(e,t,n,o=r=>du(e.sys,r)){let{state:r,sys:s}=e,a=r.answers.appOrg,c=r.answers.tenant??Ie(r.answers.owner);if(r.target==="vercel"&&!r.answers.sandbox?.consoleUrl)throw new Error("no sandbox yet \u2014 Esc back to Agent logins, where it is made");if(r.target==="cloudflare"&&!r.answers.domain)throw new Error("no domain yet \u2014 Esc back to Checks & account and press d");let i=jo(r),l=await cu({consoleUrl:i,name:`fnmoa-${c}`.slice(0,34),...a?{org:a}:{},fetch:s.fetch,open:o,onPage:p=>t([{label:"GitHub App",mark:"wait",detail:`click Create on GitHub \u2014 if no browser opened: ${p}`}]),...n?{signal:n}:{}}),d=r.answers.githubApp,u=(d?He(s,d)?.authSecret:void 0)??Pi(32).toString("base64url");await ts(s,l,{clientSecret:l.clientSecret,authSecret:u}),d&&d.id!==l.id&&await ns(s,d);let f=l.owner?.type==="Organization"?l.owner.login:a;return{githubApp:{id:l.id,slug:l.slug,clientId:l.clientId,settingsUrl:au(l.slug,f),consoleUrl:i}}}it();It();Ft();qe();Zn();it();Je();an();var uu={local:"This machine",vercel:"Vercel Sandbox",cloudflare:"Cloudflare"};function Ti(e){let{state:t,sys:n}=e,{answers:o}=t,r=t.target??"local",s=[{label:"Target",value:uu[r]}];s.push({label:"fnMoa",value:Oe(e)?Ae():`built from this checkout (${n.root})`}),o.repo&&s.push({label:"Repository",value:o.repo}),o.owner&&s.push({label:"GitHub",value:o.owner}),s.push({label:"Database",value:r==="cloudflare"?"D1":r==="vercel"?o.store==="sqlite"?"SQLite on the sandbox's kept disk":"Postgres on the sandbox's kept disk":o.runner==="compose"?"Postgres, with docker compose":"SQLite"}),s.push({label:"Agent",value:o.agentCli??"claude"}),s.push({label:"Memory",value:xe(e)?"LocusGraph":"in the workspace process"}),r==="cloudflare"&&o.domain?s.push({label:"Domain",value:o.domain}):r==="vercel"&&o.vercelTeam?s.push({label:"Vercel team",value:o.vercelTeam}):r==="local"&&s.push({label:"Ports",value:`workspace ${Jt(t)} \xB7 console ${Ut(t)}`});let a=ut.filter(i=>i!=="deploy"),c=a.filter(i=>t.passed.includes(i)).length;return s.push({label:"Checks",value:`${c} of ${a.length} screens passed`}),s.push({label:"Cost",value:r==="cloudflare"?`Workers Paid, plus the container (standard-4) while it runs \u2014 up to ${_t}h after the last request`:r==="vercel"?Lo($t(o.vercelPlan??"hobby")):"nothing billed \u2014 it runs on this machine"}),s}Je();De();Ze();qe();Wt();It();Pn();Je();an();qe();it();Ft();Je();an();qe();it();It();an();import{randomUUID as pu}from"node:crypto";import{mkdtemp as Oi,readFile as fu,rm as Ii,writeFile as mu}from"node:fs/promises";import{tmpdir as Ri}from"node:os";import{join as Gn}from"node:path";async function gu(e,t){if(!t.writeFiles)throw new Error("This sandbox SDK cannot upload the release archive.");let n=await Oi(Gn(Ri(),"fnmoa-image-")),o=`fnmoa-export-${pu()}`,r=!1;try{if(!(await e.sys.exec("docker",["create","--platform","linux/amd64","--name",o,Ae()])).ok)throw new Error("Could not open the release image.");if(r=!0,!(await e.sys.exec("docker",["cp",`${o}:/repo`,Gn(n,"repo")],{timeoutMs:6e5})).ok)throw new Error("Could not export the built release.");if(!(await e.sys.exec("tar",["-czf",Gn(n,"release.tgz"),"-C",n,"repo"],{timeoutMs:6e5})).ok)throw new Error("Could not archive the built release.");if(await t.writeFiles([{path:"/tmp/fnmoa-release.tgz",content:await fu(Gn(n,"release.tgz"))}]),await Do(t),!(await Ue(t,`set -eu
203
+ `,Ko=e=>`<!doctype html><meta charset="utf-8"><title>moa setup</title><p>${es(e)}</p>`;async function vu(e){let t=Li(16).toString("hex"),n,o=new Promise((i,l)=>{n={ok:i,no:l}}),r=hu((i,l)=>{let d=new URL(i.url??"/","http://127.0.0.1"),u=(p,g,y)=>{l.writeHead(p,{"content-type":"text/html; charset=utf-8"}),l.end(g,y)};if(d.pathname==="/"){let p=r.address().port,g=ku(e.consoleUrl,e.name,`http://127.0.0.1:${p}/created`);return u(200,$u(yu(e.org,t),g))}if(d.pathname!=="/created")return u(404,Ko("Nothing here."));let f=d.searchParams.get("code");if(!f||d.searchParams.get("state")!==t)return u(400,Ko("That is not the app moa setup asked for. Try again from setup."));Su(e.fetch,f).then(p=>u(200,Ko(`Created ${p.slug}. Back to the terminal.`),()=>n?.ok(p)),p=>u(502,Ko(`GitHub would not hand the app over: ${p.message}`),()=>n?.no(p)))});await new Promise((i,l)=>{r.once("error",l),r.listen(0,"127.0.0.1",()=>i())});let s=`http://127.0.0.1:${r.address().port}/`,a=setTimeout(()=>n?.no(new Error("no app came back from GitHub \u2014 press g to try again")),e.timeoutMs??15*6e4),c=()=>n?.no(new Error("stopped"));e.signal?.addEventListener("abort",c,{once:!0});try{return e.onPage?.(s),await e.open(s),await o}finally{clearTimeout(a),e.signal?.removeEventListener("abort",c),r.closeAllConnections(),r.close()}}async function Su(e,t){let n=await e(`https://api.github.com/app-manifests/${encodeURIComponent(t)}/conversions`,{method:"POST",headers:{accept:"application/vnd.github+json","x-github-api-version":"2022-11-28"}}),o=await n.json().catch(()=>({}));if(!n.ok)throw new Error(String(o.message??`GitHub said ${n.status}`));let{id:r,slug:s,client_id:a,client_secret:c,html_url:i,owner:l}=o;if(typeof r!="number"||!s||!a||!c)throw new Error("GitHub's answer had no app in it");return{id:r,slug:s,clientId:a,clientSecret:c,htmlUrl:i??`https://github.com/apps/${s}`,...l?{owner:l}:{}}}async function xu(e,t){let[n,o]=process.platform==="darwin"?["open",[t]]:process.platform==="win32"?["cmd",["/c","start","",t]]:["xdg-open",[t]];await e.exec(n,o)}async function ts(e,t,n){let o=Go(e,t);await fu(wu(o),{recursive:!0}),await gu(o,`${JSON.stringify(n,null,2)}
204
+ `,{mode:384}),await pu(o,384)}async function ns(e,t){await mu(Go(e,t),{force:!0})}async function Di(e,t,n,o=r=>xu(e.sys,r)){let{state:r,sys:s}=e,a=r.answers.appOrg,c=r.answers.tenant??Ie(r.answers.owner);if(r.target==="vercel"&&!r.answers.sandbox?.consoleUrl)throw new Error("no sandbox yet \u2014 Esc back to Agent logins, where it is made");if(r.target==="cloudflare"&&!r.answers.domain)throw new Error("no domain yet \u2014 Esc back to Checks & account and press d");let i=Mo(r),l=await vu({consoleUrl:i,name:`fnmoa-${c}`.slice(0,34),...a?{org:a}:{},fetch:s.fetch,open:o,onPage:p=>t([{label:"GitHub App",mark:"wait",detail:`click Create on GitHub \u2014 if no browser opened: ${p}`}]),...n?{signal:n}:{}}),d=r.answers.githubApp,u=(d?en(s,d)?.authSecret:void 0)??Li(32).toString("base64url");await ts(s,l,{clientSecret:l.clientSecret,authSecret:u}),d&&d.id!==l.id&&await ns(s,d);let f=l.owner?.type==="Organization"?l.owner.login:a;return{githubApp:{id:l.id,slug:l.slug,clientId:l.clientId,settingsUrl:bu(l.slug,f),consoleUrl:i}}}at();Lt();Jt();ze();no();at();qe();dn();var Au={local:"This machine",vercel:"Vercel Sandbox",cloudflare:"Cloudflare"};function Ui(e){let{state:t,sys:n}=e,{answers:o}=t,r=t.target??"local",s=[{label:"Target",value:Au[r]}];s.push({label:"fnMoa",value:Te(e)?Ce():`built from this checkout (${n.root})`}),o.repo&&s.push({label:"Repository",value:o.repo}),o.owner&&s.push({label:"GitHub",value:o.owner}),s.push({label:"Database",value:r==="cloudflare"?"D1":r==="vercel"?o.store==="sqlite"?"SQLite on the sandbox's kept disk":"Postgres on the sandbox's kept disk":o.runner==="compose"?"Postgres, with docker compose":"SQLite"}),s.push({label:"Agent",value:o.agentCli??"claude"}),s.push({label:"Memory",value:Ee(e)?"LocusGraph":"in the workspace process"}),r==="cloudflare"&&o.domain?s.push({label:"Domain",value:o.domain}):r==="vercel"&&o.vercelTeam?s.push({label:"Vercel team",value:o.vercelTeam}):r==="local"&&s.push({label:"Ports",value:`workspace ${Yt(t)} \xB7 console ${Mt(t)}`});let a=dt.filter(i=>i!=="deploy"),c=a.filter(i=>t.passed.includes(i)).length;return s.push({label:"Checks",value:`${c} of ${a.length} screens passed`}),s.push({label:"Cost",value:r==="cloudflare"?`Workers Paid, plus the container (standard-4) while it runs \u2014 up to ${Tt}h after the last request`:r==="vercel"?Ro(vt(o.vercelPlan??"hobby")):"nothing billed \u2014 it runs on this machine"}),s}qe();Ue();Ye();ze();Vt();Lt();In();qe();dn();ze();at();Jt();qe();dn();ze();at();Lt();dn();import{randomUUID as Eu}from"node:crypto";import{mkdtemp as Ni,readFile as Cu,rm as Mi,writeFile as Pu}from"node:fs/promises";import{tmpdir as Gi}from"node:os";import{join as Bn}from"node:path";async function _u(e,t){if(!t.writeFiles)throw new Error("This sandbox SDK cannot upload the release archive.");let n=await Ni(Bn(Gi(),"fnmoa-image-")),o=`fnmoa-export-${Eu()}`,r=!1;try{if(!(await e.sys.exec("docker",["create","--platform","linux/amd64","--name",o,Ce()])).ok)throw new Error("Could not open the release image.");if(r=!0,!(await e.sys.exec("docker",["cp",`${o}:/repo`,Bn(n,"repo")],{timeoutMs:6e5})).ok)throw new Error("Could not export the built release.");if(!(await e.sys.exec("tar",["-czf",Bn(n,"release.tgz"),"-C",n,"repo"],{timeoutMs:6e5})).ok)throw new Error("Could not archive the built release.");if(await t.writeFiles([{path:"/tmp/fnmoa-release.tgz",content:await Cu(Bn(n,"release.tgz"))}]),await Lo(t),!(await Ne(t,`set -eu
202
205
  mkdir -p "$HOME/moa/release-next"
203
206
  tar -xzf /tmp/fnmoa-release.tgz -C "$HOME/moa/release-next"
204
207
  rm -f "$HOME/moa/fnmoa"
205
208
  ln -s "$HOME/moa/release-next/repo" "$HOME/moa/fnmoa"
206
- rm -f /tmp/fnmoa-release.tgz`)).ok)throw new Error("Could not install the release; the existing data is kept.")}finally{r&&await e.sys.exec("docker",["rm",o]),await Ii(n,{recursive:!0,force:!0})}}async function Li(e,t,n){let o=e.sys.vercel;if(!o)return _("sandbox","Vercel SDK unavailable","Update the CLI");try{for(let i of await yt(e))if(i.mark==="fail")return i;let r=ao(e.state.answers.tenant??e.state.answers.owner??"workspace"),s=await o.get(t,r,!0),a=Gt();if(s&&await Uo(s)===a)return{box:s,built:!1,info:{name:r,workspaceUrl:s.domain(8787),consoleUrl:s.domain(3100),revision:a}};for(let i of await Un(e))if(i.mark==="fail")return i;if(s)n("Updating the application files; keeping the sandbox's data disk"),await gu(e,s);else{let i=await e.sys.fetch(`https://api.vercel.com/v9/projects/${encodeURIComponent(t.projectId)}?teamId=${encodeURIComponent(t.teamId)}`,{headers:{authorization:`Bearer ${t.token}`},signal:AbortSignal.timeout(15e3)});if(!i.ok)throw new Error("Could not resolve the Vercel project's registry name.");let{name:l}=await i.json();if(!/^[a-z0-9-]+$/i.test(l)||!/^[a-z0-9-]+$/i.test(t.team))throw new Error("Invalid Vercel registry namespace.");let d=`vcr.vercel.com/${t.team}/${l}/fnmoa:${a}`,u=await Oi(Gn(Ri(),"fnmoa-vcr-"));try{if(await mu(Gn(u,"config.json"),JSON.stringify({auths:{"vcr.vercel.com":{auth:Buffer.from(`${t.teamId}:${t.token}`).toString("base64")}}}),{mode:384}),n(`Copying ${Ae()} to Vercel`),!(await e.sys.exec("docker",["tag",Ae(),d])).ok)throw new Error("Could not tag the release for Vercel.");if(!(await e.sys.exec("docker",["--config",u,"push",d],{timeoutMs:9e5})).ok)throw new Error("Could not push the release to Vercel Container Registry.")}finally{await Ii(u,{recursive:!0,force:!0})}if(n("Starting the sandbox from the release image"),s=await o.create(t,{name:r,size:$t(t.plan),image:`fnmoa:${a}`}),!(await Ue(s,`set -eu
209
+ rm -f /tmp/fnmoa-release.tgz`)).ok)throw new Error("Could not install the release; the existing data is kept.")}finally{r&&await e.sys.exec("docker",["rm",o]),await Mi(n,{recursive:!0,force:!0})}}async function ji(e,t,n){let o=e.sys.vercel;if(!o)return C("sandbox","Vercel SDK unavailable","Update the CLI");try{for(let i of await bt(e))if(i.mark==="fail")return i;let r=lo(e.state.answers.tenant??e.state.answers.owner??"workspace"),s=await o.get(t,r,!0),a=Bt();if(s&&await Do(s)===a)return{box:s,built:!1,info:{name:r,workspaceUrl:s.domain(8787),consoleUrl:s.domain(3100),revision:a}};for(let i of await jn(e))if(i.mark==="fail")return i;if(s)n("Updating the application files; keeping the sandbox's data disk"),await _u(e,s);else{let i=await e.sys.fetch(`https://api.vercel.com/v9/projects/${encodeURIComponent(t.projectId)}?teamId=${encodeURIComponent(t.teamId)}`,{headers:{authorization:`Bearer ${t.token}`},signal:AbortSignal.timeout(15e3)});if(!i.ok)throw new Error("Could not resolve the Vercel project's registry name.");let{name:l}=await i.json();if(!/^[a-z0-9-]+$/i.test(l)||!/^[a-z0-9-]+$/i.test(t.team))throw new Error("Invalid Vercel registry namespace.");let d=`vcr.vercel.com/${t.team}/${l}/fnmoa:${a}`,u=await Ni(Bn(Gi(),"fnmoa-vcr-"));try{if(await Pu(Bn(u,"config.json"),JSON.stringify({auths:{"vcr.vercel.com":{auth:Buffer.from(`${t.teamId}:${t.token}`).toString("base64")}}}),{mode:384}),n(`Copying ${Ce()} to Vercel`),!(await e.sys.exec("docker",["tag",Ce(),d])).ok)throw new Error("Could not tag the release for Vercel.");if(!(await e.sys.exec("docker",["--config",u,"push",d],{timeoutMs:9e5})).ok)throw new Error("Could not push the release to Vercel Container Registry.")}finally{await Mi(u,{recursive:!0,force:!0})}if(n("Starting the sandbox from the release image"),s=await o.create(t,{name:r,size:vt(t.plan),image:`fnmoa:${a}`}),!(await Ne(s,`set -eu
207
210
  mkdir -p "$HOME/moa"
208
- ln -s /repo "$HOME/moa/fnmoa"`)).ok)throw new Error("Could not prepare the sandbox's application directory.")}if(!(await Ue(s,'printf %s "$VERSION" > "$HOME/moa/image"',{VERSION:a})).ok)throw new Error("Could not record the installed version.");return{box:s,built:!0,info:{name:r,workspaceUrl:s.domain(8787),consoleUrl:s.domain(3100),revision:a}}}catch(r){return _("sandbox",r instanceof Error?r.message:String(r),"Check your account and retry; data is kept.")}}var os=e=>{if(!e.vercel)throw new Error("this build of moa cannot reach Vercel");return e.vercel},rs=e=>e.answers.tenant??Ie(e.answers.owner),Di=e=>{let t=/^git@([^:]+):(.+)$/.exec(e.trim());return t?`https://${t[1]}/${t[2]}`:e.trim()};async function Mi(e){let t=e.root;if(!t)return{why:"not inside a fnMoa checkout",fix:"run moa setup from a clone of https://github.com/fnLog0/fnmoa"};let n=(...i)=>e.exec("git",["-C",t,...i]),[o,r,s]=await Promise.all([n("rev-parse","HEAD"),n("remote","get-url","origin"),n("branch","-r","--contains","HEAD")]),a=de(o.stdout),c=de(r.stdout);return!o.ok||!a||!r.ok||!c?{why:"this checkout has no commit, or no origin",fix:"clone fnMoa from GitHub"}:!s.ok||!s.stdout.trim()?{why:`commit ${a.slice(0,7)} is not on ${Di(c)} \u2014 the sandbox clones it from there`,fix:"push it, or check out a commit that is pushed, then press r"}:{url:Di(c),revision:a}}async function ss(e){try{let{vercelTeam:t,vercelScope:n}=e.state.answers;return await os(e.sys).account(t,n)}catch(t){let n=t instanceof Error?t.message:String(t);return _("account",n,/not installed/.test(n)?"install the Vercel CLI: npm i -g vercel":/signed in|token/i.test(n)?"run `vercel login`, then press r":"check the team (e), then press r")}}var Wo=e=>typeof e=="object"&&e!==null&&"mark"in e;async function hu(e){let{sys:t}=e,o=[Number(process.versions.node.split(".")[0])>=22?v("node",process.versions.node):_("node",process.versions.node,"install node 22 or newer"),...await Promise.all([pn(t,"git","install git"),pn(t,"gh","install the GitHub CLI: https://cli.github.com"),pn(t,"vercel","install the Vercel CLI: npm i -g vercel")])],r=Oe(e)?{url:"GHCR",revision:Ae()}:await Mi(t);o.push("why"in r?_("fnMoa",r.why,r.fix):v("fnMoa",`${r.revision.slice(0,7)} from ${r.url} \u2014 built in the sandbox`));let s=await ss(e);if(Wo(s))return o.push(s),{lines:o};let a=$t(s.plan);return o.push(v("account",`${s.user} \xB7 team ${s.team} \xB7 ${oi(s.plan,a)}`),v("estimate",Lo(a)),v("storage",ri(a))),s.plan==="hobby"&&o.push(H("note","Hobby: a session stops after 45 minutes \u2014 `moa setup status` starts it again, and pipelines carry on")),{lines:o,answers:{vercelTeam:s.team,vercelPlan:s.plan,vercelScope:{teamId:s.teamId,projectId:s.projectId}}}}async function Jo(e){if(e.secrets.github)return{token:e.secrets.github,from:"pasted"};if(e.state.answers.githubToken==="pasted"&&e.state.deployed?.runner==="vercel")return{kept:!0};let t=await e.sys.exec("gh",["auth","token"]),n=de(t.stdout);return t.ok&&n?{token:n,from:"own"}:void 0}async function Ui(e,t,n){try{let o=await e.fetch(`https://api.github.com${n}`,{headers:{Authorization:`Bearer ${t}`,Accept:"application/vnd.github+json"},signal:AbortSignal.timeout(15e3)});return o.ok?await o.json():o.status}catch{return 0}}async function wu(e){let{sys:t,state:n}=e,o=await t.exec("gh",["api","user","--jq",".login"]),r=de(o.stdout);if(!o.ok||!r)return{lines:[_("gh login",o.missing?"gh is not installed":"gh has no login on this machine","run `gh auth login`, then press r to check again")]};let s=[v("owner",`${r} \u2014 you, the first owner`)],a=await Jo(e),c,i;if(!a)s.push(_("GitHub token","none for the sandbox","press k to paste a fine-grained token \u2014 a bot account's is best"));else if("kept"in a)i="pasted",s.push(H("GitHub token","the one pasted before, kept in the sandbox (k to replace it)"));else{let d=await Ui(t,a.token,"/user");typeof d=="number"?s.push(_("GitHub token",`GitHub refused it${d?` (${d})`:""}`,"press k to paste another \u2014 contents, pull requests, issues read/write; checks, actions read")):(c=a.token,i=a.from,s.push(v("GitHub token",a.from==="pasted"?`${D} \u2014 ${d.login??"?"}${d.login?.toLowerCase()===r.toLowerCase()?" (your own)":" (bot account)"}`:`${D} \u2014 your own gh login; a bot account's is better (k to paste one)`)))}let l=n.answers.repo;if(!l)s.push(H("repo","none \u2014 a pipeline can name any repository later (e to set one)"));else if(c){let d=await Ui(t,c,`/repos/${l}`);s.push(typeof d!="number"&&d.permissions?.push?v("repo",`${l} \u2014 the token can push`):_("repo",typeof d=="number"?`${l} is not a repository the token can see`:`the token cannot push to ${l}`,"give the token this repository, or press e to change it"))}return{lines:s,answers:{owner:r,...i?{githubToken:i}:{}}}}async function as(e,t,n=()=>{}){if(Oe(e))return Li(e,t,n);let o=os(e.sys),r=await Mi(e.sys);if("why"in r)return _("sandbox",r.why,r.fix);let s=ao(rs(e.state)),a=e.state.answers.sandbox?.name===s?e.state.answers.sandbox:void 0,c=a?.teamId===t.teamId&&a.projectId===t.projectId?a.snapshotId:void 0,i=$t(t.plan),l,d=c,u=!1;try{n(`looking for ${s}`),l=await o.get(t,s,!0),!l&&d&&(n(`making ${s} from its snapshot \u2014 ${i.vcpus} vCPU, persistent`),l=await o.create(t,{name:s,size:i,snapshotId:d}).catch(()=>{}),l||(d=void 0)),l||(n(`making ${s} \u2014 ${i.vcpus} vCPU, persistent`),l=await o.create(t,{name:s,size:i}),u=!0)}catch(p){return _("sandbox",p instanceof Error?p.message.split(`
209
- `)[0]??"":String(p),"check the account on Checks & account, then press r")}let f=!1;if(await Uo(l)!==r.revision){n("stopping the servers before the build");try{await Do(l)}catch(b){return _("sandbox",`the servers did not stop: ${b instanceof Error?b.message:String(b)}`,"press r to try again")}n(`building the image at ${r.revision.slice(0,7)} \u2014 several minutes the first time`);let p=await Jo(e),g=await ii(l,r.url,r.revision,p&&"token"in p?p.token:void 0);if(!g.ok)return _("sandbox",`the image did not build: ${vt(g.stderr||g.stdout)}`,"fix that, then press r");if(f=!0,u){n("snapshotting the image");try{d=await l.snapshot(),l=await o.get(t,s,!0)??l}catch{}}}return{box:l,built:f,info:{name:s,workspaceUrl:l.domain(ft),consoleUrl:l.domain(sn),...d?{snapshotId:d,teamId:t.teamId,projectId:t.projectId}:{},revision:r.revision}}}var ku=async(e,t)=>(await Ue(e,`test -s "$HOME/moa/env/workspace/${t}"`)).ok;async function yu(e,t){return Ue(e,t?'claude -p "$PROMPT"':'CLAUDE_CODE_OAUTH_TOKEN=$(cat "$HOME/moa/env/workspace/CLAUDE_CODE_OAUTH_TOKEN") exec claude -p "$PROMPT"',{PROMPT:En,...t?{CLAUDE_CODE_OAUTH_TOKEN:t}:{}},18e4)}async function bu(e){let{state:t}=e,n=await ss(e);if(Wo(n))return{lines:[n]};let o=await as(e,n);if(Wo(o))return{lines:[o]};let{box:r,info:s}=o,a=$t(n.plan),c=[v("sandbox",`${s.name} \u2014 ${r.vcpus??a.vcpus} vCPU, persistent, fnMoa ${s.revision?.slice(0,7)??""}`)],i={claude:!1,codex:!1,cursor:!1},l=tt(e),d=!l&&await ku(r,"CLAUDE_CODE_OAUTH_TOKEN");if(l||d){let p=await yu(r,l?.token);i.claude=p.ok&&/\bok\b/i.test(p.stdout),c.push(i.claude?v("claude",`token ${D} (${l?l.from:"kept in the sandbox"}) \u2014 "reply ok" in the sandbox`):_("claude",`the token did not answer: ${vt(p.stdout||p.stderr)||"no answer"}`,"press c to make a new one with `claude setup-token`, or k for an API key"))}else $e(e,"claude")?(i.claude=!0,c.push(v("claude",`ANTHROPIC_API_KEY ${D} \u2014 carried into the sandbox`))):c.push(H("claude","not connected \u2014 c for your Claude subscription, or k for an API key"));if($e(e,"codex"))i.codex=!0,c.push(v("codex",`OPENAI_API_KEY ${D} \u2014 carried into the sandbox`));else{let p=await r.exec("codex",["login","status"],{timeoutMs:6e4});i.codex=p.ok,c.push(p.ok?v("codex",`${de(p.stdout)||"logged in"} \u2014 its own session in the sandbox (c to log in again)`):H("codex","not connected \u2014 c to log in with a code (ChatGPT), or k for an API key"))}if($e(e,"cursor"))i.cursor=!0,c.push(v("cursor",`CURSOR_API_KEY ${D} \u2014 carried into the sandbox`));else{let p=await r.exec("cursor-agent",["status"],{timeoutMs:6e4});i.cursor=p.ok&&!/not logged in/i.test(`${p.stdout}${p.stderr}`),c.push(i.cursor?v("cursor","logged in \u2014 its own session in the sandbox (c to log in again)"):H("cursor","not connected \u2014 c to log in with your Cursor account, or k for an API key"))}let u=pe.filter(p=>i[p]),f=t.answers.agentCli??u[0];return f?c.push(i[f]?v("proof run",`uses ${f} (\u2191 \u2193 to change) \xB7 ${u.length} of 3 connected`):_("proof run",`${f} is not connected in the sandbox`,"press c to connect it or k for its API key \u2014 or \u2191 \u2193 to another agent")):c.push(_("agent","no agent is connected in the sandbox","\u2191 \u2193 to an agent, then c to connect it or k for its API key")),c.push(H("note","owner only: your subscriptions; teammates use them, never see them (moa setup login)")),{lines:c,answers:{sandbox:s,...f?{agentCli:f}:{},loggedIn:u}}}function Ni(e,t,n="codex"){let o=!1,r=()=>{o=!0};return{done:(async()=>{let a=await ss(e);if(Wo(a))return{ok:!1,stdout:"",stderr:a.detail??"no account"};let c=e.state.answers.sandbox?.name??ao(rs(e.state)),i=await os(e.sys).get(a,c,!0);if(!i)return{ok:!1,stdout:"",stderr:`${c} is not there`};if(o)return{ok:!1,stdout:"",stderr:"stopped"};let l="",d=n==="codex"?i.stream("codex",["login","--device-auth"],u=>{l+=u,t(rn(l))}):i.stream("env",["NO_OPEN_BROWSER=1","cursor-agent","login"],u=>{l+=u,t(No(l))});return r=d.cancel,d.done})(),cancel:()=>r()}}async function $u(e){let{sys:t,state:n,secrets:o}=e,r=xe(e),s=[],a=Vr(e);if(a)s.push(a);else if(r){let i=await Cn(t,r,rs(n)),l=`secret ${D} (${r.from}), graph ${r.graph}`;s.push(i.read.ok&&i.write.ok?v("LocusGraph",`${l} \u2014 one graph read, one event written`):_("LocusGraph",`${l} \u2014 ${i.read.ok?`the write failed: ${i.write.why}`:`the read failed: ${i.read.why}`}`,"e to paste the secret again, or g to check the graph ID \u2014 then r"))}else n.deployed?.runner==="vercel"&&n.deployed.memoryKept&&!o.noLocusgraph?s.push(H("LocusGraph","the secret the last deploy gave the sandbox, kept there (e to replace it)")):s.push(H("LocusGraph","not connected \u2014 memory stays in the workspace process (g for the graph ID, e for its secret)"));let c=n.answers.store??"postgres";return s.push(c==="postgres"?v("database","Postgres, in the sandbox on its kept disk \u2014 migrated at deploy (\u2191 \u2193 for SQLite)"):v("database","SQLite, on the sandbox's kept disk \u2014 migrated at deploy (\u2191 \u2193 for Postgres)")),{lines:s,answers:{store:c}}}function vu(e){let t=Yr(e),{githubApp:n,sandbox:o}=e.state.answers,r=[...t.lines];return o?n&&n.consoleUrl!==o.consoleUrl?r.unshift(_("callback",`${n.slug} signs people in at ${n.consoleUrl??"localhost"}, not ${o.consoleUrl}`,"press g to create an app for the sandbox's console")):r.unshift(v("console",`${o.consoleUrl} \u2014 GitHub sends people back here`)):r.unshift(_("console","no sandbox yet","Esc back to Agent logins: the sandbox is made there")),{lines:r,answers:t.answers??{}}}var ji={...Ho,checks:hu,github:wu,logins:bu,memory:$u,access:vu};var fn="vercel";async function qo(e,t,n){let o=Date.now()+n*1e3;for(;Date.now()<o;){if(await e.fetch(t,{signal:AbortSignal.timeout(5e3)}).then(s=>s.ok).catch(()=>!1))return!0;await e.sleep(1e3)}return!1}var Su=e=>typeof e=="object"&&e!==null&&"mark"in e;async function zo(e){if(!e.sys.vercel)return{label:"account",detail:"this build of moa cannot reach Vercel",fix:"update moa"};try{let{vercelTeam:t,vercelScope:n}=e.state.answers;return await e.sys.vercel.account(t,n)}catch(t){return{label:"account",detail:t instanceof Error?t.message:String(t),fix:"run `vercel login`, then Enter"}}}var mn=e=>typeof e=="object"&&e!==null&&"fix"in e&&"label"in e;async function Vo(e,t,n=()=>{}){let{sys:o,state:r}=e,s=[],a=F=>{let Ye=s.findIndex(Xe=>Xe.label===F.label);Ye===-1?s.push(F):s[Ye]=F,t([...s])},c,i=(F,Ye,Xe)=>(a({label:F,mark:"fail",detail:Ye,fix:Xe}),c?{ok:!1,deployed:c}:{ok:!1}),l=r.answers.githubApp,d=l?He(o,l):void 0;if(!l||!d)return i("GitHub App",l?`the client secret for ${l.slug} is not on this machine`:"none yet","Esc back to Console access and press g");a({label:"sandbox",mark:"wait",detail:"looking for it"});let u=await zo(e);if(mn(u))return i(u.label,u.detail,u.fix);let f=await as(e,u,F=>a({label:"sandbox",mark:"wait",detail:F}));if(Su(f))return i("sandbox",f.detail??"",f.fix??"Enter to try again");let{box:p,info:g,built:b}=f,$=$t(u.plan);a({label:"sandbox",mark:"ok",detail:`${g.name} \u2014 ${p.vcpus??$.vcpus} vCPU, persistent${b?", image built":""}`});let m=g.workspaceUrl,h=g.consoleUrl;if(l.consoleUrl!==h)return i("GitHub App",`${l.slug} signs people in at ${l.consoleUrl??"localhost"}, not ${h}`,"Esc back to Console access and press g");let{token:A,pending:E,before:I,had:W}=await Kt(o,fn,m);a({label:"owner token",mark:"ok",detail:`${D} \u2014 profile ${fn} in ~/.moa/config.json${I===fn||!W?"":`; \`moa\` now talks to the sandbox, not profile ${I} (\`moa use ${I}\` to go back)`}`});let fe=r.answers.tenant??Ie(r.answers.owner),M=r.answers.owner,z=xe(e),R=tt(e)?.token,J=await Jo(e),V={...Object.fromEntries(Object.entries(await Ht(e)).map(([F,Ye])=>[`workspace/${F}`,Ye])),store:r.answers.store??"postgres","workspace/MOA_TOKENS":`${A}:${fe}`,"workspace/PORT":String(ft),"workspace/MOA_PORT":String(ft),"workspace/MOA_SELF_URL":`http://127.0.0.1:${ft}`,"workspace/MOA_MAX_CONCURRENT_RUNS":String($.maxRuns),"workspace/MOA_REPO":r.answers.repo,"workspace/MOA_OWNER_LOGIN":M,"workspace/MOA_GITHUB_CLIENT_ID":l.clientId,"workspace/LOCUSGRAPH_AGENT_SECRET":z?.secret,"workspace/LOCUSGRAPH_GRAPH_ID":z?.graph,"workspace/LOCUSGRAPH_SERVER_URL":z?.server,"workspace/CLAUDE_CODE_OAUTH_TOKEN":R,...Object.fromEntries(pe.map(F=>[`workspace/${Se[F]}`,$e(e,F)])),"workspace/GH_TOKEN":J&&"token"in J?J.token:void 0,"console/MOA_URL":`http://127.0.0.1:${ft}`,"console/MOA_TOKEN":A,"console/AUTH_GITHUB_ID":l.clientId,"console/AUTH_GITHUB_SECRET":d.clientSecret,"console/AUTH_SECRET":d.authSecret,"console/AUTH_URL":h,"console/AUTH_TRUST_HOST":"true"};if(!J)return i("secrets","no GitHub token for the sandbox","Esc back to GitHub and press k to paste one");let Ce=["workspace/MOA_CLIENT_ADDRESS",...r.answers.repo?[]:["workspace/MOA_REPO"],...M?[]:["workspace/MOA_OWNER_LOGIN"],...e.secrets.noLocusgraph?["workspace/LOCUSGRAPH_AGENT_SECRET","workspace/LOCUSGRAPH_GRAPH_ID","workspace/LOCUSGRAPH_SERVER_URL"]:[]];a({label:"secrets",mark:"wait",detail:"writing them into the sandbox"});let X=await si(p,V,Ce);if(!X.ok)return i("secrets",`not written: ${X.why??"no answer"}`,"Enter to try again");let Fe=["workspace/MOA_TOKENS","workspace/LOCUSGRAPH_AGENT_SECRET","workspace/CLAUDE_CODE_OAUTH_TOKEN",...pe.map(F=>`workspace/${Se[F]}`),"workspace/GH_TOKEN","console/MOA_TOKEN","console/AUTH_GITHUB_SECRET","console/AUTH_SECRET"].filter(F=>V[F]!==void 0);a({label:"secrets",mark:"ok",detail:`${Fe.length} written \u2014 none shown; no Vercel token in the sandbox`});let me=X.changed||b;a({label:"workspace",mark:"wait",detail:me?`starting on :${ft}`:"checking it runs"});try{await Rr(p,me)}catch(F){return i("workspace",`the start did not run: ${F instanceof Error?F.message:String(F)}`,"Enter to try again")}let k=r.deployed?.workspaceUrl===m?r.deployed.people:void 0,Q=F=>{c={runner:"vercel",workspaceUrl:m,consoleUrl:h,...k?{people:k}:{},...F?{memoryKept:F}:{},at:new Date().toISOString()},n(c)},O=r.deployed?.runner==="vercel"?r.deployed.memoryKept:void 0,N=z?!0:e.secrets.noLocusgraph?!1:O;if(Q(N),!await qo(o,`${m}/health`,180))return i("workspace",`did not answer at ${m} \u2014 ${await _n(p,"workspace")||"no log yet"}`,"fix that, then Enter");let ne=U({url:m,token:A},o.fetch);if(!await ne.get("/v1/whoami").then(()=>!0,()=>!1))return i("workspace","it started but refuses the owner token","Enter to try again");E&&await Bt(o,fn,m,A),a({label:"workspace",mark:"ok",detail:`${m} \u2014 :${ft} in the sandbox`});let oe=await Mr(o,m,a,r.answers.store??"postgres",`look at the sandbox's ~/moa/logs \u2014 ${await _n(p,"postgres")}`);if(oe)return i(oe.label,oe.detail,oe.fix);let ke=await ln(ne,r,a,k);if(ke)return i(ke.label,ke.detail,ke.fix);let Ve=k;if(k=r.answers.people??[],JSON.stringify(k)!==JSON.stringify(Ve??[])&&Q(N),a({label:"console",mark:"wait",detail:`waiting for :${sn}`}),!await qo(o,h,180))return i("console",`did not answer at ${h} \u2014 ${await _n(p,"console")||"no log yet"}`,"fix that, then Enter");a({label:"console",mark:"ok",detail:`${h} \u2014 Sign in with GitHub`}),me&&await ai(p);let Pe=r.answers.agentCli??"claude",Me=[...new Set([Pe,...r.answers.loggedIn??[]])],Le=await Dt(ne,Me,"in the sandbox",()=>"Esc back to Agent logins and log it in again, then Enter",a);if("label"in Le)return i(Le.label,Le.detail,Le.fix);let ye=await dn(ne,a);if("label"in ye)return i(ye.label,ye.detail,ye.fix);ye.live!==void 0&&(N=ye.live),a({label:"Console",mark:"ok",detail:h}),a({label:"Workspace",mark:"ok",detail:m}),a({label:"Next",mark:"skip",detail:`moa setup status \xB7 moa setup stop \xB7 moa run ${Rn(Pe)} "\u2026"`});let T=Le.runs[Pe];return{ok:!0,deployed:{runner:"vercel",workspaceUrl:m,consoleUrl:h,...T?{proofRunId:T}:{},memory:ye.memory,people:k,...N?{memoryKept:N}:{},at:new Date().toISOString()}}}async function Yo(e,t){let n=e.state.answers.sandbox;if(e.state.target!=="vercel"||!n)return{label:"sandbox",detail:"moa setup has not made one",fix:"run `moa setup` and choose Vercel Sandbox"};let o=await zo(e);if(mn(o))return o;try{let r=await e.sys.vercel?.get(o,n.name,t);return r?{box:r}:{label:"sandbox",detail:`${n.name} is not there`,fix:"run `moa setup` to make it again"}}catch(r){return{label:"sandbox",detail:r instanceof Error?r.message:String(r),fix:"check `vercel whoami`, then try again"}}}async function Gi(e,t){let{sys:n,state:o}=e,r=await Yo(e,!0);if(mn(r))return t({label:r.label,mark:"fail",detail:r.detail,fix:r.fix}),!1;let{box:s}=r;t({label:"sandbox",mark:"ok",detail:`${s.name} \u2014 ${s.status}${s.vcpus?`, ${s.vcpus} vCPU`:""}`});let a=o.answers.sandbox;try{await Rr(s,!1)}catch(b){return t({label:"workspace",mark:"fail",detail:`the start did not run: ${vt(b instanceof Error?b.message:String(b))}`,fix:"try again, or run `moa setup` to deploy it again"}),!1}let c={workspace:s.domain(ft),console:s.domain(sn)};if(c.workspace!==a.workspaceUrl||c.console!==a.consoleUrl){let b=[...c.workspace!==a.workspaceUrl?[`the workspace is at ${c.workspace}, not ${a.workspaceUrl}`]:[],...c.console!==a.consoleUrl?[`the console is at ${c.console}, not ${a.consoleUrl}`]:[]];return t({label:"URLs",mark:"fail",detail:`the sandbox's domain has changed \u2014 ${b.join("; ")}`,fix:"run `moa setup` to deploy it again, and press g on Console access for the new callback"}),!1}if(!await qo(n,`${a.workspaceUrl}/health`,180))return t({label:"workspace",mark:"fail",detail:`no answer at ${a.workspaceUrl} \u2014 ${await _n(s,"workspace")||"no log"}`,fix:"run `moa setup` to deploy it again"}),!1;let l=(await ve(n.env)).profiles[fn];if(!l||l.url!==a.workspaceUrl)return t({label:"workspace",mark:"fail",detail:`${a.workspaceUrl} answers, but this machine has no token for it`,fix:"run `moa setup` to deploy it again"}),!1;let d=U(l,n.fetch),u=await n.fetch(`${a.workspaceUrl}/health`,{signal:AbortSignal.timeout(5e3)}).then(b=>b.json()).catch(()=>({})),f=await d.get("/v1/whoami").then(()=>{},b=>b instanceof ae?`${b.status}`:String(b));t(f?{label:"workspace",mark:"fail",detail:`refuses the owner token (${f})`,fix:"run `moa setup` to deploy it again"}:{label:"workspace",mark:"ok",detail:`${a.workspaceUrl}${u.database?` \u2014 ${u.database}`:""}`});let p=await d.get("/v1/jobs").then(b=>b.jobs).catch(()=>{});if(p){let b=p.filter($=>$.state==="running"||$.state==="queued");t({label:"pipelines",mark:"ok",detail:b.length===0?"nothing running":`${b.length} running or waiting \u2014 carried on from before the stop (moa jobs)`})}let g=await qo(n,a.consoleUrl,180);return t(g?{label:"console",mark:"ok",detail:`${a.consoleUrl} \u2014 Sign in with GitHub`}:{label:"console",mark:"fail",detail:`no answer at ${a.consoleUrl} \u2014 ${await _n(s,"console")||"no log"}`,fix:"run `moa setup` to deploy it again"}),!f&&g}async function Hi(e,t){let n=await Yo(e,!1);if(mn(n))return t({label:n.label,mark:"fail",detail:n.detail,fix:n.fix}),!1;try{await n.box.stop()}catch(o){return t({label:"sandbox",mark:"fail",detail:`did not stop: ${vt(o instanceof Error?o.message:String(o))}`,fix:"try again"}),!1}return t({label:"sandbox",mark:"ok",detail:`${n.box.name} stopped \u2014 its disk is kept; \`moa setup status\` starts it again`}),!0}import{jsx as ee,jsxs as Ee}from"react/jsx-runtime";var Re=(e,t)=>({...e,answers:{...e.answers,...t}}),Pu=[{value:"vercel",label:"Vercel Sandbox",note:"one VM, 24h sessions, resumes by name"},{value:"cloudflare",label:"Cloudflare",note:"Worker + container, needs your domain"},{value:"local",label:"This machine",note:"Docker / local, nothing in the cloud"}],_u={where:{options:e=>Pu.map(t=>{let n=Po(t.value,ro(e,t.value));return n?{...t,note:n}:t}),value:e=>e.target,set:(e,t)=>at(e,t)},checks:{options:()=>[{value:"image",label:"Published image",note:"pull the release from GHCR \u2014 nothing is built here"},{value:"checkout",label:"This checkout",note:"build from source \u2014 for working on fnMoa"}],value:e=>xn(e),set:(e,t)=>Re(e,{source:t})},logins:{options:()=>[{value:"claude",label:"claude",note:"a Claude subscription, or an API key"},{value:"codex",label:"codex",note:"a ChatGPT plan, or an API key"},{value:"cursor",label:"cursor",note:"a Cursor plan, or an API key"}],value:e=>e.answers.agentCli,set:(e,t)=>Re(e,{agentCli:t})},memory:{options:e=>e.target==="vercel"?[{value:"postgres",label:"Postgres",note:"in the sandbox, on its kept disk"},{value:"sqlite",label:"SQLite",note:"a file on the sandbox's kept disk"}]:[{value:"node",label:"SQLite",note:"node apps/workspace/dist/node.js"},{value:"compose",label:"Postgres",note:"docker compose up (apps/workspace/compose.yaml)"}],value:e=>e.target==="vercel"?e.answers.store??"postgres":e.answers.runner??"node",set:(e,t)=>e.target==="vercel"?Re(e,{store:t}):Re(e,{runner:t})}},is=e=>e.target==="vercel",Wi=/^[a-z\d](?:[a-z\d-]{0,38})$/i;function Tu(e,t){let n=e.answers.people??[],o=f=>p=>p.login.toLowerCase()===f.toLowerCase(),r="a GitHub login, then member or viewer, then a cap in $/day \u2014 or -login to remove",[s,...a]=t.split(/\s+/).filter(Boolean);if(!s)return r;if(s.startsWith("-")){let f=s.slice(1);if(!n.some(o(f)))return`${f} is not on the list`;let p=n.filter(b=>!o(f)(b)),g=[...new Set([...e.answers.removed??[],f.toLowerCase()])];return Re(e,{people:p.length>0?p:void 0,removed:g})}if(!Wi.test(s))return r;if(e.answers.owner&&s.toLowerCase()===e.answers.owner.toLowerCase())return`${s} is you \u2014 the owner already`;let c=n.find(o(s)),i=c?.role??"member",l=c?.dailyCapUsd??Sr;for(let f of a){let p=f.toLowerCase(),g=Number(p.replace(/^\$|\/day$/g,""));if(p==="member"||p==="viewer")i=p;else if(Number.isFinite(g)&&g>=0&&g<=1e4)l=g;else return r}let d={login:s,role:i,dailyCapUsd:l},u=(e.answers.removed??[]).filter(f=>f!==s.toLowerCase());return Re(e,{people:c?n.map(f=>o(s)(f)?d:f):[...n,d],removed:u.length>0?u:void 0})}var Xo=e=>e.target==="cloudflare",Ou="\x1B",Iu=new RegExp(`(?:${Ou})?\\[20[01]~|[\\u0000-\\u001f\\u007f]`,"g"),Ki=e=>e.replace(Iu,""),Ru={checks:[{key:"l",label:"Licence key",secret:!0,shown:(e,t)=>t.licence?D:"saved key, or none",commit:(e,t,n)=>(t.licence=n||void 0,e)},{key:"d",label:"Domain",when:Xo,shown:e=>e.answers.domain??"none",commit:(e,t,n)=>{let o=n.toLowerCase().replace(/^https?:\/\//,"").replace(/\/+$/,"");return o===""?Re(e,{domain:void 0}):pr.test(o)?Re(e,{domain:o}):"a domain on your Cloudflare account, like example.com"}},{key:"k",label:"D1 token",secret:!0,when:Xo,shown:(e,t)=>t.cloudflare?D:"none",commit:(e,t,n)=>/\s/.test(n)?"one token, no spaces":(t.cloudflare=n||void 0,e)},{key:"e",label:"Vercel team",when:is,shown:e=>e.answers.vercelTeam??"the one Vercel picks",initial:e=>e.answers.vercelTeam??"",commit:(e,t,n)=>n===""||/^[\w-]{1,100}$/.test(n)?Re(e,{vercelTeam:n||void 0,vercelScope:void 0}):"a team's slug or id, as `vercel teams ls` shows it"}],github:[{key:"e",label:"Repo",shown:e=>e.answers.repo??"none",commit:(e,t,n)=>n===""?{...e,answers:{...e.answers,repo:void 0}}:/^[\w.-]+\/[\w.-]+$/.test(n)?Re(e,{repo:n}):"owner/name, like fnLog0/fnmoa"},{key:"k",label:"GitHub token",secret:!0,when:e=>is(e)||Xo(e),shown:(e,t)=>t.github?D:is(e)?"none \u2014 your own gh login":"none",commit:(e,t,n)=>/\s/.test(n)?"one token, no spaces":(t.github=n||void 0,e)}],logins:[{key:"e",label:"claude token",secret:!0,shown:(e,t)=>t.claude?D:"none",commit:(e,t,n)=>/\s/.test(n)?"one token, no spaces \u2014 what `claude setup-token` printed":(t.claude=n||void 0,e)},{key:"k",label:"API key",secret:!0,shown:(e,t)=>{let n=e.answers.agentCli??"claude";return`${Se[n]} ${t.keys?.[n]?D:"none"}`},commit:(e,t,n)=>{if(/\s/.test(n))return"one key, no spaces";let o=e.answers.agentCli??"claude";return t.keys={...t.keys,[o]:n||void 0},e}}],memory:[{key:"g",label:"LocusGraph graph ID",shown:e=>e.answers.locusgraphGraph??"none",initial:e=>e.answers.locusgraphGraph??"",commit:(e,t,n)=>n===""||/^[\w.:-]{1,100}$/.test(n)?Re(e,{locusgraphGraph:n||void 0}):"the graph's ID, as LocusGraph shows it \u2014 letters, digits, - _ . :"},{key:"e",label:"LocusGraph secret",secret:!0,shown:(e,t)=>t.locusgraph?D:"none",commit:(e,t,n)=>(t.locusgraph=n||void 0,t.noLocusgraph=!n,e)}],access:[{key:"e",label:"Tenant",shown:e=>e.answers.tenant??"",commit:(e,t,n)=>/^[a-z0-9][a-z0-9-]{0,62}$/.test(n)?Re(e,{tenant:n}):"lower-case letters, digits and dashes"},{key:"o",label:"App owner",shown:e=>e.answers.appOrg??"your account (o for an organization)",initial:e=>e.answers.appOrg??"",commit:(e,t,n)=>n===""||Wi.test(n)?Re(e,{appOrg:n||void 0}):"a GitHub organization's login, or nothing for your own account"},{key:"a",label:"Add people",shown:()=>"login member|viewer $/day \u2014 -login takes them off",initial:()=>"",commit:(e,t,n)=>Tu(e,n)}]},cs=(e,t)=>{let n=[...e];for(let o of t){let r=n.findIndex(s=>s.label===o.label);r===-1?n.unshift(o):n[r]=o}return n},Bi={ok:{char:"\u2713",color:"green"},fail:{char:"\u2717",color:"red"},wait:{char:"\u2026",color:"yellow"},skip:{char:"\u2013",color:"gray"}},ls={where:"Where",checks:"Checks",github:"GitHub",memory:"Memory",logins:"Logins",access:"Access",deploy:"Deploy"},Lu=Object.fromEntries(ut.filter(e=>e!=="where"&&e!=="deploy").map((e,t)=>[String(t+1),e])),Du={local:"this machine",vercel:"the Vercel Sandbox",cloudflare:"Cloudflare"},Uu={ok:"ok",fail:"failing",wait:"checking"};function Mu({screen:e,passed:t}){return ee(ze,{columnGap:2,flexWrap:"wrap",children:ut.map(n=>n===e?Ee(se,{bold:!0,color:"cyan",children:["\u25B8 ",ls[n]]},n):t.includes(n)?Ee(se,{color:"green",children:["\u2713 ",ls[n]]},n):Ee(se,{dimColor:!0,children:[" ",ls[n]]},n))})}function Qo({title:e,aside:t,children:n}){return Ee(ze,{flexDirection:"column",marginTop:1,children:[Ee(ze,{justifyContent:"space-between",children:[ee(se,{bold:!0,dimColor:!0,children:e.toUpperCase()}),t?ee(se,{dimColor:!0,children:t}):null]}),n]})}function Nu({rows:e}){let t=Math.max(...e.map(n=>n.label.length));return ee(Qo,{title:"review",children:e.map(n=>Ee(ze,{children:[ee(ze,{flexShrink:0,width:t+2,children:ee(se,{dimColor:!0,children:n.label})}),ee(se,{children:n.value})]},n.label))})}function ju({hints:e}){return ee(ze,{columnGap:2,flexWrap:"wrap",paddingX:1,children:e.map(t=>{let n=t.indexOf(" ");return Ee(se,{children:[ee(se,{bold:!0,children:t.slice(0,n)}),ee(se,{dimColor:!0,children:t.slice(n)})]},t)})})}var Gu=e=>[e.deployed?{label:"last deploy",mark:"skip",detail:`console ${e.deployed.consoleUrl} \xB7 workspace ${e.deployed.workspaceUrl} \u2014 Enter to check it again`}:{label:"deploy",mark:"wait",detail:e.target==="vercel"?"Enter to write the secrets into the sandbox, start the workspace and console, and prove it with one agent run and one memory read":e.target==="cloudflare"?"Enter to deploy the Worker, D1 and the container to your domain, and prove it with one agent run and one memory read":"Enter to build, start the workspace and console, and prove it with one agent run and one memory read"}];function Ji({initial:e,sys:t,save:n,checks:o,deploy:r,createApp:s=_i,onDone:a,secrets:c,onHandOver:i,pasteFirst:l=!1,deviceLogin:d=za,after:u={}}){let{exit:f}=xu(),[p,g]=mt(()=>e.screen==="where"&&!e.target?{...e,target:"local"}:e),[b,$]=mt([]),[m,h]=mt(!1),[A,E]=mt(0),I=l&&e.screen==="logins",[W,fe]=mt(I?"":void 0),[M,z]=mt(I?"e":void 0),R=xt(void 0),J=xt([]),V=w=>cs(w,J.current),[Ce,X]=mt(void 0),[Fe,me]=mt(!1),[k,Q]=mt("no"),O=xt(c??{}).current,N=xt(void 0),[ne,ge]=mt(0),oe=xt(Promise.resolve()),ke=xt(0),[Ve,Pe]=mt(!1),Me=xt(!1),Le=w=>{Me.current=w,Pe(w)},ye=xt(e.screen!=="where").current,T=p.screen,F=p.target==="vercel",Ye=o??(F?ji:Ho),Xe=r??(F?Vo:p.target==="cloudflare"?Ko:Mo),ct=T==="checks"&&Oe({sys:t,state:p}),Et=F||p.answers.runner==="compose",ie=xt(p);ie.current=p;let Yt=xt(p),re=w=>{Yt.current!==w&&(Yt.current=w,oe.current=oe.current.then(()=>n(w)).catch(()=>{}))};Fi(()=>re(p),[p,n]);let _e=()=>(re(ie.current),oe.current),{answers:ue}=p,Qe=JSON.stringify([T,p.target,ue,A,ne]);Fi(()=>{if(T==="deploy"){m||$(Gu(p));return}let w=++ke.current;$(S=>S.map(B=>J.current.some(j=>j.label===B.label)?B:{...B,mark:"wait"})),h(!0),Promise.resolve(Ye[T]?.({state:p,sys:t,secrets:O})??{lines:[]}).then(async S=>({...S,lines:[...S.lines,...!o&&T==="checks"?await yt({state:p,sys:t,secrets:O}):[]]})).then(S=>{if(w!==ke.current)return;let B=V(S.lines);$(B),R.current||h(!1);let j=S.answers??{};Object.entries(j).some(([dt,wn])=>p.answers[dt]!==wn)&&g(dt=>Re(dt,j));let Ne=Me.current;Le(!1),Ne&&po(B)&&Xt(T)},S=>{w===ke.current&&($(V([{label:"check",mark:"fail",detail:String(S),fix:"press r to check again"}])),R.current||h(!1),Le(!1))})},[Qe]);let lt=w=>{R.current?.abort(),_e().then(()=>{a?.(ie.current,w),f()})},Jn=()=>{h(!0),X(void 0);let w=j=>$([{label:"licence",mark:"wait",detail:j},{label:"note",mark:"skip",detail:"sign in there and approve it \u2014 Esc to stop"}]);w("asking the licence server for a code\u2026");let S=new AbortController,B={done:_o({state:p,sys:t,secrets:O},j=>w(`open ${j.url} and check it shows ${j.code}`),S.signal).then(()=>({ok:!0,stdout:"",stderr:""}),j=>({ok:!1,stdout:"",stderr:j instanceof Error?j.message:String(j)})),cancel:()=>S.abort()};N.current=B,B.done.then(j=>{N.current===B&&(N.current=void 0,h(!1),j.ok||X(`not connected: ${j.stderr}`),E(L=>L+1))})},qn=(w="codex")=>{let S=Oe({sys:t,state:p})?void 0:t.root,B=!S&&p.deployed?.runner==="image";if(!S&&!F&&!B)return;h(!0);let j=F?"sandbox":"container",L=dt=>$([{label:w,mark:"wait",detail:Nn(dt)??`starting its login inside the ${j}\u2026`},{label:"note",mark:"skip",detail:"its own session, not a copy of this machine's \u2014 Esc to stop"}]);L({});let Ne=F?Ni({state:p,sys:t,secrets:O},L,w):B?Mn(t,w,L):d(t,S,L);N.current=Ne,Ne.done.then(dt=>{N.current===Ne&&(N.current=void 0,h(!1),dt.ok||X(`${w} login did not finish: ${(dt.stderr||dt.stdout).trim().split(`
210
- `).slice(-1)[0]??""}`),E(wn=>wn+1))})},hn=w=>{if(X(void 0),w==="claude"){if(!i)return X("run `claude setup-token`, then e to paste the token");_e().then(()=>{i(ie.current),f()});return}let S=Oe({sys:t,state:p});if(F)return qn(w);if(p.target==="cloudflare")return X(w==="codex"?"codex logs in inside the container at Deploy \u2014 a link and a code; or k for its API key":"on Cloudflare cursor runs on an API key: k");if(S)return p.deployed?.runner==="image"?qn(w):X(`${w} logs in inside the container at Deploy when it is picked \u2014 or k for its API key`);if(Et)return w==="codex"?qn("codex"):X("cursor runs in the published image or on Vercel \u2014 k for its API key");X(`run \`${w==="codex"?"codex login":"cursor-agent login"}\` in a terminal, then r`)},gs=w=>{if(X(void 0),O.keys={...O.keys,[w]:void 0},w==="claude"&&(O.claude=void 0),ge(S=>S+1),g(S=>Re(S,{loggedIn:(S.answers.loggedIn??[]).filter(B=>B!==w)})),w!=="claude"&&p.deployed?.runner==="image"&&Oe({sys:t,state:p})){t.exec("docker",nt(t,"exec","-T","workspace",...Xr[w]),{timeoutMs:6e4}).then(()=>E(S=>S+1));return}E(S=>S+1)},go=w=>{Q("no"),X(void 0),Le(!1),J.current=[],$([]),g(S=>({...S,screen:w}))},Xt=w=>{ie.current.screen===w&&(g(S=>({...S,passed:[...new Set([...S.passed,w])]})),go(u[w]??Da(w)))},ho=()=>{h(!0),$([]),Xe({state:p,sys:t,secrets:O},$,B=>{let j={...ie.current,deployed:B};ie.current=j,re(j),g(L=>({...L,deployed:B}))},B=>{let j={...ie.current,cloudflare:B};ie.current=j,re(j),g(L=>({...L,cloudflare:B}))}).then(B=>{let j=B.deployed;B.ok&&j?(me(!0),g(L=>({...L,answers:{...L.answers,removed:void 0},deployed:j,passed:[...new Set([...L.passed,"deploy"])]}))):j&&g(L=>({...L,deployed:j}))}).catch(B=>$(j=>[...j,{label:"deploy",mark:"fail",detail:String(B),fix:"Enter to try again"}])).finally(()=>h(!1))},wo=w=>{J.current=cs(J.current,w),$(S=>cs(S,w))},Qt=()=>{let w=new AbortController;R.current=w,h(!0),X(void 0),wo([{label:"GitHub App",mark:"wait",detail:"starting a page for GitHub\u2026"}]),s({state:p,sys:t,secrets:O},wo,w.signal).then(S=>{R.current=void 0,h(!1),J.current=[],g(B=>Re(B,S)),E(B=>B+1)},S=>{R.current=void 0,h(!1),!w.signal.aborted&&wo([{label:"GitHub App",mark:"fail",detail:S instanceof Error?S.message:String(S),fix:"press g to try again"}])})},Ke=(Ru[T]??[]).filter(w=>!w.when||w.when(p)),ko=Ke.find(w=>w.key===M),Ct=T==="memory"&&Xo(p)||T==="checks"&&!t.root?void 0:_u[T],Zt=T==="access"?p.answers.githubApp:void 0;Eu(w=>{let S=Ki(w);S&&fe(B=>`${B??""}${S}`)},{isActive:W!==void 0}),Au((w,S)=>{if(W!==void 0&&ko){if(S.escape){fe(void 0),z(void 0);return}if(S.return){let L=ko.commit(p,O,W.trim());if(typeof L=="string"){X(L);return}X(void 0),fe(void 0),z(void 0),ge(Ne=>Ne+1),g(L);return}if(S.backspace||S.delete){fe(L=>(L??"").slice(0,-1));return}if(w&&!S.ctrl&&!S.meta){let L=Ki(w);L&&fe(Ne=>`${Ne??""}${L}`)}return}if(N.current){(S.escape||w==="q")&&(N.current.cancel(),N.current=void 0,h(!1),E(L=>L+1));return}if(w==="q")return lt(Fe);if(S.escape){if(k==="asking")return Q("no");T!=="where"&&!(m&&(T==="deploy"||R.current))&&go(Ua(T));return}if(m){S.return&&T!=="deploy"&&Le(!0);return}if(J.current=[],w==="r")return E(L=>L+1);let B=T==="deploy"&&!Fe?Lu[w]:void 0;if(B)return go(B);if(T==="logins"&&w==="t"&&i){_e().then(()=>{i(ie.current),f()});return}if(T==="logins"&&w==="l"&&Et)return qn();if(T==="logins"&&(w==="c"||w==="x")){let L=p.answers.agentCli??"claude";return w==="c"?hn(L):gs(L)}if(T==="checks"&&w==="c"&&ct)return Jn();let j=Ke.find(L=>L.key===w);if(j){X(void 0),z(j.key),fe(j.secret?"":j.initial?j.initial(p):j.shown(p,O)==="none"?"":j.shown(p,O));return}if(T==="access"&&w==="g")return Qt();if(Zt&&w==="d"){g(L=>{let Ne=L.answers.githubApp;return Ne?Re(L,{githubApp:{...Ne,deviceFlow:!Ne.deviceFlow}}):L});return}if((S.upArrow||S.downArrow)&&Ct){let L=Ct.options(p).map(rr=>rr.value),Ne=L.indexOf(Ct.value(p)??L[0]??""),dt=S.upArrow?-1:1,wn=L[(Ne+dt+L.length)%L.length];wn!==void 0&&g(rr=>Ct.set(rr,wn));return}if(S.return){if(T==="deploy")return Fe?lt(!0):k==="no"?Q("asking"):(Q("yes"),ho());if(!po(b))return;Xt(T)}});let K=Math.max(...b.map(w=>w.label.length),8),Z=[T==="deploy"?Fe?"Enter done":"Enter deploy":"Enter continue",T==="where"?void 0:"Esc back","q quit",Ct?"\u2191 \u2193 choose":void 0,...Ke.length===1?["e edit"]:Ke.map(w=>`${w.key} ${w.label.toLowerCase()}`),T==="access"?Zt?"g new GitHub App":"g create GitHub App":void 0,Zt?Zt.deviceFlow?"d undo device flow":"d device flow is ticked":void 0,T==="logins"?"c connect \xB7 x disconnect":void 0,ct?"c connect account":void 0,T==="deploy"?void 0:"r check again",T==="deploy"&&!Fe?"1\u20135 change a step":void 0].filter(Boolean),Be=Cu(()=>T==="deploy"?Ti({state:p,sys:t,secrets:O}):[],[T,p,t,O,ne]),he=["ok","fail","wait"].map(w=>[w,b.filter(S=>S.mark===w).length]).filter(([,w])=>w>0).map(([w,S])=>`${S} ${Uu[w]}`),or=Math.max(...Ke.map(w=>w.label.length),0);return Ee(ze,{flexDirection:"column",children:[Ee(ze,{borderStyle:"round",borderColor:"cyan",flexDirection:"column",paddingX:1,children:[ee(se,{bold:!0,color:"cyan",children:T==="where"?"moa setup":`${Ma(T)} ${oo[T]}`}),T==="where"?null:ee(Mu,{screen:T,passed:p.passed}),T==="where"?ee(se,{children:oo.where}):null,ye&&T===e.screen&&T!=="where"?ee(se,{color:"yellow",children:"resumed where the last setup stopped"}):null,Ct?ee(Qo,{title:"choose",children:Ct.options(p).map(w=>{let S=Ct.value(p)===w.value;return Ee(se,{color:S?"cyan":void 0,children:[S?" \u25CF ":" \u25CB ",ee(se,{bold:S,children:w.label.padEnd(16)}),ee(se,{dimColor:!0,children:w.note})]},w.value)})}):null,Ke.length>0?ee(Qo,{title:"settings",children:Ke.map(w=>Ee(se,{children:[w.label.padEnd(or)," ",W!==void 0&&w.key===M?Ee(se,{color:"cyan",children:[w.secret?W?`${D} ${W.length} character${W.length===1?"":"s"}`:"":W,"\u258F"]}):ee(se,{dimColor:!w.shown(p,O),children:w.shown(p,O)||"\u2014"})]},w.key))}):null,Ce?ee(ze,{marginTop:1,children:Ee(se,{color:"red",children:["\u2717 ",Ce]})}):null,T==="deploy"?ee(Nu,{rows:Be}):null,ee(Qo,{title:"status",aside:T==="deploy"?void 0:he.join(" \xB7 "),children:b.map(w=>Ee(ze,{flexDirection:"column",children:[Ee(ze,{children:[ee(ze,{flexShrink:0,width:K+4,children:Ee(se,{children:[ee(se,{color:Bi[w.mark].color,children:Bi[w.mark].char})," ",w.label]})}),ee(se,{children:w.detail??""})]}),w.mark==="fail"&&w.fix?ee(ze,{paddingLeft:K+4,children:Ee(se,{color:"red",children:["\u2192 ",w.fix]})}):null]},w.label))}),k==="asking"?ee(ze,{marginTop:1,children:Ee(se,{color:"yellow",bold:!0,children:["Enter again to deploy to ",Du[p.target??"local"],p.answers.domain&&p.target==="cloudflare"?` (${p.answers.domain})`:""," ","\u2014 Esc to cancel"]})}):null,Ve&&m?ee(se,{color:"yellow",children:"still checking \u2014 Enter goes on once every line is \u2713"}):null]}),ee(ju,{hints:W!==void 0?["Enter keep","Esc cancel"]:N.current?["Esc stop the login"]:k==="asking"?["Enter deploy now","Esc cancel"]:Z})]})}De();Ze();qe();Zn();Wt();import{randomBytes as Hu}from"node:crypto";import{rm as qi}from"node:fs/promises";import{join as Zo}from"node:path";it();It();Ft();Pn();Je();io();an();var Fu="codex/auth.json",ot=(e,t=2)=>e.replace(/\u001B\[[0-9;]*m/g,"").trim().split(`
211
- `).filter(n=>n.trim()!=="").slice(-t).join(" \xB7 ").slice(0,300),Fn=e=>e instanceof Error?e.message:String(e);function Vt(e){let t=Ar(e);return t.length>0?t:e.target?[e.target]:[]}var Kn=(e,t)=>({...e,state:at(e.state,t??e.state.target)}),Yi=(e,t)=>e.state?{...e,state:at(e.state,t)}:e,mo=e=>e==="vercel"?fn:e==="cloudflare"?jn:On;function At(e){let t=e.deployed;if(!(!t||!e.target))return e.target==="local"?t.runner==="node"||t.runner==="compose"||t.runner==="image"?t:void 0:t.runner===e.target?t:void 0}var Bn=e=>(e({label:"fnMoa",mark:"fail",detail:"moa setup has not deployed it here yet",fix:"run `moa setup`"}),{ok:!1});async function zi(e,t,n){for(let o=0;o<n*1e3;o+=500){if(!e.alive(t))return!0;await e.sleep(500)}return!e.alive(t)}var Ku=15,Bu=5,us=(e,t,n,o={},r=3e4)=>e.fetch(t,{...o,headers:{authorization:`Bearer ${n}`},signal:AbortSignal.timeout(r)});async function er(e,t,n){let o=(await ve(e.env)).profiles[mo(t)];return o?.url===n?o.token:void 0}async function Xi(e,t,n){let{sys:o}=e,r=Date.now()+t.seconds*1e3,s;for(;s=await o.fetch(`${t.workspaceUrl}/health`,{signal:AbortSignal.timeout(t.seconds>0?13e4:5e3)}).then(l=>l.json()).catch(()=>{}),!(s?.ok===!0||Date.now()>=r);)await o.sleep(2e3);let a=!0,c=await er(o,t.target,t.workspaceUrl);if(!s)a=!1,n({label:"workspace",mark:"fail",detail:`no answer at ${t.workspaceUrl}`,fix:t.fix});else if(!c)a=!1,n({label:"workspace",mark:"fail",detail:`${t.workspaceUrl} answers, but this machine has no token for it`,fix:"run `moa setup` to deploy it again"});else{let l=U({url:t.workspaceUrl,token:c},o.fetch),d=await l.get("/v1/whoami").then(()=>{},u=>u instanceof ae?`${u.status}`:Fn(u));if(d)a=!1,n({label:"workspace",mark:"fail",detail:`refuses the owner token (${d})`,fix:"run `moa setup` to deploy it again"});else{n({label:"workspace",mark:"ok",detail:`${t.workspaceUrl}${t.where}`}),s.ok===!0?n({label:"database",mark:"ok",detail:`${s.database??"the store"} \u2014 it answers`}):(a=!1,n({label:"database",mark:"fail",detail:`${s.database??"the store"} does not answer: ${ot(String(s.error??"no answer"),1)}`,fix:t.fix}));let u=await l.get("/v1/jobs").then(f=>f.jobs).catch(()=>{});if(u){let f=u.filter(p=>p.state==="running"||p.state==="queued");n({label:"pipelines",mark:"ok",detail:f.length===0?"nothing running":`${f.length} running or waiting (moa jobs)`})}}}let i=await o.fetch(t.consoleUrl,{redirect:"manual",signal:AbortSignal.timeout(t.seconds>0?13e4:5e3)}).then(l=>l.status<500).catch(()=>!1);return n(i?{label:"console",mark:"ok",detail:t.consoleUrl}:{label:"console",mark:"fail",detail:`no answer at ${t.consoleUrl}`,fix:t.fix}),a&&i}async function Wu(e,t){let n=At(e.state);if(!n)return Bn(t);let o=Ln(e.sys,n),r=o.workspacePid,s=o.runner==="compose"?` \u2014 docker compose, project ${we}`:r!==void 0&&Lt(e.sys,r,o.workspaceStarted,St(o.workspaceUrl))?` (pid ${r})`:"";return{ok:await Xi(e,{target:"local",workspaceUrl:o.workspaceUrl,consoleUrl:o.consoleUrl,where:s,fix:"run `moa setup` to start it again",seconds:0},t)}}async function Ju(e,t){let n=At(e.state);if(!n)return Bn(t);let{sys:o}=e,r=await er(o,"cloudflare",n.workspaceUrl);if(!r)return t({label:"workspace",mark:"fail",detail:`this machine has no token for ${n.workspaceUrl}`,fix:"run `moa setup` to deploy it again"}),{ok:!1};let s=await us(o,`${n.workspaceUrl}/_moa/box`,r).then(async c=>c.ok?await c.json():`${c.status} ${ot(await c.text().catch(()=>""),1)}`.trim()).catch(c=>Fn(c));return typeof s=="string"?(t({label:"Worker",mark:"fail",detail:`${n.workspaceUrl} did not answer: ${s}`,fix:"run `moa setup` to deploy it again"}),{ok:!1}):(t({label:"container",mark:"ok",detail:s.running?`running \u2014 kept up ${_t}h after the last request`:"was stopped \u2014 this check starts it again, on its data in D1"}),{ok:await Xi(e,{target:"cloudflare",workspaceUrl:n.workspaceUrl,consoleUrl:n.consoleUrl,where:" \u2014 in the Cloudflare container",fix:`look at \`pnpm --dir apps/workspace exec wrangler tail ${We}\`, or run \`moa setup\` to deploy it again`,seconds:600},t)})}var Hn={local:"This machine",vercel:"Vercel Sandbox",cloudflare:"Cloudflare"};function qu(e,t){let n=Ar(e);for(let o of n){let r=ro(e,o);t({label:o,mark:"skip",detail:`${Hn[o]} \u2014 ${Po(o,r)}${La(o,r)?"; billed while it stands":""}`})}return n}async function zu(e,t){let n=e.state.target==="vercel"?{ok:await Gi(e,t)}:e.state.target==="cloudflare"?await Ju(e,t):await Wu(e,t);return At(e.state)&&Vu(e.state,t),n}function Vu(e,t){let n=e.answers.loggedIn??[];for(let o of pe)t(n.includes(o)?{label:o,mark:"ok",detail:`connected${e.answers.agentCli===o?" \u2014 the proof runs on it":""}`}:{label:o,mark:"skip",detail:`not connected \u2014 \`moa setup login ${o}\``})}async function Qi(e,t,n){let o=qu(e.state,t),r=n==="all"?Vt(e.state):n?[n]:o.length===1&&o[0]?[o[0]]:[],s=r.length>0?r:[e.state.target??"local"],a=!0;for(let c of s){s.length>1&&t({label:c,mark:"skip",detail:`\u2500\u2500 ${Hn[c]}`});let i=await zu(Kn(e,c),t);a=a&&i.ok}return{ok:a}}async function ds(e,t,n,o=!1){let{sys:r}=e,s=r.root;if(!s)return t({label:"workspace",mark:"fail",detail:"not inside a fnMoa checkout: docker compose needs its compose.yaml",fix:"run it from your fnMoa checkout"}),!1;let a=await r.exec("docker",n==="down"?Rt(s,"down","--volumes","--remove-orphans","--rmi","local"):Rt(s,"stop"),{cwd:s,env:on(r),timeoutMs:3e5});return a.ok?(t({label:"workspace",mark:"ok",detail:o?`compose project ${we} taken down, with any volumes an earlier compose run left \u2014 codex's login among them`:n==="down"?`compose project ${we} removed, with its volumes \u2014 Postgres and codex's login`:`stopped \u2014 Postgres kept in the ${we} volumes`}),!0):(t({label:"workspace",mark:"fail",detail:`docker compose: ${ot(a.stderr||a.stdout)}`,fix:"start Docker, then run this again"}),!1)}async function tr(e,t,n,o){let{sys:r}=e;if(t.runner==="image"){let i=await r.exec("docker",nt(r,...o==="down"?["down","--volumes"]:["stop"]),{timeoutMs:12e4});return n({label:"image",mark:i.ok?"ok":"fail",detail:o==="down"?"Container and data volumes removed":"Container stopped; data kept"}),{ok:i.ok,deployed:t}}let s=!0;t=Ln(r,t);let a={...t};if(t.runner==="compose"&&!await ds(e,n,o)&&(s=!1),t.runner==="compose"&&o==="down"){let{people:i,...l}=a;a=l}let c=[["workspace",t.workspacePid,t.workspaceStarted,St(t.workspaceUrl)],["console",t.consolePid,t.consoleStarted,St(t.consoleUrl)]];for(let[i,l,d,u]of c){if(l===void 0){if(i==="workspace"&&t.runner==="compose")continue;n({label:i,mark:"ok",detail:"not running"});continue}let f=()=>{let{[i==="workspace"?"workspacePid":"consolePid"]:b,[i==="workspace"?"workspaceStarted":"consoleStarted"]:$,...m}=a;a=m};if(r.alive(l)&&!Lt(r,l,d,u)){n({label:i,mark:"ok",detail:`not running \u2014 pid ${l} is another process now, left alone`}),f();continue}let p=r.processOf(l)?.started;if(r.alive(l)&&r.stop(l),await zi(r,l,Ku)){n({label:i,mark:"ok",detail:`stopped (pid ${l})`}),f();continue}let g=r.processOf(l);if(p===void 0||g?.started!==p){let b=p!==void 0&&(g!==void 0||!r.alive(l));b?f():s=!1,n(b?{label:i,mark:"ok",detail:`stopped (pid ${l})`}:{label:i,mark:"fail",detail:`pid ${l} is still running`,fix:`stop it (\`kill -9 ${l}\`), then run this again`});continue}r.stop(l,!0),await zi(r,l,Bu)?(n({label:i,mark:"ok",detail:`stopped (pid ${l}) \u2014 killed, it did not stop when asked to`}),f()):(s=!1,n({label:i,mark:"fail",detail:`pid ${l} is still running, after SIGTERM and SIGKILL`,fix:`stop it (\`kill -9 ${l}\`), then run this again`}))}return{ok:s,deployed:a}}async function Yu(e,t){let n=At(e.state);if(!n)return Bn(t);let o=await tr(e,n,t,"stop");return o.ok&&t({label:"data",mark:"skip",detail:"kept \u2014 `moa setup` starts it all again"}),{ok:o.ok,state:{...e.state,deployed:o.deployed}}}async function Xu(e,t){let n=At(e.state);if(!n)return Bn(t);let{sys:o}=e,r=await er(o,"cloudflare",n.workspaceUrl);if(!r)return t({label:"container",mark:"fail",detail:`this machine has no token for ${n.workspaceUrl}`,fix:"run `moa setup` to deploy it again"}),{ok:!1};let s=await us(o,`${n.workspaceUrl}/_moa/restart`,r,{method:"POST"}).then(async a=>a.ok?await a.json():`${a.status} ${ot(await a.text().catch(()=>""),1)}`.trim()).catch(a=>Fn(a));return typeof s=="string"?(t({label:"container",mark:"fail",detail:`did not stop: ${s}`,fix:"try again"}),{ok:!1}):(t({label:"container",mark:"ok",detail:`${s.restarted?"stopped":"was not running"} \u2014 D1 and R2 kept; the next request to it, or \`moa setup status\`, starts it again`}),{ok:!0})}async function Zi(e,t,n){let o=Kn(e,n),r=o.state.target==="vercel"?{ok:await Hi(o,t)}:o.state.target==="cloudflare"?await Xu(o,t):await Yu(o,t);return Yi(r,e.state.target)}var Qu=(e,t)=>e.replace(/\n$/,"").split(`
211
+ ln -s /repo "$HOME/moa/fnmoa"`)).ok)throw new Error("Could not prepare the sandbox's application directory.")}if(!(await Ne(s,'printf %s "$VERSION" > "$HOME/moa/image"',{VERSION:a})).ok)throw new Error("Could not record the installed version.");return{box:s,built:!0,info:{name:r,workspaceUrl:s.domain(8787),consoleUrl:s.domain(3100),revision:a}}}catch(r){return C("sandbox",r instanceof Error?r.message:String(r),"Check your account and retry; data is kept.")}}var os=e=>{if(!e.vercel)throw new Error("this build of moa cannot reach Vercel");return e.vercel},rs=e=>e.answers.tenant??Ie(e.answers.owner),Hi=e=>{let t=/^git@([^:]+):(.+)$/.exec(e.trim());return t?`https://${t[1]}/${t[2]}`:e.trim()};async function Ki(e){let t=e.root;if(!t)return{why:"not inside a fnMoa checkout",fix:"run moa setup from a clone of https://github.com/fnLog0/fnmoa"};let n=(...i)=>e.exec("git",["-C",t,...i]),[o,r,s]=await Promise.all([n("rev-parse","HEAD"),n("remote","get-url","origin"),n("branch","-r","--contains","HEAD")]),a=ae(o.stdout),c=ae(r.stdout);return!o.ok||!a||!r.ok||!c?{why:"this checkout has no commit, or no origin",fix:"clone fnMoa from GitHub"}:!s.ok||!s.stdout.trim()?{why:`commit ${a.slice(0,7)} is not on ${Hi(c)} \u2014 the sandbox clones it from there`,fix:"push it, or check out a commit that is pushed, then press r"}:{url:Hi(c),revision:a}}async function ss(e){try{let{vercelTeam:t,vercelScope:n}=e.state.answers;return await os(e.sys).account(t,n)}catch(t){let n=t instanceof Error?t.message:String(t);return C("account",n,/not installed/.test(n)?"install the Vercel CLI: npm i -g vercel":/signed in|token/i.test(n)?"run `vercel login`, then press r":"check the team (e), then press r")}}var Bo=e=>typeof e=="object"&&e!==null&&"mark"in e;async function Ou(e){let{sys:t}=e,o=[Number(process.versions.node.split(".")[0])>=22?S("node",process.versions.node):C("node",process.versions.node,"install node 22 or newer"),...await Promise.all([gn(t,"git","install git"),gn(t,"gh","install the GitHub CLI: https://cli.github.com"),gn(t,"vercel","install the Vercel CLI: npm i -g vercel")])],r=Te(e)?{url:"GHCR",revision:Ce()}:await Ki(t);o.push("why"in r?C("fnMoa",r.why,r.fix):S("fnMoa",`${r.revision.slice(0,7)} from ${r.url} \u2014 built in the sandbox`));let s=await ss(e);if(Bo(s))return o.push(s),{lines:o};let a=vt(s.plan);return o.push(S("account",`${s.user} \xB7 team ${s.team} \xB7 ${ai(s.plan,a)}`),S("estimate",Ro(a)),S("storage",ii(a))),s.plan==="hobby"&&o.push(j("note","Hobby: a session stops after 45 minutes \u2014 `moa setup status` starts it again, and pipelines carry on")),{lines:o,answers:{vercelTeam:s.team,vercelPlan:s.plan,vercelScope:{teamId:s.teamId,projectId:s.projectId}}}}async function Wo(e){if(e.secrets.github)return{token:e.secrets.github,from:"pasted"};if(e.state.answers.githubToken==="pasted"&&e.state.deployed?.runner==="vercel")return{kept:!0};let t=await e.sys.exec("gh",["auth","token"]),n=ae(t.stdout);return t.ok&&n?{token:n,from:"own"}:void 0}async function Fi(e,t,n){try{let o=await e.fetch(`https://api.github.com${n}`,{headers:{Authorization:`Bearer ${t}`,Accept:"application/vnd.github+json"},signal:AbortSignal.timeout(15e3)});return o.ok?await o.json():o.status}catch{return 0}}async function Tu(e){let{sys:t,state:n}=e,o=await t.exec("gh",["api","user","--jq",".login"]),r=ae(o.stdout);if(!o.ok||!r)return{lines:[C("gh login",o.missing?"gh is not installed":"gh has no login on this machine","run `gh auth login`, then press r to check again")]};let s=[S("owner",`${r} \u2014 you, the first owner`)],a=await Wo(e),c,i;if(!a)s.push(C("GitHub token","none for the sandbox","press k to paste a fine-grained token \u2014 a bot account's is best"));else if("kept"in a)i="pasted",s.push(j("GitHub token","the one pasted before, kept in the sandbox (k to replace it)"));else{let d=await Fi(t,a.token,"/user");typeof d=="number"?s.push(C("GitHub token",`GitHub refused it${d?` (${d})`:""}`,"press k to paste another \u2014 contents, pull requests, issues read/write; checks, actions read")):(c=a.token,i=a.from,s.push(S("GitHub token",a.from==="pasted"?`${U} \u2014 ${d.login??"?"}${d.login?.toLowerCase()===r.toLowerCase()?" (your own)":" (bot account)"}`:`${U} \u2014 your own gh login; a bot account's is better (k to paste one)`)))}let l=n.answers.repo;if(!l)s.push(j("repo","none \u2014 a pipeline can name any repository later (e to set one)"));else if(c){let d=await Fi(t,c,`/repos/${l}`);s.push(typeof d!="number"&&d.permissions?.push?S("repo",`${l} \u2014 the token can push`):C("repo",typeof d=="number"?`${l} is not a repository the token can see`:`the token cannot push to ${l}`,"give the token this repository, or press e to change it"))}return{lines:s,answers:{owner:r,...i?{githubToken:i}:{}}}}async function as(e,t,n=()=>{}){if(Te(e))return ji(e,t,n);let o=os(e.sys),r=await Ki(e.sys);if("why"in r)return C("sandbox",r.why,r.fix);let s=lo(rs(e.state)),a=e.state.answers.sandbox?.name===s?e.state.answers.sandbox:void 0,c=a?.teamId===t.teamId&&a.projectId===t.projectId?a.snapshotId:void 0,i=vt(t.plan),l,d=c,u=!1;try{n(`looking for ${s}`),l=await o.get(t,s,!0),!l&&d&&(n(`making ${s} from its snapshot \u2014 ${i.vcpus} vCPU, persistent`),l=await o.create(t,{name:s,size:i,snapshotId:d}).catch(()=>{}),l||(d=void 0)),l||(n(`making ${s} \u2014 ${i.vcpus} vCPU, persistent`),l=await o.create(t,{name:s,size:i}),u=!0)}catch(p){return C("sandbox",p instanceof Error?p.message.split(`
212
+ `)[0]??"":String(p),"check the account on Checks & account, then press r")}let f=!1;if(await Do(l)!==r.revision){n("stopping the servers before the build");try{await Lo(l)}catch(y){return C("sandbox",`the servers did not stop: ${y instanceof Error?y.message:String(y)}`,"press r to try again")}n(`building the image at ${r.revision.slice(0,7)} \u2014 several minutes the first time`);let p=await Wo(e),g=await di(l,r.url,r.revision,p&&"token"in p?p.token:void 0);if(!g.ok)return C("sandbox",`the image did not build: ${St(g.stderr||g.stdout)}`,"fix that, then press r");if(f=!0,u){n("snapshotting the image");try{d=await l.snapshot(),l=await o.get(t,s,!0)??l}catch{}}}return{box:l,built:f,info:{name:s,workspaceUrl:l.domain(pt),consoleUrl:l.domain(ln),...d?{snapshotId:d,teamId:t.teamId,projectId:t.projectId}:{},revision:r.revision}}}var Iu=async(e,t)=>(await Ne(e,`test -s "$HOME/moa/env/workspace/${t}"`)).ok;async function Ru(e,t){return Ne(e,t?'claude -p "$PROMPT"':'CLAUDE_CODE_OAUTH_TOKEN=$(cat "$HOME/moa/env/workspace/CLAUDE_CODE_OAUTH_TOKEN") exec claude -p "$PROMPT"',{PROMPT:On,...t?{CLAUDE_CODE_OAUTH_TOKEN:t}:{}},18e4)}async function Lu(e){let{state:t}=e,n=await ss(e);if(Bo(n))return{lines:[n]};let o=await as(e,n);if(Bo(o))return{lines:[o]};let{box:r,info:s}=o,a=vt(n.plan),c=[S("sandbox",`${s.name} \u2014 ${r.vcpus??a.vcpus} vCPU, persistent, fnMoa ${s.revision?.slice(0,7)??""}`)],i={claude:!1,codex:!1,cursor:!1},l=Ze(e),d=!l&&await Iu(r,"CLAUDE_CODE_OAUTH_TOKEN");if(l||d){let p=await Ru(r,l?.token);i.claude=p.ok&&/\bok\b/i.test(p.stdout),c.push(i.claude?S("claude",`token ${U} (${l?l.from:"kept in the sandbox"}) \u2014 "reply ok" in the sandbox`):C("claude",`the token did not answer: ${St(p.stdout||p.stderr)||"no answer"}`,"press c to make a new one with `claude setup-token`, or k for an API key"))}else ye(e,"claude")?(i.claude=!0,c.push(S("claude",`ANTHROPIC_API_KEY ${U} \u2014 carried into the sandbox`))):c.push(j("claude","not connected \u2014 c for your Claude subscription, or k for an API key"));if(ye(e,"codex"))i.codex=!0,c.push(S("codex",`OPENAI_API_KEY ${U} \u2014 carried into the sandbox`));else{let p=await r.exec("codex",["login","status"],{timeoutMs:6e4});i.codex=p.ok,c.push(p.ok?S("codex",`${ae(p.stdout)||"logged in"} \u2014 its own session in the sandbox (c to log in again)`):j("codex","not connected \u2014 c to log in with a code (ChatGPT), or k for an API key"))}if(ye(e,"cursor"))i.cursor=!0,c.push(S("cursor",`CURSOR_API_KEY ${U} \u2014 carried into the sandbox`));else{let p=await r.exec("cursor-agent",["status"],{timeoutMs:6e4});i.cursor=p.ok&&!/not logged in/i.test(`${p.stdout}${p.stderr}`),c.push(i.cursor?S("cursor","logged in \u2014 its own session in the sandbox (c to log in again)"):j("cursor","not connected \u2014 c to log in with your Cursor account, or k for an API key"))}let u=pe.filter(p=>i[p]),f=t.answers.agentCli??u[0];return f?c.push(i[f]?S("proof run",`uses ${f} (\u2191 \u2193 to change) \xB7 ${u.length} of 3 connected`):C("proof run",`${f} is not connected in the sandbox`,"press c to connect it or k for its API key \u2014 or \u2191 \u2193 to another agent")):c.push(C("agent","no agent is connected in the sandbox","\u2191 \u2193 to an agent, then c to connect it or k for its API key")),c.push(j("note","owner only: your subscriptions; teammates use them, never see them (moa setup login)")),{lines:c,answers:{sandbox:s,...f?{agentCli:f}:{},loggedIn:u}}}function Bi(e,t,n="codex"){let o=!1,r=()=>{o=!0};return{done:(async()=>{let a=await ss(e);if(Bo(a))return{ok:!1,stdout:"",stderr:a.detail??"no account"};let c=e.state.answers.sandbox?.name??lo(rs(e.state)),i=await os(e.sys).get(a,c,!0);if(!i)return{ok:!1,stdout:"",stderr:`${c} is not there`};if(o)return{ok:!1,stdout:"",stderr:"stopped"};let l="",d=n==="codex"?i.stream("codex",["login","--device-auth"],u=>{l+=u,t(cn(l))}):i.stream("env",["NO_OPEN_BROWSER=1","cursor-agent","login"],u=>{l+=u,t(No(l))});return r=d.cancel,d.done})(),cancel:()=>r()}}async function Du(e){let{sys:t,state:n,secrets:o}=e,r=Ee(e),s=[],a=zr(e);if(a)s.push(a);else if(r){let i=await Tn(t,r,rs(n)),l=`secret ${U} (${r.from}), graph ${r.graph}`;s.push(i.read.ok&&i.write.ok?S("LocusGraph",`${l} \u2014 one graph read, one event written`):C("LocusGraph",`${l} \u2014 ${i.read.ok?`the write failed: ${i.write.why}`:`the read failed: ${i.read.why}`}`,"e to paste the secret again, or g to check the graph ID \u2014 then r"))}else n.deployed?.runner==="vercel"&&n.deployed.memoryKept&&!o.noLocusgraph?s.push(j("LocusGraph","the secret the last deploy gave the sandbox, kept there (e to replace it)")):s.push(j("LocusGraph","not connected \u2014 memory stays in the workspace process (g for the graph ID, e for its secret)"));let c=n.answers.store??"postgres";return s.push(c==="postgres"?S("database","Postgres, in the sandbox on its kept disk \u2014 migrated at deploy (\u2191 \u2193 for SQLite)"):S("database","SQLite, on the sandbox's kept disk \u2014 migrated at deploy (\u2191 \u2193 for Postgres)")),{lines:s,answers:{store:c}}}function Uu(e){let t=Yr(e),{githubApp:n,sandbox:o}=e.state.answers,r=[...t.lines];return o?hn(e.state)==="password"?r.unshift(S("console",`${o.consoleUrl} \u2014 you sign in there with your password`)):n&&n.consoleUrl!==o.consoleUrl?r.unshift(C("callback",`${n.slug} signs people in at ${n.consoleUrl??"localhost"}, not ${o.consoleUrl}`,"press g to create an app for the sandbox's console")):r.unshift(S("console",`${o.consoleUrl} \u2014 GitHub sends people back here`)):r.unshift(C("console","no sandbox yet","Esc back to Agent logins: the sandbox is made there")),{lines:r,answers:t.answers??{}}}var Wi={...jo,checks:Ou,github:Tu,logins:Lu,memory:Du,access:Uu};var wn="vercel";async function Jo(e,t,n){let o=Date.now()+n*1e3;for(;Date.now()<o;){if(await e.fetch(t,{signal:AbortSignal.timeout(5e3)}).then(s=>s.ok).catch(()=>!1))return!0;await e.sleep(1e3)}return!1}var Nu=e=>typeof e=="object"&&e!==null&&"mark"in e;async function qo(e){if(!e.sys.vercel)return{label:"account",detail:"this build of moa cannot reach Vercel",fix:"update moa"};try{let{vercelTeam:t,vercelScope:n}=e.state.answers;return await e.sys.vercel.account(t,n)}catch(t){return{label:"account",detail:t instanceof Error?t.message:String(t),fix:"run `vercel login`, then Enter"}}}var kn=e=>typeof e=="object"&&e!==null&&"fix"in e&&"label"in e;async function zo(e,t,n=()=>{}){let{sys:o,state:r}=e,s=[],a=F=>{let Ge=s.findIndex(nt=>nt.label===F.label);Ge===-1?s.push(F):s[Ge]=F,t([...s])},c,i=(F,Ge,nt)=>(a({label:F,mark:"fail",detail:Ge,fix:nt}),c?{ok:!1,deployed:c}:{ok:!1}),l=await Xt(e);if("why"in l)return i("console sign-in",l.why,l.fix);if(l.mode==="none")return i("console sign-in","none \u2014 a public console needs somebody to sign in","Esc back to Console access: \u2191 \u2193 to password, or press g for a GitHub App");let d=l.mode==="github"?r.answers.githubApp:void 0;a({label:"sandbox",mark:"wait",detail:"looking for it"});let u=await qo(e);if(kn(u))return i(u.label,u.detail,u.fix);let f=await as(e,u,F=>a({label:"sandbox",mark:"wait",detail:F}));if(Nu(f))return i("sandbox",f.detail??"",f.fix??"Enter to try again");let{box:p,info:g,built:y}=f,b=vt(u.plan);a({label:"sandbox",mark:"ok",detail:`${g.name} \u2014 ${p.vcpus??b.vcpus} vCPU, persistent${y?", image built":""}`});let m=g.workspaceUrl,w=g.consoleUrl;if(d&&d.consoleUrl!==w)return i("GitHub App",`${d.slug} signs people in at ${d.consoleUrl??"localhost"}, not ${w}`,"Esc back to Console access and press g");let{token:v,pending:_,before:H,had:W}=await qt(o,wn,m);a({label:"owner token",mark:"ok",detail:`${U} \u2014 profile ${wn} in ~/.moa/config.json${H===wn||!W?"":`; \`moa\` now talks to the sandbox, not profile ${H} (\`moa use ${H}\` to go back)`}`});let le=r.answers.tenant??Ie(r.answers.owner),L=r.answers.owner,X=Ee(e),D=Ze(e)?.token,B=await Wo(e),ne={...Object.fromEntries(Object.entries(await Wt(e)).map(([F,Ge])=>[`workspace/${F}`,Ge])),store:r.answers.store??"postgres","workspace/MOA_TOKENS":`${v}:${le}`,"workspace/PORT":String(pt),"workspace/MOA_PORT":String(pt),"workspace/MOA_SELF_URL":`http://127.0.0.1:${pt}`,"workspace/MOA_MAX_CONCURRENT_RUNS":String(b.maxRuns),"workspace/MOA_REPO":r.answers.repo,"workspace/MOA_OWNER_LOGIN":L,"workspace/MOA_GITHUB_CLIENT_ID":l.vars.MOA_GITHUB_CLIENT_ID,"workspace/LOCUSGRAPH_AGENT_SECRET":X?.secret,"workspace/LOCUSGRAPH_GRAPH_ID":X?.graph,"workspace/LOCUSGRAPH_SERVER_URL":X?.server,"workspace/CLAUDE_CODE_OAUTH_TOKEN":D,...Object.fromEntries(pe.map(F=>[`workspace/${Ae[F]}`,ye(e,F)])),"workspace/GH_TOKEN":B&&"token"in B?B.token:void 0,"console/MOA_URL":`http://127.0.0.1:${pt}`,"console/MOA_TOKEN":v,"console/AUTH_GITHUB_ID":l.vars.AUTH_GITHUB_ID,"console/AUTH_GITHUB_SECRET":l.secrets.AUTH_GITHUB_SECRET,"console/AUTH_SECRET":l.secrets.AUTH_SECRET,"console/MOA_CONSOLE_LOGIN":l.vars.MOA_CONSOLE_LOGIN,"console/MOA_CONSOLE_PASSWORD_HASH":l.secrets.MOA_CONSOLE_PASSWORD_HASH,"console/AUTH_URL":w,"console/AUTH_TRUST_HOST":"true"};if(!B)return i("secrets","no GitHub token for the sandbox","Esc back to GitHub and press k to paste one");let ge=[...["workspace/MOA_GITHUB_CLIENT_ID","console/AUTH_GITHUB_ID","console/AUTH_GITHUB_SECRET","console/MOA_CONSOLE_LOGIN","console/MOA_CONSOLE_PASSWORD_HASH"].filter(F=>ne[F]===void 0),"workspace/MOA_CLIENT_ADDRESS",...r.answers.repo?[]:["workspace/MOA_REPO"],...L?[]:["workspace/MOA_OWNER_LOGIN"],...e.secrets.noLocusgraph?["workspace/LOCUSGRAPH_AGENT_SECRET","workspace/LOCUSGRAPH_GRAPH_ID","workspace/LOCUSGRAPH_SERVER_URL"]:[]];a({label:"secrets",mark:"wait",detail:"writing them into the sandbox"});let ee=await ci(p,ne,ge);if(!ee.ok)return i("secrets",`not written: ${ee.why??"no answer"}`,"Enter to try again");let $e=["workspace/MOA_TOKENS","workspace/LOCUSGRAPH_AGENT_SECRET","workspace/CLAUDE_CODE_OAUTH_TOKEN",...pe.map(F=>`workspace/${Ae[F]}`),"workspace/GH_TOKEN","console/MOA_TOKEN","console/AUTH_GITHUB_SECRET","console/AUTH_SECRET","console/MOA_CONSOLE_PASSWORD_HASH"].filter(F=>ne[F]!==void 0);a({label:"secrets",mark:"ok",detail:`${$e.length} written \u2014 none shown; no Vercel token in the sandbox`});let $=ee.changed||y;a({label:"workspace",mark:"wait",detail:$?`starting on :${pt}`:"checking it runs"});try{await Ir(p,$)}catch(F){return i("workspace",`the start did not run: ${F instanceof Error?F.message:String(F)}`,"Enter to try again")}let I=r.deployed?.workspaceUrl===m?r.deployed.people:void 0,oe=F=>{c={runner:"vercel",workspaceUrl:m,consoleUrl:w,...I?{people:I}:{},...F?{memoryKept:F}:{},at:new Date().toISOString()},n(c)},O=r.deployed?.runner==="vercel"?r.deployed.memoryKept:void 0,V=X?!0:e.secrets.noLocusgraph?!1:O;if(oe(V),!await Jo(o,`${m}/health`,180))return i("workspace",`did not answer at ${m} \u2014 ${await Rn(p,"workspace")||"no log yet"}`,"fix that, then Enter");let fe=N({url:m,token:v},o.fetch);if(!await fe.get("/v1/whoami").then(()=>!0,()=>!1))return i("workspace","it started but refuses the owner token","Enter to try again");_&&await zt(o,wn,m,v),a({label:"workspace",mark:"ok",detail:`${m} \u2014 :${pt} in the sandbox`});let ve=await Ur(o,m,a,r.answers.store??"postgres",`look at the sandbox's ~/moa/logs \u2014 ${await Rn(p,"postgres")}`);if(ve)return i(ve.label,ve.detail,ve.fix);let Se=await pn(fe,r,a,I);if(Se)return i(Se.label,Se.detail,Se.fix);let Me=I;if(I=r.answers.people??[],JSON.stringify(I)!==JSON.stringify(Me??[])&&oe(V),a({label:"console",mark:"wait",detail:`waiting for :${ln}`}),!await Jo(o,w,180))return i("console",`did not answer at ${w} \u2014 ${await Rn(p,"console")||"no log yet"}`,"fix that, then Enter");a({label:"console",mark:"ok",detail:`${w} \u2014 Sign in with GitHub`}),$&&await li(p);let Re=r.answers.agentCli??"claude",Ke=[...new Set([Re,...r.answers.loggedIn??[]])],we=await Nt(fe,Ke,"in the sandbox",()=>"Esc back to Agent logins and log it in again, then Enter",a);if("label"in we)return i(we.label,we.detail,we.fix);let _e=await fn(fe,a);if("label"in _e)return i(_e.label,_e.detail,_e.fix);_e.live!==void 0&&(V=_e.live),a({label:"Console",mark:"ok",detail:w}),a({label:"Workspace",mark:"ok",detail:m}),a({label:"Next",mark:"skip",detail:`moa setup status \xB7 moa setup stop \xB7 moa run ${Nn(Re)} "\u2026"`});let T=we.runs[Re];return{ok:!0,deployed:{runner:"vercel",workspaceUrl:m,consoleUrl:w,...T?{proofRunId:T}:{},memory:_e.memory,people:I,...V?{memoryKept:V}:{},at:new Date().toISOString()}}}async function Vo(e,t){let n=e.state.answers.sandbox;if(e.state.target!=="vercel"||!n)return{label:"sandbox",detail:"moa setup has not made one",fix:"run `moa setup` and choose Vercel Sandbox"};let o=await qo(e);if(kn(o))return o;try{let r=await e.sys.vercel?.get(o,n.name,t);return r?{box:r}:{label:"sandbox",detail:`${n.name} is not there`,fix:"run `moa setup` to make it again"}}catch(r){return{label:"sandbox",detail:r instanceof Error?r.message:String(r),fix:"check `vercel whoami`, then try again"}}}async function Ji(e,t){let{sys:n,state:o}=e,r=await Vo(e,!0);if(kn(r))return t({label:r.label,mark:"fail",detail:r.detail,fix:r.fix}),!1;let{box:s}=r;t({label:"sandbox",mark:"ok",detail:`${s.name} \u2014 ${s.status}${s.vcpus?`, ${s.vcpus} vCPU`:""}`});let a=o.answers.sandbox;try{await Ir(s,!1)}catch(y){return t({label:"workspace",mark:"fail",detail:`the start did not run: ${St(y instanceof Error?y.message:String(y))}`,fix:"try again, or run `moa setup` to deploy it again"}),!1}let c={workspace:s.domain(pt),console:s.domain(ln)};if(c.workspace!==a.workspaceUrl||c.console!==a.consoleUrl){let y=[...c.workspace!==a.workspaceUrl?[`the workspace is at ${c.workspace}, not ${a.workspaceUrl}`]:[],...c.console!==a.consoleUrl?[`the console is at ${c.console}, not ${a.consoleUrl}`]:[]];return t({label:"URLs",mark:"fail",detail:`the sandbox's domain has changed \u2014 ${y.join("; ")}`,fix:"run `moa setup` to deploy it again, and press g on Console access for the new callback"}),!1}if(!await Jo(n,`${a.workspaceUrl}/health`,180))return t({label:"workspace",mark:"fail",detail:`no answer at ${a.workspaceUrl} \u2014 ${await Rn(s,"workspace")||"no log"}`,fix:"run `moa setup` to deploy it again"}),!1;let l=(await xe(n.env)).profiles[wn];if(!l||l.url!==a.workspaceUrl)return t({label:"workspace",mark:"fail",detail:`${a.workspaceUrl} answers, but this machine has no token for it`,fix:"run `moa setup` to deploy it again"}),!1;let d=N(l,n.fetch),u=await n.fetch(`${a.workspaceUrl}/health`,{signal:AbortSignal.timeout(5e3)}).then(y=>y.json()).catch(()=>({})),f=await d.get("/v1/whoami").then(()=>{},y=>y instanceof ie?`${y.status}`:String(y));t(f?{label:"workspace",mark:"fail",detail:`refuses the owner token (${f})`,fix:"run `moa setup` to deploy it again"}:{label:"workspace",mark:"ok",detail:`${a.workspaceUrl}${u.database?` \u2014 ${u.database}`:""}`});let p=await d.get("/v1/jobs").then(y=>y.jobs).catch(()=>{});if(p){let y=p.filter(b=>b.state==="running"||b.state==="queued");t({label:"pipelines",mark:"ok",detail:y.length===0?"nothing running":`${y.length} running or waiting \u2014 carried on from before the stop (moa jobs)`})}let g=await Jo(n,a.consoleUrl,180);return t(g?{label:"console",mark:"ok",detail:`${a.consoleUrl} \u2014 Sign in with GitHub`}:{label:"console",mark:"fail",detail:`no answer at ${a.consoleUrl} \u2014 ${await Rn(s,"console")||"no log"}`,fix:"run `moa setup` to deploy it again"}),!f&&g}async function qi(e,t){let n=await Vo(e,!1);if(kn(n))return t({label:n.label,mark:"fail",detail:n.detail,fix:n.fix}),!1;try{await n.box.stop()}catch(o){return t({label:"sandbox",mark:"fail",detail:`did not stop: ${St(o instanceof Error?o.message:String(o))}`,fix:"try again"}),!1}return t({label:"sandbox",mark:"ok",detail:`${n.box.name} stopped \u2014 its disk is kept; \`moa setup status\` starts it again`}),!0}import{jsx as Z,jsxs as Pe}from"react/jsx-runtime";var be=(e,t)=>({...e,answers:{...e.answers,...t}}),Fu=[{value:"vercel",label:"Vercel Sandbox",note:"one VM, 24h sessions, resumes by name"},{value:"cloudflare",label:"Cloudflare",note:"Worker + container, needs your domain"},{value:"local",label:"This machine",note:"Docker / local, nothing in the cloud"}],Ku={where:{options:e=>Fu.map(t=>{let n=Co(t.value,io(e,t.value));return n?{...t,note:n}:t}),value:e=>e.target,set:(e,t)=>st(e,t)},checks:{options:()=>[{value:"image",label:"Published image",note:"pull the release from GHCR \u2014 nothing is built here"},{value:"checkout",label:"This checkout",note:"build from source \u2014 for working on fnMoa"}],value:e=>Pn(e),set:(e,t)=>be(e,{source:t})},logins:{options:()=>[{value:"claude",label:"claude",note:"a Claude subscription, or an API key"},{value:"codex",label:"codex",note:"a ChatGPT plan, or an API key"},{value:"cursor",label:"cursor",note:"a Cursor plan, or an API key"}],value:e=>e.answers.agentCli,set:(e,t)=>be(e,{agentCli:t})},access:{options:e=>[...e.target==="local"?[{value:"none",label:"nobody",note:"the console stays on this machine, no sign-in"}]:[],{value:"password",label:"password",note:"just you: your GitHub login and a password"},{value:"github",label:"GitHub App",note:"a team: everyone signs in with GitHub"}],value:e=>hn(e)??"none",set:(e,t)=>be(e,{consoleSignIn:t==="none"?void 0:t})},memory:{options:e=>e.target==="vercel"?[{value:"postgres",label:"Postgres",note:"in the sandbox, on its kept disk"},{value:"sqlite",label:"SQLite",note:"a file on the sandbox's kept disk"}]:[{value:"node",label:"SQLite",note:"node apps/workspace/dist/node.js"},{value:"compose",label:"Postgres",note:"docker compose up (apps/workspace/compose.yaml)"}],value:e=>e.target==="vercel"?e.answers.store??"postgres":e.answers.runner??"node",set:(e,t)=>e.target==="vercel"?be(e,{store:t}):be(e,{runner:t})}},is=e=>e.target==="vercel",Xi=/^[a-z\d](?:[a-z\d-]{0,38})$/i;function Bu(e,t){let n=e.answers.people??[],o=f=>p=>p.login.toLowerCase()===f.toLowerCase(),r="a GitHub login, then member or viewer, then a cap in $/day \u2014 or -login to remove",[s,...a]=t.split(/\s+/).filter(Boolean);if(!s)return r;if(s.startsWith("-")){let f=s.slice(1);if(!n.some(o(f)))return`${f} is not on the list`;let p=n.filter(y=>!o(f)(y)),g=[...new Set([...e.answers.removed??[],f.toLowerCase()])];return be(e,{people:p.length>0?p:void 0,removed:g})}if(!Xi.test(s))return r;if(e.answers.owner&&s.toLowerCase()===e.answers.owner.toLowerCase())return`${s} is you \u2014 the owner already`;let c=n.find(o(s)),i=c?.role??"member",l=c?.dailyCapUsd??vr;for(let f of a){let p=f.toLowerCase(),g=Number(p.replace(/^\$|\/day$/g,""));if(p==="member"||p==="viewer")i=p;else if(Number.isFinite(g)&&g>=0&&g<=1e4)l=g;else return r}let d={login:s,role:i,dailyCapUsd:l},u=(e.answers.removed??[]).filter(f=>f!==s.toLowerCase());return be(e,{people:c?n.map(f=>o(s)(f)?d:f):[...n,d],removed:u.length>0?u:void 0})}var Yo=e=>e.target==="cloudflare",Wu="\x1B",Ju=new RegExp(`(?:${Wu})?\\[20[01]~|[\\u0000-\\u001f\\u007f]`,"g"),Vi=e=>e.replace(Ju,""),qu={checks:[{key:"l",label:"Licence key",secret:!0,shown:(e,t)=>t.licence?U:"saved key, or none",commit:(e,t,n)=>(t.licence=n||void 0,e)},{key:"d",label:"Domain",when:Yo,shown:e=>e.answers.domain??"none",commit:(e,t,n)=>{let o=n.toLowerCase().replace(/^https?:\/\//,"").replace(/\/+$/,"");return o===""?be(e,{domain:void 0}):ur.test(o)?be(e,{domain:o}):"a domain on your Cloudflare account, like example.com"}},{key:"k",label:"D1 token",secret:!0,when:Yo,shown:(e,t)=>t.cloudflare?U:"none",commit:(e,t,n)=>/\s/.test(n)?"one token, no spaces":(t.cloudflare=n||void 0,e)},{key:"e",label:"Vercel team",when:is,shown:e=>e.answers.vercelTeam??"the one Vercel picks",initial:e=>e.answers.vercelTeam??"",commit:(e,t,n)=>n===""||/^[\w-]{1,100}$/.test(n)?be(e,{vercelTeam:n||void 0,vercelScope:void 0}):"a team's slug or id, as `vercel teams ls` shows it"}],github:[{key:"e",label:"Repo",shown:e=>e.answers.repo??"none",commit:(e,t,n)=>n===""?{...e,answers:{...e.answers,repo:void 0}}:/^[\w.-]+\/[\w.-]+$/.test(n)?be(e,{repo:n}):"owner/name, like fnLog0/fnmoa"},{key:"k",label:"GitHub token",secret:!0,when:e=>is(e)||Yo(e),shown:(e,t)=>t.github?U:is(e)?"none \u2014 your own gh login":"none",commit:(e,t,n)=>/\s/.test(n)?"one token, no spaces":(t.github=n||void 0,e)}],logins:[{key:"e",label:"claude token",secret:!0,shown:(e,t)=>t.claude?U:"none",commit:(e,t,n)=>/\s/.test(n)?"one token, no spaces \u2014 what `claude setup-token` printed":(t.claude=n||void 0,e)},{key:"k",label:"API key",secret:!0,shown:(e,t)=>{let n=e.answers.agentCli??"claude";return`${Ae[n]} ${t.keys?.[n]?U:"none"}`},commit:(e,t,n)=>{if(/\s/.test(n))return"one key, no spaces";let o=e.answers.agentCli??"claude";return t.keys={...t.keys,[o]:n||void 0},e}}],memory:[{key:"g",label:"LocusGraph graph ID",shown:e=>e.answers.locusgraphGraph??"none",initial:e=>e.answers.locusgraphGraph??"",commit:(e,t,n)=>n===""||/^[\w.:-]{1,100}$/.test(n)?be(e,{locusgraphGraph:n||void 0}):"the graph's ID, as LocusGraph shows it \u2014 letters, digits, - _ . :"},{key:"e",label:"LocusGraph secret",secret:!0,shown:(e,t)=>t.locusgraph?U:"none",commit:(e,t,n)=>(t.locusgraph=n||void 0,t.noLocusgraph=!n,e)}],access:[{key:"p",label:"Console password",secret:!0,when:e=>hn(e)==="password",shown:(e,t)=>t.consolePassword?U:"the one kept from a deploy, or none",commit:(e,t,n)=>n.length<12?"12 characters or more \u2014 it guards a console on the internet":(t.consolePassword=n,be(e,{consoleSignIn:"password"}))},{key:"e",label:"Tenant",shown:e=>e.answers.tenant??"",commit:(e,t,n)=>/^[a-z0-9][a-z0-9-]{0,62}$/.test(n)?be(e,{tenant:n}):"lower-case letters, digits and dashes"},{key:"o",label:"App owner",shown:e=>e.answers.appOrg??"your account (o for an organization)",initial:e=>e.answers.appOrg??"",commit:(e,t,n)=>n===""||Xi.test(n)?be(e,{appOrg:n||void 0}):"a GitHub organization's login, or nothing for your own account"},{key:"a",label:"Add people",shown:()=>"login member|viewer $/day \u2014 -login takes them off",initial:()=>"",commit:(e,t,n)=>Bu(e,n)}]},cs=(e,t)=>{let n=[...e];for(let o of t){let r=n.findIndex(s=>s.label===o.label);r===-1?n.unshift(o):n[r]=o}return n},Yi={ok:{char:"\u2713",color:"green"},fail:{char:"\u2717",color:"red"},wait:{char:"\u2026",color:"yellow"},skip:{char:"\u2013",color:"gray"}},ls={where:"Where",checks:"Checks",github:"GitHub",memory:"Memory",logins:"Logins",access:"Access",deploy:"Deploy"},zu=Object.fromEntries(dt.filter(e=>e!=="where"&&e!=="deploy").map((e,t)=>[String(t+1),e])),Vu={local:"this machine",vercel:"the Vercel Sandbox",cloudflare:"Cloudflare"},Yu={ok:"ok",fail:"failing",wait:"checking"};function Xu({screen:e,passed:t}){return Z(Ve,{columnGap:2,flexWrap:"wrap",children:dt.map(n=>n===e?Pe(se,{bold:!0,color:"cyan",children:["\u25B8 ",ls[n]]},n):t.includes(n)?Pe(se,{color:"green",children:["\u2713 ",ls[n]]},n):Pe(se,{dimColor:!0,children:[" ",ls[n]]},n))})}function Xo({title:e,aside:t,children:n}){return Pe(Ve,{flexDirection:"column",marginTop:1,children:[Pe(Ve,{justifyContent:"space-between",children:[Z(se,{bold:!0,dimColor:!0,children:e.toUpperCase()}),t?Z(se,{dimColor:!0,children:t}):null]}),n]})}function Qu({rows:e}){let t=Math.max(...e.map(n=>n.label.length));return Z(Xo,{title:"review",children:e.map(n=>Pe(Ve,{children:[Z(Ve,{flexShrink:0,width:t+2,children:Z(se,{dimColor:!0,children:n.label})}),Z(se,{children:n.value})]},n.label))})}function Zu({hints:e}){return Z(Ve,{columnGap:2,flexWrap:"wrap",paddingX:1,children:e.map(t=>{let n=t.indexOf(" ");return Pe(se,{children:[Z(se,{bold:!0,children:t.slice(0,n)}),Z(se,{dimColor:!0,children:t.slice(n)})]},t)})})}var ep=e=>[e.deployed?{label:"last deploy",mark:"skip",detail:`console ${e.deployed.consoleUrl} \xB7 workspace ${e.deployed.workspaceUrl} \u2014 Enter to check it again`}:{label:"deploy",mark:"wait",detail:e.target==="vercel"?"Enter to write the secrets into the sandbox, start the workspace and console, and prove it with one agent run and one memory read":e.target==="cloudflare"?"Enter to deploy the Worker, D1 and the container to your domain, and prove it with one agent run and one memory read":"Enter to build, start the workspace and console, and prove it with one agent run and one memory read"}];function Qi({initial:e,sys:t,save:n,checks:o,deploy:r,createApp:s=Di,onDone:a,secrets:c,onHandOver:i,pasteFirst:l=!1,deviceLogin:d=Xa,after:u={}}){let{exit:f}=Mu(),[p,g]=ft(()=>e.screen==="where"&&!e.target?{...e,target:"local"}:e),[y,b]=ft([]),[m,w]=ft(!1),[v,_]=ft(0),H=l&&e.screen==="logins",[W,le]=ft(H?"":void 0),[L,X]=ft(H?"e":void 0),D=At(void 0),B=At([]),ne=h=>cs(h,B.current),[ge,ee]=ft(void 0),[$e,$]=ft(!1),[I,oe]=ft("no"),O=At(c??{}).current,V=At(void 0),[fe,te]=ft(0),ve=At(Promise.resolve()),Se=At(0),[Me,Re]=ft(!1),Ke=At(!1),we=h=>{Ke.current=h,Re(h)},_e=At(e.screen!=="where").current,T=p.screen,F=p.target==="vercel",Ge=o??(F?Wi:jo),nt=r??(F?zo:p.target==="cloudflare"?Fo:Uo),ot=T==="checks"&&Te({sys:t,state:p}),mt=F||p.answers.runner==="compose",me=At(p);me.current=p;let bn=At(p),Q=h=>{bn.current!==h&&(bn.current=h,ve.current=ve.current.then(()=>n(h)).catch(()=>{}))};zi(()=>Q(p),[p,n]);let Le=()=>(Q(me.current),ve.current),{answers:ue}=p,Be=JSON.stringify([T,p.target,ue,v,fe]);zi(()=>{if(T==="deploy"){m||b(ep(p));return}let h=++Se.current;b(x=>x.map(q=>B.current.some(M=>M.label===q.label)?q:{...q,mark:"wait"})),w(!0),Promise.resolve(Ge[T]?.({state:p,sys:t,secrets:O})??{lines:[]}).then(async x=>({...x,lines:[...x.lines,...!o&&T==="checks"?await bt({state:p,sys:t,secrets:O}):[]]})).then(x=>{if(h!==Se.current)return;let q=ne(x.lines);b(q),D.current||w(!1);let M=x.answers??{};Object.entries(M).some(([lt,$n])=>p.answers[lt]!==$n)&&g(lt=>be(lt,M));let je=Ke.current;we(!1),je&&go(q)&&Yn(T)},x=>{h===Se.current&&(b(ne([{label:"check",mark:"fail",detail:String(x),fix:"press r to check again"}])),D.current||w(!1),we(!1))})},[Be]);let gt=h=>{D.current?.abort(),Le().then(()=>{a?.(me.current,h),f()})},gs=()=>{w(!0),ee(void 0);let h=M=>b([{label:"licence",mark:"wait",detail:M},{label:"note",mark:"skip",detail:"sign in there and approve it \u2014 Esc to stop"}]);h("asking the licence server for a code\u2026");let x=new AbortController,q={done:Po({state:p,sys:t,secrets:O},M=>h(`open ${M.url} and check it shows ${M.code}`),x.signal).then(()=>({ok:!0,stdout:"",stderr:""}),M=>({ok:!1,stdout:"",stderr:M instanceof Error?M.message:String(M)})),cancel:()=>x.abort()};V.current=q,q.done.then(M=>{V.current===q&&(V.current=void 0,w(!1),M.ok||ee(`not connected: ${M.stderr}`),_(R=>R+1))})},Ct=(h="codex")=>{let x=Te({sys:t,state:p})?void 0:t.root,q=!x&&p.deployed?.runner==="image";if(!x&&!F&&!q)return;w(!0);let M=F?"sandbox":"container",R=lt=>b([{label:h,mark:"wait",detail:Fn(lt)??`starting its login inside the ${M}\u2026`},{label:"note",mark:"skip",detail:"its own session, not a copy of this machine's \u2014 Esc to stop"}]);R({});let je=F?Bi({state:p,sys:t,secrets:O},R,h):q?Hn(t,h,R):d(t,x,R);V.current=je,je.done.then(lt=>{V.current===je&&(V.current=void 0,w(!1),lt.ok||ee(`${h} login did not finish: ${(lt.stderr||lt.stdout).trim().split(`
213
+ `).slice(-1)[0]??""}`),_($n=>$n+1))})},hs=h=>{if(ee(void 0),h==="claude"){if(!i)return ee("run `claude setup-token`, then e to paste the token");Le().then(()=>{i(me.current),f()});return}let x=Te({sys:t,state:p});if(F)return Ct(h);if(p.target==="cloudflare")return ee(h==="codex"?"codex logs in inside the container at Deploy \u2014 a link and a code; or k for its API key":"on Cloudflare cursor runs on an API key: k");if(x)return p.deployed?.runner==="image"?Ct(h):ee(`${h} logs in inside the container at Deploy when it is picked \u2014 or k for its API key`);if(mt)return h==="codex"?Ct("codex"):ee("cursor runs in the published image or on Vercel \u2014 k for its API key");ee(`run \`${h==="codex"?"codex login":"cursor-agent login"}\` in a terminal, then r`)},ws=h=>{if(ee(void 0),O.keys={...O.keys,[h]:void 0},h==="claude"&&(O.claude=void 0),te(x=>x+1),g(x=>be(x,{loggedIn:(x.answers.loggedIn??[]).filter(q=>q!==h)})),h!=="claude"&&p.deployed?.runner==="image"&&Te({sys:t,state:p})){t.exec("docker",et(t,"exec","-T","workspace",...Xr[h]),{timeoutMs:6e4}).then(()=>_(x=>x+1));return}_(x=>x+1)},jt=h=>{oe("no"),ee(void 0),we(!1),B.current=[],b([]),g(x=>({...x,screen:h}))},Yn=h=>{me.current.screen===h&&(g(x=>({...x,passed:[...new Set([...x.passed,h])]})),jt(u[h]??Ma(h)))},ks=()=>{w(!0),b([]),nt({state:p,sys:t,secrets:O},b,q=>{let M={...me.current,deployed:q};me.current=M,Q(M),g(R=>({...R,deployed:q}))},q=>{let M={...me.current,cloudflare:q};me.current=M,Q(M),g(R=>({...R,cloudflare:q}))}).then(q=>{let M=q.deployed;q.ok&&M?($(!0),g(R=>({...R,answers:{...R.answers,removed:void 0},deployed:M,passed:[...new Set([...R.passed,"deploy"])]}))):M&&g(R=>({...R,deployed:M}))}).catch(q=>b(M=>[...M,{label:"deploy",mark:"fail",detail:String(q),fix:"Enter to try again"}])).finally(()=>w(!1))},Pt=h=>{B.current=cs(B.current,h),b(x=>cs(x,h))},Ht=()=>{let h=new AbortController;D.current=h,w(!0),ee(void 0),Pt([{label:"GitHub App",mark:"wait",detail:"starting a page for GitHub\u2026"}]),s({state:p,sys:t,secrets:O},Pt,h.signal).then(x=>{D.current=void 0,w(!1),B.current=[],g(q=>be(q,x)),_(q=>q+1)},x=>{D.current=void 0,w(!1),!h.signal.aborted&&Pt([{label:"GitHub App",mark:"fail",detail:x instanceof Error?x.message:String(x),fix:"press g to try again"}])})},_t=(qu[T]??[]).filter(h=>!h.when||h.when(p)),nr=_t.find(h=>h.key===L),it=T==="memory"&&Yo(p)||T==="checks"&&!t.root?void 0:Ku[T],K=T==="access"?p.answers.githubApp:void 0;ju(h=>{let x=Vi(h);x&&le(q=>`${q??""}${x}`)},{isActive:W!==void 0}),Gu((h,x)=>{if(W!==void 0&&nr){if(x.escape){le(void 0),X(void 0);return}if(x.return){let R=nr.commit(p,O,W.trim());if(typeof R=="string"){ee(R);return}ee(void 0),le(void 0),X(void 0),te(je=>je+1),g(R);return}if(x.backspace||x.delete){le(R=>(R??"").slice(0,-1));return}if(h&&!x.ctrl&&!x.meta){let R=Vi(h);R&&le(je=>`${je??""}${R}`)}return}if(V.current){(x.escape||h==="q")&&(V.current.cancel(),V.current=void 0,w(!1),_(R=>R+1));return}if(h==="q")return gt($e);if(x.escape){if(I==="asking")return oe("no");T!=="where"&&!(m&&(T==="deploy"||D.current))&&jt(Ga(T));return}if(m){x.return&&T!=="deploy"&&we(!0);return}if(B.current=[],h==="r")return _(R=>R+1);let q=T==="deploy"&&!$e?zu[h]:void 0;if(q)return jt(q);if(T==="logins"&&h==="t"&&i){Le().then(()=>{i(me.current),f()});return}if(T==="logins"&&h==="l"&&mt)return Ct();if(T==="logins"&&(h==="c"||h==="x")){let R=p.answers.agentCli??"claude";return h==="c"?hs(R):ws(R)}if(T==="checks"&&h==="c"&&ot)return gs();let M=_t.find(R=>R.key===h);if(M){ee(void 0),X(M.key),le(M.secret?"":M.initial?M.initial(p):M.shown(p,O)==="none"?"":M.shown(p,O));return}if(T==="access"&&h==="g")return Ht();if(K&&h==="d"){g(R=>{let je=R.answers.githubApp;return je?be(R,{githubApp:{...je,deviceFlow:!je.deviceFlow}}):R});return}if((x.upArrow||x.downArrow)&&it){let R=it.options(p).map(or=>or.value),je=R.indexOf(it.value(p)??R[0]??""),lt=x.upArrow?-1:1,$n=R[(je+lt+R.length)%R.length];$n!==void 0&&g(or=>it.set(or,$n));return}if(x.return){if(T==="deploy")return $e?gt(!0):I==="no"?oe("asking"):(oe("yes"),ks());if(!go(y))return;Yn(T)}});let J=Math.max(...y.map(h=>h.label.length),8),De=[T==="deploy"?$e?"Enter done":"Enter deploy":"Enter continue",T==="where"?void 0:"Esc back","q quit",it?"\u2191 \u2193 choose":void 0,..._t.length===1?["e edit"]:_t.map(h=>`${h.key} ${h.label.toLowerCase()}`),T==="access"?K?"g new GitHub App":"g create GitHub App":void 0,K?K.deviceFlow?"d undo device flow":"d device flow is ticked":void 0,T==="logins"?"c connect \xB7 x disconnect":void 0,ot?"c connect account":void 0,T==="deploy"?void 0:"r check again",T==="deploy"&&!$e?"1\u20135 change a step":void 0].filter(Boolean),ct=Hu(()=>T==="deploy"?Ui({state:p,sys:t,secrets:O}):[],[T,p,t,O,fe]),nn=["ok","fail","wait"].map(h=>[h,y.filter(x=>x.mark===h).length]).filter(([,h])=>h>0).map(([h,x])=>`${x} ${Yu[h]}`),We=Math.max(..._t.map(h=>h.label.length),0);return Pe(Ve,{flexDirection:"column",children:[Pe(Ve,{borderStyle:"round",borderColor:"cyan",flexDirection:"column",paddingX:1,children:[Z(se,{bold:!0,color:"cyan",children:T==="where"?"moa setup":`${ja(T)} ${ao[T]}`}),T==="where"?null:Z(Xu,{screen:T,passed:p.passed}),T==="where"?Z(se,{children:ao.where}):null,_e&&T===e.screen&&T!=="where"?Z(se,{color:"yellow",children:"resumed where the last setup stopped"}):null,it?Z(Xo,{title:"choose",children:it.options(p).map(h=>{let x=it.value(p)===h.value;return Pe(se,{color:x?"cyan":void 0,children:[x?" \u25CF ":" \u25CB ",Z(se,{bold:x,children:h.label.padEnd(16)}),Z(se,{dimColor:!0,children:h.note})]},h.value)})}):null,_t.length>0?Z(Xo,{title:"settings",children:_t.map(h=>Pe(se,{children:[h.label.padEnd(We)," ",W!==void 0&&h.key===L?Pe(se,{color:"cyan",children:[h.secret?W?`${U} ${W.length} character${W.length===1?"":"s"}`:"":W,"\u258F"]}):Z(se,{dimColor:!h.shown(p,O),children:h.shown(p,O)||"\u2014"})]},h.key))}):null,ge?Z(Ve,{marginTop:1,children:Pe(se,{color:"red",children:["\u2717 ",ge]})}):null,T==="deploy"?Z(Qu,{rows:ct}):null,Z(Xo,{title:"status",aside:T==="deploy"?void 0:nn.join(" \xB7 "),children:y.map(h=>Pe(Ve,{flexDirection:"column",children:[Pe(Ve,{children:[Z(Ve,{flexShrink:0,width:J+4,children:Pe(se,{children:[Z(se,{color:Yi[h.mark].color,children:Yi[h.mark].char})," ",h.label]})}),Z(se,{children:h.detail??""})]}),h.mark==="fail"&&h.fix?Z(Ve,{paddingLeft:J+4,children:Pe(se,{color:"red",children:["\u2192 ",h.fix]})}):null]},h.label))}),I==="asking"?Z(Ve,{marginTop:1,children:Pe(se,{color:"yellow",bold:!0,children:["Enter again to deploy to ",Vu[p.target??"local"],p.answers.domain&&p.target==="cloudflare"?` (${p.answers.domain})`:""," ","\u2014 Esc to cancel"]})}):null,Me&&m?Z(se,{color:"yellow",children:"still checking \u2014 Enter goes on once every line is \u2713"}):null]}),Z(Zu,{hints:W!==void 0?["Enter keep","Esc cancel"]:V.current?["Esc stop the login"]:I==="asking"?["Enter deploy now","Esc cancel"]:De})]})}Ue();Ye();ze();no();Vt();import{randomBytes as tp}from"node:crypto";import{rm as Zi}from"node:fs/promises";import{join as Qo}from"node:path";at();Lt();Jt();In();qe();uo();dn();var np="codex/auth.json",tt=(e,t=2)=>e.replace(/\u001B\[[0-9;]*m/g,"").trim().split(`
214
+ `).filter(n=>n.trim()!=="").slice(-t).join(" \xB7 ").slice(0,300),Jn=e=>e instanceof Error?e.message:String(e);function tn(e){let t=xr(e);return t.length>0?t:e.target?[e.target]:[]}var qn=(e,t)=>({...e,state:st(e.state,t??e.state.target)}),nc=(e,t)=>e.state?{...e,state:st(e.state,t)}:e,wo=e=>e==="vercel"?wn:e==="cloudflare"?Kn:Dn;function Et(e){let t=e.deployed;if(!(!t||!e.target))return e.target==="local"?t.runner==="node"||t.runner==="compose"||t.runner==="image"?t:void 0:t.runner===e.target?t:void 0}var zn=e=>(e({label:"fnMoa",mark:"fail",detail:"moa setup has not deployed it here yet",fix:"run `moa setup`"}),{ok:!1});async function ec(e,t,n){for(let o=0;o<n*1e3;o+=500){if(!e.alive(t))return!0;await e.sleep(500)}return!e.alive(t)}var op=15,rp=5,us=(e,t,n,o={},r=3e4)=>e.fetch(t,{...o,headers:{authorization:`Bearer ${n}`},signal:AbortSignal.timeout(r)});async function Zo(e,t,n){let o=(await xe(e.env)).profiles[wo(t)];return o?.url===n?o.token:void 0}async function oc(e,t,n){let{sys:o}=e,r=Date.now()+t.seconds*1e3,s;for(;s=await o.fetch(`${t.workspaceUrl}/health`,{signal:AbortSignal.timeout(t.seconds>0?13e4:5e3)}).then(l=>l.json()).catch(()=>{}),!(s?.ok===!0||Date.now()>=r);)await o.sleep(2e3);let a=!0,c=await Zo(o,t.target,t.workspaceUrl);if(!s)a=!1,n({label:"workspace",mark:"fail",detail:`no answer at ${t.workspaceUrl}`,fix:t.fix});else if(!c)a=!1,n({label:"workspace",mark:"fail",detail:`${t.workspaceUrl} answers, but this machine has no token for it`,fix:"run `moa setup` to deploy it again"});else{let l=N({url:t.workspaceUrl,token:c},o.fetch),d=await l.get("/v1/whoami").then(()=>{},u=>u instanceof ie?`${u.status}`:Jn(u));if(d)a=!1,n({label:"workspace",mark:"fail",detail:`refuses the owner token (${d})`,fix:"run `moa setup` to deploy it again"});else{n({label:"workspace",mark:"ok",detail:`${t.workspaceUrl}${t.where}`}),s.ok===!0?n({label:"database",mark:"ok",detail:`${s.database??"the store"} \u2014 it answers`}):(a=!1,n({label:"database",mark:"fail",detail:`${s.database??"the store"} does not answer: ${tt(String(s.error??"no answer"),1)}`,fix:t.fix}));let u=await l.get("/v1/jobs").then(f=>f.jobs).catch(()=>{});if(u){let f=u.filter(p=>p.state==="running"||p.state==="queued");n({label:"pipelines",mark:"ok",detail:f.length===0?"nothing running":`${f.length} running or waiting (moa jobs)`})}}}let i=await o.fetch(t.consoleUrl,{redirect:"manual",signal:AbortSignal.timeout(t.seconds>0?13e4:5e3)}).then(l=>l.status<500).catch(()=>!1);return n(i?{label:"console",mark:"ok",detail:t.consoleUrl}:{label:"console",mark:"fail",detail:`no answer at ${t.consoleUrl}`,fix:t.fix}),a&&i}async function sp(e,t){let n=Et(e.state);if(!n)return zn(t);let o=Mn(e.sys,n),r=o.workspacePid,s=o.runner==="compose"?` \u2014 docker compose, project ${he}`:r!==void 0&&Ut(e.sys,r,o.workspaceStarted,xt(o.workspaceUrl))?` (pid ${r})`:"";return{ok:await oc(e,{target:"local",workspaceUrl:o.workspaceUrl,consoleUrl:o.consoleUrl,where:s,fix:"run `moa setup` to start it again",seconds:0},t)}}async function ap(e,t){let n=Et(e.state);if(!n)return zn(t);let{sys:o}=e,r=await Zo(o,"cloudflare",n.workspaceUrl);if(!r)return t({label:"workspace",mark:"fail",detail:`this machine has no token for ${n.workspaceUrl}`,fix:"run `moa setup` to deploy it again"}),{ok:!1};let s=await us(o,`${n.workspaceUrl}/_moa/box`,r).then(async c=>c.ok?await c.json():`${c.status} ${tt(await c.text().catch(()=>""),1)}`.trim()).catch(c=>Jn(c));return typeof s=="string"?(t({label:"Worker",mark:"fail",detail:`${n.workspaceUrl} did not answer: ${s}`,fix:"run `moa setup` to deploy it again"}),{ok:!1}):(t({label:"container",mark:"ok",detail:s.running?`running \u2014 kept up ${Tt}h after the last request`:"was stopped \u2014 this check starts it again, on its data in D1"}),{ok:await oc(e,{target:"cloudflare",workspaceUrl:n.workspaceUrl,consoleUrl:n.consoleUrl,where:" \u2014 in the Cloudflare container",fix:`look at \`pnpm --dir apps/workspace exec wrangler tail ${Je}\`, or run \`moa setup\` to deploy it again`,seconds:600},t)})}var Wn={local:"This machine",vercel:"Vercel Sandbox",cloudflare:"Cloudflare"};function ip(e,t){let n=xr(e);for(let o of n){let r=io(e,o);t({label:o,mark:"skip",detail:`${Wn[o]} \u2014 ${Co(o,r)}${Na(o,r)?"; billed while it stands":""}`})}return n}async function cp(e,t){let n=e.state.target==="vercel"?{ok:await Ji(e,t)}:e.state.target==="cloudflare"?await ap(e,t):await sp(e,t);return Et(e.state)&&lp(e.state,t),n}function lp(e,t){let n=e.answers.loggedIn??[];for(let o of pe)t(n.includes(o)?{label:o,mark:"ok",detail:`connected${e.answers.agentCli===o?" \u2014 the proof runs on it":""}`}:{label:o,mark:"skip",detail:`not connected \u2014 \`moa setup login ${o}\``})}async function rc(e,t,n){let o=ip(e.state,t),r=n==="all"?tn(e.state):n?[n]:o.length===1&&o[0]?[o[0]]:[],s=r.length>0?r:[e.state.target??"local"],a=!0;for(let c of s){s.length>1&&t({label:c,mark:"skip",detail:`\u2500\u2500 ${Wn[c]}`});let i=await cp(qn(e,c),t);a=a&&i.ok}return{ok:a}}async function ds(e,t,n,o=!1){let{sys:r}=e,s=r.root;if(!s)return t({label:"workspace",mark:"fail",detail:"not inside a fnMoa checkout: docker compose needs its compose.yaml",fix:"run it from your fnMoa checkout"}),!1;let a=await r.exec("docker",n==="down"?Dt(s,"down","--volumes","--remove-orphans","--rmi","local"):Dt(s,"stop"),{cwd:s,env:an(r),timeoutMs:3e5});return a.ok?(t({label:"workspace",mark:"ok",detail:o?`compose project ${he} taken down, with any volumes an earlier compose run left \u2014 codex's login among them`:n==="down"?`compose project ${he} removed, with its volumes \u2014 Postgres and codex's login`:`stopped \u2014 Postgres kept in the ${he} volumes`}),!0):(t({label:"workspace",mark:"fail",detail:`docker compose: ${tt(a.stderr||a.stdout)}`,fix:"start Docker, then run this again"}),!1)}async function er(e,t,n,o){let{sys:r}=e;if(t.runner==="image"){let i=await r.exec("docker",et(r,...o==="down"?["down","--volumes"]:["stop"]),{timeoutMs:12e4});return n({label:"image",mark:i.ok?"ok":"fail",detail:o==="down"?"Container and data volumes removed":"Container stopped; data kept"}),{ok:i.ok,deployed:t}}let s=!0;t=Mn(r,t);let a={...t};if(t.runner==="compose"&&!await ds(e,n,o)&&(s=!1),t.runner==="compose"&&o==="down"){let{people:i,...l}=a;a=l}let c=[["workspace",t.workspacePid,t.workspaceStarted,xt(t.workspaceUrl)],["console",t.consolePid,t.consoleStarted,xt(t.consoleUrl)]];for(let[i,l,d,u]of c){if(l===void 0){if(i==="workspace"&&t.runner==="compose")continue;n({label:i,mark:"ok",detail:"not running"});continue}let f=()=>{let{[i==="workspace"?"workspacePid":"consolePid"]:y,[i==="workspace"?"workspaceStarted":"consoleStarted"]:b,...m}=a;a=m};if(r.alive(l)&&!Ut(r,l,d,u)){n({label:i,mark:"ok",detail:`not running \u2014 pid ${l} is another process now, left alone`}),f();continue}let p=r.processOf(l)?.started;if(r.alive(l)&&r.stop(l),await ec(r,l,op)){n({label:i,mark:"ok",detail:`stopped (pid ${l})`}),f();continue}let g=r.processOf(l);if(p===void 0||g?.started!==p){let y=p!==void 0&&(g!==void 0||!r.alive(l));y?f():s=!1,n(y?{label:i,mark:"ok",detail:`stopped (pid ${l})`}:{label:i,mark:"fail",detail:`pid ${l} is still running`,fix:`stop it (\`kill -9 ${l}\`), then run this again`});continue}r.stop(l,!0),await ec(r,l,rp)?(n({label:i,mark:"ok",detail:`stopped (pid ${l}) \u2014 killed, it did not stop when asked to`}),f()):(s=!1,n({label:i,mark:"fail",detail:`pid ${l} is still running, after SIGTERM and SIGKILL`,fix:`stop it (\`kill -9 ${l}\`), then run this again`}))}return{ok:s,deployed:a}}async function dp(e,t){let n=Et(e.state);if(!n)return zn(t);let o=await er(e,n,t,"stop");return o.ok&&t({label:"data",mark:"skip",detail:"kept \u2014 `moa setup` starts it all again"}),{ok:o.ok,state:{...e.state,deployed:o.deployed}}}async function up(e,t){let n=Et(e.state);if(!n)return zn(t);let{sys:o}=e,r=await Zo(o,"cloudflare",n.workspaceUrl);if(!r)return t({label:"container",mark:"fail",detail:`this machine has no token for ${n.workspaceUrl}`,fix:"run `moa setup` to deploy it again"}),{ok:!1};let s=await us(o,`${n.workspaceUrl}/_moa/restart`,r,{method:"POST"}).then(async a=>a.ok?await a.json():`${a.status} ${tt(await a.text().catch(()=>""),1)}`.trim()).catch(a=>Jn(a));return typeof s=="string"?(t({label:"container",mark:"fail",detail:`did not stop: ${s}`,fix:"try again"}),{ok:!1}):(t({label:"container",mark:"ok",detail:`${s.restarted?"stopped":"was not running"} \u2014 D1 and R2 kept; the next request to it, or \`moa setup status\`, starts it again`}),{ok:!0})}async function sc(e,t,n){let o=qn(e,n),r=o.state.target==="vercel"?{ok:await qi(o,t)}:o.state.target==="cloudflare"?await up(o,t):await dp(o,t);return nc(r,e.state.target)}var pp=(e,t)=>e.replace(/\n$/,"").split(`
212
215
  `).slice(-t).join(`
213
- `);async function Zu(e,t){let{sys:n}=e;if(e.state.deployed?.runner==="image"){let c=await n.exec("docker",nt(n,"logs","--no-color","--tail",String(t)),{timeoutMs:3e4});return c.ok?{ok:!0,sections:[{name:"image",from:"docker compose",text:c.stdout}]}:{ok:!1,line:{label:"logs",mark:"fail",detail:"Docker Compose logs failed."}}}let o=At(e.state);if(!o)return{ok:!1,line:{label:"fnMoa",mark:"fail",detail:"not deployed here yet",fix:"run `moa setup`"}};let r=c=>{let i=le(n,`${c}.log`),l=n.read(i);return{name:c,from:i,text:l===void 0?"":Qu(l,t)}};if(o.runner!=="compose")return{ok:!0,sections:[r("workspace"),r("console")]};let s=n.root;if(!s)return{ok:!1,line:{label:"workspace",mark:"fail",detail:"not inside a fnMoa checkout: docker compose needs its compose.yaml",fix:"run it from your fnMoa checkout"}};let a=await n.exec("docker",Rt(s,"logs","--no-color","--tail",String(t),"workspace"),{cwd:s,env:on(n),timeoutMs:6e4});return a.ok?{ok:!0,sections:[{name:"workspace",from:`docker compose -p ${we} logs workspace`,text:a.stdout},r("console")]}:{ok:!1,line:{label:"workspace",mark:"fail",detail:`docker compose: ${ot(a.stderr||a.stdout)}`,fix:"start Docker, then run this again"}}}async function ep(e,t){let n=await Yo(e,!1);if(mn(n))return{ok:!1,line:{label:n.label,mark:"fail",detail:n.detail,fix:n.fix}};let o=[];for(let r of["workspace","console"]){let s=`$HOME/moa/logs/${r}.log`,a=await Ue(n.box,`if [ -f "${s}" ]; then tail -n ${t} "${s}"; fi`);if(!a.ok)return{ok:!1,line:{label:"sandbox",mark:"fail",detail:`its logs could not be read: ${ot(a.stderr||a.stdout)||"no answer"}`,fix:"a stopped sandbox is started by `moa setup status` \u2014 then run this again"}};o.push({name:r,from:`${n.box.name}:~/moa/logs/${r}.log`,text:a.stdout})}return{ok:!0,sections:o}}async function tp(e,t){let{sys:n}=e,o=At(e.state),r=(i,l,d)=>({ok:!1,line:{label:i,mark:"fail",detail:l,fix:d}});if(!o)return r("fnMoa","not deployed here yet","run `moa setup`");let s=await er(n,"cloudflare",o.workspaceUrl);if(!s)return r("container",`this machine has no token for ${o.workspaceUrl}`,"run `moa setup` to deploy it again");let a=await us(n,`${o.workspaceUrl}/_moa/logs?lines=${t}`,s).catch(i=>Fn(i));if(typeof a=="string")return r("container",a,"try again");if(a.status===404)return r("container","this deploy keeps no logs to read","`moa setup update` deploys a fnMoa that does");if(!a.ok)return r("container",`${a.status} ${ot(await a.text())}`.trim(),"try again");let c=await a.json();return c.running?{ok:!0,sections:[{name:"workspace",from:"the container's /home/moa/logs",text:c.workspace??""},{name:"console",from:"the container's /home/moa/logs",text:c.console??""}]}:r("container","not running \u2014 a container's disk, and its logs, go when it stops",`\`moa setup status\` starts it; Cloudflare keeps older output: dashboard \u2192 Workers \u2192 ${We} \u2192 Logs`)}function ec(e,t,n){let o=Kn(e,n);return o.state.target==="vercel"?ep(o,t):o.state.target==="cloudflare"?tp(o,t):Zu(o,t)}var np=e=>[...e==="local"?["workspace.db","workspace.db-wal","workspace.db-shm","worktrees","workspace.log","console.log"]:[],...e==="cloudflare"?["cloudflare"]:[],Zo("rotate",`${mo(e)}.json`)],tc="~/.moa/local \u2014 the GitHub Apps' secrets, logs, and what setup kept there";function nc(e,t){if(t==="all")return[...Vt(e).map(s=>Vi(at(e,s),s,!1)).flat(),tc];let n=t??e.target??"local",o=Vt(e).filter(r=>r!==n);return Vi(at(e,n),n,o.length===0)}function Vi(e,t,n){let o=[n?tc:`its files in ~/.moa/local${t==="local"?" \u2014 the SQLite database, worktrees and logs":t==="cloudflare"?" \u2014 the Worker's config and its secrets":""}; the rest is the other targets'`,`profile ${mo(t)} in ~/.moa/config.json`];if(t==="vercel")return[`sandbox ${e.answers.sandbox?.name??"the sandbox"} and its disk \u2014 the database is on it`,"its snapshot",...o];if(t==="cloudflare"){let r=oc(e);if(!r)return["nothing on Cloudflare unless you say yes \u2014 setup recorded nothing it made there; what it finds by its names is asked about one at a time",...o];let s=e.answers.domain;return[...r.worker?[`Worker ${r.worker}${s?`, with ${en(s).workspace} and ${en(s).console}`:""}`]:[],...r.containerId?[`container ${r.containerId}`]:[],...(r.images??[]).length>0?[`${(r.images??[]).length} container image tag(s) setup pushed`]:[],...(r.unsureImages??[]).length>0?[`${(r.unsureImages??[]).length} container image tag(s) \u2014 asked about: an older moa pushed them, so whether setup did cannot be told`]:[],...r.imagesUnlisted?["any container image tags an older moa pushed \u2014 asked about: the deploy could not list Cloudflare's registry, so it is listed again"]:[],...r.d1?.made?[`D1 database ${r.d1.id} \u2014 the database`]:r.d1?.unsure?[`D1 database ${r.d1.id} \u2014 asked about: an older moa deployed it, so whether setup made it cannot be told`]:[],...r.r2?.made?[`R2 bucket ${r.r2.name} \u2014 codex's login`]:r.r2?.unsure?[`R2 bucket ${r.r2.name} \u2014 asked about: an older moa deployed it, so whether setup made it cannot be told`]:[],...o]}return[(e.deployed?.runner??e.answers.runner)==="compose"?`the compose project ${we} and its volumes \u2014 the database`:"the workspace and console setup started; the database is in ~/.moa/local",...o]}async function op(e,t){let{sys:n,state:o}=e,r=o.answers.sandbox,s=[];if(!r)return t({label:"sandbox",mark:"ok",detail:"setup made none"}),{ok:!0,removed:s};let a=await zo(e);if(mn(a))return t({label:a.label,mark:"fail",detail:a.detail,fix:a.fix}),{ok:!1,removed:s};let c=n.vercel;if(!c)return t({label:"sandbox",mark:"fail",detail:"this build of moa cannot reach Vercel",fix:"update moa"}),{ok:!1,removed:s};try{let i=await c.get(a,r.name,!1);i?(await i.delete(),s.push(`sandbox ${r.name}`),t({label:"sandbox",mark:"ok",detail:`${r.name} deleted, its disk with it`})):t({label:"sandbox",mark:"ok",detail:`${r.name} was already gone`})}catch(i){return t({label:"sandbox",mark:"fail",detail:`${r.name} was not deleted: ${ot(Fn(i))}`,fix:"check `vercel whoami`, then run this again"}),{ok:!1,removed:s}}if(r.snapshotId)try{await c.deleteSnapshot(a,r.snapshotId),s.push(`snapshot ${r.snapshotId}`),t({label:"snapshot",mark:"ok",detail:`${r.snapshotId} deleted`})}catch(i){return t({label:"snapshot",mark:"fail",detail:`${r.snapshotId} was not deleted: ${ot(Fn(i))}`,fix:"run this again"}),{ok:!1,removed:s}}return{ok:!0,removed:s}}var gn=/not found|does not exist|couldn't find|could not find|no such|10007\b/i,oc=e=>e.cloudflare??(e.deployed?.runner==="cloudflare"?e.deployed.cloudflare:void 0);async function rp(e,t,n){let{sys:o,state:r}=e,s=r.answers.cloudflareAccount,a=o.root;if(!s)return{declined:[],why:"setup recorded no Cloudflare account"};if(!a)return{declined:[],why:"not inside a fnMoa checkout: wrangler is run from it"};let c=M=>Ge(o,a,M,{account:s,timeoutMs:6e4}),i=M=>`${M.stdout}
214
- ${M.stderr}`,l=[],d=[],u=(M,z)=>{d.push(`${M}: ${ot(i(z))||"wrangler did not answer"}`)},f=await c(["deployments","list","--name",We,"--json"]);f.ok?l.push({what:`Worker ${We}, and its two names`,more:{worker:We}}):gn.test(i(f))||u("wrangler deployments list",f);let p=await mr(o,a,s);p.ok||d.push(`wrangler containers list: ${p.why}`);let g=p.ok?gr(p.apps):void 0;g&&l.push({what:`container ${g.id} (${je})`,more:{containerId:g.id}});let b=await Xn(o,a,s);b.ok||d.push(`wrangler containers images list: ${b.why}`);let $=[...new Set([...b.ok?b.images:[],...g?.image?[g.image]:[]])];for(let M=0;M<$.length;M+=nn){let z=$.slice(M,M+nn),R=z.map(V=>V.slice(je.length+1)),J=$.length>nn?` \u2014 ${M+1} to ${M+z.length} of ${$.length}`:"";l.push({what:`${z.length} image tag${z.length===1?"":"s"} of ${je} in Cloudflare's registry${J} (${R.join(", ")})`,more:{images:z}})}let m=await c(["d1","list","--json"]),h=tn(m.stdout);(!m.ok||!Array.isArray(h))&&u("wrangler d1 list",m);let A=(Array.isArray(h)?h:[]).filter(M=>M.name===ht),E=A.length===1?A[0]?.uuid:void 0;E&&l.push({what:`D1 database ${ht} (${E}) \u2014 the workspace's data`,more:{d1:{id:E,made:!0}}});let I=await c(["r2","bucket","info",wt,"--json"]);if(I.ok?l.push({what:`R2 bucket ${wt} \u2014 codex's login`,more:{r2:{name:wt,made:!0}}}):gn.test(i(I))||u("wrangler r2 bucket info",I),l.length===0)return{declined:[],why:d.length>0?`wrangler could not look for what setup may have made \u2014 ${d.join("; ")}`:`nothing is found by setup's names on account ${s}`};t({label:"Cloudflare",mark:"skip",detail:`setup recorded nothing it made on account ${s} \u2014 an older moa deployed it. ${l.length} found by setup's names: each is deleted only if you say yes`});let W={account:s},fe=d.map(M=>`not looked for \u2014 ${M}; anything there is left as it was`);d.length>0&&t({label:"Cloudflare",mark:"skip",detail:`wrangler could not look for all of it \u2014 ${d.join("; ")}`});for(let M of l)await n(`Delete ${M.what}? Only if setup made it [y/N] `)?W={...W,...M.more,...M.more.images?{images:[...W.images??[],...M.more.images]}:{}}:fe.push(`${M.what}: you said no \u2014 left as it was`);return{made:W,declined:fe}}async function sp(e,t){let n=[],o=e,r=i=>t(`Delete ${i}? An older moa deployed it, so setup cannot tell \u2014 only if setup made it [y/N] `);if(e.d1?.unsure&&!e.d1.made){let i=`D1 database ${ht} (${e.d1.id}) \u2014 the workspace's data`;await r(i)?o={...o,d1:{id:e.d1.id,made:!0}}:n.push(`${i}: you said no \u2014 left as it was`)}if(e.r2?.unsure&&!e.r2.made){let i=`R2 bucket ${e.r2.name} \u2014 codex's login`;await r(i)?o={...o,r2:{name:e.r2.name,made:!0}}:n.push(`${i}: you said no \u2014 left as it was`)}let s=e.unsureImages??[],a=[],c=[];for(let i=0;i<s.length;i+=nn){let l=s.slice(i,i+nn),d=l.map(p=>p.slice(je.length+1)),u=s.length>nn?` \u2014 ${i+1} to ${i+l.length} of ${s.length}`:"",f=`${l.length} image tag${l.length===1?"":"s"} of ${je} in Cloudflare's registry${u} (${d.join(", ")})`;await r(f)?a=[...a,...l]:(c=[...c,...l],n.push(`${f}: you said no \u2014 left as they were`))}if(a.length>0&&(o={...o,images:[...new Set([...o.images??[],...a])],...c.length>0?{unsureImages:c}:{}},c.length===0)){let{unsureImages:i,...l}=o;o=l}return{made:o,declined:n}}async function ap(e,t,n){let{sys:o,state:r}=e,s=[],a=[],c=oc(r),i;if(!c&&n){let m=await rp(e,t,n);c=m.made,i=m.why,a.push(...m.declined)}if(!c)return t({label:"Cloudflare",mark:"skip",detail:`setup recorded no deploy there${i?`, and ${i}`:""} \u2014 nothing on Cloudflare was deleted; anything left is in the dashboard`}),r.answers.cloudflareAccount&&a.push(`Cloudflare account ${r.answers.cloudflareAccount}: nothing recorded, nothing deleted`),{ok:!0,removed:s,left:a,unsure:!0};let l=o.root;if(!l)return t({label:"Cloudflare",mark:"fail",detail:"not inside a fnMoa checkout: wrangler is run from it",fix:"run it from your fnMoa checkout"}),{ok:!1,removed:s,left:a};let d=c.account,u=m=>Ge(o,l,m,{account:d,timeoutMs:18e4}),f=m=>`${m.stdout}
215
- ${m.stderr}`,p=(m,h,A)=>(t({label:m,mark:"fail",detail:ot(f(h))||"no answer",fix:A}),{ok:!1,removed:s,left:a}),g;if(c.imagesUnlisted){let m=await Xn(o,l,d);if(m.ok){let{imagesUnlisted:h,images:A=[],...E}=c,I=[...new Set([...c.unsureImages??[],...m.images.filter(W=>!A.includes(W))])];c={...E,...A.length>0?{images:A}:{},...I.length>0?{unsureImages:I}:{}}}else g=m.why}if(n){let m=await sp(c,n);c=m.made,a.push(...m.declined)}let b=a.length>0||c.d1?.unsure===!0||c.r2?.unsure===!0||(c.unsureImages??[]).length>0||g!==void 0;if(c.worker){let m=await u(["delete",c.worker,"--force"]);if(!m.ok&&!gn.test(f(m)))return p("Worker",m,"check `wrangler whoami`, then run this again");m.ok&&s.push(`Worker ${c.worker}`),t({label:"Worker",mark:"ok",detail:m.ok?`${c.worker} deleted, and its two names with it`:`${c.worker} was already gone`})}else t({label:"Worker",mark:"ok",detail:"setup recorded none"});if(c.containerId){let m=await u(["containers","delete",c.containerId]);if(!m.ok&&!gn.test(f(m)))return p("container",m,"run this again \u2014 or delete it in the dashboard: Workers \u2192 Containers");m.ok&&s.push(`container ${c.containerId}`),t({label:"container",mark:"ok",detail:m.ok?`${c.containerId} deleted`:`${c.containerId} was already gone`})}else t({label:"container",mark:"ok",detail:"setup recorded none"});let $=0;for(let m of c.images??[]){let h=await u(["containers","images","delete",m,"-y"]);if(!h.ok&&!gn.test(f(h)))return p("images",h,"run this again");h.ok&&($+=1)}if($>0&&s.push(`${$} container image${$===1?"":"s"}`),t({label:"images",mark:"ok",detail:(c.images??[]).length===0?"setup recorded none":$>0?`${$} setup pushed deleted from Cloudflare's registry`:"the ones setup pushed were already gone"}),(c.unsureImages??[]).length>0){let m=`${(c.unsureImages??[]).length} image tag(s) of ${je} \u2014 setup cannot tell whether it pushed them; left as they were`;n||a.push(m),t({label:"images",mark:"skip",detail:m})}if(g!==void 0){let m=`any image tags of ${je} an older moa pushed \u2014 Cloudflare's registry could not be listed; left as they were`;a.push(m),t({label:"images",mark:"skip",detail:`${m}: ${g} \u2014 check the dashboard: Workers \u2192 Containers \u2192 Images`})}if(c.d1?.made){let m=c.d1.id,h=await u(["d1","list","--json"]),A=tn(h.stdout);if(!h.ok||!Array.isArray(A))return p("D1",h,"run this again");let E=A.find(I=>I.uuid===m);if(!E?.name)t({label:"D1",mark:"ok",detail:`${m} was already gone`});else{let I=await u(["d1","delete",E.name,"-y"]);if(!I.ok&&!gn.test(f(I)))return p("D1",I,"run this again");I.ok&&s.push(`D1 ${E.name} (${m})`),t({label:"D1",mark:"ok",detail:I.ok?`${E.name} (${m}) deleted`:`${m} was already gone`})}}else c.d1?.unsure?(n||a.push(`D1 ${c.d1.id} \u2014 setup cannot tell whether it made it; left as it was`),t({label:"D1",mark:"skip",detail:`${c.d1.id} \u2014 setup cannot tell whether it made it; left as it was`})):c.d1&&(a.push(`D1 ${c.d1.id} \u2014 it was there before setup; left as it was`),t({label:"D1",mark:"skip",detail:`${c.d1.id} was there before setup used it \u2014 left as it was`}));if(c.r2&&await u(["r2","object","delete",`${c.r2.name}/${Fu}`,"--remote"]),c.r2?.made){let m=await u(["r2","bucket","delete",c.r2.name]);if(!m.ok&&!gn.test(f(m)))return p("R2",m,`empty ${c.r2.name} in the dashboard (R2 \u2192 ${c.r2.name}), then run this again`);m.ok&&s.push(`R2 ${c.r2.name}`),t({label:"R2",mark:"ok",detail:m.ok?`${c.r2.name} deleted`:`${c.r2.name} was already gone`})}else c.r2?.unsure?(n||a.push(`R2 ${c.r2.name} \u2014 setup cannot tell whether it made it; left as it was`),t({label:"R2",mark:"skip",detail:`${c.r2.name} \u2014 setup cannot tell whether it made it; codex's login taken out, the bucket left`})):c.r2&&(a.push(`R2 ${c.r2.name} \u2014 it was there before setup; left as it was`),t({label:"R2",mark:"skip",detail:`${c.r2.name} was there before setup used it \u2014 codex's login taken out, the bucket left`}));return{ok:!0,removed:s,left:a,unsure:b}}async function rc(e,t,n=new Date,o,r){let s=r??e.state.target;if(!s)return t({label:"fnMoa",mark:"ok",detail:"moa setup has made nothing to take down"}),{ok:!0};let a=e.state.target,c=R=>Yi(R,a),{sys:i,state:l}=Kn(e,s),d=Vt(l).filter(R=>R!==s),u=d.length===0,f=[],p=[],g=!1;if(s==="vercel"||s==="cloudflare"){let R=s==="vercel"?{...await op({...e,state:l},t),left:[],unsure:!1}:await ap({...e,state:l},t,o);if(f.push(...R.removed),p.push(...R.left),g=R.unsure===!0,!R.ok)return{ok:!1}}else{let R=At(l),J=!1,V={ok:!1};if(R){let Ce=await tr({...e,state:l},R,t,"down");if(V=c({ok:!1,state:{...l,deployed:Ce.deployed}}),!Ce.ok)return V;J=R.runner==="compose",f.push(J?`compose project ${we} and its volumes`:"the workspace and console setup started")}else if(l.answers.runner==="compose"){if(!await ds({...e,state:l},t,"down"))return{ok:!1};J=!0,f.push(`compose project ${we} and its volumes`)}if(!J){let Ce=i.root?await i.exec("docker",["info","--format","{{.ServerVersion}}"]):void 0;if(Ce?.ok){if(!await ds({...e,state:l},t,"down",!0))return V;f.push(`compose project ${we}, if an earlier run left one`)}else Ce&&!Ce.missing&&(p.push(`any ${we} volumes an earlier compose run left \u2014 Docker was not running`),t({label:"compose",mark:"skip",detail:`Docker is not running \u2014 any ${we} volumes an earlier compose run left are still there: start it, then \`docker compose -p ${we} down --volumes\``}))}}let b=await ve(i.env),$=mo(s);if(b.profiles[$]){let{[$]:R,...J}=b.profiles,V=b.current===$?Object.keys(J)[0]??"default":b.current;await gt({current:V,profiles:J},i.env),f.push(`profile ${$}`),t({label:"owner token",mark:"ok",detail:`profile ${$} removed from ~/.moa/config.json${b.current===$&&J[V]?`; \`moa\` now uses profile ${V}`:""}`})}if(u)await qi(Zo(pt(i.env),"..","local"),{recursive:!0,force:!0}),f.push("~/.moa/local"),t({label:"this machine",mark:"ok",detail:"~/.moa/local removed"});else{for(let R of np(s))await qi(le(i,R),{recursive:!0,force:!0});f.push("this target's files in ~/.moa/local"),t({label:"this machine",mark:"ok",detail:`${Hn[s]}'s files in ~/.moa/local removed; the rest kept \u2014 ${d.map(R=>Hn[R]).join(" and ")} still ${d.length===1?"uses":"use"} it`})}let m=l.answers.githubApp;m&&(u||await ns(i,m),p.push(`GitHub App ${m.slug} \u2014 ${m.settingsUrl}/advanced`),t({label:"GitHub App",mark:"skip",detail:`${m.slug} is yours to delete: ${m.settingsUrl}/advanced \u2192 Delete GitHub App (it costs nothing)${u?"":"; its client secret is gone from this machine"}`}));let h=d.map(R=>`${Hn[R]} \u2014 \`moa setup down --target ${R}\``).join("; ");t(g?{label:"billing",mark:"skip",detail:`setup cannot tell all it made on Cloudflare is gone \u2014 check the dashboard for anything billed${u?"":`; still deployed: ${h}`}`}:u?{label:"billing",mark:"ok",detail:"nothing setup made is left running or stored"}:{label:"billing",mark:"ok",detail:`nothing ${Hn[s]} had is left running or stored; still deployed: ${h}`});let A={target:s,at:n.toISOString(),removed:f,...p.length>0?{left:p}:{}};if(u)return{ok:!0,state:{...Eo(),down:A}};let{deployed:E,cloudflare:I,...W}=l,{sandbox:fe,githubApp:M,...z}=l.answers;return c({ok:!0,state:{...W,answers:z,...a===s?{screen:"where",passed:W.passed.filter(R=>R!=="deploy")}:{},down:A}})}async function ip(e,t,n){let o=(...u)=>e.exec("git",["-C",t,...u],{timeoutMs:12e4}),r=async()=>(await o("rev-parse","HEAD")).stdout.trim().slice(0,7),s=await r(),a=await o("status","--porcelain","--untracked-files=no"),c=await o("rev-parse","--abbrev-ref","--symbolic-full-name","@{u}");if(!a.ok||a.stdout.trim()!=="")return n({label:"fnMoa",mark:"skip",detail:`${t} has changes of its own \u2014 deploying it as it is, at ${s||"its commit"}`}),!0;if(!c.ok||!c.stdout.trim())return n({label:"fnMoa",mark:"skip",detail:`no upstream branch to pull \u2014 deploying the checkout as it is, at ${s}`}),!0;let i=c.stdout.trim(),l=await o("pull","--ff-only");if(!l.ok)return n({label:"fnMoa",mark:"fail",detail:`git pull: ${ot(l.stderr||l.stdout)}`,fix:`bring ${t} up to date yourself, then run \`moa setup update\` again`}),!1;let d=await r();return n({label:"fnMoa",mark:"ok",detail:s===d?`${d} \u2014 the newest on ${i}`:`${s} \u2192 ${d}, from ${i}`}),!0}async function cp(e,t,n,o){let r=Zo(t,"apps","console",".next");if(e.exists(r)&&!e.exists(Zo(r,"BUILD_ID")))return o({label:"build",mark:"fail",detail:"apps/console/.next holds no build \u2014 `next dev` may be using it",fix:"stop the console's dev server, then run `moa setup update` again"}),!1;let s=[...n?[]:[["--filter","@fnmoa/workspace...","run","build"]],["--filter","@fnmoa/console","run","build"]];o({label:"build",mark:"wait",detail:"building the new fnMoa \u2014 a few minutes"});for(let a of[["install"],...s]){let c=await e.exec("pnpm",a,{cwd:t,timeoutMs:9e5});if(!c.ok)return o({label:"build",mark:"fail",detail:`pnpm ${a.join(" ")}: ${ot(c.stderr||c.stdout)}`,fix:`run \`pnpm ${a.join(" ")}\` in ${t}, then \`moa setup update\` again`}),!1}return o({label:"build",mark:"ok",detail:n?"console built":"workspace and console built"}),!0}async function nr(e,t,n){e=Kn(e,n);let{sys:o,state:r}=e,s=At(r);if(!s)return Bn(t);if(s.runner==="image"||!o.root){let i=await yt(e);return i.forEach(t),i.some(l=>l.mark==="fail")?{ok:!1}:{ok:!0,state:{...r,screen:"deploy"}}}let a=o.root;if(!a)return t({label:"checkout",mark:"fail",detail:"not inside a fnMoa checkout: the new fnMoa is built from one",fix:"run it from your fnMoa checkout"}),{ok:!1};if(!await ip(o,a,t))return{ok:!1};let c=s;if(r.target==="local"){let i=await tr(e,s,t,"stop");if(c=i.deployed,!i.ok)return{ok:!1,state:{...r,deployed:c}};if(!await cp(o,a,s.runner==="compose",t))return{ok:!1,state:{...r,deployed:c}};t({label:"data",mark:"skip",detail:s.runner==="compose"?`kept in the ${we} volumes \u2014 Deploy builds the image and starts it all again`:"kept in ~/.moa/local \u2014 Deploy starts it all again"})}else t({label:"data",mark:"skip",detail:r.target==="vercel"?"kept on the sandbox's disk \u2014 Deploy builds its image at this commit and restarts it":"kept in D1 and R2 \u2014 Deploy builds the Worker and the container image at this commit"});return{ok:!0,state:{...r,screen:"deploy",deployed:c}}}async function sc(e,t,n,o){e=Kn(e,o);let{sys:r,state:s}=e,a=At(s),c=s.target;if(!a||!c)return Bn(t);let i={},l=s.answers.githubApp,d=l?He(r,l):void 0,u=l&&d?(await n(`GitHub App ${l.slug}: on ${l.settingsUrl} press "Generate a new client secret" and paste it (Enter keeps the current one): `)).trim():"",f;if(c!=="local"&&(f=(await n(`New GitHub token for the ${c==="vercel"?"sandbox":"container"} \u2014 fine-grained: contents, pull requests, issues read/write; checks, actions read (Enter keeps the current one): `)).trim(),f)){let m=await r.fetch("https://api.github.com/user",{headers:{Authorization:`Bearer ${f}`,Accept:"application/vnd.github+json"},signal:AbortSignal.timeout(15e3)}).then(async h=>h.ok?(await h.json()).login:void 0).catch(()=>{});if(!m)return t({label:"GitHub token",mark:"fail",detail:"GitHub refuses it",fix:"make another, then run `moa setup rotate` again \u2014 nothing was changed"}),{ok:!1};i.github=f,t({label:"GitHub token",mark:"ok",detail:`${D} \u2014 ${m}'s, new`})}let p=a.memoryKept===!0||xe(e)!==void 0,g=c==="vercel"||xe(e)!==void 0;if(p){let m=(await n(g?"New LocusGraph agent secret (Enter keeps the current one): ":"LocusGraph agent secret \u2014 this machine has no copy, and Deploy needs one: paste the current one or a new one: ")).trim();if(!m&&!g)return t({label:"LocusGraph",mark:"fail",detail:"the workspace keeps its memory there, and this machine has no copy of the secret \u2014 Deploy would turn memory off",fix:"run `moa setup rotate` again and paste the secret, the current one or a new one \u2014 nothing was changed"}),{ok:!1};if(m){let h=xe({...e,secrets:{locusgraph:m}});if(!h)return t({label:"LocusGraph",mark:"fail",detail:"setup has no graph ID for this secret",fix:"run `moa setup`, type the graph ID on Memory (g), then `moa setup rotate` again \u2014 nothing was changed"}),{ok:!1};let A=s.answers.tenant??Ie(s.answers.owner),E=await Cn(r,h,A);if(!E.read.ok||!E.write.ok)return t({label:"LocusGraph",mark:"fail",detail:`the new secret does not work: ${E.read.why??E.write.why??"no answer"}`,fix:"check it, then run `moa setup rotate` again \u2014 nothing was changed"}),{ok:!1};i.locusgraph=m,t({label:"LocusGraph",mark:"ok",detail:`${D} \u2014 new; it reads and writes ${h.graph}`})}}let b=mo(c);await Xa(r,b,a.workspaceUrl,Or()),t({label:"owner token",mark:"ok",detail:`${D} \u2014 new; Deploy gives it to the workspace, and profile ${b} takes it once the workspace answers to it`}),l&&d?(await ts(r,l,{clientSecret:u||d.clientSecret,authSecret:Hu(32).toString("base64url")}),t({label:"GitHub App",mark:"ok",detail:u?`new client secret and AUTH_SECRET \u2014 once Deploy is done, delete the old secret on ${l.settingsUrl}`:"new AUTH_SECRET; client secret kept \u2014 everyone signs in again"})):t({label:"GitHub App",mark:"skip",detail:l?"its secret is not on this machine \u2014 Console access, g, makes a new app":"none \u2014 the console stays on this machine"}),c==="local"?t({label:"GitHub token",mark:"skip",detail:"this machine's own gh login \u2014 `gh auth refresh` renews it"}):f||t({label:"GitHub token",mark:"skip",detail:"kept"}),p?i.locusgraph||t({label:"LocusGraph",mark:"skip",detail:"kept"}):t({label:"LocusGraph",mark:"skip",detail:"not used \u2014 memory stays in the workspace"});let $=a;if(c==="local"){let m=await tr(e,a,t,"stop");if($=m.deployed,!m.ok)return{ok:!1,state:{...s,screen:"deploy",deployed:$}}}return{ok:!0,secrets:i,state:{...s,screen:"deploy",answers:{...s.answers,...i.github?{githubToken:"pasted"}:{}},deployed:$}}}It();Je();io();qe();Wt();function lp(e){let{state:t,sys:n}=e;if(!t.target||!t.deployed||!t.passed.includes("deploy"))return"finish the initial deployment with `moa setup`";if(!t.answers.owner)return"the GitHub owner (run `moa setup`)";if(un(e))return"the LocusGraph secret (set LOCUSGRAPH_AGENT_SECRET)";if(t.answers.githubApp&&!He(n,t.answers.githubApp))return"the GitHub App client secret (run `moa setup`)";if(t.target==="cloudflare"&&!t.answers.domain)return"the Cloudflare domain (run `moa setup`)"}async function ac(e,t,n){let o=lp(e);if(o)return t({label:"update",mark:"fail",detail:`Update needs ${o}`}),!1;let r=await nr(e,t);if(r.state&&await n(r.state),!r.ok||!r.state)return!1;let s=r.state,a=Promise.resolve(),c=u=>{s=u,a=a.then(()=>n(u))},i=new Map,l=u=>{for(let f of u){let p=JSON.stringify(f);i.get(f.label)!==p&&t(f),i.set(f.label,p)}},d=s.target==="vercel"?Vo:s.target==="cloudflare"?Ko:Mo;try{let u=await d({...e,state:s},l,f=>c({...s,deployed:f}),f=>c({...s,cloudflare:f}));return u.deployed&&c({...s,deployed:u.deployed,...u.ok?{answers:{...s.answers,removed:void 0}}:{}}),u.ok}finally{await a}}var mp=["status","login","logout","licence","rotate","update","logs","stop","down"],gp={ok:"\u2713",fail:"\u2717",wait:"\u2026",skip:"\u2013"},Mt=e=>{process.stdout.write(`${gp[e.mark]} ${e.label.padEnd(12)} ${e.detail??""}
216
+ `);async function fp(e,t){let{sys:n}=e;if(e.state.deployed?.runner==="image"){let c=await n.exec("docker",et(n,"logs","--no-color","--tail",String(t)),{timeoutMs:3e4});return c.ok?{ok:!0,sections:[{name:"image",from:"docker compose",text:c.stdout}]}:{ok:!1,line:{label:"logs",mark:"fail",detail:"Docker Compose logs failed."}}}let o=Et(e.state);if(!o)return{ok:!1,line:{label:"fnMoa",mark:"fail",detail:"not deployed here yet",fix:"run `moa setup`"}};let r=c=>{let i=ce(n,`${c}.log`),l=n.read(i);return{name:c,from:i,text:l===void 0?"":pp(l,t)}};if(o.runner!=="compose")return{ok:!0,sections:[r("workspace"),r("console")]};let s=n.root;if(!s)return{ok:!1,line:{label:"workspace",mark:"fail",detail:"not inside a fnMoa checkout: docker compose needs its compose.yaml",fix:"run it from your fnMoa checkout"}};let a=await n.exec("docker",Dt(s,"logs","--no-color","--tail",String(t),"workspace"),{cwd:s,env:an(n),timeoutMs:6e4});return a.ok?{ok:!0,sections:[{name:"workspace",from:`docker compose -p ${he} logs workspace`,text:a.stdout},r("console")]}:{ok:!1,line:{label:"workspace",mark:"fail",detail:`docker compose: ${tt(a.stderr||a.stdout)}`,fix:"start Docker, then run this again"}}}async function mp(e,t){let n=await Vo(e,!1);if(kn(n))return{ok:!1,line:{label:n.label,mark:"fail",detail:n.detail,fix:n.fix}};let o=[];for(let r of["workspace","console"]){let s=`$HOME/moa/logs/${r}.log`,a=await Ne(n.box,`if [ -f "${s}" ]; then tail -n ${t} "${s}"; fi`);if(!a.ok)return{ok:!1,line:{label:"sandbox",mark:"fail",detail:`its logs could not be read: ${tt(a.stderr||a.stdout)||"no answer"}`,fix:"a stopped sandbox is started by `moa setup status` \u2014 then run this again"}};o.push({name:r,from:`${n.box.name}:~/moa/logs/${r}.log`,text:a.stdout})}return{ok:!0,sections:o}}async function gp(e,t){let{sys:n}=e,o=Et(e.state),r=(i,l,d)=>({ok:!1,line:{label:i,mark:"fail",detail:l,fix:d}});if(!o)return r("fnMoa","not deployed here yet","run `moa setup`");let s=await Zo(n,"cloudflare",o.workspaceUrl);if(!s)return r("container",`this machine has no token for ${o.workspaceUrl}`,"run `moa setup` to deploy it again");let a=await us(n,`${o.workspaceUrl}/_moa/logs?lines=${t}`,s).catch(i=>Jn(i));if(typeof a=="string")return r("container",a,"try again");if(a.status===404)return r("container","this deploy keeps no logs to read","`moa setup update` deploys a fnMoa that does");if(!a.ok)return r("container",`${a.status} ${tt(await a.text())}`.trim(),"try again");let c=await a.json();return c.running?{ok:!0,sections:[{name:"workspace",from:"the container's /home/moa/logs",text:c.workspace??""},{name:"console",from:"the container's /home/moa/logs",text:c.console??""}]}:r("container","not running \u2014 a container's disk, and its logs, go when it stops",`\`moa setup status\` starts it; Cloudflare keeps older output: dashboard \u2192 Workers \u2192 ${Je} \u2192 Logs`)}function ac(e,t,n){let o=qn(e,n);return o.state.target==="vercel"?mp(o,t):o.state.target==="cloudflare"?gp(o,t):fp(o,t)}var hp=e=>[...e==="local"?["workspace.db","workspace.db-wal","workspace.db-shm","worktrees","workspace.log","console.log"]:[],...e==="cloudflare"?["cloudflare"]:[],Qo("rotate",`${wo(e)}.json`)],ic="~/.moa/local \u2014 the GitHub Apps' secrets, logs, and what setup kept there";function cc(e,t){if(t==="all")return[...tn(e).map(s=>tc(st(e,s),s,!1)).flat(),ic];let n=t??e.target??"local",o=tn(e).filter(r=>r!==n);return tc(st(e,n),n,o.length===0)}function tc(e,t,n){let o=[n?ic:`its files in ~/.moa/local${t==="local"?" \u2014 the SQLite database, worktrees and logs":t==="cloudflare"?" \u2014 the Worker's config and its secrets":""}; the rest is the other targets'`,`profile ${wo(t)} in ~/.moa/config.json`];if(t==="vercel")return[`sandbox ${e.answers.sandbox?.name??"the sandbox"} and its disk \u2014 the database is on it`,"its snapshot",...o];if(t==="cloudflare"){let r=lc(e);if(!r)return["nothing on Cloudflare unless you say yes \u2014 setup recorded nothing it made there; what it finds by its names is asked about one at a time",...o];let s=e.answers.domain;return[...r.worker?[`Worker ${r.worker}${s?`, with ${on(s).workspace} and ${on(s).console}`:""}`]:[],...r.containerId?[`container ${r.containerId}`]:[],...(r.images??[]).length>0?[`${(r.images??[]).length} container image tag(s) setup pushed`]:[],...(r.unsureImages??[]).length>0?[`${(r.unsureImages??[]).length} container image tag(s) \u2014 asked about: an older moa pushed them, so whether setup did cannot be told`]:[],...r.imagesUnlisted?["any container image tags an older moa pushed \u2014 asked about: the deploy could not list Cloudflare's registry, so it is listed again"]:[],...r.d1?.made?[`D1 database ${r.d1.id} \u2014 the database`]:r.d1?.unsure?[`D1 database ${r.d1.id} \u2014 asked about: an older moa deployed it, so whether setup made it cannot be told`]:[],...r.r2?.made?[`R2 bucket ${r.r2.name} \u2014 codex's login`]:r.r2?.unsure?[`R2 bucket ${r.r2.name} \u2014 asked about: an older moa deployed it, so whether setup made it cannot be told`]:[],...o]}return[(e.deployed?.runner??e.answers.runner)==="compose"?`the compose project ${he} and its volumes \u2014 the database`:"the workspace and console setup started; the database is in ~/.moa/local",...o]}async function wp(e,t){let{sys:n,state:o}=e,r=o.answers.sandbox,s=[];if(!r)return t({label:"sandbox",mark:"ok",detail:"setup made none"}),{ok:!0,removed:s};let a=await qo(e);if(kn(a))return t({label:a.label,mark:"fail",detail:a.detail,fix:a.fix}),{ok:!1,removed:s};let c=n.vercel;if(!c)return t({label:"sandbox",mark:"fail",detail:"this build of moa cannot reach Vercel",fix:"update moa"}),{ok:!1,removed:s};try{let i=await c.get(a,r.name,!1);i?(await i.delete(),s.push(`sandbox ${r.name}`),t({label:"sandbox",mark:"ok",detail:`${r.name} deleted, its disk with it`})):t({label:"sandbox",mark:"ok",detail:`${r.name} was already gone`})}catch(i){return t({label:"sandbox",mark:"fail",detail:`${r.name} was not deleted: ${tt(Jn(i))}`,fix:"check `vercel whoami`, then run this again"}),{ok:!1,removed:s}}if(r.snapshotId)try{await c.deleteSnapshot(a,r.snapshotId),s.push(`snapshot ${r.snapshotId}`),t({label:"snapshot",mark:"ok",detail:`${r.snapshotId} deleted`})}catch(i){return t({label:"snapshot",mark:"fail",detail:`${r.snapshotId} was not deleted: ${tt(Jn(i))}`,fix:"run this again"}),{ok:!1,removed:s}}return{ok:!0,removed:s}}var yn=/not found|does not exist|couldn't find|could not find|no such|10007\b/i,lc=e=>e.cloudflare??(e.deployed?.runner==="cloudflare"?e.deployed.cloudflare:void 0);async function kp(e,t,n){let{sys:o,state:r}=e,s=r.answers.cloudflareAccount,a=o.root;if(!s)return{declined:[],why:"setup recorded no Cloudflare account"};if(!a)return{declined:[],why:"not inside a fnMoa checkout: wrangler is run from it"};let c=L=>Fe(o,a,L,{account:s,timeoutMs:6e4}),i=L=>`${L.stdout}
217
+ ${L.stderr}`,l=[],d=[],u=(L,X)=>{d.push(`${L}: ${tt(i(X))||"wrangler did not answer"}`)},f=await c(["deployments","list","--name",Je,"--json"]);f.ok?l.push({what:`Worker ${Je}, and its two names`,more:{worker:Je}}):yn.test(i(f))||u("wrangler deployments list",f);let p=await fr(o,a,s);p.ok||d.push(`wrangler containers list: ${p.why}`);let g=p.ok?mr(p.apps):void 0;g&&l.push({what:`container ${g.id} (${He})`,more:{containerId:g.id}});let y=await eo(o,a,s);y.ok||d.push(`wrangler containers images list: ${y.why}`);let b=[...new Set([...y.ok?y.images:[],...g?.image?[g.image]:[]])];for(let L=0;L<b.length;L+=sn){let X=b.slice(L,L+sn),D=X.map(ne=>ne.slice(He.length+1)),B=b.length>sn?` \u2014 ${L+1} to ${L+X.length} of ${b.length}`:"";l.push({what:`${X.length} image tag${X.length===1?"":"s"} of ${He} in Cloudflare's registry${B} (${D.join(", ")})`,more:{images:X}})}let m=await c(["d1","list","--json"]),w=rn(m.stdout);(!m.ok||!Array.isArray(w))&&u("wrangler d1 list",m);let v=(Array.isArray(w)?w:[]).filter(L=>L.name===wt),_=v.length===1?v[0]?.uuid:void 0;_&&l.push({what:`D1 database ${wt} (${_}) \u2014 the workspace's data`,more:{d1:{id:_,made:!0}}});let H=await c(["r2","bucket","info",kt,"--json"]);if(H.ok?l.push({what:`R2 bucket ${kt} \u2014 codex's login`,more:{r2:{name:kt,made:!0}}}):yn.test(i(H))||u("wrangler r2 bucket info",H),l.length===0)return{declined:[],why:d.length>0?`wrangler could not look for what setup may have made \u2014 ${d.join("; ")}`:`nothing is found by setup's names on account ${s}`};t({label:"Cloudflare",mark:"skip",detail:`setup recorded nothing it made on account ${s} \u2014 an older moa deployed it. ${l.length} found by setup's names: each is deleted only if you say yes`});let W={account:s},le=d.map(L=>`not looked for \u2014 ${L}; anything there is left as it was`);d.length>0&&t({label:"Cloudflare",mark:"skip",detail:`wrangler could not look for all of it \u2014 ${d.join("; ")}`});for(let L of l)await n(`Delete ${L.what}? Only if setup made it [y/N] `)?W={...W,...L.more,...L.more.images?{images:[...W.images??[],...L.more.images]}:{}}:le.push(`${L.what}: you said no \u2014 left as it was`);return{made:W,declined:le}}async function yp(e,t){let n=[],o=e,r=i=>t(`Delete ${i}? An older moa deployed it, so setup cannot tell \u2014 only if setup made it [y/N] `);if(e.d1?.unsure&&!e.d1.made){let i=`D1 database ${wt} (${e.d1.id}) \u2014 the workspace's data`;await r(i)?o={...o,d1:{id:e.d1.id,made:!0}}:n.push(`${i}: you said no \u2014 left as it was`)}if(e.r2?.unsure&&!e.r2.made){let i=`R2 bucket ${e.r2.name} \u2014 codex's login`;await r(i)?o={...o,r2:{name:e.r2.name,made:!0}}:n.push(`${i}: you said no \u2014 left as it was`)}let s=e.unsureImages??[],a=[],c=[];for(let i=0;i<s.length;i+=sn){let l=s.slice(i,i+sn),d=l.map(p=>p.slice(He.length+1)),u=s.length>sn?` \u2014 ${i+1} to ${i+l.length} of ${s.length}`:"",f=`${l.length} image tag${l.length===1?"":"s"} of ${He} in Cloudflare's registry${u} (${d.join(", ")})`;await r(f)?a=[...a,...l]:(c=[...c,...l],n.push(`${f}: you said no \u2014 left as they were`))}if(a.length>0&&(o={...o,images:[...new Set([...o.images??[],...a])],...c.length>0?{unsureImages:c}:{}},c.length===0)){let{unsureImages:i,...l}=o;o=l}return{made:o,declined:n}}async function bp(e,t,n){let{sys:o,state:r}=e,s=[],a=[],c=lc(r),i;if(!c&&n){let m=await kp(e,t,n);c=m.made,i=m.why,a.push(...m.declined)}if(!c)return t({label:"Cloudflare",mark:"skip",detail:`setup recorded no deploy there${i?`, and ${i}`:""} \u2014 nothing on Cloudflare was deleted; anything left is in the dashboard`}),r.answers.cloudflareAccount&&a.push(`Cloudflare account ${r.answers.cloudflareAccount}: nothing recorded, nothing deleted`),{ok:!0,removed:s,left:a,unsure:!0};let l=o.root;if(!l)return t({label:"Cloudflare",mark:"fail",detail:"not inside a fnMoa checkout: wrangler is run from it",fix:"run it from your fnMoa checkout"}),{ok:!1,removed:s,left:a};let d=c.account,u=m=>Fe(o,l,m,{account:d,timeoutMs:18e4}),f=m=>`${m.stdout}
218
+ ${m.stderr}`,p=(m,w,v)=>(t({label:m,mark:"fail",detail:tt(f(w))||"no answer",fix:v}),{ok:!1,removed:s,left:a}),g;if(c.imagesUnlisted){let m=await eo(o,l,d);if(m.ok){let{imagesUnlisted:w,images:v=[],..._}=c,H=[...new Set([...c.unsureImages??[],...m.images.filter(W=>!v.includes(W))])];c={..._,...v.length>0?{images:v}:{},...H.length>0?{unsureImages:H}:{}}}else g=m.why}if(n){let m=await yp(c,n);c=m.made,a.push(...m.declined)}let y=a.length>0||c.d1?.unsure===!0||c.r2?.unsure===!0||(c.unsureImages??[]).length>0||g!==void 0;if(c.worker){let m=await u(["delete",c.worker,"--force"]);if(!m.ok&&!yn.test(f(m)))return p("Worker",m,"check `wrangler whoami`, then run this again");m.ok&&s.push(`Worker ${c.worker}`),t({label:"Worker",mark:"ok",detail:m.ok?`${c.worker} deleted, and its two names with it`:`${c.worker} was already gone`})}else t({label:"Worker",mark:"ok",detail:"setup recorded none"});if(c.containerId){let m=await u(["containers","delete",c.containerId]);if(!m.ok&&!yn.test(f(m)))return p("container",m,"run this again \u2014 or delete it in the dashboard: Workers \u2192 Containers");m.ok&&s.push(`container ${c.containerId}`),t({label:"container",mark:"ok",detail:m.ok?`${c.containerId} deleted`:`${c.containerId} was already gone`})}else t({label:"container",mark:"ok",detail:"setup recorded none"});let b=0;for(let m of c.images??[]){let w=await u(["containers","images","delete",m,"-y"]);if(!w.ok&&!yn.test(f(w)))return p("images",w,"run this again");w.ok&&(b+=1)}if(b>0&&s.push(`${b} container image${b===1?"":"s"}`),t({label:"images",mark:"ok",detail:(c.images??[]).length===0?"setup recorded none":b>0?`${b} setup pushed deleted from Cloudflare's registry`:"the ones setup pushed were already gone"}),(c.unsureImages??[]).length>0){let m=`${(c.unsureImages??[]).length} image tag(s) of ${He} \u2014 setup cannot tell whether it pushed them; left as they were`;n||a.push(m),t({label:"images",mark:"skip",detail:m})}if(g!==void 0){let m=`any image tags of ${He} an older moa pushed \u2014 Cloudflare's registry could not be listed; left as they were`;a.push(m),t({label:"images",mark:"skip",detail:`${m}: ${g} \u2014 check the dashboard: Workers \u2192 Containers \u2192 Images`})}if(c.d1?.made){let m=c.d1.id,w=await u(["d1","list","--json"]),v=rn(w.stdout);if(!w.ok||!Array.isArray(v))return p("D1",w,"run this again");let _=v.find(H=>H.uuid===m);if(!_?.name)t({label:"D1",mark:"ok",detail:`${m} was already gone`});else{let H=await u(["d1","delete",_.name,"-y"]);if(!H.ok&&!yn.test(f(H)))return p("D1",H,"run this again");H.ok&&s.push(`D1 ${_.name} (${m})`),t({label:"D1",mark:"ok",detail:H.ok?`${_.name} (${m}) deleted`:`${m} was already gone`})}}else c.d1?.unsure?(n||a.push(`D1 ${c.d1.id} \u2014 setup cannot tell whether it made it; left as it was`),t({label:"D1",mark:"skip",detail:`${c.d1.id} \u2014 setup cannot tell whether it made it; left as it was`})):c.d1&&(a.push(`D1 ${c.d1.id} \u2014 it was there before setup; left as it was`),t({label:"D1",mark:"skip",detail:`${c.d1.id} was there before setup used it \u2014 left as it was`}));if(c.r2&&await u(["r2","object","delete",`${c.r2.name}/${np}`,"--remote"]),c.r2?.made){let m=await u(["r2","bucket","delete",c.r2.name]);if(!m.ok&&!yn.test(f(m)))return p("R2",m,`empty ${c.r2.name} in the dashboard (R2 \u2192 ${c.r2.name}), then run this again`);m.ok&&s.push(`R2 ${c.r2.name}`),t({label:"R2",mark:"ok",detail:m.ok?`${c.r2.name} deleted`:`${c.r2.name} was already gone`})}else c.r2?.unsure?(n||a.push(`R2 ${c.r2.name} \u2014 setup cannot tell whether it made it; left as it was`),t({label:"R2",mark:"skip",detail:`${c.r2.name} \u2014 setup cannot tell whether it made it; codex's login taken out, the bucket left`})):c.r2&&(a.push(`R2 ${c.r2.name} \u2014 it was there before setup; left as it was`),t({label:"R2",mark:"skip",detail:`${c.r2.name} was there before setup used it \u2014 codex's login taken out, the bucket left`}));return{ok:!0,removed:s,left:a,unsure:y}}async function dc(e,t,n=new Date,o,r){let s=r??e.state.target;if(!s)return t({label:"fnMoa",mark:"ok",detail:"moa setup has made nothing to take down"}),{ok:!0};let a=e.state.target,c=D=>nc(D,a),{sys:i,state:l}=qn(e,s),d=tn(l).filter(D=>D!==s),u=d.length===0,f=[],p=[],g=!1;if(s==="vercel"||s==="cloudflare"){let D=s==="vercel"?{...await wp({...e,state:l},t),left:[],unsure:!1}:await bp({...e,state:l},t,o);if(f.push(...D.removed),p.push(...D.left),g=D.unsure===!0,!D.ok)return{ok:!1}}else{let D=Et(l),B=!1,ne={ok:!1};if(D){let ge=await er({...e,state:l},D,t,"down");if(ne=c({ok:!1,state:{...l,deployed:ge.deployed}}),!ge.ok)return ne;B=D.runner==="compose",f.push(B?`compose project ${he} and its volumes`:"the workspace and console setup started")}else if(l.answers.runner==="compose"){if(!await ds({...e,state:l},t,"down"))return{ok:!1};B=!0,f.push(`compose project ${he} and its volumes`)}if(!B){let ge=i.root?await i.exec("docker",["info","--format","{{.ServerVersion}}"]):void 0;if(ge?.ok){if(!await ds({...e,state:l},t,"down",!0))return ne;f.push(`compose project ${he}, if an earlier run left one`)}else ge&&!ge.missing&&(p.push(`any ${he} volumes an earlier compose run left \u2014 Docker was not running`),t({label:"compose",mark:"skip",detail:`Docker is not running \u2014 any ${he} volumes an earlier compose run left are still there: start it, then \`docker compose -p ${he} down --volumes\``}))}}let y=await xe(i.env),b=wo(s);if(y.profiles[b]){let{[b]:D,...B}=y.profiles,ne=y.current===b?Object.keys(B)[0]??"default":y.current;await ht({current:ne,profiles:B},i.env),f.push(`profile ${b}`),t({label:"owner token",mark:"ok",detail:`profile ${b} removed from ~/.moa/config.json${y.current===b&&B[ne]?`; \`moa\` now uses profile ${ne}`:""}`})}if(u)await Zi(Qo(ut(i.env),"..","local"),{recursive:!0,force:!0}),f.push("~/.moa/local"),t({label:"this machine",mark:"ok",detail:"~/.moa/local removed"});else{for(let D of hp(s))await Zi(ce(i,D),{recursive:!0,force:!0});f.push("this target's files in ~/.moa/local"),t({label:"this machine",mark:"ok",detail:`${Wn[s]}'s files in ~/.moa/local removed; the rest kept \u2014 ${d.map(D=>Wn[D]).join(" and ")} still ${d.length===1?"uses":"use"} it`})}let m=l.answers.githubApp;m&&(u||await ns(i,m),p.push(`GitHub App ${m.slug} \u2014 ${m.settingsUrl}/advanced`),t({label:"GitHub App",mark:"skip",detail:`${m.slug} is yours to delete: ${m.settingsUrl}/advanced \u2192 Delete GitHub App (it costs nothing)${u?"":"; its client secret is gone from this machine"}`}));let w=d.map(D=>`${Wn[D]} \u2014 \`moa setup down --target ${D}\``).join("; ");t(g?{label:"billing",mark:"skip",detail:`setup cannot tell all it made on Cloudflare is gone \u2014 check the dashboard for anything billed${u?"":`; still deployed: ${w}`}`}:u?{label:"billing",mark:"ok",detail:"nothing setup made is left running or stored"}:{label:"billing",mark:"ok",detail:`nothing ${Wn[s]} had is left running or stored; still deployed: ${w}`});let v={target:s,at:n.toISOString(),removed:f,...p.length>0?{left:p}:{}};if(u)return{ok:!0,state:{...Ao(),down:v}};let{deployed:_,cloudflare:H,...W}=l,{sandbox:le,githubApp:L,...X}=l.answers;return c({ok:!0,state:{...W,answers:X,...a===s?{screen:"where",passed:W.passed.filter(D=>D!=="deploy")}:{},down:v}})}async function $p(e,t,n){let o=(...u)=>e.exec("git",["-C",t,...u],{timeoutMs:12e4}),r=async()=>(await o("rev-parse","HEAD")).stdout.trim().slice(0,7),s=await r(),a=await o("status","--porcelain","--untracked-files=no"),c=await o("rev-parse","--abbrev-ref","--symbolic-full-name","@{u}");if(!a.ok||a.stdout.trim()!=="")return n({label:"fnMoa",mark:"skip",detail:`${t} has changes of its own \u2014 deploying it as it is, at ${s||"its commit"}`}),!0;if(!c.ok||!c.stdout.trim())return n({label:"fnMoa",mark:"skip",detail:`no upstream branch to pull \u2014 deploying the checkout as it is, at ${s}`}),!0;let i=c.stdout.trim(),l=await o("pull","--ff-only");if(!l.ok)return n({label:"fnMoa",mark:"fail",detail:`git pull: ${tt(l.stderr||l.stdout)}`,fix:`bring ${t} up to date yourself, then run \`moa setup update\` again`}),!1;let d=await r();return n({label:"fnMoa",mark:"ok",detail:s===d?`${d} \u2014 the newest on ${i}`:`${s} \u2192 ${d}, from ${i}`}),!0}async function vp(e,t,n,o){let r=Qo(t,"apps","console",".next");if(e.exists(r)&&!e.exists(Qo(r,"BUILD_ID")))return o({label:"build",mark:"fail",detail:"apps/console/.next holds no build \u2014 `next dev` may be using it",fix:"stop the console's dev server, then run `moa setup update` again"}),!1;let s=[...n?[]:[["--filter","@fnmoa/workspace...","run","build"]],["--filter","@fnmoa/console","run","build"]];o({label:"build",mark:"wait",detail:"building the new fnMoa \u2014 a few minutes"});for(let a of[["install"],...s]){let c=await e.exec("pnpm",a,{cwd:t,timeoutMs:9e5});if(!c.ok)return o({label:"build",mark:"fail",detail:`pnpm ${a.join(" ")}: ${tt(c.stderr||c.stdout)}`,fix:`run \`pnpm ${a.join(" ")}\` in ${t}, then \`moa setup update\` again`}),!1}return o({label:"build",mark:"ok",detail:n?"console built":"workspace and console built"}),!0}async function tr(e,t,n){e=qn(e,n);let{sys:o,state:r}=e,s=Et(r);if(!s)return zn(t);if(s.runner==="image"||!o.root){let i=await bt(e);return i.forEach(t),i.some(l=>l.mark==="fail")?{ok:!1}:{ok:!0,state:{...r,screen:"deploy"}}}let a=o.root;if(!a)return t({label:"checkout",mark:"fail",detail:"not inside a fnMoa checkout: the new fnMoa is built from one",fix:"run it from your fnMoa checkout"}),{ok:!1};if(!await $p(o,a,t))return{ok:!1};let c=s;if(r.target==="local"){let i=await er(e,s,t,"stop");if(c=i.deployed,!i.ok)return{ok:!1,state:{...r,deployed:c}};if(!await vp(o,a,s.runner==="compose",t))return{ok:!1,state:{...r,deployed:c}};t({label:"data",mark:"skip",detail:s.runner==="compose"?`kept in the ${he} volumes \u2014 Deploy builds the image and starts it all again`:"kept in ~/.moa/local \u2014 Deploy starts it all again"})}else t({label:"data",mark:"skip",detail:r.target==="vercel"?"kept on the sandbox's disk \u2014 Deploy builds its image at this commit and restarts it":"kept in D1 and R2 \u2014 Deploy builds the Worker and the container image at this commit"});return{ok:!0,state:{...r,screen:"deploy",deployed:c}}}async function uc(e,t,n,o){e=qn(e,o);let{sys:r,state:s}=e,a=Et(s),c=s.target;if(!a||!c)return zn(t);let i={},l=s.answers.githubApp,d=l?en(r,l):void 0,u=l&&d?(await n(`GitHub App ${l.slug}: on ${l.settingsUrl} press "Generate a new client secret" and paste it (Enter keeps the current one): `)).trim():"",f;if(c!=="local"&&(f=(await n(`New GitHub token for the ${c==="vercel"?"sandbox":"container"} \u2014 fine-grained: contents, pull requests, issues read/write; checks, actions read (Enter keeps the current one): `)).trim(),f)){let m=await r.fetch("https://api.github.com/user",{headers:{Authorization:`Bearer ${f}`,Accept:"application/vnd.github+json"},signal:AbortSignal.timeout(15e3)}).then(async w=>w.ok?(await w.json()).login:void 0).catch(()=>{});if(!m)return t({label:"GitHub token",mark:"fail",detail:"GitHub refuses it",fix:"make another, then run `moa setup rotate` again \u2014 nothing was changed"}),{ok:!1};i.github=f,t({label:"GitHub token",mark:"ok",detail:`${U} \u2014 ${m}'s, new`})}let p=a.memoryKept===!0||Ee(e)!==void 0,g=c==="vercel"||Ee(e)!==void 0;if(p){let m=(await n(g?"New LocusGraph agent secret (Enter keeps the current one): ":"LocusGraph agent secret \u2014 this machine has no copy, and Deploy needs one: paste the current one or a new one: ")).trim();if(!m&&!g)return t({label:"LocusGraph",mark:"fail",detail:"the workspace keeps its memory there, and this machine has no copy of the secret \u2014 Deploy would turn memory off",fix:"run `moa setup rotate` again and paste the secret, the current one or a new one \u2014 nothing was changed"}),{ok:!1};if(m){let w=Ee({...e,secrets:{locusgraph:m}});if(!w)return t({label:"LocusGraph",mark:"fail",detail:"setup has no graph ID for this secret",fix:"run `moa setup`, type the graph ID on Memory (g), then `moa setup rotate` again \u2014 nothing was changed"}),{ok:!1};let v=s.answers.tenant??Ie(s.answers.owner),_=await Tn(r,w,v);if(!_.read.ok||!_.write.ok)return t({label:"LocusGraph",mark:"fail",detail:`the new secret does not work: ${_.read.why??_.write.why??"no answer"}`,fix:"check it, then run `moa setup rotate` again \u2014 nothing was changed"}),{ok:!1};i.locusgraph=m,t({label:"LocusGraph",mark:"ok",detail:`${U} \u2014 new; it reads and writes ${w.graph}`})}}let y=wo(c);await ei(r,y,a.workspaceUrl,Or()),t({label:"owner token",mark:"ok",detail:`${U} \u2014 new; Deploy gives it to the workspace, and profile ${y} takes it once the workspace answers to it`}),l&&d?(await ts(r,l,{clientSecret:u||d.clientSecret,authSecret:tp(32).toString("base64url")}),t({label:"GitHub App",mark:"ok",detail:u?`new client secret and AUTH_SECRET \u2014 once Deploy is done, delete the old secret on ${l.settingsUrl}`:"new AUTH_SECRET; client secret kept \u2014 everyone signs in again"})):t({label:"GitHub App",mark:"skip",detail:l?"its secret is not on this machine \u2014 Console access, g, makes a new app":"none \u2014 the console stays on this machine"}),c==="local"?t({label:"GitHub token",mark:"skip",detail:"this machine's own gh login \u2014 `gh auth refresh` renews it"}):f||t({label:"GitHub token",mark:"skip",detail:"kept"}),p?i.locusgraph||t({label:"LocusGraph",mark:"skip",detail:"kept"}):t({label:"LocusGraph",mark:"skip",detail:"not used \u2014 memory stays in the workspace"});let b=a;if(c==="local"){let m=await er(e,a,t,"stop");if(b=m.deployed,!m.ok)return{ok:!1,state:{...s,screen:"deploy",deployed:b}}}return{ok:!0,secrets:i,state:{...s,screen:"deploy",answers:{...s.answers,...i.github?{githubToken:"pasted"}:{}},deployed:b}}}Lt();qe();uo();ze();Vt();function Sp(e){let{state:t,sys:n}=e;if(!t.target||!t.deployed||!t.passed.includes("deploy"))return"finish the initial deployment with `moa setup`";if(!t.answers.owner)return"the GitHub owner (run `moa setup`)";if(mn(e))return"the LocusGraph secret (set LOCUSGRAPH_AGENT_SECRET)";if(t.answers.githubApp&&!en(n,t.answers.githubApp))return"the GitHub App client secret (run `moa setup`)";if(t.target==="cloudflare"&&!t.answers.domain)return"the Cloudflare domain (run `moa setup`)"}async function pc(e,t,n){let o=Sp(e);if(o)return t({label:"update",mark:"fail",detail:`Update needs ${o}`}),!1;let r=await tr(e,t);if(r.state&&await n(r.state),!r.ok||!r.state)return!1;let s=r.state,a=Promise.resolve(),c=u=>{s=u,a=a.then(()=>n(u))},i=new Map,l=u=>{for(let f of u){let p=JSON.stringify(f);i.get(f.label)!==p&&t(f),i.set(f.label,p)}},d=s.target==="vercel"?zo:s.target==="cloudflare"?Fo:Uo;try{let u=await d({...e,state:s},l,f=>c({...s,deployed:f}),f=>c({...s,cloudflare:f}));return u.deployed&&c({...s,deployed:u.deployed,...u.ok?{answers:{...s.answers,removed:void 0}}:{}}),u.ok}finally{await a}}var Pp=["status","login","logout","licence","rotate","update","logs","stop","down"],_p={ok:"\u2713",fail:"\u2717",wait:"\u2026",skip:"\u2013"},Gt=e=>{process.stdout.write(`${_p[e.mark]} ${e.label.padEnd(12)} ${e.detail??""}
216
219
  ${e.mark==="fail"&&e.fix?` ${"".padEnd(12)} \u2192 ${e.fix}
217
- `:""}`)};async function fs(e){let t=ms({input:process.stdin,output:process.stdout});try{return await t.question(e)}finally{t.close()}}async function ps(e){process.stdout.write(e);let t=new up({write:(o,r,s)=>s()}),n=ms({input:process.stdin,output:t,terminal:!0});try{return await n.question("")}finally{n.close(),process.stdout.write(`
218
- `)}}var hp=e=>{let t=P(e,"lines");if(t===void 0)return 100;let n=Number(t);if(!Number.isInteger(n)||n<=0||n>2e3)throw new x("--lines must be a whole number, 1\u20132000");return n},ic=e=>Tt.includes(e);async function Wn(e,t,n){let o=e==="status"||e==="down",r=P(n,"target");if(r!==void 0){if(ic(r)||o&&r==="all")return r;throw new x(`--target must be one of ${Tt.join(", ")}${o?" or all":""}, not ${r}`)}let s=Vt(t);if(s.length<=1)return s[0];let a=`${s.join(", ")}${o?" or all":""}`;if(C(n,"yes")||!process.stdin.isTTY)throw new x(`moa setup has ${s.length} deployments on record, ${s.join(" and ")}: say which with --target ${s.join("|")}${o?"|all":""}`);for(process.stdout.write(`moa setup has ${s.length} deployments on record: ${s.map(c=>`--target ${c}`).join(", ")}
219
- `);;){let c=(await fs(`Which one? ${a}: `)).trim().toLowerCase();if(ic(c)&&s.includes(c)||o&&c==="all")return c;if(c==="")throw new x(`moa setup ${e} needs a target: ${a}`);process.stdout.write(`One of ${a}.
220
- `)}}async function wp(e,t,n){let o=await An(n),r={state:o,sys:cn(n),secrets:{}},s=await Wn(e,o,t);if(e==="logs"){let i=await ec(r,hp(t),s==="all"?void 0:s);if(!i.ok)return Mt(i.line),y.failed;for(let l of i.sections)process.stdout.write(`\u2500\u2500 ${l.name} \xB7 ${l.from}
220
+ `:""}`)};async function fs(e){let t=ms({input:process.stdin,output:process.stdout});try{return await t.question(e)}finally{t.close()}}async function ps(e){process.stdout.write(e);let t=new Ap({write:(o,r,s)=>s()}),n=ms({input:process.stdin,output:t,terminal:!0});try{return await n.question("")}finally{n.close(),process.stdout.write(`
221
+ `)}}var Op=e=>{let t=P(e,"lines");if(t===void 0)return 100;let n=Number(t);if(!Number.isInteger(n)||n<=0||n>2e3)throw new A("--lines must be a whole number, 1\u20132000");return n},fc=e=>It.includes(e);async function Vn(e,t,n){let o=e==="status"||e==="down",r=P(n,"target");if(r!==void 0){if(fc(r)||o&&r==="all")return r;throw new A(`--target must be one of ${It.join(", ")}${o?" or all":""}, not ${r}`)}let s=tn(t);if(s.length<=1)return s[0];let a=`${s.join(", ")}${o?" or all":""}`;if(E(n,"yes")||!process.stdin.isTTY)throw new A(`moa setup has ${s.length} deployments on record, ${s.join(" and ")}: say which with --target ${s.join("|")}${o?"|all":""}`);for(process.stdout.write(`moa setup has ${s.length} deployments on record: ${s.map(c=>`--target ${c}`).join(", ")}
222
+ `);;){let c=(await fs(`Which one? ${a}: `)).trim().toLowerCase();if(fc(c)&&s.includes(c)||o&&c==="all")return c;if(c==="")throw new A(`moa setup ${e} needs a target: ${a}`);process.stdout.write(`One of ${a}.
223
+ `)}}async function Tp(e,t,n){let o=await _n(n),r={state:o,sys:un(n),secrets:{}},s=await Vn(e,o,t);if(e==="logs"){let i=await ac(r,Op(t),s==="all"?void 0:s);if(!i.ok)return Gt(i.line),k.failed;for(let l of i.sections)process.stdout.write(`\u2500\u2500 ${l.name} \xB7 ${l.from}
221
224
  `),process.stdout.write(l.text.trim()?`${l.text.replace(/\n?$/,`
222
225
  `)}`:`(nothing yet)
223
- `);return y.ok}let a;if(e==="down"&&s&&!C(t,"yes")){if(!process.stdin.isTTY)throw new x("moa setup down asks first, and needs a terminal to ask in \u2014 or --yes");let i=s==="all"?[]:Vt(o).filter(l=>l!==s);if(process.stdout.write(`moa setup down deletes, for good:
224
- ${nc(o,s).map(l=>` \xB7 ${l}
226
+ `);return k.ok}let a;if(e==="down"&&s&&!E(t,"yes")){if(!process.stdin.isTTY)throw new A("moa setup down asks first, and needs a terminal to ask in \u2014 or --yes");let i=s==="all"?[]:tn(o).filter(l=>l!==s);if(process.stdout.write(`moa setup down deletes, for good:
227
+ ${cc(o,s).map(l=>` \xB7 ${l}
225
228
  `).join("")}${i.length>0?`and leaves ${i.join(" and ")} deployed, with ${i.length===1?"its":"their"} profile and record.
226
229
  `:""}`),(await fs("Type down to delete it all: ")).trim()!=="down")return process.stdout.write(`Nothing was deleted.
227
- `),y.ok;a=async l=>/^y(es)?$/i.test((await fs(l)).trim())}if(e==="status")return(await Qi(r,Mt,s)).ok?y.ok:y.failed;if(e==="stop"){let i=await Zi(r,Mt,s==="all"?void 0:s);return i.state&&await Ot(i.state,n),i.ok?y.ok:y.failed}let c=o;for(let i of s==="all"?Vt(o):[s]){s==="all"&&process.stdout.write(`\u2500\u2500 ${i}
228
- `);let l=await rc({...r,state:c},Mt,new Date,a,i);if(l.state&&(c=l.state,await Ot(c,n)),!l.ok)return y.failed}return y.ok}var cc=(e,t)=>{let n=P(e,t);if(n===void 0)return;let o=Number(n);if(!Number.isInteger(o)||o<=0||o>=65536)throw new x(`--${t} must be a port, 1\u201365535`);return o};async function lc(){process.stdout.write(`
230
+ `),k.ok;a=async l=>/^y(es)?$/i.test((await fs(l)).trim())}if(e==="status")return(await rc(r,Gt,s)).ok?k.ok:k.failed;if(e==="stop"){let i=await sc(r,Gt,s==="all"?void 0:s);return i.state&&await Rt(i.state,n),i.ok?k.ok:k.failed}let c=o;for(let i of s==="all"?tn(o):[s]){s==="all"&&process.stdout.write(`\u2500\u2500 ${i}
231
+ `);let l=await dc({...r,state:c},Gt,new Date,a,i);if(l.state&&(c=l.state,await Rt(c,n)),!l.ok)return k.failed}return k.ok}var mc=(e,t)=>{let n=P(e,t);if(n===void 0)return;let o=Number(n);if(!Number.isInteger(o)||o<=0||o>=65536)throw new A(`--${t} must be a port, 1\u201365535`);return o};async function gc(){process.stdout.write(`
229
232
  moa setup: handing the terminal to \`claude setup-token\`.
230
233
 
231
- `);let e=dp("claude",["setup-token"],{stdio:"inherit"}),t=ms({input:process.stdin,output:process.stdout});await t.question(e.error?`
234
+ `);let e=xp("claude",["setup-token"],{stdio:"inherit"}),t=ms({input:process.stdin,output:process.stdout});await t.question(e.error?`
232
235
  claude setup-token did not start: ${e.error.message}. Enter to go back. `:`
233
- Copy the token it printed, then press Enter: the screen is cleared and setup asks for it. `),t.close(),process.stdout.write("\x1B[2J\x1B[3J\x1B[H")}async function dc(e,t=process.env){let n=e.positional[1];if(n!==void 0&&!mp.includes(n))throw new x(`moa setup has no ${n}`);if(n==="licence"){let $=await An(t),m=await Wn(n,$,e),A={state:at($,m==="all"?void 0:m),sys:cn(t),secrets:{}};if(t.FNMOA_LICENCE_KEY||C(e,"key")){let E=t.FNMOA_LICENCE_KEY??(process.stdin.isTTY?await ps("Licence key: "):"");if(!E.trim())throw new x("Licence activation needs a key: set FNMOA_LICENCE_KEY or run in a terminal.");await Pr(A,E.trim())}else await _o(A,E=>process.stdout.write(`Open ${E.url}
234
- Sign in, check the page shows ${E.code}, and approve it. Waiting\u2026
235
- `),new AbortController().signal);return process.stdout.write("Licence activated. Run `moa setup update` to apply it to the workspace.\n"),y.ok}if(n==="status"||n==="stop"||n==="logs"||n==="down")return wp(n,e,t);let o=e.positional[2],r;if(n==="login"&&o!==void 0||n==="logout"){if(!$i(o))throw new x(`moa setup ${n} takes an agent: ${pe.join(", ")}`);if(!process.stdin.isTTY&&n==="login")throw new x("moa setup login asks for a login, and needs a terminal to ask in");let $=await An(t),m=await Wn(n,$,e),h={state:at($,m==="all"?void 0:m),sys:cn(t),secrets:{}};if(n==="login"&&h.state.deployed?.runner!=="image")r=o;else{let A=n==="logout"?await Ei(h,o,Mt):await Ai(h,o,C(e,"key"),{print:Mt,secret:ps,setupToken:lc});return A.state&&await Ot(A.state,t),A.ok?y.ok:y.failed}}if(!process.stdin.isTTY){if(n==="update"){let $=await An(t),m=await Wn(n,$,e),h=at($,m==="all"?void 0:m);return await ac({state:h,sys:cn(t),secrets:{}},Mt,E=>Ot(E,t))?y.ok:y.failed}throw new x("moa setup asks questions, and needs a terminal to ask them in")}let s={},a=await An(t);if(n==="login"){let $=await Wn(n,a,e);$&&$!=="all"&&$!==a.target&&(a=at(a,$),await Ot(a,t))}if(n==="update"||n==="rotate"){let $={state:a,sys:cn(t),secrets:s},m=await Wn(n,a,e),h=m==="all"?void 0:m,A=n==="update"?await nr($,Mt,h):await sc($,Mt,ps,h);if(A.state&&await Ot(A.state,t),!A.ok||!A.state)return y.failed;a=A.state,s=A.secrets??{},process.stdout.write(`
236
+ Copy the token it printed, then press Enter: the screen is cleared and setup asks for it. `),t.close(),process.stdout.write("\x1B[2J\x1B[3J\x1B[H")}async function hc(e,t=process.env){let n=e.positional[1];if(n!==void 0&&!Pp.includes(n))throw new A(`moa setup has no ${n}`);if(n==="licence"){let b=await _n(t),m=await Vn(n,b,e),v={state:st(b,m==="all"?void 0:m),sys:un(t),secrets:{}};if(t.FNMOA_LICENCE_KEY||E(e,"key")){let _=t.FNMOA_LICENCE_KEY??(process.stdin.isTTY?await ps("Licence key: "):"");if(!_.trim())throw new A("Licence activation needs a key: set FNMOA_LICENCE_KEY or run in a terminal.");await Cr(v,_.trim())}else await Po(v,_=>process.stdout.write(`Open ${_.url}
237
+ Sign in, check the page shows ${_.code}, and approve it. Waiting\u2026
238
+ `),new AbortController().signal);return process.stdout.write("Licence activated. Run `moa setup update` to apply it to the workspace.\n"),k.ok}if(n==="status"||n==="stop"||n==="logs"||n==="down")return Tp(n,e,t);let o=e.positional[2],r;if(n==="login"&&o!==void 0||n==="logout"){if(!Ci(o))throw new A(`moa setup ${n} takes an agent: ${pe.join(", ")}`);if(!process.stdin.isTTY&&n==="login")throw new A("moa setup login asks for a login, and needs a terminal to ask in");let b=await _n(t),m=await Vn(n,b,e),w={state:st(b,m==="all"?void 0:m),sys:un(t),secrets:{}};if(n==="login"&&w.state.deployed?.runner!=="image")r=o;else{let v=n==="logout"?await Ii(w,o,Gt):await Ti(w,o,E(e,"key"),{print:Gt,secret:ps,setupToken:gc});return v.state&&await Rt(v.state,t),v.ok?k.ok:k.failed}}if(!process.stdin.isTTY){if(n==="update"){let b=await _n(t),m=await Vn(n,b,e),w=st(b,m==="all"?void 0:m);return await pc({state:w,sys:un(t),secrets:{}},Gt,_=>Rt(_,t))?k.ok:k.failed}throw new A("moa setup asks questions, and needs a terminal to ask them in")}let s={},a=await _n(t);if(n==="login"){let b=await Vn(n,a,e);b&&b!=="all"&&b!==a.target&&(a=st(a,b),await Rt(a,t))}if(n==="update"||n==="rotate"){let b={state:a,sys:un(t),secrets:s},m=await Vn(n,a,e),w=m==="all"?void 0:m,v=n==="update"?await tr(b,Gt,w):await uc(b,Gt,ps,w);if(v.state&&await Rt(v.state,t),!v.ok||!v.state)return k.failed;a=v.state,s=v.secrets??{},process.stdout.write(`
236
239
  Deploy runs next: Enter there hands it all to fnMoa.
237
- `)}let c=cc(e,"workspace-port"),i=cc(e,"console-port"),{down:l,...d}=a,u={...d,answers:{...a.answers,...c?{workspacePort:c}:{},...i?{consolePort:i}:{}}};(c||i)&&await Ot(u,t);let f={};n==="login"&&(u.screen="logins",r&&(u.answers={...u.answers,agentCli:r}),u.passed.includes("deploy")&&(f={logins:"deploy"}));let p=cn(t),g,b=!1;for(;;){let $;if(await pp(fp(Ji,{initial:u,sys:p,secrets:s,pasteFirst:b,after:f,save:h=>Ot(h,t),onDone:(h,A)=>{g={state:h,finished:A}},onHandOver:h=>{$=h}})).waitUntilExit(),!$)break;await lc(),u=$,b=!0}return g&&!g.finished&&process.stdout.write(`Saved. \`moa setup\` picks up at ${oo[g.state.screen]}.
238
- `),y.ok}var uc=`moa \u2014 talk to a workspace
240
+ `)}let c=mc(e,"workspace-port"),i=mc(e,"console-port"),{down:l,...d}=a,u={...d,answers:{...a.answers,...c?{workspacePort:c}:{},...i?{consolePort:i}:{}}};(c||i)&&await Rt(u,t);let f={};n==="login"&&(u.screen="logins",r&&(u.answers={...u.answers,agentCli:r}),u.passed.includes("deploy")&&(f={logins:"deploy"}));let p=un(t),g,y=!1;for(;;){let b;if(await Ep(Cp(Qi,{initial:u,sys:p,secrets:s,pasteFirst:y,after:f,save:w=>Rt(w,t),onDone:(w,v)=>{g={state:w,finished:v}},onHandOver:w=>{b=w}})).waitUntilExit(),!b)break;await gc(),u=b,y=!0}return g&&!g.finished&&process.stdout.write(`Saved. \`moa setup\` picks up at ${ao[g.state.screen]}.
241
+ `),k.ok}var wc=`moa \u2014 talk to a workspace
239
242
 
240
243
  moa setup set fnMoa up \u2014 this machine, Vercel or Cloudflare \u2014
241
244
  step by step; resumes where it stopped
@@ -324,9 +327,9 @@ Flags
324
327
 
325
328
  Environment
326
329
  MOA_URL, MOA_TOKEN override the saved profile entirely
327
- `,$p="Proprietary. Copyright (c) 2026 fnLog0. See LICENSE.";function vp(){let e=JSON.parse(kp(new URL("../package.json",import.meta.url),"utf8"));return`moa ${typeof e.version=="string"?e.version:"unknown"}
328
- ${$p}
329
- `}var Sp=["profile","json","help"],xp={login:["token","github"],whoami:[],health:["url"],doctor:[],profiles:[],use:[],logout:[],seats:[],spend:["since"],agent:["cli","role","peers"],peers:["all"],run:["watch","detach","timeout","key"],runs:["limit","state","failed","before"],watch:["every"],logs:["tail","since","watch","every"],ask:["watch","detach","timeout","key"],mcp:["file","revoke"],send:["thread"],inbox:[],mail:["limit"],delegate:["parent"],delegations:["blocked"],thread:[],reply:["kind"],team:["watch","timeout","nudge","route-replies","max-cost","max-turns","key"],ship:["watch","timeout","repo","max-cost","max-steps","key"],jobs:[],stop:[],manager:["timeout"],completion:[],setup:["workspace-port","console-port","lines","yes"]};function Ap(e,t){let n=(r,s)=>{if(r.length!==s.length)return!1;let a=[...r].map((l,d)=>d).filter(l=>r[l]!==s[l]),[c,i]=a;return a.length===2&&c!==void 0&&i!==void 0&&r[c]===s[i]&&r[i]===s[c]},o=(r,s)=>{if(r===s||n(r,s))return!0;if(r.startsWith(s)||s.startsWith(r))return Math.abs(r.length-s.length)<=2;if(Math.abs(r.length-s.length)>1)return!1;let a=0,c=0,i=0;for(;a<r.length&&c<s.length;){if(r[a]===s[c]){a+=1,c+=1;continue}if(++i>1)return!1;r.length>s.length?a+=1:(s.length>r.length||(a+=1),c+=1)}return i+(r.length-a)+(s.length-c)<=1};return t.find(r=>o(e,r))}function Ep(e,t){let n=xp[e];if(n===void 0)return;let o=[...n,...Sp],r=[...t.flags.keys()].filter(c=>!o.includes(c));if(r.length===0)return;let s=r[0],a=Ap(s,o);throw new x(`moa ${e} has no --${s}${a===void 0?"":` \u2014 did you mean --${a}?`}`)}var pc={login:xs,whoami:As,health:Es,doctor:Cs,profiles:_s,use:Os,logout:Ts,seats:Ps,spend:Is,agent:Ls,peers:Ds,run:Qs,runs:oa,watch:ra,logs:ta,ask:na,mcp:Js,send:Ms,inbox:Ns,mail:js,delegate:Gs,delegations:Hs,thread:Fs,reply:Ks,team:qs,ship:zs,jobs:Vs,stop:Ys,manager:Ws,setup:dc};async function Cp(e,t=process.env){let n=hs(e),o=n.positional[0];if(!o&&C(n,"version"))return process.stdout.write(vp()),y.ok;if(!o||C(n,"help")||o==="help")return process.stdout.write(uc),o?y.ok:y.misuse;if(o==="completion")return process.stdout.write(sa(n.positional[1]??"",Object.keys(pc))),y.ok;let r=pc[o];if(!r)throw new x(`unknown command ${o}
330
+ `,Dp="Proprietary. Copyright (c) 2026 fnLog0. See LICENSE.";function Up(){let e=JSON.parse(Ip(new URL("../package.json",import.meta.url),"utf8"));return`moa ${typeof e.version=="string"?e.version:"unknown"}
331
+ ${Dp}
332
+ `}var Np=["profile","json","help"],Mp={login:["token","github"],whoami:[],health:["url"],doctor:[],profiles:[],use:[],logout:[],seats:[],spend:["since"],agent:["cli","role","peers"],peers:["all"],run:["watch","detach","timeout","key"],runs:["limit","state","failed","before"],watch:["every"],logs:["tail","since","watch","every"],ask:["watch","detach","timeout","key"],mcp:["file","revoke"],send:["thread"],inbox:[],mail:["limit"],delegate:["parent"],delegations:["blocked"],thread:[],reply:["kind"],team:["watch","timeout","nudge","route-replies","max-cost","max-turns","key"],ship:["watch","timeout","repo","max-cost","max-steps","key"],jobs:[],stop:[],manager:["timeout"],completion:[],setup:["workspace-port","console-port","lines","yes"]};function Gp(e,t){let n=(r,s)=>{if(r.length!==s.length)return!1;let a=[...r].map((l,d)=>d).filter(l=>r[l]!==s[l]),[c,i]=a;return a.length===2&&c!==void 0&&i!==void 0&&r[c]===s[i]&&r[i]===s[c]},o=(r,s)=>{if(r===s||n(r,s))return!0;if(r.startsWith(s)||s.startsWith(r))return Math.abs(r.length-s.length)<=2;if(Math.abs(r.length-s.length)>1)return!1;let a=0,c=0,i=0;for(;a<r.length&&c<s.length;){if(r[a]===s[c]){a+=1,c+=1;continue}if(++i>1)return!1;r.length>s.length?a+=1:(s.length>r.length||(a+=1),c+=1)}return i+(r.length-a)+(s.length-c)<=1};return t.find(r=>o(e,r))}function jp(e,t){let n=Mp[e];if(n===void 0)return;let o=[...n,...Np],r=[...t.flags.keys()].filter(c=>!o.includes(c));if(r.length===0)return;let s=r[0],a=Gp(s,o);throw new A(`moa ${e} has no --${s}${a===void 0?"":` \u2014 did you mean --${a}?`}`)}var kc={login:Cs,whoami:Ps,health:_s,doctor:Os,profiles:Is,use:Ls,logout:Rs,seats:Ts,spend:Ds,agent:Ns,peers:Ms,run:ta,runs:aa,watch:ia,logs:ra,ask:sa,mcp:Vs,send:js,inbox:Hs,mail:Fs,delegate:Ks,delegations:Bs,thread:Ws,reply:Js,team:Ys,ship:Xs,jobs:Qs,stop:Zs,manager:zs,setup:hc};async function Hp(e,t=process.env){let n=ys(e),o=n.positional[0];if(!o&&E(n,"version"))return process.stdout.write(Up()),k.ok;if(!o||E(n,"help")||o==="help")return process.stdout.write(wc),o?k.ok:k.misuse;if(o==="completion")return process.stdout.write(ca(n.positional[1]??"",Object.keys(kc))),k.ok;let r=kc[o];if(!r)throw new A(`unknown command ${o}
330
333
 
331
- ${uc}`);return Ep(o,n),r(n,t)}var Pp=()=>{let e=process.argv[1];if(!e)return!1;try{return yp(e)===bp(import.meta.url)}catch{return!1}};if(Pp()){for(let e of[process.stdout,process.stderr])e.on("error",t=>{throw t.code==="EPIPE"&&process.exit(0),t});try{process.exitCode=await Cp(process.argv.slice(2))}catch(e){let{message:t,code:n}=$s(e);process.stderr.write(`moa: ${t}
332
- `),process.exitCode=n}}export{pc as COMMANDS,xp as FLAGS,$p as NOTICE,Ep as checkFlags,Ap as nearest,Cp as run,vp as versionText};
334
+ ${wc}`);return jp(o,n),r(n,t)}var Fp=()=>{let e=process.argv[1];if(!e)return!1;try{return Rp(e)===Lp(import.meta.url)}catch{return!1}};if(Fp()){for(let e of[process.stdout,process.stderr])e.on("error",t=>{throw t.code==="EPIPE"&&process.exit(0),t});try{process.exitCode=await Hp(process.argv.slice(2))}catch(e){let{message:t,code:n}=xs(e);process.stderr.write(`moa: ${t}
335
+ `),process.exitCode=n}}export{kc as COMMANDS,Mp as FLAGS,Dp as NOTICE,jp as checkFlags,Gp as nearest,Hp as run,Up as versionText};