eve
Version:
Filesystem-first framework for durable backend AI agents that run anywhere.
1 lines • 5.32 kB
JavaScript
import{defineSetupIntegration}from"../types.js";import{installScaffoldDependencies,reportOverwrittenFiles}from"../shared/scaffold.js";import{deriveSlackConnectorSlug,ensureChannel}from"#setup/scaffold/index.js";import{WizardCancelledError}from"#setup/step.js";import{select}from"#setup/ask.js";import{inspectSlackbotConnectors,provisionSlackbot,reconcileSlackUid}from"#setup/slackbot.js";import{slackMessageDeepLink}from"#setup/slack-connect.js";function slackbotFailureCopy(e){switch(e.state){case`not-installed`:return{reason:`Slackbot is not connected to a Slack workspace. Slack channel was not added.`,followUp:"Re-run `eve add channel/slack` after the workspace install is complete."};case`cleanup-failed`:return{reason:`The abandoned Slack connector could not be removed. Slack channel was not added.`,followUp:`Resolve the cleanup warning above before trying again.`};case`connector-lookup-failed`:return{reason:`Existing Slack connectors could not be inspected. Slack channel was not added.`,followUp:"Restore Vercel CLI access, then re-run `eve add channel/slack`."};case`installation-check-failed`:return{reason:`Slack workspace installation could not be verified. Slack channel was not added.`,followUp:"Verify Vercel Connect is reachable, then re-run `eve add channel/slack`."};case`existing-not-installed`:return{reason:`The existing Slack connector is not connected to a Slack workspace. Slack channel was not added.`,followUp:`Resolve the existing connector warning above before trying again.`};case`detach-failed`:return{reason:`Slackbot provisioning could not replace the existing trigger destination. Slack channel was not added.`,followUp:"Run the `vercel connect detach` and `vercel connect attach` commands above."};case`attach-failed`:return{reason:`Slackbot provisioning did not attach this project. Slack channel was not added.`,followUp:"Finish event delivery with the `vercel connect attach` command above."};case`create-failed`:return{reason:`Slackbot creation failed.`,followUp:"Add it later with `eve add channel/slack`."}}}const defaultDeps={deriveSlackConnectorSlug,ensureChannel,inspectConnectors:inspectSlackbotConnectors,provisionSlackbot,reconcileSlackUid};async function chooseConnector(e,t,n){return t.length===0?`create`:e.asker.ask(select({key:`slack-connector`,message:`Which Slack app would you like to use?`,options:[...t.map(e=>({id:e.uid,value:e,label:`Use ${e.uid}`,hint:e.uid===n?.uid?`Matches this agent`:void 0})),{id:`create`,value:`create`,label:`Create a new Slack app`}],recommended:n??t[0]??`create`,required:!0}))}async function prepareSlackSetup(e,t=defaultDeps){let n=await e.asker.ask(select({key:`slack-credentials`,message:`How would you like to configure Slack?`,options:[{id:`vercel`,value:`vercel-connect`,label:`Set up Vercel Connect`,hint:`Use a linked Vercel project`},{id:`portable`,value:`environment`,label:`Use portable credentials`,hint:`Read Slack tokens from environment variables`}],recommended:`vercel-connect`,required:!0})),r=await t.deriveSlackConnectorSlug(e.appRoot);if(n===`environment`)return{credentials:n,slug:r};let i=await e.resolveVercelProject(`Slack`);if(i.projectId.length===0)throw Error(`Slack setup with Vercel Connect requires a linked Vercel project.`);let a=await t.inspectConnectors(e.presenter.log,e.projectRoot,r,e.signal);return{credentials:n,slug:r,project:i,connector:a.state===`found`?await chooseConnector(e,a.connectors,a.preferred):`create`}}async function applySlackSetup(e,t,n=defaultDeps){if(e.credentials===`environment`){let r=await n.ensureChannel({projectRoot:t.appRoot,environmentRoot:t.projectRoot,kind:`slack`,slackConnectorSlug:e.slug,slackCredentials:`environment`,force:t.force,skipDependencyMutation:!0});return reportOverwrittenFiles(t.presenter.log,r.filesOverwritten),t.presenter.log.success(`Scaffolded channel: slack`),t.presenter.nextSteps([`Set SLACK_BOT_TOKEN and SLACK_SIGNING_SECRET in .env.local (listed in .env.example).`,`Configure your Slack app to send events to /eve/v1/slack on your public agent URL.`]),{facts:[],deploymentRequired:!0}}let r=await n.provisionSlackbot(t.presenter.log,t.projectRoot,e.slug,void 0,{signal:t.signal,selectConnector:async()=>e.connector});if(t.signal?.throwIfAborted(),r.state===`cancelled`)throw new WizardCancelledError;if(r.state!==`attached`){let e=slackbotFailureCopy(r);throw Error(`${e.reason} ${e.followUp}`)}let i=await n.ensureChannel({projectRoot:t.appRoot,kind:`slack`,slackConnectorUid:r.connectorUid,slackConnectorSlug:e.slug,force:t.force,skipDependencyMutation:!0});if(reportOverwrittenFiles(t.presenter.log,i.filesOverwritten),i.action===`skipped`&&!await n.reconcileSlackUid(t.presenter.log,t.projectRoot,r,`slack/${e.slug}`))throw Error(`Slack connector UID update is required before deployment.`);return t.presenter.log.success(`Scaffolded channel: slack`),await installScaffoldDependencies({changed:i.packageJsonUpdated.length>0,log:t.presenter.log,projectPath:t.projectRoot,signal:t.signal}),{facts:r.chatUrl===void 0?[]:[{label:`Agent Slack DM`,value:slackMessageDeepLink(r.chatUrl),kind:`url`}],deploymentRequired:!0}}const SLACK_SETUP=defineSetupIntegration({kind:`slack`,label:`Slack`,hint:`Slack app mentions and DMs`,prepare:prepareSlackSetup,apply:applySlackSetup});export{SLACK_SETUP,applySlackSetup,prepareSlackSetup};