eve 0.9.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/bin/eve.d.ts +5 -0
- package/bin/eve.js +15 -13
- package/dist/src/cli/commands/init.js +1 -1
- package/dist/src/cli/dev/tui/runner.d.ts +5 -0
- package/dist/src/cli/dev/tui/runner.js +1 -1
- package/dist/src/cli/dev/tui/terminal-renderer.d.ts +1 -0
- package/dist/src/cli/dev/tui/terminal-renderer.js +9 -6
- package/dist/src/compiled/.vendor-stamp.json +2 -1
- package/dist/src/compiled/semver/LICENSE +15 -0
- package/dist/src/compiled/semver/index.d.ts +23 -0
- package/dist/src/compiled/semver/index.js +1 -0
- package/dist/src/execution/sandbox/logging-session.js +2 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/nitro/host/dev-watcher-log.d.ts +3 -0
- package/dist/src/internal/nitro/host/dev-watcher-log.js +1 -1
- package/dist/src/internal/nitro/host/start-development-server.js +2 -1
- package/dist/src/setup/boxes/add-channels.d.ts +4 -6
- package/dist/src/setup/boxes/add-channels.js +1 -1
- package/dist/src/setup/boxes/scaffold.d.ts +2 -2
- package/dist/src/setup/boxes/scaffold.js +1 -1
- package/dist/src/setup/node-engine.d.ts +31 -0
- package/dist/src/setup/node-engine.js +1 -0
- package/dist/src/setup/onboarding.d.ts +3 -2
- package/dist/src/setup/onboarding.js +1 -1
- package/dist/src/setup/scaffold/create/add-to-project.d.ts +10 -5
- package/dist/src/setup/scaffold/create/add-to-project.js +1 -1
- package/dist/src/setup/scaffold/create/project.d.ts +17 -4
- package/dist/src/setup/scaffold/create/project.js +9 -5
- package/dist/src/setup/scaffold/index.d.ts +1 -1
- package/dist/src/setup/scaffold/update/channels.d.ts +4 -2
- package/dist/src/setup/scaffold/update/channels.js +2 -2
- package/dist/src/setup/scaffold/update/package-json.d.ts +12 -1
- package/dist/src/setup/scaffold/update/package-json.js +1 -1
- package/dist/src/setup/scaffold/version-tokens.js +1 -1
- package/docs/getting-started.mdx +2 -2
- package/docs/reference/cli.md +2 -0
- package/package.json +7 -5
|
@@ -1 +1,2 @@
|
|
|
1
|
-
import{startDevelopmentSandboxPrewarmInBackground}from"#execution/sandbox/development-prewarm.js";import{loadDevelopmentEnvironmentFiles}from"#cli/dev/environment.js";import{EVE_DEV_ENV_FLAG}from"#internal/application/optional-package-install.js";import{EVE_DEVELOPMENT_SANDBOX_RUN_ID_ENV,clearInitializedDevelopmentSandboxBackendNames,createDevelopmentSandboxRunId,getInitializedDevelopmentSandboxBackendNames}from"#execution/sandbox/development-run.js";import{pruneDevelopmentRuntimeArtifactsSnapshotsInBackground}from"#internal/nitro/dev-runtime-artifacts.js";import{build,createDevServer,prepare}from"nitro/builder";import{createApplicationNitro}from"#internal/nitro/host/create-application-nitro.js";import{prepareApplicationHost}from"#internal/nitro/host/prepare-application-host.js";import{createNitroArtifactsConfig}from"#internal/nitro/host/artifacts-config.js";import{resolveNitroCompiledArtifactsSource}from"#internal/nitro/routes/runtime-artifacts.js";import{pruneLocalSandboxTemplatesInBackground,stopDevelopmentSandboxResources}from"#execution/sandbox/bindings/local.js";import{DEFAULT_DEVELOPMENT_SERVER_PORT,MAX_DEVELOPMENT_SERVER_PORT_ATTEMPTS}from"#internal/nitro/host/ports.js";const MAX_ALLOWED_DEVELOPMENT_SERVER_PORT=65535,WORKFLOW_LOCAL_BASE_URL_ENV=`WORKFLOW_LOCAL_BASE_URL`,PORT_ENV=`PORT`,WILDCARD_LISTEN_HOSTNAMES=new Set([`[::]`,`::`,`0.0.0.0`]);function normalizeDevelopmentServerClientUrl(e){let t=new URL(e);return WILDCARD_LISTEN_HOSTNAMES.has(t.hostname)?(t.hostname=`127.0.0.1`,t.toString()):e}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}function
|
|
1
|
+
import{join}from"node:path";import{mkdir,readFile,rm,writeFile}from"node:fs/promises";import{startDevelopmentSandboxPrewarmInBackground}from"#execution/sandbox/development-prewarm.js";import{loadDevelopmentEnvironmentFiles}from"#cli/dev/environment.js";import{EVE_DEV_ENV_FLAG}from"#internal/application/optional-package-install.js";import{EVE_DEVELOPMENT_SANDBOX_RUN_ID_ENV,clearInitializedDevelopmentSandboxBackendNames,createDevelopmentSandboxRunId,getInitializedDevelopmentSandboxBackendNames}from"#execution/sandbox/development-run.js";import{pruneDevelopmentRuntimeArtifactsSnapshotsInBackground}from"#internal/nitro/dev-runtime-artifacts.js";import{build,createDevServer,prepare}from"nitro/builder";import{createApplicationNitro}from"#internal/nitro/host/create-application-nitro.js";import{prepareApplicationHost}from"#internal/nitro/host/prepare-application-host.js";import{createNitroArtifactsConfig}from"#internal/nitro/host/artifacts-config.js";import{resolveNitroCompiledArtifactsSource}from"#internal/nitro/routes/runtime-artifacts.js";import{pruneLocalSandboxTemplatesInBackground,stopDevelopmentSandboxResources}from"#execution/sandbox/bindings/local.js";import{DEFAULT_DEVELOPMENT_SERVER_PORT,MAX_DEVELOPMENT_SERVER_PORT_ATTEMPTS}from"#internal/nitro/host/ports.js";const MAX_ALLOWED_DEVELOPMENT_SERVER_PORT=65535,WORKFLOW_LOCAL_BASE_URL_ENV=`WORKFLOW_LOCAL_BASE_URL`,PORT_ENV=`PORT`,WILDCARD_LISTEN_HOSTNAMES=new Set([`[::]`,`::`,`0.0.0.0`]);function normalizeDevelopmentServerClientUrl(e){let t=new URL(e);return WILDCARD_LISTEN_HOSTNAMES.has(t.hostname)?(t.hostname=`127.0.0.1`,t.toString()):e}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}function resolveDevelopmentProcessIdPath(t){return join(t,`.eve`,`dev-process.pid`)}function parseProcessId(e){let t=e.trim();if(!/^\d+$/.test(t))return;let n=Number(t);return Number.isSafeInteger(n)&&n>0?n:void 0}function isProcessRunning(e){try{return process.kill(e,0),!0}catch(e){return e instanceof Error&&`code`in e&&e.code===`EPERM`}}function formatKillCommand(e){return process.platform===`win32`?`taskkill /PID ${e}`:`kill ${e}`}async function readActiveDevelopmentProcessId(e){let t;try{t=parseProcessId(await readFile(resolveDevelopmentProcessIdPath(e),`utf8`))}catch{return}if(!(t===void 0||!isProcessRunning(t)))return t}async function writeDevelopmentProcessId(a){let o=resolveDevelopmentProcessIdPath(a),s=await readActiveDevelopmentProcessId(a);if(s!==void 0)throw Error([`A dev server is already running for this Eve agent (pid ${s}).`,`To stop it, run: ${formatKillCommand(s)}`].join(`
|
|
2
|
+
`));return await mkdir(join(a,`.eve`),{recursive:!0}),await writeFile(o,`${process.pid}\n`,`utf8`),async()=>{let e;try{e=parseProcessId(await readFile(o,`utf8`))}catch{return}e===process.pid&&await rm(o,{force:!0})}}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 installWorkflowLocalQueueEnvironment(e){let t=process.env[WORKFLOW_LOCAL_BASE_URL_ENV],n=process.env[PORT_ENV],r=new URL(normalizeDevelopmentServerClientUrl(e));return process.env[WORKFLOW_LOCAL_BASE_URL_ENV]=r.origin,r.port&&(process.env[PORT_ENV]=r.port),()=>{t===void 0?delete process.env[WORKFLOW_LOCAL_BASE_URL_ENV]:process.env[WORKFLOW_LOCAL_BASE_URL_ENV]=t,n===void 0?delete process.env[PORT_ENV]:process.env[PORT_ENV]=n}}function attachTemporarySocketErrorHandler(e){let onSocketError=()=>{};return e.once(`error`,onSocketError),()=>{e.off(`error`,onSocketError)}}function shouldProxyDevelopmentServerWebSocketUpgrades(e){return e.options.features.websocket===!0||e.options.experimental.websocket===!0}function guardDevelopmentServerWebSocketUpgrades(e,t){let n=t.upgrade.bind(t),r=shouldProxyDevelopmentServerWebSocketUpgrades(e);t.upgrade=async(e,t,i)=>{if(!r){t.destroyed||t.destroy();return}let a=attachTemporarySocketErrorHandler(t);try{await n(e,t,i)}catch{t.destroyed||t.destroy()}finally{a()}}}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,silent:!0});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 startDevelopmentServer(e,t={}){process.env[EVE_DEV_ENV_FLAG]??=`1`,loadDevelopmentEnvironmentFiles(e);let n=process.env[EVE_DEVELOPMENT_SANDBOX_RUN_ID_ENV],r=createDevelopmentSandboxRunId();process.env[EVE_DEVELOPMENT_SANDBOX_RUN_ID_ENV]=r;let i,u,d,f,p;try{let o=await prepareApplicationHost(e,{dev:!0});p=await writeDevelopmentProcessId(o.appRoot),pruneDevelopmentRuntimeArtifactsSnapshotsInBackground(o.appRoot);let s=resolveNitroCompiledArtifactsSource(createNitroArtifactsConfig({appRoot:o.appRoot,dev:!0}));startDevelopmentSandboxPrewarmInBackground({appRoot:o.appRoot,compiledArtifactsSource:s}),pruneLocalSandboxTemplatesInBackground(o.appRoot),i=await createApplicationNitro(o,!0),u=createDevServer(i),guardDevelopmentServerWebSocketUpgrades(i,u);let c=t.host??i.options.devServer.hostname,l=t.port??readEnvironmentPort(),m=l??i.options.devServer.port,h=await listenForDevelopmentServer({devServer:u,host:c,port:m,retryOnAddressInUse:l===void 0});if(!h.url)throw Error(`Nitro dev server did not expose a URL.`);d=installWorkflowLocalQueueEnvironment(h.url),await prepare(i),await build(i);let{startAuthoredSourceWatcher:g}=await import(`#internal/nitro/host/dev-authored-source-watcher.js`);f=await g({nitro:i,preparedHost:o});let _=d;if(_===void 0)throw Error(`Workflow local queue environment was not initialized.`);let v=f,y=u,b=i;return{async close(){try{await v.close(),await y.close(),await b.close(),await stopDevelopmentSandboxResources({backendNames:getInitializedDevelopmentSandboxBackendNames(r),devRunId:r,log:e=>console.warn(`[eve:dev] ${e}`)})}finally{clearInitializedDevelopmentSandboxBackendNames(r),await p?.(),_(),restoreDevelopmentSandboxRunId(n)}},url:normalizeDevelopmentServerClientUrl(h.url)}}catch(e){throw await f?.close().catch(()=>{}),d?.(),await u?.close().catch(()=>{}),await i?.close().catch(()=>{}),await stopDevelopmentSandboxResources({backendNames:getInitializedDevelopmentSandboxBackendNames(r),devRunId:r,log:e=>console.warn(`[eve:dev] ${e}`)}).catch(()=>{}),clearInitializedDevelopmentSandboxBackendNames(r),await p?.().catch(()=>{}),restoreDevelopmentSandboxRunId(n),e}}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{normalizeDevelopmentServerClientUrl,startDevelopmentServer};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { deriveSlackConnectorSlug, ensureChannel, type ChannelKind } from "#setup/scaffold/index.js";
|
|
1
|
+
import { deriveSlackConnectorSlug, ensureChannel, type ChannelKind, type EvePackageContract } from "#setup/scaffold/index.js";
|
|
2
2
|
import { detectPackageManager } from "#setup/package-manager.js";
|
|
3
3
|
import { runPackageManagerInstall } from "#setup/primitives/pm/run.js";
|
|
4
4
|
import { runVercel } from "#setup/primitives/run-vercel.js";
|
|
@@ -35,12 +35,10 @@ export interface AddChannelsOptions {
|
|
|
35
35
|
*/
|
|
36
36
|
headless?: boolean;
|
|
37
37
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* `webPackageVersions` at all, so every version comes from its build-stamped
|
|
41
|
-
* defaults.
|
|
38
|
+
* Eve package metadata for the scaffolded web `package.json`. When omitted,
|
|
39
|
+
* every package value comes from the build-stamped defaults.
|
|
42
40
|
*/
|
|
43
|
-
|
|
41
|
+
evePackage?: EvePackageContract;
|
|
44
42
|
/** Skip the "Create slackbot?" prompt and use this answer. */
|
|
45
43
|
presetCreateSlackbot?: boolean;
|
|
46
44
|
/** Overwrite existing channel files (`eve channels add --force`). */
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{SkippedSignal,confirm}from"../ask.js";import{detectDeployment,isProjectResolved,mergeProjectResolution,projectResolutionFromDeployment}from"../project-resolution.js";import{provisionSlackbot,reconcileSlackUid}from"../slackbot.js";import{hasVercelProject,requireProjectPath}from"../state.js";import{WizardCancelledError}from"../step.js";import{deriveSlackConnectorSlug,ensureChannel}from"#setup/scaffold/index.js";import{detectPackageManager}from"#setup/package-manager.js";import{HumanActionRequiredError}from"#setup/human-action.js";import{createPromptCommandOutput,withPhase}from"#setup/cli/index.js";import{runPackageManagerInstall}from"#setup/primitives/pm/run.js";import{runVercel}from"#setup/primitives/run-vercel.js";const SLACKBOT_NOT_ATTACHED_ERROR=`Slackbot provisioning did not attach this project. Slack channel was not added.`;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:"Continuing without Slack — the install timed out and was cleaned up; re-run `eve channels add slack` to try again."};case`cleanup-failed`:return{reason:`The abandoned Slack connector could not be removed. Slack channel was not added.`,followUp:`Continuing without Slack — 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:"Continuing without Slack — restore Vercel CLI access, then re-run `eve channels add slack`."};case`installation-check-failed`:return{reason:`Slack workspace installation could not be verified. Slack channel was not added.`,followUp:"Continuing without Slack — verify Vercel Connect is reachable, then re-run `eve channels add slack`."};case`existing-not-installed`:return{reason:`The existing Slack connector is not connected to a Slack workspace. Slack channel was not added.`,followUp:`Continuing without Slack — 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:"Continuing without Slack — run the `vercel connect detach` and `vercel connect attach` commands above."};case`attach-failed`:return{reason:SLACKBOT_NOT_ATTACHED_ERROR,followUp:"Continuing without Slack — finish event delivery with the `vercel connect attach` command above."};case`create-failed`:return{reason:`Slackbot creation failed.`,followUp:"Continuing without Slack — add it later with `eve channels add slack`."}}}function warnOverwrittenFiles(e,t){for(let n of t??[])e.warning(`Overwrote ${n}`)}function warnCompetingNextConfigFiles(e,t){for(let n of t??[])e.warning(`Found competing Next.js config at ${n}; merge any needed settings into next.config.ts and remove it before starting the preview, or Next.js may ignore the generated Eve rewrite.`)}function addChannels(l){let u=l.deps??{ensureChannel,deriveSlackConnectorSlug,provisionSlackbot,reconcileSlackUid,detectPackageManager,runPackageManagerInstall,runVercel,detectDeployment};async function scaffoldSlackChannel(e,t,n,r,i,a){let o=!1;if(!t.slackScaffolded){let t=await u.ensureChannel({projectRoot:n,kind:`slack`,slackConnectorUid:a,slackConnectorSlug:r,force:l.force});warnOverwrittenFiles(e,t.filesOverwritten),t.action===`created`||t.action===`overwritten`?e.success(`Scaffolded channel: slack`):e.info(`Channel "slack" already exists. Skipping file creation.`),o=t.action!==`skipped`,i.slackScaffolded=!0}return i.channelsAdded.push(`slack`),o}async function linkProjectForSlackbot(e,t,n,o,s){if(o)throw new HumanActionRequiredError({kind:`vercel-link`,command:`vercel link`,reason:`Slackbot creation needs this directory linked to a Vercel project.`});if(e.message(`Linking this directory to a Vercel project...`),!await u.runVercel([`link`],{cwd:t,signal:s}))throw s?.throwIfAborted(),Error(`Vercel project linking failed. Slackbot creation did not start.`);let c=mergeProjectResolution(n,projectResolutionFromDeployment(s===void 0?await u.detectDeployment(t):await u.detectDeployment(t,{signal:s})));if(!isProjectResolved(c))throw Error(`Vercel project linking failed. Slackbot creation did not start.`);return c}async function addWebChannelToPayload(e,t,n,r,i,a){if(!t.channelSelection.includes(`web`))return;if(t.webScaffolded){i.channelsAdded.push(`web`);return}e.message(`Scaffolding Web Chat channel files...`);let o={projectRoot:n,kind:`web`,packageManager:r,force:l.force,configureVercelServices:l.configureVercelServices??hasVercelProject(t)};l.
|
|
1
|
+
import{SkippedSignal,confirm}from"../ask.js";import{detectDeployment,isProjectResolved,mergeProjectResolution,projectResolutionFromDeployment}from"../project-resolution.js";import{provisionSlackbot,reconcileSlackUid}from"../slackbot.js";import{hasVercelProject,requireProjectPath}from"../state.js";import{WizardCancelledError}from"../step.js";import{deriveSlackConnectorSlug,ensureChannel}from"#setup/scaffold/index.js";import{formatNodeEngineOverrideWarning}from"#setup/node-engine.js";import{detectPackageManager}from"#setup/package-manager.js";import{HumanActionRequiredError}from"#setup/human-action.js";import{createPromptCommandOutput,withPhase}from"#setup/cli/index.js";import{runPackageManagerInstall}from"#setup/primitives/pm/run.js";import{runVercel}from"#setup/primitives/run-vercel.js";const SLACKBOT_NOT_ATTACHED_ERROR=`Slackbot provisioning did not attach this project. Slack channel was not added.`;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:"Continuing without Slack — the install timed out and was cleaned up; re-run `eve channels add slack` to try again."};case`cleanup-failed`:return{reason:`The abandoned Slack connector could not be removed. Slack channel was not added.`,followUp:`Continuing without Slack — 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:"Continuing without Slack — restore Vercel CLI access, then re-run `eve channels add slack`."};case`installation-check-failed`:return{reason:`Slack workspace installation could not be verified. Slack channel was not added.`,followUp:"Continuing without Slack — verify Vercel Connect is reachable, then re-run `eve channels add slack`."};case`existing-not-installed`:return{reason:`The existing Slack connector is not connected to a Slack workspace. Slack channel was not added.`,followUp:`Continuing without Slack — 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:"Continuing without Slack — run the `vercel connect detach` and `vercel connect attach` commands above."};case`attach-failed`:return{reason:SLACKBOT_NOT_ATTACHED_ERROR,followUp:"Continuing without Slack — finish event delivery with the `vercel connect attach` command above."};case`create-failed`:return{reason:`Slackbot creation failed.`,followUp:"Continuing without Slack — add it later with `eve channels add slack`."}}}function warnOverwrittenFiles(e,t){for(let n of t??[])e.warning(`Overwrote ${n}`)}function warnCompetingNextConfigFiles(e,t){for(let n of t??[])e.warning(`Found competing Next.js config at ${n}; merge any needed settings into next.config.ts and remove it before starting the preview, or Next.js may ignore the generated Eve rewrite.`)}function addChannels(l){let u=l.deps??{ensureChannel,deriveSlackConnectorSlug,provisionSlackbot,reconcileSlackUid,detectPackageManager,runPackageManagerInstall,runVercel,detectDeployment};async function scaffoldSlackChannel(e,t,n,r,i,a){let o=!1;if(!t.slackScaffolded){let t=await u.ensureChannel({projectRoot:n,kind:`slack`,slackConnectorUid:a,slackConnectorSlug:r,force:l.force});warnOverwrittenFiles(e,t.filesOverwritten),t.action===`created`||t.action===`overwritten`?e.success(`Scaffolded channel: slack`):e.info(`Channel "slack" already exists. Skipping file creation.`),o=t.action!==`skipped`,i.slackScaffolded=!0}return i.channelsAdded.push(`slack`),o}async function linkProjectForSlackbot(e,t,n,o,s){if(o)throw new HumanActionRequiredError({kind:`vercel-link`,command:`vercel link`,reason:`Slackbot creation needs this directory linked to a Vercel project.`});if(e.message(`Linking this directory to a Vercel project...`),!await u.runVercel([`link`],{cwd:t,signal:s}))throw s?.throwIfAborted(),Error(`Vercel project linking failed. Slackbot creation did not start.`);let c=mergeProjectResolution(n,projectResolutionFromDeployment(s===void 0?await u.detectDeployment(t):await u.detectDeployment(t,{signal:s})));if(!isProjectResolved(c))throw Error(`Vercel project linking failed. Slackbot creation did not start.`);return c}async function addWebChannelToPayload(e,t,n,r,i,a){if(!t.channelSelection.includes(`web`))return;if(t.webScaffolded){i.channelsAdded.push(`web`);return}e.message(`Scaffolding Web Chat channel files...`);let o={projectRoot:n,kind:`web`,packageManager:r,force:l.force,configureVercelServices:l.configureVercelServices??hasVercelProject(t)};l.evePackage!==void 0&&(o.webPackageVersions={evePackage:l.evePackage});let s=await u.ensureChannel(o);if(a?.throwIfAborted(),warnOverwrittenFiles(e,s.filesOverwritten),s.kind===`web`&&s.action!==`skipped`&&s.nodeEngineOverride!==void 0&&e.warning(formatNodeEngineOverrideWarning(s.nodeEngineOverride)),warnCompetingNextConfigFiles(e,`competingNextConfigFiles`in s?s.competingNextConfigFiles:void 0),s.action===`created`||s.action===`overwritten`){e.success(`Scaffolded channel: web`),i.webScaffolded=!0,i.channelsAdded.push(`web`);return}e.info(`Next.js project detected. Skipping Web Chat scaffolding.`)}function assertSlackProjectReady(e){if(l.ensureLinkedProject===void 0){if(!hasVercelProject(e))throw Error(`Slack requires a Vercel project. Re-run and choose to deploy to Vercel to add Slack.`);if(!isProjectResolved(e.project))throw Error(`Expected a linked Vercel project for Slack, but none was resolved.`)}}async function provisionSlackbotWithControls(e,t,n,r){if(r===void 0&&l.prompter.awaitChoice===void 0)return u.provisionSlackbot(e,t,n);let i={};return r!==void 0&&(i.signal=r),l.prompter.awaitChoice!==void 0&&(i.awaitChoice=l.prompter.awaitChoice),u.provisionSlackbot(e,t,n,void 0,i)}async function scaffoldAttachedSlackChannel(e,t,n,r,i,a){if(!await scaffoldSlackChannel(e,t,n,r,i,a.connectorUid)&&!await u.reconcileSlackUid(e,n,a,`slack/${r}`))throw Error(`Slack connector UID update is required before deployment.`)}async function addSlackChannelToPayload(e,t,n,i,a,o){if(!t.channelSelection.includes(`slack`))return;assertSlackProjectReady(t);let s=await u.deriveSlackConnectorSlug(i,t.agentName);if(t.slackbotCreated){if(!t.slackbotAttached)throw Error(SLACKBOT_NOT_ATTACHED_ERROR);if(!t.deploymentPending)return;let n=t.slackConnectorUid;if(n===void 0)throw Error(`Slack connector UID was not resolved. Slack deployment did not start.`);await scaffoldAttachedSlackChannel(e,t,i,s,a,{state:`attached`,connectorUid:n});return}if(n.createSlackbot!==!0){e.info(`Slack channel was not added because Slackbot setup was skipped.`);return}isProjectResolved(a.project)||(a.project=await linkProjectForSlackbot(e,i,a.project,n.headless,o));let c=await provisionSlackbotWithControls(e,i,s,o);if(o?.throwIfAborted(),c.state===`cancelled`)throw new WizardCancelledError;if(c.state!==`attached`){let t=slackbotFailureCopy(c);if(l.slackbotFailure!==`warn-and-continue`)throw Error(t.reason);e.warning(`${t.reason} ${t.followUp}`);return}a.slackbot={connectorUid:c.connectorUid,chatUrl:c.chatUrl,workspaceName:c.workspaceName},await scaffoldAttachedSlackChannel(e,t,i,s,a,c)}async function installChannelDependencies(e,t,n,r,i){if(r.channelsAdded.length!==0){if(await withPhase(e,`Installing channel dependencies (${n} install)...`,()=>u.runPackageManagerInstall(n,t,{onOutput:createPromptCommandOutput(e),signal:i}))){r.dependenciesInstalled=!0;return}e.warning(`Dependency installation failed. The new channels stay unloadable until \`${n} install\` or a deploy succeeds.`)}}async function performAddChannels(e,t,n){n?.throwIfAborted();let r=l.prompter.log,i=requireProjectPath(e),a={channelsAdded:[],webScaffolded:e.webScaffolded,slackScaffolded:e.slackScaffolded,dependenciesInstalled:!1,project:e.project},o=await u.detectPackageManager(i);return await addWebChannelToPayload(r,e,i,o.kind,a,n),await addSlackChannelToPayload(r,e,t,i,a,n),await installChannelDependencies(r,i,o.kind,a,n),a}return{id:`add-channels`,async gather({state:n}){let r=l.headless??!1;if(r&&n.channelSelection.includes(`slack`))throw Error("Slack setup is interactive. Run `eve channels add slack` from an interactive terminal.");if(!n.channelSelection.includes(`slack`)||l.presetCreateSlackbot!==void 0||n.slackbotCreated)return{headless:r,createSlackbot:l.presetCreateSlackbot};try{return{headless:r,createSlackbot:await l.asker.ask(confirm({key:`create-slackbot`,message:`Do you want to create your slackbot?`}))}}catch(t){if(t instanceof SkippedSignal)return{headless:r,createSlackbot:!1};throw t}},async perform({state:e,input:t,signal:n}){try{return await performAddChannels(e,t,n)}catch(e){if(!(e instanceof WizardCancelledError)){let t=e instanceof Error?e.message:String(e),n=t.split(`
|
|
2
2
|
`)[0]?.trim()??t;l.prompter.log.error(n)}throw e}},apply(e,t){let n=[...e.channels];for(let e of t.channelsAdded)n.includes(e)||n.push(e);let r={...e,channels:n,webScaffolded:t.webScaffolded,slackScaffolded:t.slackScaffolded,deploymentPending:e.deploymentPending||t.channelsAdded.length>0,deploymentDependenciesInstalled:t.channelsAdded.length>0?t.dependenciesInstalled:e.deploymentDependenciesInstalled,project:mergeProjectResolution(e.project,t.project)};return t.slackbot===void 0?r:{...r,slackbotCreated:!0,slackbotAttached:!0,slackConnectorUid:t.slackbot.connectorUid,slackChatUrl:t.slackbot.chatUrl,slackWorkspaceName:t.slackbot.workspaceName}}}}export{addChannels};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isEveProject, scaffoldBaseProject } from "#setup/scaffold/index.js";
|
|
1
|
+
import { isEveProject, scaffoldBaseProject, type EvePackageContract } from "#setup/scaffold/index.js";
|
|
2
2
|
import type { Prompter } from "../prompter.js";
|
|
3
3
|
import { type SetupState } from "../state.js";
|
|
4
4
|
import type { SetupBox } from "../step.js";
|
|
@@ -10,7 +10,7 @@ export interface ScaffoldDeps {
|
|
|
10
10
|
export interface ScaffoldOptions {
|
|
11
11
|
/** Reports scaffold progress and overwrite warnings. The box never prompts. */
|
|
12
12
|
prompter: Prompter;
|
|
13
|
-
|
|
13
|
+
evePackage?: EvePackageContract;
|
|
14
14
|
/** Parent directory the project folder is created inside. Defaults to cwd. */
|
|
15
15
|
targetDirectory?: string;
|
|
16
16
|
/** Allow the in-place scaffold to replace Eve scaffold files that already exist. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{CURRENT_DIRECTORY_PROJECT_NAME,requireProjectPath}from"../state.js";import{isEveProject,scaffoldBaseProject}from"#setup/scaffold/index.js";function scaffold(i){let a=i.deps??{scaffoldBaseProject,isEveProject};return{id:`scaffold`,async gather(){return{headless:i.headless??!1}},async perform({state:n,input:r}){let{prompter:o}=i,s=n.projectPath.inPlace?CURRENT_DIRECTORY_PROJECT_NAME:n.agentName,c=requireProjectPath(n);if(r.headless&&!i.overwriteExisting&&await a.isEveProject(c))return o.log.message(`Existing Eve project detected; continuing setup...`),c;o.log.message(`Scaffolding project files...`);let l=await a.scaffoldBaseProject({projectName:s,model:n.modelId,byokProvider:n.modelWiring===`self`,targetDirectory:i.targetDirectory,overwriteExisting:i.overwriteExisting,onOverwriteFile:e=>o.log.warning(`Overwrote ${e}`),
|
|
1
|
+
import{CURRENT_DIRECTORY_PROJECT_NAME,requireProjectPath}from"../state.js";import{isEveProject,scaffoldBaseProject}from"#setup/scaffold/index.js";function scaffold(i){let a=i.deps??{scaffoldBaseProject,isEveProject};return{id:`scaffold`,async gather(){return{headless:i.headless??!1}},async perform({state:n,input:r}){let{prompter:o}=i,s=n.projectPath.inPlace?CURRENT_DIRECTORY_PROJECT_NAME:n.agentName,c=requireProjectPath(n);if(r.headless&&!i.overwriteExisting&&await a.isEveProject(c))return o.log.message(`Existing Eve project detected; continuing setup...`),c;o.log.message(`Scaffolding project files...`);let l=await a.scaffoldBaseProject({projectName:s,model:n.modelId,byokProvider:n.modelWiring===`self`,targetDirectory:i.targetDirectory,overwriteExisting:i.overwriteExisting,onOverwriteFile:e=>o.log.warning(`Overwrote ${e}`),evePackage:i.evePackage});return o.log.success(`Scaffolded project at ${l}`),l},apply(e,t){return{...e,projectPath:{kind:`resolved`,inPlace:e.projectPath.inPlace,path:t}}}}}export{scaffold};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** An authored Node.js engine value replaced by Eve's selected scaffold major. */
|
|
2
|
+
export interface NodeEngineOverride {
|
|
3
|
+
previous: unknown;
|
|
4
|
+
next: string;
|
|
5
|
+
}
|
|
6
|
+
export type NodeEngineReconciliation = {
|
|
7
|
+
kind: "added";
|
|
8
|
+
next: string;
|
|
9
|
+
} | ({
|
|
10
|
+
kind: "overridden";
|
|
11
|
+
} & NodeEngineOverride) | {
|
|
12
|
+
kind: "unchanged";
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* The single-major `engines.node` value a generated project should declare,
|
|
16
|
+
* derived from Eve's required range — e.g. `">=24"` → `"24.x"`. A scaffolded
|
|
17
|
+
* app is a deployment artifact, not a library: Vercel reads `engines.node` to
|
|
18
|
+
* pick the build's Node and resolves an open range to the newest *supported*
|
|
19
|
+
* major, so `">=24"` would float onto a future major as Vercel widens its set,
|
|
20
|
+
* whereas `"24.x"` stays on major 24 while still taking minor/patch updates.
|
|
21
|
+
* Eve's own package keeps the open range; only generated apps pin.
|
|
22
|
+
*/
|
|
23
|
+
export declare function pinnedNodeEngineMajor(requiredRange: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* Reconciles an authored `engines.node` value with the single Node.js major
|
|
26
|
+
* selected for scaffolded Eve projects. Existing ranges are preserved only
|
|
27
|
+
* when every version they permit remains inside that selected major.
|
|
28
|
+
*/
|
|
29
|
+
export declare function reconcileNodeEngine(existingValue: unknown, requiredRange: string): NodeEngineReconciliation;
|
|
30
|
+
/** Formats the warning shown when Eve replaces an incompatible Node.js engine value. */
|
|
31
|
+
export declare function formatNodeEngineOverrideWarning(override: NodeEngineOverride): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import semver from"#compiled/semver/index.js";const{Range,intersects,minVersion,subset,validRange}=semver;function isNonEmptySubset(e,t){let r=validRange(e);return r!==null&&intersects(r,t)&&subset(r,t)}function nextAllowedMajor(e,n){let i=`>=${n+1}.0.0`,a;for(let n of new Range(e).set){let e=minVersion([...n.map(e=>e.value).filter(Boolean),i].join(` `));e!==null&&(a===void 0||e.major<a)&&(a=e.major)}return a}function pinnedNodeEngineMajor(e){let t=validRange(e);if(t===null)throw Error(`Eve declares an invalid Node.js engine range: "${e}".`);let n=minVersion(t);if(n===null)throw Error(`Eve declares an empty Node.js engine range: "${e}".`);let i=n.major;for(;i!==void 0;){let e=`${i}.x`;if(isNonEmptySubset(e,t))return e;i=nextAllowedMajor(t,i)}throw Error(`Eve's Node.js engine range "${e}" cannot be represented by a major pin without widening it.`)}function reconcileNodeEngine(e,t){let n=pinnedNodeEngineMajor(t);return e===void 0?{kind:`added`,next:n}:typeof e==`string`&&isNonEmptySubset(e,n)?{kind:`unchanged`}:{kind:`overridden`,previous:e,next:n}}function formatPackageJsonValue(e){return JSON.stringify(e)??String(e)}function formatNodeEngineOverrideWarning(e){return`Overrode package.json engines.node from ${formatPackageJsonValue(e.previous)} to "${e.next}" because the previous value was not confined to the Node.js major selected by Eve.`}export{formatNodeEngineOverrideWarning,pinnedNodeEngineMajor,reconcileNodeEngine};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Prompter } from "./prompter.js";
|
|
2
2
|
import type { AnySetupBox } from "./runner.js";
|
|
3
|
+
import type { EvePackageContract } from "./scaffold/index.js";
|
|
3
4
|
import type { ArgsHeadlessAiGateway, ArgsHeadlessProject, ChannelKind, ChatPreference, SetupMode, SetupState } from "./state.js";
|
|
4
5
|
/**
|
|
5
6
|
* Options for {@link composeOnboardingBoxes}. These carry exactly what the
|
|
@@ -41,8 +42,8 @@ export interface OnboardingBoxesOptions {
|
|
|
41
42
|
* setup remains an interactive/onboarding handoff, not a headless flow.
|
|
42
43
|
*/
|
|
43
44
|
headless?: boolean;
|
|
44
|
-
/**
|
|
45
|
-
|
|
45
|
+
/** Eve package metadata baked into the scaffolded `package.json`. */
|
|
46
|
+
evePackage?: EvePackageContract;
|
|
46
47
|
}
|
|
47
48
|
/**
|
|
48
49
|
* Composes the full programmatic onboarding flow.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{headlessAsker,interactiveAsker}from"./ask.js";import{addChannels}from"./boxes/add-channels.js";import{selectConnections}from"./boxes/select-connections.js";import{addConnections}from"./boxes/add-connections.js";import{detectAiGateway}from"./boxes/detect-ai-gateway.js";import{applyAiGatewayCredential}from"./boxes/apply-ai-gateway-credential.js";import{deployProject}from"./boxes/deploy-project.js";import{linkVercelProject}from"./boxes/link-project.js";import{oneShotNextSteps}from"./boxes/one-shot-next-steps.js";import{preflight}from"./boxes/preflight.js";import{resolveProvisioning}from"./boxes/resolve-provisioning.js";import{resolveTarget}from"./boxes/resolve-target.js";import{scaffold}from"./boxes/scaffold.js";import{selectChannels}from"./boxes/select-channels.js";import{selectChat}from"./boxes/select-chat.js";import{selectModel}from"./boxes/select-model.js";import{selectSetupMode}from"./boxes/select-setup-mode.js";import{resolve}from"node:path";function onlyWhen(e,t){return{...t,shouldRun:n=>e(n)&&(t.shouldRun?.(n)??!0)}}function completeSetupOnly(e){return onlyWhen(e=>e.setupMode===`complete`,e)}function composeOnboardingBoxes(r){let i=r.headless?{headless:!0,project:r.provisioning?.project??{},aiGateway:r.provisioning?.aiGateway??{}}:{headless:!1},a=r.headless?headlessAsker():interactiveAsker(r.prompter);return[resolveTarget({asker:a,notify:e=>r.prompter.note(e),presetName:r.presetName,targetDirectory:r.targetDirectory,inPlace:r.inPlace,resumeExisting:r.headless}),selectSetupMode({asker:a,presetMode:r.presetMode,presetModel:r.presetModel}),...[selectModel({asker:a,presetModel:r.presetModel}),selectChannels({asker:a,presetChannels:r.presetChannels,variant:`onboarding`}),selectConnections({asker:a,presetConnections:r.presetConnections,headless:r.headless}),resolveProvisioning({asker:a,prompter:r.prompter,targetDirectory:r.targetDirectory,mode:i})].map(completeSetupOnly),preflight({cwd:resolve(r.targetDirectory??process.cwd()),headless:r.headless}),scaffold({prompter:r.prompter,
|
|
1
|
+
import{headlessAsker,interactiveAsker}from"./ask.js";import{addChannels}from"./boxes/add-channels.js";import{selectConnections}from"./boxes/select-connections.js";import{addConnections}from"./boxes/add-connections.js";import{detectAiGateway}from"./boxes/detect-ai-gateway.js";import{applyAiGatewayCredential}from"./boxes/apply-ai-gateway-credential.js";import{deployProject}from"./boxes/deploy-project.js";import{linkVercelProject}from"./boxes/link-project.js";import{oneShotNextSteps}from"./boxes/one-shot-next-steps.js";import{preflight}from"./boxes/preflight.js";import{resolveProvisioning}from"./boxes/resolve-provisioning.js";import{resolveTarget}from"./boxes/resolve-target.js";import{scaffold}from"./boxes/scaffold.js";import{selectChannels}from"./boxes/select-channels.js";import{selectChat}from"./boxes/select-chat.js";import{selectModel}from"./boxes/select-model.js";import{selectSetupMode}from"./boxes/select-setup-mode.js";import{resolve}from"node:path";function onlyWhen(e,t){return{...t,shouldRun:n=>e(n)&&(t.shouldRun?.(n)??!0)}}function completeSetupOnly(e){return onlyWhen(e=>e.setupMode===`complete`,e)}function composeOnboardingBoxes(r){let i=r.headless?{headless:!0,project:r.provisioning?.project??{},aiGateway:r.provisioning?.aiGateway??{}}:{headless:!1},a=r.headless?headlessAsker():interactiveAsker(r.prompter);return[resolveTarget({asker:a,notify:e=>r.prompter.note(e),presetName:r.presetName,targetDirectory:r.targetDirectory,inPlace:r.inPlace,resumeExisting:r.headless}),selectSetupMode({asker:a,presetMode:r.presetMode,presetModel:r.presetModel}),...[selectModel({asker:a,presetModel:r.presetModel}),selectChannels({asker:a,presetChannels:r.presetChannels,variant:`onboarding`}),selectConnections({asker:a,presetConnections:r.presetConnections,headless:r.headless}),resolveProvisioning({asker:a,prompter:r.prompter,targetDirectory:r.targetDirectory,mode:i})].map(completeSetupOnly),preflight({cwd:resolve(r.targetDirectory??process.cwd()),headless:r.headless}),scaffold({prompter:r.prompter,evePackage:r.evePackage,targetDirectory:r.targetDirectory,overwriteExisting:r.overwriteExisting,headless:r.headless}),...[detectAiGateway(),linkVercelProject({prompter:r.prompter}),applyAiGatewayCredential({prompter:r.prompter}),addChannels({asker:a,prompter:r.prompter,evePackage:r.evePackage,presetCreateSlackbot:r.presetCreateSlackbot,headless:r.headless,slackbotFailure:`warn-and-continue`}),addConnections({prompter:r.prompter})].map(completeSetupOnly),completeSetupOnly(onlyWhen(e=>e.slackScaffolded,deployProject({prompter:r.prompter,skip:r.presetNoDeploy,headless:r.headless}))),completeSetupOnly(selectChat({asker:a,presetPreference:r.presetChatPreference})),oneShotNextSteps({prompter:r.prompter})]}export{composeOnboardingBoxes};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { PackageManagerKind } from "../../package-manager.js";
|
|
2
|
+
import type { NodeEngineOverride } from "../../node-engine.js";
|
|
3
|
+
import { type EvePackageContract } from "./project.js";
|
|
2
4
|
export interface AddAgentToProjectOptions {
|
|
3
5
|
projectRoot: string;
|
|
4
6
|
model: string;
|
|
@@ -7,7 +9,7 @@ export interface AddAgentToProjectOptions {
|
|
|
7
9
|
* generated project configuration. Defaults to pnpm.
|
|
8
10
|
*/
|
|
9
11
|
packageManager?: PackageManagerKind;
|
|
10
|
-
|
|
12
|
+
evePackage?: EvePackageContract;
|
|
11
13
|
aiPackageVersion?: string;
|
|
12
14
|
connectPackageVersion?: string;
|
|
13
15
|
zodPackageVersion?: string;
|
|
@@ -16,12 +18,15 @@ export interface AddAgentToProjectResult {
|
|
|
16
18
|
filesWritten: string[];
|
|
17
19
|
/** Dependencies added to package.json; ones the project already declares anywhere are left untouched. */
|
|
18
20
|
dependenciesAdded: string[];
|
|
21
|
+
/** Present when an incompatible package.json engines.node value was replaced. */
|
|
22
|
+
nodeEngineOverride?: NodeEngineOverride;
|
|
19
23
|
}
|
|
20
24
|
/**
|
|
21
25
|
* Adds an Eve agent to an existing package: writes the `agent/` files, adds
|
|
22
|
-
*
|
|
23
|
-
* the selected package manager's project
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
+
* missing runtime dependencies, reconciles `engines.node` with Eve's
|
|
27
|
+
* requirement, and applies the selected package manager's project
|
|
28
|
+
* configuration. Other host configuration (tsconfig, scripts, ignore files)
|
|
29
|
+
* remains untouched. All conflicts are gathered and reported before anything
|
|
30
|
+
* is written.
|
|
26
31
|
*/
|
|
27
32
|
export declare function addAgentToProject(options: AddAgentToProjectOptions): Promise<AddAgentToProjectResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getPackageManagerStrategy}from"../../primitives/pm/index.js";import{pathExists,writeTextFile}from"../files.js";import{patchPackageJson}from"../update/package-json.js";import{resolveVersionToken}from"../version-tokens.js";import{agentTemplateFiles,formatEveDependencySpecifier}from"./project.js";import{join}from"node:path";import{readFile}from"node:fs/promises";const DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`,`optionalDependencies`,`peerDependencies`];function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function hasDeclaredDependency(e,t){if(!isJsonObject(e))return!1;for(let n of DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function addAgentToProject(i){let a=join(i.projectRoot,`package.json`);if(!await pathExists(a))throw Error(`Cannot add an Eve agent to "${i.projectRoot}" because it has no package.json. Run \`eve init <name>\` to create a new project instead.`);let o=agentTemplateFiles(i.model),s=[];for(let e of Object.keys(o))await pathExists(join(i.projectRoot,e))&&s.push(e);if(s.length===0&&await pathExists(join(i.projectRoot,`agent`))&&s.push(`agent/`),s.length>0)throw Error(`Cannot add an Eve agent to "${i.projectRoot}" because it already has: ${s.join(`, `)}. Move them aside first.`);let c=
|
|
1
|
+
import{getPackageManagerStrategy}from"../../primitives/pm/index.js";import{pathExists,writeTextFile}from"../files.js";import{patchPackageJson}from"../update/package-json.js";import{resolveVersionToken}from"../version-tokens.js";import{agentTemplateFiles,formatEveDependencySpecifier,resolveEvePackageContract}from"./project.js";import{join}from"node:path";import{readFile}from"node:fs/promises";const DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`,`optionalDependencies`,`peerDependencies`];function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function hasDeclaredDependency(e,t){if(!isJsonObject(e))return!1;for(let n of DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function addAgentToProject(i){let a=join(i.projectRoot,`package.json`);if(!await pathExists(a))throw Error(`Cannot add an Eve agent to "${i.projectRoot}" because it has no package.json. Run \`eve init <name>\` to create a new project instead.`);let o=agentTemplateFiles(i.model),s=[];for(let e of Object.keys(o))await pathExists(join(i.projectRoot,e))&&s.push(e);if(s.length===0&&await pathExists(join(i.projectRoot,`agent`))&&s.push(`agent/`),s.length>0)throw Error(`Cannot add an Eve agent to "${i.projectRoot}" because it already has: ${s.join(`, `)}. Move them aside first.`);let c=resolveEvePackageContract(i.evePackage),l=resolveVersionToken(`aiPackageVersion`,i.aiPackageVersion??`>=7.0.0-beta.177`),u=resolveVersionToken(`connectPackageVersion`,i.connectPackageVersion??`0.2.2`),d=resolveVersionToken(`zodPackageVersion`,i.zodPackageVersion??`4.4.3`),f=[];for(let[e,t]of Object.entries(o)){let r=join(i.projectRoot,e);await writeTextFile(r,t),f.push(r)}let p=JSON.parse(await readFile(a,`utf8`)),m={"@vercel/connect":u,ai:l,eve:formatEveDependencySpecifier(c.version),zod:d},h={};for(let[e,t]of Object.entries(m))hasDeclaredDependency(p,e)||(h[e]=t);let g={nodeEngineRequirement:c.nodeEngine};Object.keys(h).length>0&&(g.dependencies=h);let _=await patchPackageJson(a,g);return await getPackageManagerStrategy(i.packageManager??`pnpm`).applyProjectConfiguration(i.projectRoot),{filesWritten:f,dependenciesAdded:Object.keys(h).sort(),nodeEngineOverride:_.nodeEngineOverride}}export{addAgentToProject};
|
|
@@ -1,9 +1,23 @@
|
|
|
1
1
|
import type { PackageManagerKind } from "../../package-manager.js";
|
|
2
2
|
export declare const CURRENT_DIRECTORY_PROJECT_NAME = ".";
|
|
3
|
-
export declare const DEFAULT_EVE_PACKAGE_VERSION = "__EVE_PACKAGE_VERSION__";
|
|
4
3
|
export declare const DEFAULT_AI_PACKAGE_VERSION = "__AI_SDK_VERSION__";
|
|
5
4
|
export declare const DEFAULT_CONNECT_PACKAGE_VERSION = "__VERCEL_CONNECT_VERSION__";
|
|
6
5
|
export declare const DEFAULT_ZOD_PACKAGE_VERSION = "__ZOD_VERSION__";
|
|
6
|
+
/**
|
|
7
|
+
* The Eve package metadata that generated projects consume together. Keeping
|
|
8
|
+
* the dependency version and Node.js requirement in one value prevents a
|
|
9
|
+
* scaffold from installing one Eve release while declaring another release's
|
|
10
|
+
* runtime contract.
|
|
11
|
+
*/
|
|
12
|
+
export interface EvePackageContract {
|
|
13
|
+
/** Eve dependency version or npm specifier written to the generated package. */
|
|
14
|
+
version: string;
|
|
15
|
+
/** The matching Eve release's authored `package.json` `engines.node` value. */
|
|
16
|
+
nodeEngine: string;
|
|
17
|
+
}
|
|
18
|
+
export declare const DEFAULT_EVE_PACKAGE_CONTRACT: EvePackageContract;
|
|
19
|
+
/** Resolves a stamped or explicitly supplied Eve package contract. */
|
|
20
|
+
export declare function resolveEvePackageContract(contract?: EvePackageContract): EvePackageContract;
|
|
7
21
|
/**
|
|
8
22
|
* Provider slug a gateway model id routes through: the segment before the
|
|
9
23
|
* first "/" (e.g. `anthropic/claude-sonnet-4.6` → `anthropic`). The slug is
|
|
@@ -39,16 +53,15 @@ export interface ScaffoldBaseProjectOptions {
|
|
|
39
53
|
targetDirectory?: string;
|
|
40
54
|
overwriteExisting?: boolean;
|
|
41
55
|
onOverwriteFile?: (filePath: string) => void | Promise<void>;
|
|
42
|
-
|
|
56
|
+
evePackage?: EvePackageContract;
|
|
43
57
|
aiPackageVersion?: string;
|
|
44
58
|
connectPackageVersion?: string;
|
|
45
59
|
zodPackageVersion?: string;
|
|
46
60
|
tsgoPackageVersion?: string;
|
|
47
|
-
typesNodePackageVersion?: string;
|
|
48
61
|
/**
|
|
49
62
|
* Scaffold an inline provider `byok` block in `agent.ts` that reads the
|
|
50
63
|
* provider key from `process.env` instead of relying on the managed Vercel
|
|
51
|
-
* AI Gateway.
|
|
64
|
+
* AI Gateway. `process` is typed by the `@types/node` every scaffold ships.
|
|
52
65
|
*/
|
|
53
66
|
byokProvider?: boolean;
|
|
54
67
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import{getPackageManagerStrategy}from"../../primitives/pm/index.js";import{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{basename,join,resolve}from"node:path";import{mkdir,readdir,stat}from"node:fs/promises";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,ALLOWED_CREATE_IN_PLACE_ENTRIES=new Set([`.DS_Store`,`.git`,`.gitkeep`,`.hg`]),
|
|
1
|
+
import{getPackageManagerStrategy}from"../../primitives/pm/index.js";import{pinnedNodeEngineMajor}from"../../node-engine.js";import{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{basename,join,resolve}from"node:path";import{mkdir,readdir,stat}from"node:fs/promises";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,ALLOWED_CREATE_IN_PLACE_ENTRIES=new Set([`.DS_Store`,`.git`,`.gitkeep`,`.hg`]),DEFAULT_AI_PACKAGE_VERSION=`>=7.0.0-beta.177`,DEFAULT_CONNECT_PACKAGE_VERSION=`0.2.2`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.9.1`,nodeEngine:`>=24`};function resolveEvePackageContract(e=DEFAULT_EVE_PACKAGE_CONTRACT){return{version:resolveVersionToken(`evePackage.version`,e.version),nodeEngine:resolveVersionToken(`evePackage.nodeEngine`,e.nodeEngine)}}function modelProviderSlug(e){let t=(e.split(`/`)[0]??``).replaceAll(/[^A-Za-z0-9._-]/gu,``);return t.length>0?t:`anthropic`}function byokProviderEnvVar(e){let t=modelProviderSlug(e).toUpperCase().replaceAll(/[^A-Z0-9]/gu,`_`);return`${/^[0-9]/.test(t)?`_`:``}${t}_API_KEY`}function agentTemplateFiles(e){return{"agent/agent.ts":BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e),"agent/channels/eve.ts":WEB_APP_TEMPLATE_FILES[`agent/channels/eve.ts`],"agent/instructions.md":AGENT_INSTRUCTIONS_TEMPLATE}}function renderTemplate(e,t){return e.replaceAll(`__EVE_INIT_APP_NAME__`,t.appName).replaceAll(`__EVE_INIT_MODEL__`,t.model).replaceAll(`__EVE_INIT_BYOK_PROVIDER__`,modelProviderSlug(t.model)).replaceAll(`__EVE_INIT_BYOK_ENV_VAR__`,byokProviderEnvVar(t.model)).replaceAll(`__EVE_INIT_PACKAGE_VERSION__`,formatEveDependencySpecifier(t.eveVersion)).replaceAll(`__EVE_INIT_AI_SDK_VERSION__`,t.aiPackageVersion).replaceAll(`__EVE_INIT_CONNECT_VERSION__`,t.connectPackageVersion).replaceAll(`__EVE_INIT_ZOD_VERSION__`,t.zodPackageVersion).replaceAll(`__EVE_INIT_TSGO_VERSION__`,t.tsgoPackageVersion).replaceAll(`__EVE_INIT_TYPES_NODE_VERSION__`,t.nodeTypesVersion).replaceAll(`__EVE_INIT_NODE_ENGINE__`,t.nodeEngine)}function formatEveDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}const BASE_AGENT_TEMPLATE=`import { defineAgent } from "eve";
|
|
2
2
|
|
|
3
3
|
export default defineAgent({
|
|
4
4
|
model: "__EVE_INIT_MODEL__",
|
|
5
5
|
});
|
|
6
|
-
`;function packageJsonTemplate(
|
|
6
|
+
`;function packageJsonTemplate(){return`{
|
|
7
7
|
"name": "__EVE_INIT_APP_NAME__",
|
|
8
8
|
"version": "0.0.0",
|
|
9
9
|
"type": "module",
|
|
@@ -24,14 +24,17 @@ export default defineAgent({
|
|
|
24
24
|
"zod": "__EVE_INIT_ZOD_VERSION__"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
|
|
28
|
-
"@typescript/native-preview": "__EVE_INIT_TSGO_VERSION__"
|
|
27
|
+
"@types/node": "__EVE_INIT_TYPES_NODE_VERSION__",
|
|
28
|
+
"@typescript/native-preview": "__EVE_INIT_TSGO_VERSION__"
|
|
29
29
|
},
|
|
30
30
|
"overrides": {
|
|
31
31
|
"ai": "__EVE_INIT_AI_SDK_VERSION__"
|
|
32
32
|
},
|
|
33
33
|
"resolutions": {
|
|
34
34
|
"ai": "__EVE_INIT_AI_SDK_VERSION__"
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": "__EVE_INIT_NODE_ENGINE__"
|
|
35
38
|
}
|
|
36
39
|
}
|
|
37
40
|
`}const AGENT_INSTRUCTIONS_TEMPLATE=`# Identity
|
|
@@ -42,6 +45,7 @@ You are a helpful assistant.
|
|
|
42
45
|
"target": "ES2022",
|
|
43
46
|
"module": "NodeNext",
|
|
44
47
|
"moduleResolution": "NodeNext",
|
|
48
|
+
"types": ["node"],
|
|
45
49
|
"strict": true,
|
|
46
50
|
"esModuleInterop": true,
|
|
47
51
|
"skipLibCheck": true,
|
|
@@ -86,4 +90,4 @@ export default defineAgent({
|
|
|
86
90
|
},
|
|
87
91
|
},
|
|
88
92
|
});
|
|
89
|
-
`:BASE_AGENT_TEMPLATE,...SHARED_TEMPLATE_FILES,"package.json":packageJsonTemplate(
|
|
93
|
+
`:BASE_AGENT_TEMPLATE,...SHARED_TEMPLATE_FILES,"package.json":packageJsonTemplate(),...getPackageManagerStrategy(n).scaffoldFiles}}async function assertCanCreateInPlace(e,t){if(!await pathExists(e))return;let r=(await readdir(e)).filter(e=>!ALLOWED_CREATE_IN_PLACE_ENTRIES.has(e));if(r.length>0&&!t){let e=r.slice(0,5).join(`, `),t=r.length>5?`, and ${r.length-5} more`:``;throw Error(`Cannot create project in current directory because it is not empty. Found: ${e}${t}. Use an empty directory.`)}}async function scaffoldBaseProject(e){let a=resolve(e.targetDirectory??process.cwd(),e.projectName),o=e.projectName===`.`,c=e.overwriteExisting??!1,u=e.byokProvider??!1,d=e.packageManager??`pnpm`,f=resolveEvePackageContract(e.evePackage),p=pinnedNodeEngineMajor(f.nodeEngine);if(o)await assertCanCreateInPlace(a,c);else if(await pathExists(a))throw Error(`Cannot create project because "${a}" already exists.`);let m={appName:basename(a),model:e.model,eveVersion:f.version,aiPackageVersion:resolveVersionToken(`aiPackageVersion`,e.aiPackageVersion??`>=7.0.0-beta.177`),connectPackageVersion:resolveVersionToken(`connectPackageVersion`,e.connectPackageVersion??`0.2.2`),zodPackageVersion:resolveVersionToken(`zodPackageVersion`,e.zodPackageVersion??`4.4.3`),tsgoPackageVersion:resolveVersionToken(`tsgoPackageVersion`,e.tsgoPackageVersion??`7.0.0-dev.20260523.1`),nodeTypesVersion:p,nodeEngine:p};await mkdir(a,{recursive:!0});for(let[t,i]of Object.entries(templateFiles(u,d))){let s=`${a}/${t}`,l=await pathExists(s);await writeTextFile(s,renderTemplate(i,m),{force:o&&c}),l&&await e.onOverwriteFile?.(s)}return a}async function isEveProject(e){for(let t of SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS)try{return await stat(join(e,`agent`,`agent${t}`)),!0}catch{}return!1}export{CURRENT_DIRECTORY_PROJECT_NAME,DEFAULT_AI_PACKAGE_VERSION,DEFAULT_CONNECT_PACKAGE_VERSION,DEFAULT_EVE_PACKAGE_CONTRACT,DEFAULT_ZOD_PACKAGE_VERSION,agentTemplateFiles,byokProviderEnvVar,formatEveDependencySpecifier,isEveProject,modelProviderSlug,resolveEvePackageContract,scaffoldBaseProject};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { byokProviderEnvVar, CURRENT_DIRECTORY_PROJECT_NAME, isEveProject, scaffoldBaseProject, type ScaffoldBaseProjectOptions, } from "./create/project.js";
|
|
1
|
+
export { byokProviderEnvVar, CURRENT_DIRECTORY_PROJECT_NAME, isEveProject, scaffoldBaseProject, type EvePackageContract, type ScaffoldBaseProjectOptions, } from "./create/project.js";
|
|
2
2
|
export { DEFAULT_SLACK_CONNECTOR_SLUG, SLACK_CHANNEL_DEFAULT_ROUTE, deriveSlackConnectorSlug, ensureChannel, isNextJsProject, listAuthoredChannels, normalizeSlackConnectorSlug, type ChannelKind, type ChannelMutationResult, type EnsureChannelOptions, type SlackConnectorSlug, type WebPackageVersions, } from "./update/channels.js";
|
|
3
3
|
export { SCAFFOLDABLE_CHANNELS, type ScaffoldableChannel } from "./channels-catalog.js";
|
|
4
4
|
export { ensureConnection, listAuthoredConnections, type ConnectionInput, type ConnectionMutationAction, type ConnectionMutationResult, type EnsureConnectionOptions, } from "./update/connections.js";
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { PackageManagerKind } from "../../package-manager.js";
|
|
2
|
+
import { type NodeEngineOverride } from "../../node-engine.js";
|
|
3
|
+
import { type EvePackageContract } from "../create/project.js";
|
|
2
4
|
export declare const SLACK_CHANNEL_DEFAULT_ROUTE = "/eve/v1/slack";
|
|
3
5
|
export declare const DEFAULT_SLACK_CONNECTOR_SLUG = "my-agent";
|
|
4
6
|
declare const slackConnectorSlugBrand: unique symbol;
|
|
@@ -38,6 +40,7 @@ interface WebChannelWrittenResult {
|
|
|
38
40
|
filesWritten: string[];
|
|
39
41
|
filesOverwritten?: string[];
|
|
40
42
|
competingNextConfigFiles?: string[];
|
|
43
|
+
nodeEngineOverride?: NodeEngineOverride;
|
|
41
44
|
filesSkipped: string[];
|
|
42
45
|
packageJsonUpdated: PackageJsonMutation[];
|
|
43
46
|
}
|
|
@@ -76,7 +79,7 @@ export interface EnsureChannelOptions {
|
|
|
76
79
|
configureVercelServices?: boolean;
|
|
77
80
|
}
|
|
78
81
|
export interface WebPackageVersions {
|
|
79
|
-
|
|
82
|
+
evePackage?: EvePackageContract;
|
|
80
83
|
aiPackageVersion?: string;
|
|
81
84
|
nextPackageVersion?: string;
|
|
82
85
|
reactPackageVersion?: string;
|
|
@@ -84,7 +87,6 @@ export interface WebPackageVersions {
|
|
|
84
87
|
streamdownPackageVersion?: string;
|
|
85
88
|
zodPackageVersion?: string;
|
|
86
89
|
tsgoPackageVersion?: string;
|
|
87
|
-
typesNodePackageVersion?: string;
|
|
88
90
|
typesReactPackageVersion?: string;
|
|
89
91
|
typesReactDomPackageVersion?: string;
|
|
90
92
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{getPackageManagerStrategy}from"../../primitives/pm/index.js";import{pathExists,writeTextFile}from"../files.js";import{patchPackageJson}from"./package-json.js";import{resolveVersionToken}from"../version-tokens.js";import{getSupportedModuleBaseName,matchesSupportedModuleBaseName}from"./module-files.js";import{WEB_APP_TEMPLATE_FILES,WEB_APP_TEMPLATE_PACKAGE_JSON}from"../create/web-template.js";import"../create/project.js";import{basename,join,resolve}from"node:path";import{readFile,readdir,writeFile}from"node:fs/promises";const SLACK_CHANNEL_DEFAULT_ROUTE=`/eve/v1/slack`,DEFAULT_SLACK_CONNECTOR_SLUG=`my-agent`,PACKAGE_DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`,`peerDependencies`,`optionalDependencies`],WEB_NEXT_CONFIG_PATH=`next.config.ts`,WEB_VERCEL_JSON_PATH=`vercel.json`,WEB_VERCEL_JSON_SCHEMA=`https://openapi.vercel.sh/vercel.json`,WEB_COMPETING_NEXT_CONFIG_PATHS=[`next.config.js`,`next.config.mjs`,WEB_NEXT_CONFIG_PATH,`next.config.mts`].filter(e=>e!==WEB_NEXT_CONFIG_PATH),WEB_DEFAULT_VERCEL_SERVICES={web:{entrypoint:`.`,framework:`nextjs`,routePrefix:`/`},eve:{buildCommand:`eve build`,entrypoint:`.`,framework:`eve`,routePrefix:`/_eve_internal/eve`}};function toSlackConnectorSlug(e){return e}function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}async function readDependencyVersion(e,t){let n=JSON.parse(await readFile(e,`utf8`));if(!isJsonObject(n)||!isJsonObject(n.dependencies))return;let r=n.dependencies[t];return typeof r==`string`?r:void 0}function packageJsonHasDependency(e,t){for(let n of PACKAGE_DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function hasPackageDependency(e,
|
|
1
|
+
import{getPackageManagerStrategy}from"../../primitives/pm/index.js";import{pinnedNodeEngineMajor}from"../../node-engine.js";import{pathExists,writeTextFile}from"../files.js";import{patchPackageJson}from"./package-json.js";import{resolveVersionToken}from"../version-tokens.js";import{getSupportedModuleBaseName,matchesSupportedModuleBaseName}from"./module-files.js";import{WEB_APP_TEMPLATE_FILES,WEB_APP_TEMPLATE_PACKAGE_JSON}from"../create/web-template.js";import{DEFAULT_EVE_PACKAGE_CONTRACT,resolveEvePackageContract}from"../create/project.js";import{basename,join,resolve}from"node:path";import{readFile,readdir,writeFile}from"node:fs/promises";const SLACK_CHANNEL_DEFAULT_ROUTE=`/eve/v1/slack`,DEFAULT_SLACK_CONNECTOR_SLUG=`my-agent`,PACKAGE_DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`,`peerDependencies`,`optionalDependencies`],WEB_NEXT_CONFIG_PATH=`next.config.ts`,WEB_VERCEL_JSON_PATH=`vercel.json`,WEB_VERCEL_JSON_SCHEMA=`https://openapi.vercel.sh/vercel.json`,WEB_COMPETING_NEXT_CONFIG_PATHS=[`next.config.js`,`next.config.mjs`,WEB_NEXT_CONFIG_PATH,`next.config.mts`].filter(e=>e!==WEB_NEXT_CONFIG_PATH),WEB_DEFAULT_VERCEL_SERVICES={web:{entrypoint:`.`,framework:`nextjs`,routePrefix:`/`},eve:{buildCommand:`eve build`,entrypoint:`.`,framework:`eve`,routePrefix:`/_eve_internal/eve`}};function toSlackConnectorSlug(e){return e}function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}async function readDependencyVersion(e,t){let n=JSON.parse(await readFile(e,`utf8`));if(!isJsonObject(n)||!isJsonObject(n.dependencies))return;let r=n.dependencies[t];return typeof r==`string`?r:void 0}function packageJsonHasDependency(e,t){for(let n of PACKAGE_DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function hasPackageDependency(e,t){if(!await pathExists(e))return!1;let r=JSON.parse(await readFile(e,`utf8`));return isJsonObject(r)&&packageJsonHasDependency(r,t)}async function isNextJsProject(e){return hasPackageDependency(join(e,`package.json`),`next`)}async function ensurePackageDependency(e,t,r){return!await pathExists(e)||await readDependencyVersion(e,t)===r?[]:(await patchPackageJson(e,{dependencies:{[t]:r}}),[{path:e,dependencies:[t],devDependencies:[],scripts:[]}])}function resolveWebPackageVersions(e){return{evePackage:e?.evePackage??DEFAULT_EVE_PACKAGE_CONTRACT,aiPackageVersion:e?.aiPackageVersion??`>=7.0.0-beta.177`,nextPackageVersion:e?.nextPackageVersion??`16.2.6`,reactPackageVersion:e?.reactPackageVersion??`19.2.6`,reactDomPackageVersion:e?.reactDomPackageVersion??`19.2.6`,streamdownPackageVersion:e?.streamdownPackageVersion??`2.5.0`,zodPackageVersion:e?.zodPackageVersion??`4.4.3`,tsgoPackageVersion:e?.tsgoPackageVersion??`7.0.0-dev.20260523.1`,typesReactPackageVersion:e?.typesReactPackageVersion??`19.2.15`,typesReactDomPackageVersion:e?.typesReactDomPackageVersion??`19.2.3`}}function formatEveDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}async function patchWebPackageJson(e,r){if(!await pathExists(e))return{mutations:[]};let o=resolveEvePackageContract(r.evePackage),s=pinnedNodeEngineMajor(o.nodeEngine),c={...WEB_APP_TEMPLATE_PACKAGE_JSON.dependencies,ai:resolveVersionToken(`aiPackageVersion`,r.aiPackageVersion),eve:formatEveDependencySpecifier(o.version),next:resolveVersionToken(`nextPackageVersion`,r.nextPackageVersion),react:resolveVersionToken(`reactPackageVersion`,r.reactPackageVersion),"react-dom":resolveVersionToken(`reactDomPackageVersion`,r.reactDomPackageVersion),streamdown:resolveVersionToken(`streamdownPackageVersion`,r.streamdownPackageVersion),zod:resolveVersionToken(`zodPackageVersion`,r.zodPackageVersion)},u={...WEB_APP_TEMPLATE_PACKAGE_JSON.devDependencies,"@types/node":s,"@types/react":resolveVersionToken(`typesReactPackageVersion`,r.typesReactPackageVersion),"@types/react-dom":resolveVersionToken(`typesReactDomPackageVersion`,r.typesReactDomPackageVersion),"@typescript/native-preview":resolveVersionToken(`tsgoPackageVersion`,r.tsgoPackageVersion)},f=WEB_APP_TEMPLATE_PACKAGE_JSON.scripts,p=await patchPackageJson(e,{dependencies:c,devDependencies:u,scripts:f,nodeEngineRequirement:o.nodeEngine});return{mutations:[{path:e,dependencies:Object.keys(c),devDependencies:Object.keys(u),scripts:Object.keys(f)}],nodeEngineOverride:p.nodeEngineOverride}}function normalizeSlackConnectorSlug(e){return toSlackConnectorSlug((e.trim().replace(/^@/,``).split(`/`).at(-1)??``).toLowerCase().replace(/[^a-z0-9_-]+/g,`-`).replace(/^[^a-z0-9]+/,``).replace(/[^a-z0-9]+$/,``).slice(0,100).replace(/[^a-z0-9]+$/,``)||`my-agent`)}async function deriveSlackConnectorSlug(e,t){if(t!==void 0&&t.length>0&&t!==`.`)return normalizeSlackConnectorSlug(t);try{let t=await readFile(join(e,`package.json`),`utf8`),n=JSON.parse(t);if(typeof n.name==`string`&&n.name.length>0)return normalizeSlackConnectorSlug(n.name)}catch{}return normalizeSlackConnectorSlug(basename(resolve(e))||`my-agent`)}function buildSlackTemplate(e){if(!e.startsWith(`slack/`)||e.length===6)throw Error(`Invalid Slack connector UID "${e}".`);return`import { connectSlackCredentials } from "@vercel/connect/eve";
|
|
2
2
|
import { slackChannel } from "eve/channels/slack";
|
|
3
3
|
|
|
4
4
|
export default slackChannel({
|
|
5
5
|
credentials: connectSlackCredentials(${JSON.stringify(e)}),
|
|
6
6
|
});
|
|
7
|
-
`}function renderWebAppTemplate(e,t,n){let r=n?``:`, { configureVercelOutput: false }`;return e.replaceAll(`__EVE_INIT_APP_NAME__`,t).replaceAll(`__EVE_INIT_WITH_EVE_OPTIONS__`,r)}function withWebVercelServices(e){let t=JSON.parse(e);if(!isJsonObject(t))throw Error(`${WEB_VERCEL_JSON_PATH} must contain a JSON object.`);let n=t.experimentalServices;if(n!==void 0&&!isJsonObject(n))throw Error(`${WEB_VERCEL_JSON_PATH} experimentalServices must contain a JSON object.`);let r={...t,$schema:typeof t.$schema==`string`?t.$schema:WEB_VERCEL_JSON_SCHEMA,experimentalServices:{...n,web:n?.web??WEB_DEFAULT_VERCEL_SERVICES.web,eve:n?.eve??WEB_DEFAULT_VERCEL_SERVICES.eve}};return JSON.stringify(t)===JSON.stringify(r)?e:`${JSON.stringify(r,null,2)}\n`}async function ensureWebVercelServices(e){if(!await pathExists(e))return await writeTextFile(e,`${JSON.stringify({$schema:WEB_VERCEL_JSON_SCHEMA,experimentalServices:WEB_DEFAULT_VERCEL_SERVICES},null,2)}\n`,{force:!0}),`written`;let
|
|
7
|
+
`}function renderWebAppTemplate(e,t,n){let r=n?``:`, { configureVercelOutput: false }`;return e.replaceAll(`__EVE_INIT_APP_NAME__`,t).replaceAll(`__EVE_INIT_WITH_EVE_OPTIONS__`,r)}function withWebVercelServices(e){let t=JSON.parse(e);if(!isJsonObject(t))throw Error(`${WEB_VERCEL_JSON_PATH} must contain a JSON object.`);let n=t.experimentalServices;if(n!==void 0&&!isJsonObject(n))throw Error(`${WEB_VERCEL_JSON_PATH} experimentalServices must contain a JSON object.`);let r={...t,$schema:typeof t.$schema==`string`?t.$schema:WEB_VERCEL_JSON_SCHEMA,experimentalServices:{...n,web:n?.web??WEB_DEFAULT_VERCEL_SERVICES.web,eve:n?.eve??WEB_DEFAULT_VERCEL_SERVICES.eve}};return JSON.stringify(t)===JSON.stringify(r)?e:`${JSON.stringify(r,null,2)}\n`}async function ensureWebVercelServices(e){if(!await pathExists(e))return await writeTextFile(e,`${JSON.stringify({$schema:WEB_VERCEL_JSON_SCHEMA,experimentalServices:WEB_DEFAULT_VERCEL_SERVICES},null,2)}\n`,{force:!0}),`written`;let t=await readFile(e,`utf8`),i=withWebVercelServices(t);return i===t?`skipped`:(await writeFile(e,i,`utf8`),`written`)}async function findCompetingNextConfigFiles(e){let t=[];for(let r of WEB_COMPETING_NEXT_CONFIG_PATHS){let i=join(e,r);await pathExists(i)&&t.push(i)}return t}async function ensureChannel(e){switch(e.kind){case`slack`:return ensureSlackChannel({...e,kind:`slack`});case`web`:return ensureWebChannel({...e,kind:`web`})}}async function ensureWebChannel(t){let i=join(t.projectRoot,`package.json`),a=await pathExists(join(t.projectRoot,`app/page.tsx`));if(!t.force&&await isNextJsProject(t.projectRoot))return{kind:`web`,action:`skipped`,skipReason:`nextjs-project`,filesWritten:[],filesSkipped:[i],packageJsonUpdated:[]};let o=await patchWebPackageJson(i,resolveWebPackageVersions(t.webPackageVersions)),s=[],l=[],u=[],d=[],m=basename(resolve(t.projectRoot)),h=t.configureVercelServices??!0;if(h){let e=join(t.projectRoot,WEB_VERCEL_JSON_PATH);await ensureWebVercelServices(e)===`written`?s.push(e):d.push(e)}let g=await getPackageManagerStrategy(t.packageManager??`pnpm`).applyProjectConfiguration(t.projectRoot);s.push(...g.filesWritten),d.push(...g.filesSkipped);for(let[e,i]of Object.entries(WEB_APP_TEMPLATE_FILES)){let a=join(t.projectRoot,e);if(e===`agent/channels/eve.ts`&&!t.force&&await pathExists(a)){d.push(a);continue}let o=await pathExists(a);await writeTextFile(a,renderWebAppTemplate(i,m,h),{force:!0}),s.push(a),o&&l.push(a)}u.push(...await findCompetingNextConfigFiles(t.projectRoot));let _={kind:`web`,action:a?`overwritten`:`created`,filesWritten:s,filesSkipped:d,packageJsonUpdated:o.mutations};return l.length>0&&(_.filesOverwritten=l),u.length>0&&(_.competingNextConfigFiles=u),o.nodeEngineOverride!==void 0&&(_.nodeEngineOverride=o.nodeEngineOverride),_}async function ensureSlackChannel(e){let t=join(e.projectRoot,`agent/channels/slack.ts`),i=await pathExists(t);if(!e.force&&i)return{kind:`slack`,action:`skipped`,filesWritten:[],filesSkipped:[t],packageJsonUpdated:[]};let o=resolveVersionToken(`connectPackageVersion`,e.connectPackageVersion??`0.2.2`),s=await ensurePackageDependency(join(e.projectRoot,`package.json`),`@vercel/connect`,o),c=e.slackConnectorSlug??await deriveSlackConnectorSlug(e.projectRoot);await writeTextFile(t,buildSlackTemplate(e.slackConnectorUid??`slack/${c}`),{force:e.force});let l={kind:`slack`,action:i?`overwritten`:`created`,filesWritten:[t],filesSkipped:[],packageJsonUpdated:s,slackConnectorSlug:c};return i&&(l.filesOverwritten=[t]),l}async function listAuthoredChannels(e){let t=join(e,`agent/channels`),n;try{n=await readdir(t,{withFileTypes:!0})}catch(e){if(e.code===`ENOENT`)return[];throw e}let r=[];for(let e of n){if(e.isFile()){let t=getSupportedModuleBaseName(e.name);t!==null&&r.push(t);continue}if(e.isDirectory())try{(await readdir(join(t,e.name))).some(e=>matchesSupportedModuleBaseName(e,`connection`))&&r.push(e.name)}catch{}}return r.sort()}export{DEFAULT_SLACK_CONNECTOR_SLUG,SLACK_CHANNEL_DEFAULT_ROUTE,deriveSlackConnectorSlug,ensureChannel,isNextJsProject,listAuthoredChannels,normalizeSlackConnectorSlug};
|
|
@@ -1,6 +1,17 @@
|
|
|
1
|
+
import { type NodeEngineOverride } from "../../node-engine.js";
|
|
1
2
|
export interface PackageJsonPatch {
|
|
2
3
|
dependencies?: Record<string, string>;
|
|
3
4
|
devDependencies?: Record<string, string>;
|
|
4
5
|
scripts?: Record<string, string>;
|
|
6
|
+
/**
|
|
7
|
+
* Eve's required Node.js range (e.g. `">=24"`). When the target's
|
|
8
|
+
* `engines.node` is absent or is not confined to the scaffolded major, it is
|
|
9
|
+
* set to that pinned major (e.g. `"24.x"`). Existing ranges within the same
|
|
10
|
+
* major are left untouched.
|
|
11
|
+
*/
|
|
12
|
+
nodeEngineRequirement?: string;
|
|
5
13
|
}
|
|
6
|
-
export
|
|
14
|
+
export interface PackageJsonPatchResult {
|
|
15
|
+
nodeEngineOverride?: NodeEngineOverride;
|
|
16
|
+
}
|
|
17
|
+
export declare function patchPackageJson(path: string, patch: PackageJsonPatch): Promise<PackageJsonPatchResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readFile,writeFile}from"node:fs/promises";async function patchPackageJson(
|
|
1
|
+
import{reconcileNodeEngine}from"../../node-engine.js";import{readFile,writeFile}from"node:fs/promises";function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}async function patchPackageJson(r,i){let a=await readFile(r,`utf8`),o=JSON.parse(a),s=!1,c;if(i.dependencies!==void 0&&(o.dependencies={...o.dependencies,...i.dependencies},s=!0),i.devDependencies!==void 0&&(o.devDependencies={...o.devDependencies,...i.devDependencies},s=!0),i.scripts!==void 0&&(o.scripts={...o.scripts,...i.scripts},s=!0),i.nodeEngineRequirement!==void 0){let t=isJsonObject(o.engines)?o.engines:{},n=reconcileNodeEngine(t.node,i.nodeEngineRequirement);(n.kind===`added`||n.kind===`overridden`)&&(o.engines={...t,node:n.next},s=!0),n.kind===`overridden`&&(c=n)}return s&&await writeFile(r,`${JSON.stringify(o,null,2)}\n`,`utf8`),{nodeEngineOverride:c}}export{patchPackageJson};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{dirname,join}from"node:path";import{existsSync,readFileSync,realpathSync}from"node:fs";import{fileURLToPath}from"node:url";function versionToken(e){return`__${e}_VERSION__`}const TOKEN_SOURCES={[versionToken(`EVE_PACKAGE`)]:{kind:`eve-version`},[versionToken(`AI_SDK`)]:{kind:`catalog`,packageName:`ai`},[versionToken(`VERCEL_CONNECT`)]:{kind:`catalog`,packageName:`@vercel/connect`},[versionToken(`NEXT`)]:{kind:`catalog`,packageName:`next`},[versionToken(`REACT`)]:{kind:`catalog`,packageName:`react`},[versionToken(`REACT_DOM`)]:{kind:`catalog`,packageName:`react-dom`},[versionToken(`STREAMDOWN`)]:{kind:`catalog`,packageName:`streamdown`},[versionToken(`ZOD`)]:{kind:`catalog`,packageName:`zod`},[versionToken(`TSGO`)]:{kind:`catalog`,packageName:`@typescript/native-preview`},[versionToken(`
|
|
1
|
+
import{dirname,join}from"node:path";import{existsSync,readFileSync,realpathSync}from"node:fs";import{fileURLToPath}from"node:url";function versionToken(e){return`__${e}_VERSION__`}function bareToken(e){return`__${e}__`}const NODE_ENGINE_TOKEN=bareToken(`NODE_ENGINE`),TOKEN_SOURCES={[versionToken(`EVE_PACKAGE`)]:{kind:`eve-version`},[NODE_ENGINE_TOKEN]:{kind:`eve-node-engine`},[versionToken(`AI_SDK`)]:{kind:`catalog`,packageName:`ai`},[versionToken(`VERCEL_CONNECT`)]:{kind:`catalog`,packageName:`@vercel/connect`},[versionToken(`NEXT`)]:{kind:`catalog`,packageName:`next`},[versionToken(`REACT`)]:{kind:`catalog`,packageName:`react`},[versionToken(`REACT_DOM`)]:{kind:`catalog`,packageName:`react-dom`},[versionToken(`STREAMDOWN`)]:{kind:`catalog`,packageName:`streamdown`},[versionToken(`ZOD`)]:{kind:`catalog`,packageName:`zod`},[versionToken(`TSGO`)]:{kind:`catalog`,packageName:`@typescript/native-preview`},[versionToken(`TYPES_REACT`)]:{kind:`catalog`,packageName:`@types/react`},[versionToken(`TYPES_REACT_DOM`)]:{kind:`catalog`,packageName:`@types/react-dom`}},resolvedTokens=new Map;function findEvePackageRoot(){let o=dirname(realpathSync(fileURLToPath(import.meta.url)));for(;;){let i=join(o,`package.json`);if(existsSync(i)&&JSON.parse(readFileSync(i,`utf8`)).name===`eve`)return o;let a=dirname(o);if(a===o)return;o=a}}function findWorkspaceManifest(r){let i=r;for(;;){let r=join(i,`pnpm-workspace.yaml`);if(existsSync(r))return r;let a=dirname(i);if(a===i)return;i=a}}function readCatalogVersion(e,t){let n=readFileSync(e,`utf8`).split(/\r?\n/),i=!1;for(let e of n){if(/^catalog:\s*$/.test(e)){i=!0;continue}if(!i)continue;if(/^\S/.test(e))break;let n=e.match(/^\s+(?:"([^"]+)"|([\w@/.-]+)):\s*"([^"]+)"/);if(n&&(n[1]??n[2])===t)return n[3]}}function resolveTokenFromDevTree(e){let i=TOKEN_SOURCES[e];if(i!==void 0)try{let e=findEvePackageRoot();if(e===void 0||!existsSync(join(e,`scripts/stamp-version-tokens.mjs`)))return;if(i.kind===`eve-version`){let n=JSON.parse(readFileSync(join(e,`package.json`),`utf8`));return typeof n.version==`string`?n.version:void 0}if(i.kind===`eve-node-engine`){let n=JSON.parse(readFileSync(join(e,`package.json`),`utf8`)).engines?.node;return typeof n==`string`?n:void 0}let a=findWorkspaceManifest(e);return a===void 0?void 0:readCatalogVersion(a,i.packageName)}catch{return}}function resolveVersionToken(e,t){if(!t.startsWith(`__`))return t;let n=resolvedTokens.get(t);if(n!==void 0)return n;let r=resolveTokenFromDevTree(t);if(r===void 0)throw Error(`Scaffold received unstamped version token (${e}=${t}). Build eve before using its dist entrypoint.`);return resolvedTokens.set(t,r),r}export{resolveVersionToken};
|
package/docs/getting-started.mdx
CHANGED
|
@@ -24,14 +24,14 @@ You also need a model credential. Set the provider or gateway key your model str
|
|
|
24
24
|
|
|
25
25
|
## Manual installation
|
|
26
26
|
|
|
27
|
-
The quick start uses `eve init` for a guided scaffold. The target can also be an existing project directory (`eve init .`): the project must have a `package.json`, the `agent/` files must not exist yet, and the missing `eve`, `ai`, and `zod` dependencies
|
|
27
|
+
The quick start uses `eve init` for a guided scaffold. The target can also be an existing project directory (`eve init .`): the project must have a `package.json`, the `agent/` files must not exist yet, and `eve init` adds the missing `eve`, `ai`, and `zod` dependencies. The generated Eve dependency and Node engine come from the same Eve release; the engine is the lowest complete major supported by that release (e.g. `24.x`). An existing range is kept only when every version it permits stays within that major; otherwise Eve replaces it with the pinned major and prints a warning. Either way the final handoff runs the `eve dev` binary through the project's package manager, never the project's own `dev` script.
|
|
28
28
|
|
|
29
29
|
To wire Eve into an existing app yourself instead, make sure the app declares a compatible Node runtime in `package.json`:
|
|
30
30
|
|
|
31
31
|
```json
|
|
32
32
|
{
|
|
33
33
|
"engines": {
|
|
34
|
-
"node": "
|
|
34
|
+
"node": "24.x"
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
```
|
package/docs/reference/cli.md
CHANGED
|
@@ -90,6 +90,8 @@ Pass a bare URL as the only argument and the UI connects to that server instead
|
|
|
90
90
|
| `--context-size <tokens>` | Model context window size, shown as a usage percentage |
|
|
91
91
|
| `--logs <mode>` | Server/agent logs to show: `all` \| `stderr` \| `sandbox` \| `none` |
|
|
92
92
|
|
|
93
|
+
Local dev writes the active server process ID to `.eve/dev-process.pid`. If another `eve dev` starts for the same agent while that process is still running, Eve exits with a message that includes the command to stop the existing server.
|
|
94
|
+
|
|
93
95
|
Local dev keeps immutable runtime source snapshots under `.eve/dev-runtime/snapshots/` so in-flight sessions keep a consistent code revision while new prompts pick up rebuilds. `eve dev` prunes stale runtime snapshots and old local sandbox templates in the background on startup; stopping `eve dev` and deleting `.eve/dev-runtime/snapshots/` or `.eve/sandbox-cache/local/templates/` is safe when you want a manual cleanup.
|
|
94
96
|
|
|
95
97
|
## `eve link`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eve",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Filesystem-first framework for durable backend AI agents that run anywhere.",
|
|
6
6
|
"keywords": [
|
|
@@ -265,7 +265,8 @@
|
|
|
265
265
|
},
|
|
266
266
|
"dependencies": {
|
|
267
267
|
"nitro": "3.0.260610-beta",
|
|
268
|
-
"oxc-parser": "0.134.0"
|
|
268
|
+
"oxc-parser": "0.134.0",
|
|
269
|
+
"semver": "7.8.4"
|
|
269
270
|
},
|
|
270
271
|
"devDependencies": {
|
|
271
272
|
"@ai-sdk/anthropic": "4.0.0-canary.65",
|
|
@@ -289,7 +290,7 @@
|
|
|
289
290
|
"@workflow/errors": "5.0.0-beta.7",
|
|
290
291
|
"@workflow/world": "5.0.0-beta.9",
|
|
291
292
|
"@workflow/world-local": "5.0.0-beta.16",
|
|
292
|
-
"ai": "7.0.0-
|
|
293
|
+
"ai": ">=7.0.0-beta.177",
|
|
293
294
|
"autoevals": "0.0.132",
|
|
294
295
|
"chat": "4.29.0",
|
|
295
296
|
"chokidar": "5.0.0",
|
|
@@ -317,7 +318,7 @@
|
|
|
317
318
|
"peerDependencies": {
|
|
318
319
|
"@opentelemetry/api": "^1.0.0",
|
|
319
320
|
"@sveltejs/kit": "^2.0.0",
|
|
320
|
-
"ai": "7.0.0-
|
|
321
|
+
"ai": ">=7.0.0-beta.177",
|
|
321
322
|
"braintrust": "^3.0.0",
|
|
322
323
|
"just-bash": "^3.0.0",
|
|
323
324
|
"microsandbox": "^0.5.0",
|
|
@@ -368,10 +369,11 @@
|
|
|
368
369
|
},
|
|
369
370
|
"scripts": {
|
|
370
371
|
"clean": "node -e \"fs.rmSync('dist', { recursive: true, force: true })\"",
|
|
371
|
-
"build": "pnpm run build:js && node ./scripts/copy-docs.mjs && node ./scripts/stamp-version-tokens.mjs",
|
|
372
|
+
"build": "pnpm run check:bin-runtime-dependencies && pnpm run build:js && node ./scripts/copy-docs.mjs && node ./scripts/stamp-version-tokens.mjs",
|
|
372
373
|
"build:compiled": "node ./scripts/vendor-compiled.mjs",
|
|
373
374
|
"build:js": "pnpm run build:compiled && pnpm run clean && pnpm run build:types && node ./scripts/copy-compiled-assets.mjs && node ./scripts/build-rolldown.mjs",
|
|
374
375
|
"build:types": "pnpm run build:compiled && tsgo -p tsconfig.build.json",
|
|
376
|
+
"check:bin-runtime-dependencies": "node ./scripts/check-bin-runtime-dependencies.mjs",
|
|
375
377
|
"dev": "pnpm run build:compiled && tsgo -p tsconfig.dev.json --watch --preserveWatchOutput",
|
|
376
378
|
"test": "pnpm run test:unit && pnpm run test:integration",
|
|
377
379
|
"test:integration": "pnpm run build:js && vitest run --config vitest.integration.config.ts",
|