eve
Version:
Filesystem-first framework for durable backend AI agents that run anywhere.
2 lines • 11.7 kB
JavaScript
import{randomBytes}from"node:crypto";import{EVE_DEV_RUNTIME_ARTIFACTS_REBUILD_ROUTE_PATH,EVE_DEV_RUNTIME_ARTIFACTS_RESUME_ROUTE_PATH,EVE_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH,EVE_DEV_RUNTIME_ARTIFACTS_SUSPEND_ROUTE_PATH}from"#protocol/routes.js";import{isLoopbackServerUrl}from"#shared/network-address.js";import{loadDevelopmentEnvironmentFiles}from"#cli/dev/environment.js";import{resolveDiscoveryProject}from"#discover/project.js";import{eveDevArguments}from"#setup/primitives/index.js";import{detectPackageManager}from"#setup/package-manager.js";import{EVE_DEVELOPMENT_SANDBOX_RUN_ID_ENV,createDevelopmentSandboxRunId}from"#execution/sandbox/development-run.js";import{pruneLocalSandboxTemplatesInBackground,stopDevelopmentSandboxResources}from"#execution/sandbox/bindings/local.js";import{EVE_DEV_ENV_FLAG}from"#internal/application/optional-package-install.js";import{devBootPhase}from"#internal/dev-boot-progress.js";import{readDevelopmentRuntimeArtifactsRevision}from"#services/dev-client/runtime-artifacts.js";import{toErrorMessage}from"#shared/errors.js";import{startDevelopmentSandboxPrewarmInBackground}from"#execution/sandbox/development-prewarm.js";import{createDevelopmentApplicationNitro}from"#internal/nitro/host/create-application-nitro.js";import{prepareDevelopmentApplicationHost}from"#internal/nitro/host/prepare-application-host.js";import{createDevelopmentNitroArtifactsConfig}from"#internal/nitro/host/artifacts-config.js";import{buildDevelopmentHostCandidate}from"#internal/nitro/host/dev-host-candidate.js";import{removeDevelopmentHostWorkspace}from"#internal/nitro/host/dev-host-workspace.js";import{DrainedNitroDevServer}from"#internal/nitro/host/drained-nitro-dev-server.js";import{activateDevelopmentGeneration,discardDevelopmentGeneration}from"#internal/nitro/development-generation.js";import{resolveNitroCompiledArtifactsSource}from"#internal/nitro/routes/runtime-artifacts.js";import{DEFAULT_DEVELOPMENT_SERVER_HOST,normalizeDevelopmentServerClientUrl}from"#internal/nitro/host/dev-server-url.js";import{createDevelopmentAuthoredRebuildCoordinator}from"#internal/nitro/host/dev-authored-rebuild-coordinator.js";import{DevelopmentServerState}from"#internal/nitro/host/dev-server-state.js";import{handleDevRuntimeArtifactsRequest}from"#internal/nitro/routes/dev-runtime-artifacts.js";import{DEFAULT_DEVELOPMENT_SERVER_PORT,MAX_DEVELOPMENT_SERVER_PORT_ATTEMPTS}from"#internal/nitro/host/ports.js";import{installLocalDevCapabilityEnvironment}from"#runtime/local-dev-capability.js";import{createDevelopmentWorkflowWorld,installWorkflowLocalQueueEnvironment,installWorkflowTransportEnvironment}from"#internal/nitro/host/dev-workflow-world-setup.js";const MAX_ALLOWED_DEVELOPMENT_SERVER_PORT=65535,PORT_ENV=`PORT`;async function isActiveDevelopmentServerForApp(e){try{let t=await resolveDiscoveryProject(e.appRoot),n=await new DevelopmentServerState(t).read();return n===void 0||!isLoopbackServerUrl(n)||!await isDevelopmentServerReady(n)?!1:new URL(n).origin===new URL(normalizeDevelopmentServerClientUrl(e.serverUrl)).origin}catch{return!1}}async function isDevelopmentServerReady(e){return await readDevelopmentRuntimeArtifactsRevision({serverUrl:e,timeoutMs:1e3})!==void 0}function isAddressInUseError(e){return e instanceof Error&&`code`in e&&e.code===`EADDRINUSE`}function resolveDevelopmentServerPort(e){let t=typeof e==`string`?Number(e):e??DEFAULT_DEVELOPMENT_SERVER_PORT;if(!Number.isInteger(t)||t<0||t>MAX_ALLOWED_DEVELOPMENT_SERVER_PORT)throw Error(`Invalid development server port "${String(e)}". Expected an integer between 0 and ${MAX_ALLOWED_DEVELOPMENT_SERVER_PORT}.`);return t}function readEnvironmentPort(){let e=process.env[PORT_ENV];if(e===void 0||e.trim()===``)return;let t=Number(e);if(!Number.isInteger(t)||t<0||t>MAX_ALLOWED_DEVELOPMENT_SERVER_PORT)throw Error(`Invalid ${PORT_ENV} environment variable "${e}". Expected an integer between 0 and ${MAX_ALLOWED_DEVELOPMENT_SERVER_PORT}.`);return t}async function detectDevelopmentCommandPackageManager(e){try{return(await detectPackageManager(e)).kind}catch{return`pnpm`}}async function formatDevelopmentServerConnectCommand(e,t){let n=await detectDevelopmentCommandPackageManager(e);return[n,...eveDevArguments(n),t].join(` `)}async function createDevelopmentServerAlreadyRunningError(e,t){let n=await formatDevelopmentServerConnectCommand(e,t);return Error([`A dev server is already running for this eve agent.`,`To connect to the existing instance, run: ${n}`].join(`
`))}function resolveDevelopmentServerPorts(e){let t=resolveDevelopmentServerPort(e.port);if(t===0||!e.retryOnAddressInUse)return[t];let n=[];for(let e=0;e<MAX_DEVELOPMENT_SERVER_PORT_ATTEMPTS;e+=1){let r=t+e;if(r>65535)break;n.push(r)}return n}function addDevelopmentControlHandler(e){e.devServer.setControlHandler(async t=>{let n=await e.workflowWorld?.handleRequest(t);if(n!==void 0)return n;let r=new URL(t.url);if(r.pathname===EVE_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH&&t.method===`GET`)return handleDevRuntimeArtifactsRequest({appRoot:e.appRoot});let i=r.pathname===EVE_DEV_RUNTIME_ARTIFACTS_SUSPEND_ROUTE_PATH&&t.method===`POST`,a=r.pathname===EVE_DEV_RUNTIME_ARTIFACTS_RESUME_ROUTE_PATH&&t.method===`POST`,o=r.pathname===EVE_DEV_RUNTIME_ARTIFACTS_REBUILD_ROUTE_PATH&&(t.method===`GET`||t.method===`POST`);if(!i&&!a&&!o)return;let s=e.getWatcher();if(s===void 0)return Response.json({error:`The development server is still starting.`},{status:503});let c=r.searchParams.get(`lease`);return(i||a)&&(c===null||c.length===0)?Response.json({error:`A suspension lease is required.`},{status:400}):i?(await s.suspend(c),Response.json({suspended:!0})):a?(await s.resume(c,{silent:r.searchParams.get(`silent`)===`1`}),handleDevRuntimeArtifactsRequest({appRoot:e.appRoot})):(r.searchParams.get(`force`)===`1`?await s.rebuild():await s.flush(),handleDevRuntimeArtifactsRequest({appRoot:e.appRoot}))})}async function closeDevelopmentServerResources(e){let t=[],attempt=async e=>{try{return await e(),!0}catch(e){return t.push(e),!1}},n=e.authoredSourceWatcher;n!==void 0&&await attempt(()=>n.close());let r=e.workflowWorld;r!==void 0&&await attempt(()=>r.close());let i=e.devServer,a=i===void 0||await attempt(()=>i.close()),o=e.nitro;return o!==void 0&&await attempt(()=>o.close()),await attempt(()=>stopDevelopmentSandboxResources({appRoot:e.appRoot,devRunId:e.developmentSandboxRunId,log:e=>console.warn(`[eve:dev] ${e}`)})),{errors:t,listenerClosed:a}}function createDevelopmentServerCleanupError(e){if(e.length!==0){if(e.length===1){let t=e[0];return t instanceof Error?t:Error(`Failed to close the development server: ${toErrorMessage(t)}`,{cause:t})}return AggregateError(e,`Multiple development-server resources failed to close.`)}}function createDevelopmentServerStartupCleanupError(e,t){return AggregateError([e,...t],`${toErrorMessage(e)} Cleanup also failed.`,{cause:e})}async function listenForDevelopmentServer(e){let t=resolveDevelopmentServerPorts({port:e.port,retryOnAddressInUse:e.retryOnAddressInUse}),n;for(let r of t){let t=e.devServer.listen({hostname:e.host,port:r});try{return await t.ready(),t}catch(r){if(n=r,await t.close().catch(()=>{}),!isAddressInUseError(r)||!e.retryOnAddressInUse)throw r}}throw Error(`Failed to start Nitro dev server after ${t.length} attempts. Tried ports ${t.join(`, `)}.`,{cause:n})}async function startNitroDevelopmentServer(e,t){process.env[EVE_DEV_ENV_FLAG]??=`1`;let n=await resolveDiscoveryProject(e);await loadDevelopmentEnvironmentFiles(n.appRoot);let r=readEnvironmentPort(),i=t.port??r,a=t.host!==void 0||t.port!==void 0||r!==void 0,o=new DevelopmentServerState(n),s=await o.read();if(s!==void 0&&isLoopbackServerUrl(s)&&await isDevelopmentServerReady(s)){if(t.existing===`attach-if-unconfigured`&&!a)return{handle:{kind:`existing`,appRoot:n.appRoot,url:s},close:void 0};throw await createDevelopmentServerAlreadyRunningError(n.appRoot,s)}let c=process.env[EVE_DEVELOPMENT_SANDBOX_RUN_ID_ENV],l=createDevelopmentSandboxRunId();process.env[EVE_DEVELOPMENT_SANDBOX_RUN_ID_ENV]=l;let u,d,f,p,m,h,g,_,v=!1,y=!1;try{let e=await devBootPhase(`compiling agent`,()=>prepareDevelopmentApplicationHost(n.appRoot),t.onBootProgress);_=e;let r=resolveNitroCompiledArtifactsSource(createDevelopmentNitroArtifactsConfig({appRoot:e.appRoot,configuredWorld:e.compileResult.manifest.config.experimental?.workflow?.world}));pruneLocalSandboxTemplatesInBackground(e.appRoot);let a=await devBootPhase(`creating dev server`,()=>createDevelopmentApplicationNitro(e),t.onBootProgress);u=a,d=new DrainedNitroDevServer(a.logger);let s=d,b=randomBytes(32).toString(`base64url`);s.setClientAddressSecret(b),m=installWorkflowTransportEnvironment(n.appRoot,b),h=createDevelopmentWorkflowWorld({appRoot:n.appRoot,preparedHost:e,transportSecret:b}),addDevelopmentControlHandler({appRoot:n.appRoot,devServer:s,getWatcher:()=>g,workflowWorld:h});let x=t.host??a.options.devServer.hostname??DEFAULT_DEVELOPMENT_SERVER_HOST,S=i===void 0,C=await devBootPhase(`binding port`,()=>listenForDevelopmentServer({devServer:s,host:x,port:i,retryOnAddressInUse:S}),t.onBootProgress);if(!C.url)throw Error(`Nitro dev server did not expose a URL.`);let w=normalizeDevelopmentServerClientUrl(C.url);p=installWorkflowLocalQueueEnvironment(w),f=installLocalDevCapabilityEnvironment({appRoot:n.appRoot,serverUrl:w}),await devBootPhase(`building dev bundle`,async()=>{let t=await buildDevelopmentHostCandidate({host:e,nitro:a});u=void 0;let n=e.workspace;y=!0,await s.replaceWorker({dispose:async()=>await removeDevelopmentHostWorkspace(n),entry:t.entry,workerData:t.workerData}),await activateDevelopmentGeneration({appRoot:e.appRoot,generation:e.generation}),v=!0},t.onBootProgress),await h?.start(),startDevelopmentSandboxPrewarmInBackground({appRoot:e.appRoot,compiledArtifactsSource:r});let T=await createDevelopmentAuthoredRebuildCoordinator({devServer:s,initialHost:e});g=await devBootPhase(`starting file watcher`,async()=>{let{startAuthoredSourceWatcher:t}=await import(`#internal/nitro/host/dev-authored-source-watcher.js`);return t({coordinator:T,preparedHost:e})},t.onBootProgress),await o.write(w);let E=p;if(E===void 0)throw Error(`Workflow local queue environment was not initialized.`);let D=g,O=d,k=h,A=m,j=f,M;return{handle:{kind:`started`,appRoot:n.appRoot,url:w},close:()=>(M??=(async()=>{let e=await closeDevelopmentServerResources({appRoot:n.appRoot,authoredSourceWatcher:D,devServer:O,developmentSandboxRunId:l,nitro:void 0,workflowWorld:k});e.listenerClosed&&await o.remove().catch(()=>{});try{let t=createDevelopmentServerCleanupError(e.errors);if(t!==void 0)throw t}finally{E(),A?.(),j?.(),restoreDevelopmentSandboxRunId(c)}})(),M)}}catch(e){let t=await closeDevelopmentServerResources({appRoot:n.appRoot,authoredSourceWatcher:g,devServer:d,developmentSandboxRunId:l,nitro:u,workflowWorld:h}),r=[...t.errors];throw _!==void 0&&!v&&await discardDevelopmentGeneration(_.generation).catch(e=>{r.push(e)}),_!==void 0&&!y&&await removeDevelopmentHostWorkspace(_.workspace).catch(e=>{r.push(e)}),p?.(),m?.(),f?.(),t.listenerClosed&&await o.remove().catch(()=>{}),restoreDevelopmentSandboxRunId(c),r.length>0?createDevelopmentServerStartupCleanupError(e,r):e}}function createDevelopmentServer(e,t={}){let n,r;return{start(){if(n!==void 0)throw Error(`DevelopmentServer.start() was already called.`);return n=startNitroDevelopmentServer(e,t).then(({handle:e,close:t})=>(r=t,e)),n},async close(){n!==void 0&&(await n.catch(()=>void 0),await r?.())}}}function restoreDevelopmentSandboxRunId(e){if(e===void 0){delete process.env[EVE_DEVELOPMENT_SANDBOX_RUN_ID_ENV];return}process.env[EVE_DEVELOPMENT_SANDBOX_RUN_ID_ENV]=e}export{createDevelopmentServer,isActiveDevelopmentServerForApp,normalizeDevelopmentServerClientUrl};