UNPKG

eve

Version:

Filesystem-first framework for durable backend AI agents that run anywhere.

1 lines 5.26 kB
import{findPackageJSON}from"node:module";import{readFile}from"node:fs/promises";import{z}from"#compiled/zod/index.js";import{dirname,isAbsolute,relative,resolve}from"node:path";import{spawn}from"node:child_process";import{WizardCancelledError}from"#setup/step.js";import{pathToFileURL}from"node:url";import{createProcessOutputBuffer}from"#setup/primitives/process-output.js";import{REGISTRY_SETUP_PROTOCOL_VERSION,isRegistrySetupChildMessage}from"#setup/registry-setup-protocol.js";const PackageJsonSchema=z.object({name:z.string().min(1),bin:z.union([z.string(),z.record(z.string(),z.string())]).optional()});function declaredBinPath(e,t){return typeof e.bin==`string`?t===e.name.slice(e.name.lastIndexOf(`/`)+1)?e.bin:void 0:e.bin?.[t]}async function resolveNodePackageBin(e,t){let n=dirname(e),r=PackageJsonSchema.parse(JSON.parse(await readFile(e,`utf8`))),i=declaredBinPath(r,t);if(i===void 0)throw Error(`Package "${r.name}" does not declare a "${t}" binary.`);let a=resolve(n,i),o=relative(n,a);if(o.startsWith(`..`)||isAbsolute(o))throw Error(`Package "${r.name}" declares its "${t}" binary outside the package directory.`);return a}function send(e,t){e.connected&&e.send(t)}async function answerPrompt(e,t,n,r){try{let i,a=n.prompt;switch(a.kind){case`text`:i=await t.text(a);break;case`password`:i=await t.password(a);break;case`select`:i=(a.options.multiple,await t.select(a.options));break;case`editable-select`:i=t.selectEditable===void 0?{kind:`selected`,value:await t.select(a.options)}:await t.selectEditable({...a.options,editable:{...a.options.editable,formatHint:e=>e}});break;case`acknowledge`:await t.acknowledge?.(a.options);break;case`choice`:{if(t.awaitChoice===void 0){i=await t.select({message:a.options.context,options:[...a.options.actions]});break}let e=t.awaitChoice(a.options);r.set(n.id,e.close);try{i=await e.choice}finally{r.delete(n.id)}break}}send(e,{type:`prompt-result`,id:n.id,value:i})}catch(t){if(t instanceof WizardCancelledError){send(e,{type:`prompt-result`,id:n.id,cancelled:!0});return}throw t}}function handlePresentation(e,t,n,r){switch(n.type){case`log`:return(t.replaceContent===void 0||n.level===`warning`||n.level===`error`||n.level===`commandOutput`)&&t.log[n.level](n.text),!0;case`note`:return(t.replaceContent===void 0||n.tone===`warning`)&&t.note(n.message,n.title,{tone:n.tone}),!0;case`intro`:return t.intro(n.text,n.subtitle),!0;case`outro`:return t.outro(n.text),!0;case`result`:return!1;case`status`:if(r.get(n.id)?.(),r.delete(n.id),n.status!==void 0){let e=t.log.spinner?.(n.status);e!==void 0&&r.set(n.id,()=>e.stop())}return!0;case`close-prompt`:return r.get(n.id)?.(),r.delete(n.id),!0;case`prompt`:return answerPrompt(e,t,n,r).catch(t=>{terminateChild(e,`SIGTERM`),e.emit(`error`,t)}),!0;case`ready`:return!1}}async function runRegistrySetupCommand(e,t,n,r){let i=findPackageJSON(t.package,pathToFileURL(resolve(e,`package.json`)));if(i===void 0)throw Error(`Setup package "${t.package}" is not installed. Run \`eve add ${n}\` first.`);let a=await resolveNodePackageBin(i,t.bin);if(r===void 0)throw Error(`Registry setup commands require a parent prompter.`);return new Promise((i,o)=>{let s=spawn(process.execPath,[a,...t.args],{cwd:e,env:{...process.env,EVE_SETUP:`1`,EVE_SETUP_ITEM:n,EVE_SETUP_PROTOCOL:String(REGISTRY_SETUP_PROTOCOL_VERSION)},stdio:[`ignore`,`pipe`,`pipe`,`ipc`],detached:process.platform!==`win32`}),c=!1,l=!1,u,d=new Map,f=createProcessOutputBuffer(({text:e})=>r.prompter.log.commandOutput(e));s.stdout?.on(`data`,e=>f.write(`stdout`,e)),s.stderr?.on(`data`,e=>f.write(`stderr`,e));let p,cancel=()=>{send(s,{type:`cancel`}),p=setTimeout(()=>terminateChild(s,`SIGTERM`),3e3),p.unref()};r.signal?.addEventListener(`abort`,cancel,{once:!0});let cleanup=()=>{f.flush(),r.signal?.removeEventListener(`abort`,cancel),p!==void 0&&clearTimeout(p);for(let e of d.values())e();d.clear()};s.on(`message`,e=>{if(!isRegistrySetupChildMessage(e)){cancel(),o(Error(`Setup command sent an invalid registry protocol message.`));return}if(e.type===`ready`){if(e.version!==REGISTRY_SETUP_PROTOCOL_VERSION){cancel(),o(Error(`Setup command does not support registry setup protocol v${REGISTRY_SETUP_PROTOCOL_VERSION}.`));return}l=!0;return}if(e.type===`result`){u=e.outcome;return}handlePresentation(s,r.prompter,e,d)}),s.once(`error`,e=>{cleanup(),o(e)}),s.once(`close`,(e,t)=>{if(cleanup(),!c){if(c=!0,u?.kind===`completed`){if(e!==0){o(Error(`Setup command reported success, then exited with code ${e??`unknown`}.`));return}let t={kind:`completed`,facts:u.facts};u.deploymentRequired===!0&&(t.deploymentRequired=!0),i(t);return}if(u?.kind===`blocked`){i({kind:`blocked`,blocker:u.blocker});return}if(u?.kind===`cancelled`){i({kind:`cancelled`});return}if(u?.kind===`failed`){o(Error(u.error.message));return}if(r.signal?.aborted===!0||e===130||t===`SIGINT`){i({kind:`cancelled`});return}if(e===0&&l){o(Error(`Setup command exited without reporting a result.`));return}o(Error(t===null?`Setup command exited with code ${e??`unknown`} before reporting a result.`:`Setup command was terminated by ${t} before reporting a result.`))}})})}function terminateChild(e,t){if(process.platform!==`win32`&&e.pid!==void 0)try{process.kill(-e.pid,t);return}catch{}e.kill(t)}export{runRegistrySetupCommand};