eve
Version:
Filesystem-first framework for durable backend AI agents that run anywhere.
117 lines (116 loc) • 5.59 kB
TypeScript
import { deriveSlackConnectorSlug, ensureChannel, type ChannelKind, type EvePackageContract } from "#setup/scaffold/index.js";
import { detectPackageManager } from "#setup/package-manager.js";
import { runPackageManagerInstall } from "#setup/primitives/pm/run.js";
import { runVercel } from "#setup/primitives/run-vercel.js";
import { detectDeployment, type ProjectResolution } from "../project-resolution.js";
import { type Asker } from "../ask.js";
import type { Prompter } from "../prompter.js";
import { provisionSlackbot, reconcileSlackUid } from "../slackbot.js";
import { type SetupState } from "../state.js";
import { type SetupBox } from "../step.js";
/** Injected for tests; defaults to the real scaffold, Connect, and Vercel effects. */
export interface AddChannelsDeps {
ensureChannel: typeof ensureChannel;
deriveSlackConnectorSlug: typeof deriveSlackConnectorSlug;
provisionSlackbot: typeof provisionSlackbot;
reconcileSlackUid: typeof reconcileSlackUid;
detectPackageManager: typeof detectPackageManager;
runPackageManagerInstall: typeof runPackageManagerInstall;
runVercel: typeof runVercel;
detectDeployment: typeof detectDeployment;
}
export interface AddChannelsOptions {
/** Resolves the slackbot question; the composed stack decides how. */
asker: Asker;
/**
* Logs through `prompter.log` in `perform`, and owns the interactive
* `vercel link` fallback. The slackbot question itself now travels the asker,
* not this prompter.
*/
prompter: Prompter;
/**
* Headless mode: gates the interactive `vercel link` fallback inside `perform`
* and refuses Slack up front. Fixed at composition time (the same place the
* asker base is chosen), since `gather` cannot read the mode off the asker.
*/
headless?: boolean;
/**
* eve package metadata for the scaffolded web `package.json`. When omitted,
* every package value comes from the build-stamped defaults.
*/
evePackage?: EvePackageContract;
/** Skip the "Create slackbot?" prompt and use this answer. */
presetCreateSlackbot?: boolean;
/** Overwrite existing channel files (`eve channels add --force`). */
force?: boolean;
/**
* Override for the web scaffold's Vercel services config. Defaults to
* `hasVercelProject(state)`; `eve channels add` pins it to true so an
* unlinked directory still gets the config, matching the dissolved engine.
*/
configureVercelServices?: boolean;
/**
* Opt-in fallback when Slack is chosen interactively but `state.project` is
* unresolved: run the interactive bare `vercel link` before provisioning the
* slackbot. Only the `eve channels add` composition sets this; onboarding
* resolves the project up front via the link box and keeps the hard gate.
*/
ensureLinkedProject?: "interactive-vercel-link";
/**
* What a failed slackbot provision (create or attach) does to the run. The
* default, "abort", fails the whole box — right for `eve channels add slack`,
* where Slack is the point. Onboarding passes "warn-and-continue": the agent
* still scaffolds, deploys, and chats without Slack (recorded as nothing, so
* a later `eve channels add slack` starts clean).
*/
slackbotFailure?: "abort" | "warn-and-continue";
deps?: AddChannelsDeps;
}
/**
* What the user (or the preset) decided before `perform` runs effects.
* `createSlackbot` is only consulted when Slack is in the channel selection.
*/
export interface AddChannelsInput {
headless: boolean;
createSlackbot: boolean | undefined;
}
/** Slackbot facts resolved by a successful Connect provision. */
export interface AddChannelsSlackbotFacts {
connectorUid: string;
/** Deep link that opens a DM compose with the bot ("chat with your agent"). */
chatUrl?: string;
workspaceName?: string;
}
/**
* What `perform` actually did. `channelsAdded` lists the channels recorded this
* run (web before slack); a skipped Web scaffold (Next.js detected) records
* nothing, deliberately. `slackbot` is present only after a fresh, fully
* attached provision; every failure mode either throws or (under
* `slackbotFailure: "warn-and-continue"`) skips Slack entirely, so a failed
* Slack setup records nothing (atomicity).
*/
export interface AddChannelsPayload {
channelsAdded: ChannelKind[];
webScaffolded: boolean;
slackScaffolded: boolean;
/**
* Whether the post-scaffold dependency install succeeded. False both when no
* channels were recorded (nothing ran) and when the install failed; only a
* success lets `apply` mark the deploy-time install as already done.
*/
dependenciesInstalled: boolean;
project: ProjectResolution;
slackbot?: AddChannelsSlackbotFacts;
}
/**
* THE CHANNEL SCAFFOLD BOX. Scaffolds the channels chosen up front by the
* select-channels box (`state.channelSelection`): writes the Web Chat files,
* provisions the Slackbot through Vercel Connect, writes the Slack channel
* definition, reconciles a Connect-assigned connector UID, and installs the
* dependencies the scaffold added to `package.json` so a running `eve dev`
* can load the new channel modules right away. The only prompt
* (the slackbot question) travels the asker in `gather`; `perform` is promptless
* and reads `state.project` directly, resolved earlier by the link box or the
* in-project seed.
*/
export declare function addChannels(options: AddChannelsOptions): SetupBox<SetupState, AddChannelsInput, AddChannelsPayload>;