eve 0.8.6 → 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.
Files changed (91) hide show
  1. package/CHANGELOG.md +18 -1
  2. package/bin/eve.d.ts +5 -0
  3. package/bin/eve.js +15 -13
  4. package/dist/src/cli/commands/init.js +1 -1
  5. package/dist/src/cli/dev/tui/runner.d.ts +5 -0
  6. package/dist/src/cli/dev/tui/runner.js +1 -1
  7. package/dist/src/cli/dev/tui/terminal-renderer.d.ts +1 -0
  8. package/dist/src/cli/dev/tui/terminal-renderer.js +9 -6
  9. package/dist/src/compiled/.vendor-stamp.json +2 -1
  10. package/dist/src/compiled/semver/LICENSE +15 -0
  11. package/dist/src/compiled/semver/index.d.ts +23 -0
  12. package/dist/src/compiled/semver/index.js +1 -0
  13. package/dist/src/execution/sandbox/bindings/docker-cli.d.ts +1 -1
  14. package/dist/src/execution/sandbox/bindings/docker-cli.js +1 -1
  15. package/dist/src/execution/sandbox/bindings/docker-network.js +1 -1
  16. package/dist/src/execution/sandbox/bindings/docker-options.d.ts +1 -1
  17. package/dist/src/execution/sandbox/bindings/docker-options.js +1 -1
  18. package/dist/src/execution/sandbox/bindings/docker.d.ts +1 -1
  19. package/dist/src/execution/sandbox/bindings/just-bash-runtime.js +1 -1
  20. package/dist/src/execution/sandbox/bindings/just-bash.d.ts +1 -1
  21. package/dist/src/execution/sandbox/bindings/microsandbox-options.d.ts +1 -1
  22. package/dist/src/execution/sandbox/bindings/microsandbox-platform.d.ts +1 -1
  23. package/dist/src/execution/sandbox/bindings/microsandbox-platform.js +1 -1
  24. package/dist/src/execution/sandbox/bindings/microsandbox-runtime.js +1 -1
  25. package/dist/src/execution/sandbox/bindings/microsandbox.d.ts +1 -1
  26. package/dist/src/execution/sandbox/bindings/vercel.d.ts +4 -4
  27. package/dist/src/execution/sandbox/bindings/vercel.js +1 -1
  28. package/dist/src/execution/sandbox/ensure.d.ts +1 -1
  29. package/dist/src/execution/sandbox/lazy-backend.d.ts +2 -2
  30. package/dist/src/execution/sandbox/logging-session.js +2 -1
  31. package/dist/src/internal/application/package.js +1 -1
  32. package/dist/src/internal/authored-definition/sandbox.d.ts +1 -1
  33. package/dist/src/internal/authored-definition/sandbox.js +1 -1
  34. package/dist/src/internal/nitro/host/create-application-nitro.d.ts +1 -1
  35. package/dist/src/internal/nitro/host/dev-watcher-log.d.ts +3 -0
  36. package/dist/src/internal/nitro/host/dev-watcher-log.js +1 -1
  37. package/dist/src/internal/nitro/host/start-development-server.js +2 -1
  38. package/dist/src/public/sandbox/backends/default.d.ts +10 -10
  39. package/dist/src/public/sandbox/backends/default.js +1 -1
  40. package/dist/src/public/sandbox/backends/docker.d.ts +1 -1
  41. package/dist/src/public/sandbox/backends/docker.js +1 -1
  42. package/dist/src/public/sandbox/backends/just-bash.d.ts +1 -1
  43. package/dist/src/public/sandbox/backends/just-bash.js +1 -1
  44. package/dist/src/public/sandbox/backends/microsandbox.d.ts +1 -1
  45. package/dist/src/public/sandbox/backends/microsandbox.js +1 -1
  46. package/dist/src/public/sandbox/backends/vercel.d.ts +1 -1
  47. package/dist/src/public/sandbox/backends/vercel.js +1 -1
  48. package/dist/src/public/sandbox/docker-sandbox.d.ts +2 -2
  49. package/dist/src/public/sandbox/docker.d.ts +2 -0
  50. package/dist/src/public/sandbox/docker.js +1 -0
  51. package/dist/src/public/sandbox/index.d.ts +1 -9
  52. package/dist/src/public/sandbox/index.js +1 -1
  53. package/dist/src/public/sandbox/just-bash-sandbox.d.ts +1 -1
  54. package/dist/src/public/sandbox/just-bash.d.ts +2 -0
  55. package/dist/src/public/sandbox/just-bash.js +1 -0
  56. package/dist/src/public/sandbox/microsandbox-sandbox.d.ts +1 -1
  57. package/dist/src/public/sandbox/microsandbox.d.ts +2 -0
  58. package/dist/src/public/sandbox/microsandbox.js +1 -0
  59. package/dist/src/public/sandbox/vercel-sandbox.d.ts +1 -1
  60. package/dist/src/public/sandbox/vercel.d.ts +2 -0
  61. package/dist/src/public/sandbox/vercel.js +1 -0
  62. package/dist/src/runtime/resolve-sandbox.d.ts +1 -1
  63. package/dist/src/runtime/resolve-sandbox.js +1 -1
  64. package/dist/src/runtime/sandbox/registry.d.ts +2 -2
  65. package/dist/src/runtime/sandbox/registry.js +1 -1
  66. package/dist/src/runtime/types.d.ts +2 -2
  67. package/dist/src/setup/boxes/add-channels.d.ts +4 -6
  68. package/dist/src/setup/boxes/add-channels.js +1 -1
  69. package/dist/src/setup/boxes/scaffold.d.ts +2 -2
  70. package/dist/src/setup/boxes/scaffold.js +1 -1
  71. package/dist/src/setup/node-engine.d.ts +31 -0
  72. package/dist/src/setup/node-engine.js +1 -0
  73. package/dist/src/setup/onboarding.d.ts +3 -2
  74. package/dist/src/setup/onboarding.js +1 -1
  75. package/dist/src/setup/scaffold/create/add-to-project.d.ts +10 -5
  76. package/dist/src/setup/scaffold/create/add-to-project.js +1 -1
  77. package/dist/src/setup/scaffold/create/project.d.ts +17 -4
  78. package/dist/src/setup/scaffold/create/project.js +9 -5
  79. package/dist/src/setup/scaffold/index.d.ts +1 -1
  80. package/dist/src/setup/scaffold/update/channels.d.ts +4 -2
  81. package/dist/src/setup/scaffold/update/channels.js +2 -2
  82. package/dist/src/setup/scaffold/update/package-json.d.ts +12 -1
  83. package/dist/src/setup/scaffold/update/package-json.js +1 -1
  84. package/dist/src/setup/scaffold/version-tokens.js +1 -1
  85. package/dist/src/shared/sandbox-backend.d.ts +4 -4
  86. package/dist/src/shared/sandbox-definition.d.ts +4 -4
  87. package/docs/getting-started.mdx +2 -2
  88. package/docs/guides/deployment.md +4 -3
  89. package/docs/reference/cli.md +2 -0
  90. package/docs/sandbox.mdx +21 -19
  91. package/package.json +27 -5
@@ -7,7 +7,7 @@ import type { ResolvedSandboxDefinition } from "#runtime/types.js";
7
7
  * (when present) attached from the authored module.
8
8
  *
9
9
  * If the authored module omits `backend`, the resolver substitutes
10
- * {@link defaultBackend} so the rest of the runtime can rely on a
10
+ * {@link defaultSandbox} so the rest of the runtime can rely on a
11
11
  * non-null backend value.
12
12
  */
13
13
  export declare function resolveSandboxDefinition(definition: CompiledSandboxDefinition, moduleMap: CompiledModuleMap, nodeId: string | undefined): Promise<ResolvedSandboxDefinition>;
@@ -1 +1 @@
1
- import{expectObjectRecord}from"#internal/authored-module.js";import{toErrorMessage}from"#shared/errors.js";import{lazyBackend}from"#execution/sandbox/lazy-backend.js";import{ResolveAgentError,loadResolvedModuleExport}from"#runtime/resolve-helpers.js";import{defaultBackend}from"#public/sandbox/backends/default.js";async function resolveSandboxDefinition(n,i,a){try{let t=expectObjectRecord(await loadResolvedModuleExport({definition:n,kindLabel:`sandbox`,moduleMap:i,nodeId:a}),`Expected the sandbox export "${n.exportName??`default`}" from "${n.logicalPath}" to return an object.`);return{backend:resolveBackend(t.backend,n.logicalPath),bootstrap:t.bootstrap,description:n.description,exportName:n.exportName,logicalPath:n.logicalPath,onSession:t.onSession,revalidationKey:n.revalidationKey,sourceHash:n.sourceHash,sourceId:n.sourceId,sourceKind:`module`}}catch(e){throw e instanceof ResolveAgentError?e:new ResolveAgentError(`Failed to attach the sandbox lifecycle handlers from "${n.logicalPath}": ${toErrorMessage(e)}`,{logicalPath:n.logicalPath,sourceId:n.sourceId})}}function resolveBackend(e,t){if(e===void 0)return defaultBackend();if(typeof e==`function`)return lazyBackend(e);if(typeof e!=`object`||!e)throw new ResolveAgentError(`Sandbox "${t}" exposed a non-object "backend" field. Use dockerBackend(), vercelSandboxBackend(), another factory that returns a SandboxBackend value, or a zero-arg callback returning one.`,{logicalPath:t});let r=e;if(typeof r.name!=`string`||r.name.length===0)throw new ResolveAgentError(`Sandbox "${t}" backend is missing a non-empty string "name" identifier.`,{logicalPath:t});if(typeof r.create!=`function`)throw new ResolveAgentError(`Sandbox "${t}" backend is missing a "create" function.`,{logicalPath:t});return r}export{resolveSandboxDefinition};
1
+ import{expectObjectRecord}from"#internal/authored-module.js";import{toErrorMessage}from"#shared/errors.js";import{lazyBackend}from"#execution/sandbox/lazy-backend.js";import{ResolveAgentError,loadResolvedModuleExport}from"#runtime/resolve-helpers.js";import{defaultSandbox}from"#public/sandbox/backends/default.js";async function resolveSandboxDefinition(n,i,a){try{let t=expectObjectRecord(await loadResolvedModuleExport({definition:n,kindLabel:`sandbox`,moduleMap:i,nodeId:a}),`Expected the sandbox export "${n.exportName??`default`}" from "${n.logicalPath}" to return an object.`);return{backend:resolveBackend(t.backend,n.logicalPath),bootstrap:t.bootstrap,description:n.description,exportName:n.exportName,logicalPath:n.logicalPath,onSession:t.onSession,revalidationKey:n.revalidationKey,sourceHash:n.sourceHash,sourceId:n.sourceId,sourceKind:`module`}}catch(e){throw e instanceof ResolveAgentError?e:new ResolveAgentError(`Failed to attach the sandbox lifecycle handlers from "${n.logicalPath}": ${toErrorMessage(e)}`,{logicalPath:n.logicalPath,sourceId:n.sourceId})}}function resolveBackend(e,t){if(e===void 0)return defaultSandbox();if(typeof e==`function`)return lazyBackend(e);if(typeof e!=`object`||!e)throw new ResolveAgentError(`Sandbox "${t}" exposed a non-object "backend" field. Use docker(), vercel(), another factory that returns a SandboxBackend value, or a zero-arg callback returning one.`,{logicalPath:t});let r=e;if(typeof r.name!=`string`||r.name.length===0)throw new ResolveAgentError(`Sandbox "${t}" backend is missing a non-empty string "name" identifier.`,{logicalPath:t});if(typeof r.create!=`function`)throw new ResolveAgentError(`Sandbox "${t}" backend is missing a "create" function.`,{logicalPath:t});return r}export{resolveSandboxDefinition};
@@ -51,9 +51,9 @@ export declare function createRuntimeSandboxRegistry(input: {
51
51
  * Builds the framework default sandbox definition used when no agent
52
52
  * authored override is present.
53
53
  *
54
- * The `backend` is resolved through {@link defaultBackend} on each
54
+ * The `backend` is resolved through {@link defaultSandbox} on each
55
55
  * call so the framework default picks up the same environment-aware
56
- * fallback as authored sandboxes that omit `backend` (`vercelSandboxBackend()`
56
+ * fallback as authored sandboxes that omit `backend` (`vercel()`
57
57
  * on hosted Vercel, then Docker, microsandbox, or just-bash by availability). Implemented as
58
58
  * a factory rather than a constant so the environment is read at
59
59
  * graph-resolution time rather than at module-load time.
@@ -1 +1 @@
1
- import{defaultBackend}from"#public/sandbox/backends/default.js";const DEFAULT_SANDBOX_SOURCE_ID=`eve:default-sandbox`;function createRuntimeSandboxRegistry(e){return{sandbox:{definition:e.authoredSandbox??createFrameworkSandboxDefinition(),workspaceResourceRoot:e.workspaceResourceRoot}}}function createFrameworkSandboxDefinition(){return{backend:defaultBackend(),logicalPath:`eve:framework/default-sandbox`,sourceId:DEFAULT_SANDBOX_SOURCE_ID,sourceKind:`module`}}export{DEFAULT_SANDBOX_SOURCE_ID,createFrameworkSandboxDefinition,createRuntimeSandboxRegistry};
1
+ import{defaultSandbox}from"#public/sandbox/backends/default.js";const DEFAULT_SANDBOX_SOURCE_ID=`eve:default-sandbox`;function createRuntimeSandboxRegistry(e){return{sandbox:{definition:e.authoredSandbox??createFrameworkSandboxDefinition(),workspaceResourceRoot:e.workspaceResourceRoot}}}function createFrameworkSandboxDefinition(){return{backend:defaultSandbox(),logicalPath:`eve:framework/default-sandbox`,sourceId:DEFAULT_SANDBOX_SOURCE_ID,sourceKind:`module`}}export{DEFAULT_SANDBOX_SOURCE_ID,createFrameworkSandboxDefinition,createRuntimeSandboxRegistry};
@@ -96,8 +96,8 @@ export interface ResolvedConnectionDefinition extends ResolvedModuleSourceRef {
96
96
  * The resolved `backend` is non-optional: every sandbox in the runtime
97
97
  * graph carries a concrete SandboxBackend value, even when the
98
98
  * authored definition omits `backend`. The unauthored case is filled
99
- * in by `defaultBackend()` (which itself selects between
100
- * `vercelSandboxBackend()`, `dockerBackend()`, `microsandboxBackend()`, and `justBashBackend()` based on the current
99
+ * in by `defaultSandbox()` (which itself selects between
100
+ * `vercel()`, `docker()`, `microsandbox()`, and `justbash()` based on the current
101
101
  * environment).
102
102
  */
103
103
  export type ResolvedSandboxDefinition = ResolvedModuleSourceRef & {
@@ -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
- * The `eve` dependency version for the scaffolded web `package.json`. When
39
- * omitted (the `eve channels add` composition), `ensureChannel` receives no
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
- evePackageVersion?: string;
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.evePackageVersion!==void 0&&(o.webPackageVersions={evePackageVersion:l.evePackageVersion});let s=await u.ensureChannel(o);if(a?.throwIfAborted(),warnOverwrittenFiles(e,s.filesOverwritten),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(`
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
- evePackageVersion: string;
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}`),evePackageVersion:i.evePackageVersion});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};
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
- /** The `eve` dependency version baked into the scaffolded `package.json`. */
45
- evePackageVersion: string;
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,evePackageVersion:r.evePackageVersion,targetDirectory:r.targetDirectory,overwriteExisting:r.overwriteExisting,headless:r.headless}),...[detectAiGateway(),linkVercelProject({prompter:r.prompter}),applyAiGatewayCredential({prompter:r.prompter}),addChannels({asker:a,prompter:r.prompter,evePackageVersion:r.evePackageVersion,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
+ 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
- evePackageVersion?: string;
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
- * the runtime dependencies the project does not already declare, and applies
23
- * the selected package manager's project configuration. The host project owns
24
- * everything else (tsconfig, scripts, ignore files), so this mode never
25
- * touches it. All conflicts are gathered and reported before anything is written.
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=resolveVersionToken(`evePackageVersion`,i.evePackageVersion??`0.8.6`),l=resolveVersionToken(`aiPackageVersion`,i.aiPackageVersion??`7.0.0-canary.171`),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),zod:d},h={};for(let[e,t]of Object.entries(m))hasDeclaredDependency(p,e)||(h[e]=t);return Object.keys(h).length>0&&await patchPackageJson(a,{dependencies:h}),await getPackageManagerStrategy(i.packageManager??`pnpm`).applyProjectConfiguration(i.projectRoot),{filesWritten:f,dependenciesAdded:Object.keys(h).sort()}}export{addAgentToProject};
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
- evePackageVersion?: string;
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. Adds `@types/node` to the project so `process` is typed.
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`]),DEFAULT_EVE_PACKAGE_VERSION=`0.8.6`,DEFAULT_AI_PACKAGE_VERSION=`7.0.0-canary.171`,DEFAULT_CONNECT_PACKAGE_VERSION=`0.2.2`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`;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.evePackageVersion)).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.typesNodePackageVersion)}function formatEveDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}const BASE_AGENT_TEMPLATE=`import { defineAgent } from "eve";
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(e){return`{
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
- ${e?` "@types/node": "__EVE_INIT_TYPES_NODE_VERSION__",
28
- "@typescript/native-preview": "__EVE_INIT_TSGO_VERSION__"`:` "@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(t),...getPackageManagerStrategy(n).scaffoldFiles}}async function assertCanCreateInPlace(e,n){if(!await pathExists(e))return;let r=(await readdir(e)).filter(e=>!ALLOWED_CREATE_IN_PLACE_ENTRIES.has(e));if(r.length>0&&!n){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 i=resolve(e.targetDirectory??process.cwd(),e.projectName),a=e.projectName===`.`,s=e.overwriteExisting??!1,u=e.byokProvider??!1,d=e.packageManager??`pnpm`;if(a)await assertCanCreateInPlace(i,s);else if(await pathExists(i))throw Error(`Cannot create project because "${i}" already exists.`);let f=e.typesNodePackageVersion??`25.9.1`,p={appName:basename(i),model:e.model,evePackageVersion:resolveVersionToken(`evePackageVersion`,e.evePackageVersion??`0.8.6`),aiPackageVersion:resolveVersionToken(`aiPackageVersion`,e.aiPackageVersion??`7.0.0-canary.171`),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`),typesNodePackageVersion:u?resolveVersionToken(`typesNodePackageVersion`,f):f};await mkdir(i,{recursive:!0});for(let[r,o]of Object.entries(templateFiles(u,d))){let c=`${i}/${r}`,l=await pathExists(c);await writeTextFile(c,renderTemplate(o,p),{force:a&&s}),l&&await e.onOverwriteFile?.(c)}return i}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_VERSION,DEFAULT_ZOD_PACKAGE_VERSION,agentTemplateFiles,byokProviderEnvVar,formatEveDependencySpecifier,isEveProject,modelProviderSlug,scaffoldBaseProject};
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
- evePackageVersion?: string;
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,n){if(!await pathExists(e))return!1;let r=JSON.parse(await readFile(e,`utf8`));return isJsonObject(r)&&packageJsonHasDependency(r,n)}async function isNextJsProject(e){return hasPackageDependency(join(e,`package.json`),`next`)}async function ensurePackageDependency(e,n,i){return!await pathExists(e)||await readDependencyVersion(e,n)===i?[]:(await patchPackageJson(e,{dependencies:{[n]:i}}),[{path:e,dependencies:[n],devDependencies:[],scripts:[]}])}function resolveWebPackageVersions(e){return{evePackageVersion:e?.evePackageVersion??`0.8.6`,aiPackageVersion:e?.aiPackageVersion??`7.0.0-canary.171`,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`,typesNodePackageVersion:e?.typesNodePackageVersion??`25.9.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,n){if(!await pathExists(e))return[];let a={...WEB_APP_TEMPLATE_PACKAGE_JSON.dependencies,ai:resolveVersionToken(`aiPackageVersion`,n.aiPackageVersion),eve:formatEveDependencySpecifier(resolveVersionToken(`evePackageVersion`,n.evePackageVersion)),next:resolveVersionToken(`nextPackageVersion`,n.nextPackageVersion),react:resolveVersionToken(`reactPackageVersion`,n.reactPackageVersion),"react-dom":resolveVersionToken(`reactDomPackageVersion`,n.reactDomPackageVersion),streamdown:resolveVersionToken(`streamdownPackageVersion`,n.streamdownPackageVersion),zod:resolveVersionToken(`zodPackageVersion`,n.zodPackageVersion)},o={...WEB_APP_TEMPLATE_PACKAGE_JSON.devDependencies,"@types/node":resolveVersionToken(`typesNodePackageVersion`,n.typesNodePackageVersion),"@types/react":resolveVersionToken(`typesReactPackageVersion`,n.typesReactPackageVersion),"@types/react-dom":resolveVersionToken(`typesReactDomPackageVersion`,n.typesReactDomPackageVersion),"@typescript/native-preview":resolveVersionToken(`tsgoPackageVersion`,n.tsgoPackageVersion)},s=WEB_APP_TEMPLATE_PACKAGE_JSON.scripts;return await patchPackageJson(e,{dependencies:a,devDependencies:o,scripts:s}),[{path:e,dependencies:Object.keys(a),devDependencies:Object.keys(o),scripts:Object.keys(s)}]}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";
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 r=await readFile(e,`utf8`),i=withWebVercelServices(r);return i===r?`skipped`:(await writeFile(e,i,`utf8`),`written`)}async function findCompetingNextConfigFiles(e){let n=[];for(let r of WEB_COMPETING_NEXT_CONFIG_PATHS){let i=join(e,r);await pathExists(i)&&n.push(i)}return n}async function ensureChannel(e){switch(e.kind){case`slack`:return ensureSlackChannel({...e,kind:`slack`});case`web`:return ensureWebChannel({...e,kind:`web`})}}async function ensureWebChannel(r){let i=join(r.projectRoot,`package.json`),a=await pathExists(join(r.projectRoot,`app/page.tsx`));if(!r.force&&await isNextJsProject(r.projectRoot))return{kind:`web`,action:`skipped`,skipReason:`nextjs-project`,filesWritten:[],filesSkipped:[i],packageJsonUpdated:[]};let o=await patchWebPackageJson(i,resolveWebPackageVersions(r.webPackageVersions)),c=[],u=[],d=[],f=[],p=basename(resolve(r.projectRoot)),m=r.configureVercelServices??!0;if(m){let e=join(r.projectRoot,WEB_VERCEL_JSON_PATH);await ensureWebVercelServices(e)===`written`?c.push(e):f.push(e)}let h=await getPackageManagerStrategy(r.packageManager??`pnpm`).applyProjectConfiguration(r.projectRoot);c.push(...h.filesWritten),f.push(...h.filesSkipped);for(let[e,i]of Object.entries(WEB_APP_TEMPLATE_FILES)){let a=join(r.projectRoot,e);if(e===`agent/channels/eve.ts`&&!r.force&&await pathExists(a)){f.push(a);continue}let o=await pathExists(a);await writeTextFile(a,renderWebAppTemplate(i,p,m),{force:!0}),c.push(a),o&&u.push(a)}d.push(...await findCompetingNextConfigFiles(r.projectRoot));let g={kind:`web`,action:a?`overwritten`:`created`,filesWritten:c,filesSkipped:f,packageJsonUpdated:o};return u.length>0&&(g.filesOverwritten=u),d.length>0&&(g.competingNextConfigFiles=d),g}async function ensureSlackChannel(e){let r=join(e.projectRoot,`agent/channels/slack.ts`),a=await pathExists(r);if(!e.force&&a)return{kind:`slack`,action:`skipped`,filesWritten:[],filesSkipped:[r],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(r,buildSlackTemplate(e.slackConnectorUid??`slack/${c}`),{force:e.force});let l={kind:`slack`,action:a?`overwritten`:`created`,filesWritten:[r],filesSkipped:[],packageJsonUpdated:s,slackConnectorSlug:c};return a&&(l.filesOverwritten=[r]),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};
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 declare function patchPackageJson(path: string, patch: PackageJsonPatch): Promise<void>;
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(e,t){let n=await readFile(e,`utf8`),r=JSON.parse(n);t.dependencies!==void 0&&(r.dependencies={...r.dependencies,...t.dependencies}),t.devDependencies!==void 0&&(r.devDependencies={...r.devDependencies,...t.devDependencies}),t.scripts!==void 0&&(r.scripts={...r.scripts,...t.scripts}),await writeFile(e,`${JSON.stringify(r,null,2)}\n`,`utf8`)}export{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(`TYPES_NODE`)]:{kind:`catalog`,packageName:`@types/node`},[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}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};
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};
@@ -114,10 +114,10 @@ export interface SandboxBackendPrewarmResult {
114
114
  *
115
115
  * A `SandboxBackend` is a value an author attaches to a
116
116
  * {@link SandboxDefinition} to choose which underlying runtime hosts the
117
- * sandbox. Eve ships built-in backends (`dockerBackend()`,
118
- * `justBashBackend()`, `microsandboxBackend()`,
119
- * `vercelSandboxBackend()`, and the availability-aware
120
- * `defaultBackend()`), but the interface is public so authors can write
117
+ * sandbox. Eve ships built-in backends (`docker()`,
118
+ * `justbash()`, `microsandbox()`,
119
+ * `vercel()`, and the availability-aware
120
+ * `defaultSandbox()`), but the interface is public so authors can write
121
121
  * their own.
122
122
  *
123
123
  * A backend implements the full two-phase lifecycle:
@@ -48,7 +48,7 @@ export type SandboxRevalidationKeyFn = () => Promise<string> | string;
48
48
  *
49
49
  * Each agent (and each subagent) owns exactly one sandbox. When the
50
50
  * module file is absent the framework auto-provides a default sandbox
51
- * via `defaultBackend()`. Authors override lifecycle and backend by
51
+ * via `defaultSandbox()`. Authors override lifecycle and backend by
52
52
  * creating `agent/sandbox.ts` (or `agent/sandbox/sandbox.ts` when they
53
53
  * also want a workspace folder); subagents override independently via
54
54
  * `subagents/<name>/sandbox.ts` (or the folder form) and do not inherit
@@ -69,12 +69,12 @@ interface SandboxDefinitionBase<BO = Record<string, never>, SO = Record<string,
69
69
  *
70
70
  * ```ts
71
71
  * defineSandbox({
72
- * backend: () => vercelSandboxBackend({ env: { TOKEN: process.env.TOKEN ?? "" } }),
72
+ * backend: () => vercel({ env: { TOKEN: process.env.TOKEN ?? "" } }),
73
73
  * });
74
74
  * ```
75
75
  *
76
- * When this field is omitted, Eve substitutes `defaultBackend()` at
77
- * runtime, which picks the best available backend: `vercelSandboxBackend()`
76
+ * When this field is omitted, Eve substitutes `defaultSandbox()` at
77
+ * runtime, which picks the best available backend: `vercel()`
78
78
  * on hosted Vercel (where `process.env.VERCEL` is set), then Docker,
79
79
  * microsandbox, or just-bash
80
80
  * everywhere else. Set `backend` explicitly to pin the sandbox to a
@@ -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 are added without touching anything else the project owns. Either way the final handoff runs the `eve dev` binary through the project's package manager, never the project's own `dev` script.
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": ">=24"
34
+ "node": "24.x"
35
35
  }
36
36
  }
37
37
  ```