UNPKG

eve

Version:

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

1 lines 4.66 kB
import{select,text}from"../ask.js";import{CONNECTION_CATALOG,CUSTOM_CONNECTION_SLUG,SUPPORTED_PROTOCOLS,catalogSlugs,effectiveProtocols,getCatalogEntry,isValidConnectionSlug}from"#setup/scaffold/index.js";import{connectorServiceForEntry}from"#setup/scaffold/connections/catalog.js";const CONNECT_REQUIRES_VERCEL=`Authenticates through Vercel Connect, which needs a Vercel project. Re-run and choose to deploy to Vercel.`,PROTOCOL_LABELS={mcp:`MCP`,openapi:`OpenAPI`};function buildCatalogOptions(e){return CONNECTION_CATALOG.map(t=>{let n=e[t.slug];return n===void 0?{value:t.slug,label:t.label,hint:t.hint}:{value:t.slug,label:t.label,hint:t.hint,disabled:!0,disabledReason:n}})}function unknownSlugError(e){return Error(`Unknown connection "${e}". Known: ${catalogSlugs().join(`, `)}, or pass a custom name with a definition.`)}function assertSupportedProtocols(e,t){if(e.length===0)throw Error(`No supported protocol for "${t}". Supported: ${SUPPORTED_PROTOCOLS.join(`, `)}.`)}async function resolveProtocolInteractive(t,n,r){let i=effectiveProtocols(n);return assertSupportedProtocols(i,r),i.length===1?i[0]:t.ask(select({key:`protocol:${r}`,message:`Protocol for ${r}`,options:i.map(e=>({id:e,value:e,label:PROTOCOL_LABELS[e]}))}))}function resolveProtocolHeadless(e,t){let n=effectiveProtocols(e);if(assertSupportedProtocols(n,t),n.length>1)throw Error(`Connection "${t}" supports multiple protocols (${n.join(`, `)}). Pass --protocol to choose one.`);return n[0]}function deriveProvision(e,t){if(e.auth?.kind!==`connect`)return{kind:`none`};let n=connectorServiceForEntry({mcp:e.mcp,auth:e.auth});return n===void 0?{kind:`connect-manual`}:t?{kind:`command-hint`,service:n}:{kind:`connect`,service:n}}async function promptCustomSlug(e){return e.ask(text({key:`connection-name`,message:`Connection name`,placeholder:`mycorp`,validate:e=>{let t=e.trim();return t.length===0?`A name is required.`:isValidConnectionSlug(t)?null:`Start with a lowercase letter; use only lowercase letters, digits, and hyphens (max 64 characters).`}}))}async function planCustomInteractive(e,n){let r=await resolveProtocolInteractive(e,void 0,n),i=await e.ask(text({key:`description:${n}`,message:`Description for ${n}`,placeholder:`What this connection exposes`}));if(r===`mcp`){let a={slug:n,description:i,protocols:[`mcp`],mcp:{url:(await e.ask(text({key:`mcp-url:${n}`,message:`MCP server URL for ${n}`,placeholder:`https://mcp.example.com/sse`,validate:e=>e.trim().length===0?`A URL is required.`:null}))).trim()},auth:{kind:`connect`,connector:n}};return{slug:n,protocol:r,entry:a,provision:deriveProvision(a,!1)}}let a=await e.ask(text({key:`openapi-spec:${n}`,message:`OpenAPI spec URL for ${n}`,placeholder:`https://api.example.com/openapi.json`,validate:e=>e.trim().length===0?`A spec URL is required.`:null})),o=await e.ask(text({key:`openapi-base-url:${n}`,message:`Base URL for ${n} (optional)`,placeholder:`https://api.example.com`})),s={slug:n,description:i,protocols:[`openapi`],openapi:o.trim().length>0?{spec:a.trim(),baseUrl:o.trim()}:{spec:a.trim()},auth:{kind:`connect`,connector:n}};return{slug:n,protocol:r,entry:s,provision:deriveProvision(s,!1)}}async function planSelectionInteractive(e,t){if(t===CUSTOM_CONNECTION_SLUG)return planCustomInteractive(e,(await promptCustomSlug(e)).trim());let n=getCatalogEntry(t);if(n!==void 0)return{slug:t,protocol:await resolveProtocolInteractive(e,n.protocols,t),entry:n,provision:deriveProvision(n,!1)};if(!isValidConnectionSlug(t))throw unknownSlugError(t);return planCustomInteractive(e,t)}function planPresetHeadless(e){if(e===CUSTOM_CONNECTION_SLUG)throw Error(`Custom connection requires interactive input or a preset definition.`);let t=getCatalogEntry(e);if(t!==void 0)return{slug:e,protocol:resolveProtocolHeadless(t.protocols,e),entry:t,provision:deriveProvision(t,!0)};throw isValidConnectionSlug(e)?Error(`Custom connection "${e}" requires interactive input or a preset definition.`):unknownSlugError(e)}function selectConnections(e){return{id:`select-connections`,async gather(){let t=e.headless??!1,n=e.presetConnections??[];if(t)return n.map(e=>planPresetHeadless(e));let r;if(n.length>0)r=[...n];else{let t=buildCatalogOptions({}).map(e=>({id:String(e.value),value:String(e.value),label:e.label,hint:e.hint,disabled:e.disabled,disabledReason:e.disabledReason}));r=await e.asker.askMany({key:`connection`,message:`What should your agent connect to?`,options:t})}let i=[];for(let t of r)i.push(await planSelectionInteractive(e.asker,t));return i},async perform({input:e}){return e},apply(e,t){return{...e,connectionSelection:t}}}}export{CONNECT_REQUIRES_VERCEL,buildCatalogOptions,selectConnections};