eve 0.9.1 → 0.9.2

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 (94) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/bin/eve.js +1 -0
  3. package/dist/src/cli/agent-detection.d.ts +8 -0
  4. package/dist/src/cli/agent-detection.js +1 -0
  5. package/dist/src/cli/commands/agent-instructions.d.ts +7 -0
  6. package/dist/src/cli/commands/agent-instructions.js +1 -0
  7. package/dist/src/cli/commands/init-agent-handoff.md +12 -0
  8. package/dist/src/cli/commands/init-agent-instructions.md +16 -0
  9. package/dist/src/cli/commands/init-git.js +1 -1
  10. package/dist/src/cli/commands/init.d.ts +8 -1
  11. package/dist/src/cli/commands/init.js +1 -1
  12. package/dist/src/cli/dev/environment.js +1 -1
  13. package/dist/src/cli/dev/tui/blocks.d.ts +8 -0
  14. package/dist/src/cli/dev/tui/blocks.js +2 -2
  15. package/dist/src/cli/dev/tui/command-typeahead.js +1 -1
  16. package/dist/src/cli/dev/tui/prompt-commands.d.ts +1 -1
  17. package/dist/src/cli/dev/tui/prompt-commands.js +1 -1
  18. package/dist/src/cli/dev/tui/runner.d.ts +5 -0
  19. package/dist/src/cli/dev/tui/runner.js +1 -1
  20. package/dist/src/cli/dev/tui/setup-commands.d.ts +4 -0
  21. package/dist/src/cli/dev/tui/setup-commands.js +2 -2
  22. package/dist/src/cli/dev/tui/setup-issues.d.ts +15 -0
  23. package/dist/src/cli/dev/tui/setup-issues.js +1 -1
  24. package/dist/src/cli/dev/tui/terminal-renderer.d.ts +7 -2
  25. package/dist/src/cli/dev/tui/terminal-renderer.js +9 -9
  26. package/dist/src/cli/run.js +1 -1
  27. package/dist/src/compiled/.vendor-stamp.json +2 -1
  28. package/dist/src/compiled/@vercel/detect-agent/LICENSE +202 -0
  29. package/dist/src/compiled/@vercel/detect-agent/index.d.ts +20 -0
  30. package/dist/src/compiled/@vercel/detect-agent/index.js +1 -0
  31. package/dist/src/execution/sandbox/bindings/docker-templates.js +1 -1
  32. package/dist/src/execution/sandbox/bindings/just-bash.js +1 -1
  33. package/dist/src/execution/sandbox/bindings/microsandbox-templates.js +1 -1
  34. package/dist/src/internal/application/compiled-artifacts.js +1 -1
  35. package/dist/src/internal/application/optional-package-install.js +1 -1
  36. package/dist/src/internal/application/package.js +1 -1
  37. package/dist/src/internal/application/paths.js +1 -1
  38. package/dist/src/internal/application/tsconfig-dependencies.js +1 -1
  39. package/dist/src/internal/authored-module-loader.js +2 -2
  40. package/dist/src/internal/bundler/nitro-rolldown.d.ts +3 -0
  41. package/dist/src/internal/bundler/nitro-rolldown.js +1 -1
  42. package/dist/src/internal/nitro/dev-runtime-artifacts.js +1 -1
  43. package/dist/src/internal/nitro/dev-runtime-source-snapshot-copy.js +1 -1
  44. package/dist/src/internal/nitro/dev-runtime-source-snapshot.js +1 -1
  45. package/dist/src/internal/nitro/host/dev-authored-source-watcher.js +1 -1
  46. package/dist/src/internal/nitro/host/start-development-server.d.ts +1 -2
  47. package/dist/src/internal/nitro/host/start-development-server.js +2 -2
  48. package/dist/src/internal/nitro/host/start-production-server.js +2 -2
  49. package/dist/src/internal/process/pnpm.js +1 -1
  50. package/dist/src/internal/workflow-bundle/builder-support.js +2 -2
  51. package/dist/src/internal/workflow-bundle/dynamic-tool-transform.js +1 -1
  52. package/dist/src/internal/workflow-bundle/workflow-builders.js +1 -1
  53. package/dist/src/internal/workflow-bundle/workflow-transformer.js +3 -3
  54. package/dist/src/public/next/server.js +1 -1
  55. package/dist/src/setup/boxes/add-channels.js +1 -1
  56. package/dist/src/setup/boxes/apply-ai-gateway-credential.js +1 -1
  57. package/dist/src/setup/boxes/link-project.js +1 -1
  58. package/dist/src/setup/boxes/resolve-provisioning.js +1 -1
  59. package/dist/src/setup/flows/channels.d.ts +2 -0
  60. package/dist/src/setup/flows/channels.js +1 -1
  61. package/dist/src/setup/flows/deploy.js +1 -1
  62. package/dist/src/setup/flows/install-vercel-cli.d.ts +42 -0
  63. package/dist/src/setup/flows/install-vercel-cli.js +1 -0
  64. package/dist/src/setup/flows/link.js +1 -1
  65. package/dist/src/setup/flows/login.d.ts +49 -0
  66. package/dist/src/setup/flows/login.js +1 -0
  67. package/dist/src/setup/flows/model.js +1 -1
  68. package/dist/src/setup/flows/vercel.d.ts +2 -0
  69. package/dist/src/setup/flows/vercel.js +1 -1
  70. package/dist/src/setup/primitives/coding-agent-env.d.ts +17 -0
  71. package/dist/src/setup/primitives/coding-agent-env.js +1 -0
  72. package/dist/src/setup/primitives/pm/pnpm.js +2 -2
  73. package/dist/src/setup/primitives/pm/run.d.ts +6 -0
  74. package/dist/src/setup/primitives/pm/run.js +1 -1
  75. package/dist/src/setup/primitives/run-vercel.d.ts +1 -1
  76. package/dist/src/setup/primitives/run-vercel.js +1 -1
  77. package/dist/src/setup/scaffold/create/project.js +1 -1
  78. package/dist/src/setup/scaffold/version-tokens.js +1 -1
  79. package/dist/src/setup/slack-connect-create.d.ts +41 -0
  80. package/dist/src/setup/slack-connect-create.js +1 -0
  81. package/dist/src/setup/slack-connect-lifecycle.d.ts +40 -11
  82. package/dist/src/setup/slack-connect-lifecycle.js +1 -1
  83. package/dist/src/setup/slack-connect.d.ts +25 -14
  84. package/dist/src/setup/slack-connect.js +1 -1
  85. package/dist/src/setup/slackbot.d.ts +12 -16
  86. package/dist/src/setup/slackbot.js +1 -1
  87. package/dist/src/setup/vercel-project.d.ts +25 -0
  88. package/dist/src/setup/vercel-project.js +1 -1
  89. package/dist/src/source-change/apply-model-name.d.ts +2 -2
  90. package/dist/src/source-change/apply-model-name.js +1 -1
  91. package/dist/src/source-change/static-source-change.js +1 -1
  92. package/docs/getting-started.mdx +5 -5
  93. package/docs/guides/dev-tui.md +3 -1
  94. package/package.json +4 -4
@@ -1 +1 @@
1
- import{detectProjectResolution,mergeProjectResolution}from"../project-resolution.js";import{requireProjectPath}from"../state.js";import{linkProject,resolveProjectByNameOrId,unresolvedProject}from"../vercel-project.js";import{createPromptCommandOutput}from"#setup/cli/index.js";function linkVercelProject(o){let s=o.deps??{linkProject,detectProjectResolution,resolveProjectByNameOrId,unresolvedProject};return{id:`link-project`,shouldRun(e){return e.vercelProject.kind!==`none`},async gather(){return null},async perform({state:e,signal:t}){let r=e.vercelProject;if(r.kind===`none`)return s.unresolvedProject();let i=requireProjectPath(e),a=createPromptCommandOutput(o.prompter.log),c=t===void 0?await s.linkProject(o.prompter,i,r,a):await s.linkProject(o.prompter,i,r,a,{signal:t});if(t?.throwIfAborted(),!c)throw Error("Vercel project provisioning did not complete. Run `vercel link` manually, or re-run and choose not to deploy to Vercel.");let l=t===void 0?await s.detectProjectResolution(i):await s.detectProjectResolution(i,{signal:t});if(l.kind===`unresolved`)throw Error(`Linked the directory, but could not resolve the Vercel project from .vercel/project.json.`);let u=t===void 0?await s.resolveProjectByNameOrId(i,r.team,r.project):await s.resolveProjectByNameOrId(i,r.team,r.project,{signal:t});if(u===null||l.projectId!==u.id)throw Error(`Linked project identity did not match the planned Vercel project "${r.project}".`);return l},apply(e,n){return{...e,project:mergeProjectResolution(e.project,n)}}}}export{linkVercelProject};
1
+ import{detectProjectResolution,mergeProjectResolution}from"../project-resolution.js";import{requireProjectPath}from"../state.js";import{linkProject,resolveProjectByNameOrId,unresolvedProject}from"../vercel-project.js";import{createPromptCommandOutput}from"#setup/cli/index.js";function linkVercelProject(o){let s=o.deps??{linkProject,detectProjectResolution,resolveProjectByNameOrId,unresolvedProject};return{id:`link-project`,shouldRun(e){return e.vercelProject.kind!==`none`},async gather(){return null},async perform({state:e,signal:t}){let r=e.vercelProject;if(r.kind===`none`)return s.unresolvedProject();let i=requireProjectPath(e),a=createPromptCommandOutput(o.prompter.log),c=await s.linkProject(o.prompter,i,r,a,{signal:t});if(t?.throwIfAborted(),!c)throw Error("Vercel project provisioning did not complete. Run `vercel link` manually, or re-run and choose not to deploy to Vercel.");let l=await s.detectProjectResolution(i,{signal:t});if(l.kind===`unresolved`)throw Error(`Linked the directory, but could not resolve the Vercel project from .vercel/project.json.`);let u=await s.resolveProjectByNameOrId(i,r.team,r.project,{signal:t});if(u===null||l.projectId!==u.id)throw Error(`Linked project identity did not match the planned Vercel project "${r.project}".`);return l},apply(e,n){return{...e,project:mergeProjectResolution(e.project,n)}}}}export{linkVercelProject};
@@ -1 +1 @@
1
- import{select,text}from"../ask.js";import{detectProjectResolution,isProjectResolved,mergeProjectResolution}from"../project-resolution.js";import{assertNewProjectNameAvailable,isVercelAuthenticated,pickNewProjectName,pickProject,pickTeam,requireAuth,resolveTeam,validateTeam,withNetworkSpinner}from"../vercel-project.js";import{pathExists}from"../path-exists.js";import{join,resolve}from"node:path";import{byokProviderEnvVar}from"#setup/scaffold/index.js";import{whimsyFor}from"#setup/cli/index.js";function vercelDemands(e){return{slack:e.channelSelection.includes(`slack`),connectSlugs:e.connectionSelection.filter(e=>e.entry.auth?.kind===`connect`).map(e=>e.slug)}}function connectClause(e){let t=e.length===1?`authenticates`:`authenticate`;return`${e.join(`, `)} ${t} through Vercel Connect`}function vercelRequirements(e){let t=[];return e.slack&&t.push(`Slack needs a public URL`),e.connectSlugs.length>0&&t.push(connectClause(e.connectSlugs)),t}function resolveProvisioning(l){let u=l.deps??{requireAuth,isVercelAuthenticated,detectProjectResolution,pathExists,validateTeam,resolveTeam,pickTeam,pickProject,pickNewProjectName,assertNewProjectNameAvailable},parent=()=>resolve(l.targetDirectory??process.cwd());async function detectAdoptableLink(e,t){if(e.projectPath.kind!==`resolved`)return;let n=e.projectPath.path;if(await u.pathExists(join(n,`.vercel`,`project.json`)))return withNetworkSpinner(l.prompter,whimsyFor(`project-detect`),async()=>{let e=t===void 0?await u.detectProjectResolution(n):await u.detectProjectResolution(n,{signal:t});if(!(!isProjectResolved(e)||!(t===void 0?await u.isVercelAuthenticated(n):await u.isVercelAuthenticated(n,{signal:t}))))return e})}async function plansFromFlags(e,t,n,r){if(t.skipVercel)return n.apiKey===void 0?{vercelProject:{kind:`none`},aiGateway:{kind:`byop`},modelWiring:`self`}:{vercelProject:{kind:`none`},aiGateway:{kind:`byok`,apiGatewayKey:n.apiKey},modelWiring:`gateway`};if(t.team===void 0||t.team.length===0)throw Error(`Headless Vercel provisioning requires --team <slug> or --scope <slug> so the current CLI scope is not applied silently.`);r===void 0?(await u.requireAuth(parent()),await u.validateTeam(l.prompter,parent(),t.team)):(await u.requireAuth(parent(),void 0,{signal:r}),await u.validateTeam(l.prompter,parent(),t.team,{signal:r}));let i=r===void 0?await u.resolveTeam(parent(),t.team):await u.resolveTeam(parent(),t.team,{signal:r}),a=n.apiKey===void 0?{kind:`inherit`}:{kind:`byok`,apiGatewayKey:n.apiKey},o=t.project===void 0?{kind:`new`,project:e,team:i}:{kind:`existing`,project:t.project,team:i};return o.kind===`new`&&(r===void 0?await u.assertNewProjectNameAvailable(parent(),i,o.project):await u.assertNewProjectNameAvailable(parent(),i,o.project,{signal:r})),{vercelProject:o,aiGateway:a,modelWiring:`gateway`}}async function promptPlans(n,r){let i=l.prompter,a=n.agentName,o=l.adoptExistingLink===!1?void 0:await detectAdoptableLink(n,r);if(o!==void 0)return i.log.info(`This directory is already linked to a Vercel project, so your agent will run there — the AI Gateway authenticates through your Vercel login.`),{vercelProject:{kind:`none`},aiGateway:{kind:`inherit`},modelWiring:`gateway`,project:o};let s=vercelRequirements(vercelDemands(n)),c=!0;if(s.length>0?i.log.info(`${s.join(` and `)}, so your agent will run on Vercel.`):c=await l.asker.ask(select({key:`deploy`,message:`Where should your agent run?`,options:[{id:`vercel`,value:!0,label:`On Vercel`,hint:`AI Gateway, Durable Workflow, Sandbox, and more`},{id:`local`,value:!1,label:`Locally for now`,hint:`run with eve dev, deploy any time later`}],recommended:!0,required:!0})),c){r===void 0?await u.requireAuth(parent(),i):await u.requireAuth(parent(),i,{signal:r});let t=r===void 0?await u.pickTeam(i,parent(),void 0):await u.pickTeam(i,parent(),void 0,{signal:r}),n=[{value:`new`,label:`Create a new project`,hint:`Named ${a}`},{value:`link`,label:`Link an existing project`}],o=l.projectSelection!==`existing-only`&&l.prompter.selectEditable?await l.prompter.selectEditable({message:`Vercel project`,options:n,initialValue:`new`,editable:{value:`new`,defaultValue:a,formatHint:e=>`Named ${e}`,validate:e=>e.trim().length===0?`Project name cannot be empty.`:void 0}}):void 0;if((l.projectSelection===`existing-only`?`link`:o?.value??await l.asker.ask(select({key:`vercel-project`,message:`Vercel project`,options:[{id:`new`,value:`new`,label:`Create a new project`,hint:`Named ${a}`},{id:`link`,value:`link`,label:`Link an existing project`}],recommended:`new`,required:!0})))===`new`){let e=o?.kind===`edited`?o.text:a;return{vercelProject:{kind:`new`,project:r===void 0?await u.pickNewProjectName(i,parent(),t,e):await u.pickNewProjectName(i,parent(),t,e,{signal:r}),team:t},aiGateway:{kind:`inherit`},modelWiring:`gateway`}}let s=r===void 0?await u.pickProject(i,parent(),t,{allowCreateWhenEmpty:l.projectSelection!==`existing-only`}):await u.pickProject(i,parent(),t,{allowCreateWhenEmpty:l.projectSelection!==`existing-only`,signal:r});return{vercelProject:{kind:s.exists?`existing`:`new`,project:s.project,team:t},aiGateway:{kind:`inherit`},modelWiring:`gateway`}}return await l.asker.ask(select({key:`credential`,message:`How should your agent reach the model?`,options:[{id:`api-key`,value:`api-key`,label:`Use my own AI Gateway API key`,hint:`AI_GATEWAY_API_KEY`},{id:`local`,value:`local`,label:`Use my own provider API key`,hint:byokProviderEnvVar(n.modelId)}],recommended:`api-key`,required:!0}))===`api-key`?{vercelProject:{kind:`none`},aiGateway:{kind:`byok`,apiGatewayKey:await l.asker.ask(text({key:`gateway-api-key`,message:`Enter your AI_GATEWAY_API_KEY`,sensitive:!0,validate:e=>e.trim().length===0?`API key cannot be empty.`:null,required:!0}))},modelWiring:`gateway`}:{vercelProject:{kind:`none`},aiGateway:{kind:`byop`},modelWiring:`self`}}return{id:`resolve-provisioning`,async gather({state:e,signal:t}){if(l.mode.headless){let n=await plansFromFlags(e.agentName,l.mode.project,l.mode.aiGateway,t);if(n.vercelProject.kind===`none`){let t=vercelDemands(e);if(t.slack)throw Error(`Slack requires a Vercel project. Remove --skip-vercel to add Slack.`);if(t.connectSlugs.length>0)throw Error(`${connectClause(t.connectSlugs)}, which needs a Vercel project. Remove --skip-vercel to add ${t.connectSlugs.length===1?`it`:`them`}.`)}return n}return promptPlans(e,t)},async perform({input:e}){return e},apply(e,t){return{...e,vercelProject:t.vercelProject,aiGateway:t.aiGateway,modelWiring:t.modelWiring,project:t.project===void 0?e.project:mergeProjectResolution(e.project,t.project)}}}}export{resolveProvisioning};
1
+ import{select,text}from"../ask.js";import{detectProjectResolution,isProjectResolved,mergeProjectResolution}from"../project-resolution.js";import{assertNewProjectNameAvailable,isVercelAuthenticated,pickNewProjectName,pickProject,pickTeam,requireAuth,resolveTeam,validateTeam,withNetworkSpinner}from"../vercel-project.js";import{pathExists}from"../path-exists.js";import{join,resolve}from"node:path";import{byokProviderEnvVar}from"#setup/scaffold/index.js";import{whimsyFor}from"#setup/cli/index.js";function vercelDemands(e){return{slack:e.channelSelection.includes(`slack`),connectSlugs:e.connectionSelection.filter(e=>e.entry.auth?.kind===`connect`).map(e=>e.slug)}}function connectClause(e){let t=e.length===1?`authenticates`:`authenticate`;return`${e.join(`, `)} ${t} through Vercel Connect`}function vercelRequirements(e){let t=[];return e.slack&&t.push(`Slack needs a public URL`),e.connectSlugs.length>0&&t.push(connectClause(e.connectSlugs)),t}function resolveProvisioning(l){let u=l.deps??{requireAuth,isVercelAuthenticated,detectProjectResolution,pathExists,validateTeam,resolveTeam,pickTeam,pickProject,pickNewProjectName,assertNewProjectNameAvailable},parent=()=>resolve(l.targetDirectory??process.cwd());async function detectAdoptableLink(e,t){if(e.projectPath.kind!==`resolved`)return;let n=e.projectPath.path;if(await u.pathExists(join(n,`.vercel`,`project.json`)))return withNetworkSpinner(l.prompter,whimsyFor(`project-detect`),async()=>{let e=await u.detectProjectResolution(n,{signal:t});if(!(!isProjectResolved(e)||!await u.isVercelAuthenticated(n,{signal:t})))return e})}async function plansFromFlags(e,t,n,r){if(t.skipVercel)return n.apiKey===void 0?{vercelProject:{kind:`none`},aiGateway:{kind:`byop`},modelWiring:`self`}:{vercelProject:{kind:`none`},aiGateway:{kind:`byok`,apiGatewayKey:n.apiKey},modelWiring:`gateway`};if(t.team===void 0||t.team.length===0)throw Error(`Headless Vercel provisioning requires --team <slug> or --scope <slug> so the current CLI scope is not applied silently.`);await u.requireAuth(parent(),void 0,{signal:r}),await u.validateTeam(l.prompter,parent(),t.team,{signal:r});let i=await u.resolveTeam(parent(),t.team,{signal:r}),a=n.apiKey===void 0?{kind:`inherit`}:{kind:`byok`,apiGatewayKey:n.apiKey},o=t.project===void 0?{kind:`new`,project:e,team:i}:{kind:`existing`,project:t.project,team:i};return o.kind===`new`&&await u.assertNewProjectNameAvailable(parent(),i,o.project,{signal:r}),{vercelProject:o,aiGateway:a,modelWiring:`gateway`}}async function promptPlans(n,r){let i=l.prompter,a=n.agentName,o=l.adoptExistingLink===!1?void 0:await detectAdoptableLink(n,r);if(o!==void 0)return i.log.info(`This directory is already linked to a Vercel project, so your agent will run there — the AI Gateway authenticates through your Vercel login.`),{vercelProject:{kind:`none`},aiGateway:{kind:`inherit`},modelWiring:`gateway`,project:o};let s=vercelRequirements(vercelDemands(n)),c=!0;if(s.length>0?i.log.info(`${s.join(` and `)}, so your agent will run on Vercel.`):c=await l.asker.ask(select({key:`deploy`,message:`Where should your agent run?`,options:[{id:`vercel`,value:!0,label:`On Vercel`,hint:`AI Gateway, Durable Workflow, Sandbox, and more`},{id:`local`,value:!1,label:`Locally for now`,hint:`run with eve dev, deploy any time later`}],recommended:!0,required:!0})),c){await u.requireAuth(parent(),i,{signal:r});let t=await u.pickTeam(i,parent(),void 0,{signal:r}),n=[{value:`new`,label:`Create a new project`,hint:`Named ${a}`},{value:`link`,label:`Link an existing project`}],o=l.projectSelection!==`existing-only`&&l.prompter.selectEditable?await l.prompter.selectEditable({message:`Vercel project`,options:n,initialValue:`new`,editable:{value:`new`,defaultValue:a,formatHint:e=>`Named ${e}`,validate:e=>e.trim().length===0?`Project name cannot be empty.`:void 0}}):void 0;if((l.projectSelection===`existing-only`?`link`:o?.value??await l.asker.ask(select({key:`vercel-project`,message:`Vercel project`,options:[{id:`new`,value:`new`,label:`Create a new project`,hint:`Named ${a}`},{id:`link`,value:`link`,label:`Link an existing project`}],recommended:`new`,required:!0})))===`new`){let e=o?.kind===`edited`?o.text:a;return{vercelProject:{kind:`new`,project:await u.pickNewProjectName(i,parent(),t,e,{signal:r}),team:t},aiGateway:{kind:`inherit`},modelWiring:`gateway`}}let s=await u.pickProject(i,parent(),t,{allowCreateWhenEmpty:l.projectSelection!==`existing-only`,signal:r});return{vercelProject:{kind:s.exists?`existing`:`new`,project:s.project,team:t},aiGateway:{kind:`inherit`},modelWiring:`gateway`}}return await l.asker.ask(select({key:`credential`,message:`How should your agent reach the model?`,options:[{id:`api-key`,value:`api-key`,label:`Use my own AI Gateway API key`,hint:`AI_GATEWAY_API_KEY`},{id:`local`,value:`local`,label:`Use my own provider API key`,hint:byokProviderEnvVar(n.modelId)}],recommended:`api-key`,required:!0}))===`api-key`?{vercelProject:{kind:`none`},aiGateway:{kind:`byok`,apiGatewayKey:await l.asker.ask(text({key:`gateway-api-key`,message:`Enter your AI_GATEWAY_API_KEY`,sensitive:!0,validate:e=>e.trim().length===0?`API key cannot be empty.`:null,required:!0}))},modelWiring:`gateway`}:{vercelProject:{kind:`none`},aiGateway:{kind:`byop`},modelWiring:`self`}}return{id:`resolve-provisioning`,async gather({state:e,signal:t}){if(l.mode.headless){let n=await plansFromFlags(e.agentName,l.mode.project,l.mode.aiGateway,t);if(n.vercelProject.kind===`none`){let t=vercelDemands(e);if(t.slack)throw Error(`Slack requires a Vercel project. Remove --skip-vercel to add Slack.`);if(t.connectSlugs.length>0)throw Error(`${connectClause(t.connectSlugs)}, which needs a Vercel project. Remove --skip-vercel to add ${t.connectSlugs.length===1?`it`:`them`}.`)}return n}return promptPlans(e,t)},async perform({input:e}){return e},apply(e,t){return{...e,vercelProject:t.vercelProject,aiGateway:t.aiGateway,modelWiring:t.modelWiring,project:t.project===void 0?e.project:mergeProjectResolution(e.project,t.project)}}}}export{resolveProvisioning};
@@ -2,10 +2,12 @@ import { type AddChannelsDeps } from "../boxes/add-channels.js";
2
2
  import { inspectExistingChannelRegistrations } from "../channel-add-conflicts.js";
3
3
  import { detectDeployment } from "../project-resolution.js";
4
4
  import type { Prompter } from "../prompter.js";
5
+ import { getVercelAuthStatus } from "../vercel-project.js";
5
6
  /** Injected for tests; defaults to the real detection and box effects. */
6
7
  export interface ChannelsFlowDeps {
7
8
  detectDeployment: typeof detectDeployment;
8
9
  inspectExistingChannelRegistrations: typeof inspectExistingChannelRegistrations;
10
+ getVercelAuthStatus: typeof getVercelAuthStatus;
9
11
  addChannels?: AddChannelsDeps;
10
12
  }
11
13
  export type ChannelsFlowResult = {
@@ -1 +1 @@
1
- import{interactiveAsker}from"../ask.js";import{detectDeployment,isProjectResolved,projectResolutionFromDeployment}from"../project-resolution.js";import{createDefaultSetupState,snapshotSetupState}from"../state.js";import{WizardCancelledError}from"../step.js";import{addChannels}from"../boxes/add-channels.js";import{CHANNELS_PROMPT_MESSAGE,selectChannels}from"../boxes/select-channels.js";import{assertCanAddSelectedChannels,inspectExistingChannelRegistrations}from"../channel-add-conflicts.js";import{runInteractive}from"../runner.js";import{prompterSink}from"./in-project.js";import{SCAFFOLDABLE_CHANNELS}from"#setup/scaffold/index.js";import{toErrorMessage}from"#shared/errors.js";const SEE_IT_LIVE_MESSAGE=`See it live`;async function promptSeeItLive(e){try{return await e.select({message:SEE_IT_LIVE_MESSAGE,options:[{value:`deploy`,label:`Deploy and chat`},{value:`later`,label:`Later`}]})}catch(e){if(e instanceof WizardCancelledError)return`later`;throw e}}function channelAlreadyAdded(e,t){return t===`web`?e.webAppPresent:e.slackOwners.length>0}function appendChannel(e,t){return e.includes(t)?[...e]:[...e,t]}async function pickChannel(e,t,n){let r=channelListRows(t,n),i=!r.some(e=>e.value!==`done`&&e.completed!==!0&&e.disabled!==!0),a={message:CHANNELS_PROMPT_MESSAGE,options:r,hintLayout:`inline`};i&&(a.initialValue=`done`);try{return{kind:`picked`,value:await e.select(a)}}catch(e){if(e instanceof WizardCancelledError)return{kind:`cancelled`};throw e}}function channelLandedDuringSubflow(e,t,n){return!channelAlreadyAdded(e,n)&&channelAlreadyAdded(t,n)}function deployAndChatDetails(e){let t={};return e.slackChatUrl!==void 0&&(t.chatUrl=e.slackChatUrl),e.slackWorkspaceName!==void 0&&(t.workspaceName=e.slackWorkspaceName),t}function channelListRows(e,t){let n=[{value:`repl`,label:`Terminal UI`,completed:!0,focusHint:`Already installed`}];for(let r of SCAFFOLDABLE_CHANNELS){if(channelAlreadyAdded(e,r.kind)){n.push({value:r.kind,label:r.label,completed:!0,focusHint:`Already installed`});continue}let i=e.disabledChannelReasons[r.kind];if(i!==void 0){n.push({value:r.kind,label:r.label,disabled:!0,disabledReason:i});continue}if(r.requiresVercelProject===!0&&!t){n.push({value:r.kind,label:r.label,disabled:!0,disabledReason:`Requires Vercel account, see /model`,disabledReasonTone:`warning`});continue}let a={value:r.kind,label:r.label};r.hint!==void 0&&(a.hint=r.hint),n.push(a)}return n.push({value:`done`,label:`Done`}),n}async function runChannelsFlow(o){let{appRoot:s,prompter:c,signal:l}=o,u={detectDeployment,inspectExistingChannelRegistrations,...o.deps};async function checkProject(e){let t=c.log.spinner?.(`Checking the project…`);try{return await e()}finally{t?.stop()}}let[d,f]=await checkProject(()=>Promise.all([l===void 0?u.detectDeployment(s):u.detectDeployment(s,{signal:l}),u.inspectExistingChannelRegistrations(s)]));l?.throwIfAborted();let p=f,m={...createDefaultSetupState(),project:projectResolutionFromDeployment(d),projectPath:{kind:`resolved`,inPlace:!0,path:s}},h;for(;;){let t=await pickChannel(c,p,isProjectResolved(m.project));if(t.kind===`cancelled`){if(m.channels.length===0)return{kind:`cancelled`};break}let r=t.value;if(r===`done`)break;if(r===`repl`||channelAlreadyAdded(p,r))continue;let i=[selectChannels({asker:interactiveAsker(c),variant:`channels-add`,presetChannels:[r],validateSelection:e=>assertCanAddSelectedChannels(e,p)}),addChannels({asker:interactiveAsker(c),prompter:c,configureVercelServices:!0,deps:u.addChannels})],o;try{o=await runInteractive(i,m,prompterSink(c),{snapshot:snapshotSetupState,signal:l})}catch(e){let t=await checkProject(()=>u.inspectExistingChannelRegistrations(s));if(channelLandedDuringSubflow(p,t,r)){if(m={...m,channels:appendChannel(m.channels,r)},p=t,h=toErrorMessage(e),l?.aborted===!0)break;continue}throw e}if(o.kind===`done`){if(m=o.state,p=await checkProject(()=>u.inspectExistingChannelRegistrations(s)),l?.throwIfAborted(),r===`slack`&&m.slackbotAttached&&await promptSeeItLive(c)===`deploy`)return{kind:`deploy-and-chat`,addedChannels:m.channels,chat:deployAndChatDetails(m)}}else{let e=await checkProject(()=>u.inspectExistingChannelRegistrations(s));if(channelLandedDuringSubflow(p,e,r))return{kind:`done`,addedChannels:appendChannel(m.channels,r)};p=e}}return h===void 0?{kind:`done`,addedChannels:m.channels}:{kind:`failed`,addedChannels:m.channels,message:h}}export{SEE_IT_LIVE_MESSAGE,runChannelsFlow};
1
+ import{interactiveAsker}from"../ask.js";import{detectDeployment,isProjectResolved,projectResolutionFromDeployment}from"../project-resolution.js";import{createDefaultSetupState,snapshotSetupState}from"../state.js";import{WizardCancelledError}from"../step.js";import{addChannels}from"../boxes/add-channels.js";import{getVercelAuthStatus}from"../vercel-project.js";import{CHANNELS_PROMPT_MESSAGE,selectChannels}from"../boxes/select-channels.js";import{assertCanAddSelectedChannels,inspectExistingChannelRegistrations}from"../channel-add-conflicts.js";import{runInteractive}from"../runner.js";import{prompterSink}from"./in-project.js";import{SCAFFOLDABLE_CHANNELS}from"#setup/scaffold/index.js";import{toErrorMessage}from"#shared/errors.js";const SEE_IT_LIVE_MESSAGE=`See it live`;async function promptSeeItLive(e){try{return await e.select({message:SEE_IT_LIVE_MESSAGE,options:[{value:`deploy`,label:`Deploy and chat`},{value:`later`,label:`Later`}]})}catch(e){if(e instanceof WizardCancelledError)return`later`;throw e}}function channelAlreadyAdded(e,t){return t===`web`?e.webAppPresent:e.slackOwners.length>0}function appendChannel(e,t){return e.includes(t)?[...e]:[...e,t]}async function pickChannel(e,t,n,r){let i=channelListRows(t,n,r),a=!i.some(e=>e.value!==`done`&&e.completed!==!0&&e.disabled!==!0),s={message:CHANNELS_PROMPT_MESSAGE,options:i,hintLayout:`inline`};a&&(s.initialValue=`done`);try{return{kind:`picked`,value:await e.select(s)}}catch(e){if(e instanceof WizardCancelledError)return{kind:`cancelled`};throw e}}function channelLandedDuringSubflow(e,t,n){return!channelAlreadyAdded(e,n)&&channelAlreadyAdded(t,n)}function deployAndChatDetails(e){let t={};return e.slackChatUrl!==void 0&&(t.chatUrl=e.slackChatUrl),e.slackWorkspaceName!==void 0&&(t.workspaceName=e.slackWorkspaceName),t}function vercelChannelBlocker(e,t){if(e===`cli-missing`)return`Vercel CLI not found, see /vc`;if(e===`logged-out`)return`Log in to Vercel first, see /login`;if(e===`unavailable`)return`Couldn't reach Vercel, check your connection`;if(!t)return`Requires Vercel account, see /model`}function channelListRows(e,t,n){let r=[{value:`repl`,label:`Terminal UI`,completed:!0,focusHint:`Already installed`}];for(let i of SCAFFOLDABLE_CHANNELS){if(channelAlreadyAdded(e,i.kind)){r.push({value:i.kind,label:i.label,completed:!0,focusHint:`Already installed`});continue}let a=e.disabledChannelReasons[i.kind];if(a!==void 0){r.push({value:i.kind,label:i.label,disabled:!0,disabledReason:a});continue}if(i.requiresVercelProject===!0){let e=vercelChannelBlocker(n,t);if(e!==void 0){r.push({value:i.kind,label:i.label,disabled:!0,disabledReason:e,disabledReasonTone:`warning`});continue}}let o={value:i.kind,label:i.label};i.hint!==void 0&&(o.hint=i.hint),r.push(o)}return r.push({value:`done`,label:`Done`}),r}async function runChannelsFlow(o){let{appRoot:c,prompter:l,signal:u}=o,d={detectDeployment,inspectExistingChannelRegistrations,getVercelAuthStatus,...o.deps};async function checkProject(e){let t=l.log.spinner?.(`Checking the project…`);try{return await e()}finally{t?.stop()}}let[f,p,m]=await checkProject(()=>Promise.all([d.detectDeployment(c,{signal:u}),d.inspectExistingChannelRegistrations(c),d.getVercelAuthStatus(c,{signal:u})]));u?.throwIfAborted();let h=p,g={...createDefaultSetupState(),project:projectResolutionFromDeployment(f),projectPath:{kind:`resolved`,inPlace:!0,path:c}},_;for(;;){let t=await pickChannel(l,h,isProjectResolved(g.project),m);if(t.kind===`cancelled`){if(g.channels.length===0)return{kind:`cancelled`};break}let r=t.value;if(r===`done`)break;if(r===`repl`||channelAlreadyAdded(h,r))continue;let i=[selectChannels({asker:interactiveAsker(l),variant:`channels-add`,presetChannels:[r],validateSelection:e=>assertCanAddSelectedChannels(e,h)}),addChannels({asker:interactiveAsker(l),prompter:l,configureVercelServices:!0,deps:d.addChannels})],o;try{o=await runInteractive(i,g,prompterSink(l),{snapshot:snapshotSetupState,signal:u})}catch(e){let t=await checkProject(()=>d.inspectExistingChannelRegistrations(c));if(channelLandedDuringSubflow(h,t,r)){if(g={...g,channels:appendChannel(g.channels,r)},h=t,_=toErrorMessage(e),u?.aborted===!0)break;continue}throw e}if(o.kind===`done`){if(g=o.state,h=await checkProject(()=>d.inspectExistingChannelRegistrations(c)),u?.throwIfAborted(),r===`slack`&&g.slackbotAttached&&await promptSeeItLive(l)===`deploy`)return{kind:`deploy-and-chat`,addedChannels:g.channels,chat:deployAndChatDetails(g)}}else{let e=await checkProject(()=>d.inspectExistingChannelRegistrations(c));if(channelLandedDuringSubflow(h,e,r))return{kind:`done`,addedChannels:appendChannel(g.channels,r)};h=e}}return _===void 0?{kind:`done`,addedChannels:g.channels}:{kind:`failed`,addedChannels:g.channels,message:_}}export{SEE_IT_LIVE_MESSAGE,runChannelsFlow};
@@ -1 +1 @@
1
- import{interactiveAsker,withAnswers}from"../ask.js";import{detectDeployment,isProjectResolved,projectResolutionFromDeployment}from"../project-resolution.js";import{snapshotSetupState}from"../state.js";import{deployProject}from"../boxes/deploy-project.js";import{linkVercelProject}from"../boxes/link-project.js";import{resolveProvisioning}from"../boxes/resolve-provisioning.js";import{runHeadless,runInteractive}from"../runner.js";import{inProjectSetupState,prompterSink}from"./in-project.js";function productionUrlOf(e){return e.kind===`deployed`?e.productionUrl:void 0}async function runDeployFlow(t){let{appRoot:n,prompter:r,interactive:i,signal:a}=t,o={detectDeployment,...t.deps},s=r.log.spinner?.(`Checking the current Vercel link...`),c;try{let e=a===void 0?await o.detectDeployment(n):await o.detectDeployment(n,{signal:a});a?.throwIfAborted(),c=projectResolutionFromDeployment(e)}finally{s?.stop()}let l=isProjectResolved(c);if(!l&&!i)return{kind:`needs-link`};let u=inProjectSetupState(n,c,{deploymentPending:!0}),d=l?[deployProject({prompter:r,headless:!i,deps:o.deployProject})]:[resolveProvisioning({asker:withAnswers({deploy:`vercel`})(interactiveAsker(r)),prompter:r,targetDirectory:n,mode:{headless:!1},deps:o.resolveProvisioning}),linkVercelProject({prompter:r,deps:o.linkProject}),deployProject({prompter:r,headless:!i,deps:o.deployProject})],f=prompterSink(r);if(!i)return{kind:`deployed`,productionUrl:productionUrlOf((await runHeadless(d,u,f,{snapshot:snapshotSetupState,signal:a})).project)};let p=await runInteractive(d,u,f,{snapshot:snapshotSetupState,signal:a});return p.kind===`cancelled`?{kind:`cancelled`}:{kind:`deployed`,productionUrl:productionUrlOf(p.state.project)}}export{runDeployFlow};
1
+ import{interactiveAsker,withAnswers}from"../ask.js";import{detectDeployment,isProjectResolved,projectResolutionFromDeployment}from"../project-resolution.js";import{snapshotSetupState}from"../state.js";import{deployProject}from"../boxes/deploy-project.js";import{linkVercelProject}from"../boxes/link-project.js";import{resolveProvisioning}from"../boxes/resolve-provisioning.js";import{runHeadless,runInteractive}from"../runner.js";import{inProjectSetupState,prompterSink}from"./in-project.js";function productionUrlOf(e){return e.kind===`deployed`?e.productionUrl:void 0}async function runDeployFlow(t){let{appRoot:n,prompter:r,interactive:i,signal:a}=t,o={detectDeployment,...t.deps},s=r.log.spinner?.(`Checking the current Vercel link...`),c;try{let e=await o.detectDeployment(n,{signal:a});a?.throwIfAborted(),c=projectResolutionFromDeployment(e)}finally{s?.stop()}let l=isProjectResolved(c);if(!l&&!i)return{kind:`needs-link`};let u=inProjectSetupState(n,c,{deploymentPending:!0}),d=l?[deployProject({prompter:r,headless:!i,deps:o.deployProject})]:[resolveProvisioning({asker:withAnswers({deploy:`vercel`})(interactiveAsker(r)),prompter:r,targetDirectory:n,mode:{headless:!1},deps:o.resolveProvisioning}),linkVercelProject({prompter:r,deps:o.linkProject}),deployProject({prompter:r,headless:!i,deps:o.deployProject})],f=prompterSink(r);if(!i)return{kind:`deployed`,productionUrl:productionUrlOf((await runHeadless(d,u,f,{snapshot:snapshotSetupState,signal:a})).project)};let p=await runInteractive(d,u,f,{snapshot:snapshotSetupState,signal:a});return p.kind===`cancelled`?{kind:`cancelled`}:{kind:`deployed`,productionUrl:productionUrlOf(p.state.project)}}export{runDeployFlow};
@@ -0,0 +1,42 @@
1
+ import { detectPackageManager } from "#setup/package-manager.js";
2
+ import { spawnPackageManager } from "#setup/primitives/index.js";
3
+ import { getVercelAuthStatus } from "#setup/vercel-project.js";
4
+ import type { Prompter } from "../prompter.js";
5
+ export type InstallVercelCliResult =
6
+ /** The CLI is already resolvable; nothing to do. */
7
+ {
8
+ kind: "already";
9
+ }
10
+ /** The package manager installed it and it now resolves. */
11
+ | {
12
+ kind: "installed";
13
+ }
14
+ /** The install exited non-zero, or the CLI still isn't on PATH afterward. */
15
+ | {
16
+ kind: "failed";
17
+ }
18
+ /** The user interrupted (Ctrl-C / Esc) before the install finished. */
19
+ | {
20
+ kind: "cancelled";
21
+ };
22
+ /** Injected for tests; defaults to the real probe, detection, and install. */
23
+ export interface InstallVercelCliDeps {
24
+ getVercelAuthStatus: typeof getVercelAuthStatus;
25
+ detectPackageManager: typeof detectPackageManager;
26
+ spawnPackageManager: typeof spawnPackageManager;
27
+ }
28
+ /**
29
+ * THE INSTALL FLOW for the dev TUI's `/vc`: the fix command for the
30
+ * "Vercel CLI not found" diagnostic, so every diagnostic has a matching
31
+ * command. Short-circuits when the CLI already resolves; otherwise runs a
32
+ * global install with the project's package manager, streaming output to the
33
+ * rail, then re-probes. A global install can exit clean yet leave the binary
34
+ * off PATH (pnpm/yarn global bins commonly aren't), so success is confirmed by
35
+ * the re-probe, not the exit code alone.
36
+ */
37
+ export declare function runInstallVercelCliFlow(input: {
38
+ appRoot: string;
39
+ prompter: Prompter;
40
+ signal?: AbortSignal;
41
+ deps?: Partial<InstallVercelCliDeps>;
42
+ }): Promise<InstallVercelCliResult>;
@@ -0,0 +1 @@
1
+ import{detectPackageManager}from"#setup/package-manager.js";import{spawnPackageManager}from"#setup/primitives/index.js";import{getVercelAuthStatus}from"#setup/vercel-project.js";import{createPromptCommandOutput}from"#setup/cli/index.js";const defaultDeps={getVercelAuthStatus,detectPackageManager,spawnPackageManager};function globalInstallArguments(e){switch(e){case`npm`:return[`install`,`-g`,`vercel@latest`];case`yarn`:return[`global`,`add`,`vercel@latest`];case`pnpm`:case`bun`:return[`add`,`-g`,`vercel@latest`]}}async function withSpinner(e,t,n){let r=e.log.spinner?.(t);try{return await n()}finally{r?.stop()}}async function runInstallVercelCliFlow(e){let{appRoot:t,prompter:n,signal:i}=e,a={...defaultDeps,...e.deps},o=createPromptCommandOutput(n.log),probe=async()=>await a.getVercelAuthStatus(t,{signal:i})!==`cli-missing`;if(await withSpinner(n,`Checking for the Vercel CLI…`,probe))return i?.throwIfAborted(),{kind:`already`};i?.throwIfAborted();let s=await a.detectPackageManager(t),c=await withSpinner(n,`Installing the Vercel CLI with ${s.kind}…`,()=>a.spawnPackageManager(s.kind,t,globalInstallArguments(s.kind),{onOutput:o,signal:i,nonInteractive:!0}));if(i?.aborted===!0)return{kind:`cancelled`};if(!c)return{kind:`failed`};let l=await withSpinner(n,`Verifying the Vercel CLI…`,probe);return i?.throwIfAborted(),l?{kind:`installed`}:{kind:`failed`}}export{runInstallVercelCliFlow};
@@ -1 +1 @@
1
- import{__toESM}from"../../_virtual/_rolldown/runtime.js";import{require_picocolors}from"../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js";import{interactiveAsker,withAnswers}from"../ask.js";import{detectProjectIdentity}from"../project-resolution.js";import{snapshotSetupState}from"../state.js";import{WizardCancelledError}from"../step.js";import{detectAiGateway,findEnvFileWithKey}from"../boxes/detect-ai-gateway.js";import{applyAiGatewayCredential}from"../boxes/apply-ai-gateway-credential.js";import{linkVercelProject}from"../boxes/link-project.js";import{resolveProvisioning}from"../boxes/resolve-provisioning.js";import{runInteractive}from"../runner.js";import{inProjectSetupState,prompterSink}from"./in-project.js";var import_picocolors=__toESM(require_picocolors(),1);async function runLinkFlow(e){let{appRoot:t,prompter:i,signal:a,projectSelection:o=`existing-only`}=e,s={detectProjectIdentity,findEnvFileWithKey,...e.deps},c=i.log.spinner?.(`Checking the current Vercel link...`),l;try{l=a===void 0?await s.detectProjectIdentity(t):await s.detectProjectIdentity(t,{signal:a}),a?.throwIfAborted()}finally{c?.stop()}if(l===void 0){let[e,n]=await Promise.all([s.findEnvFileWithKey(t,`AI_GATEWAY_API_KEY`),s.findEnvFileWithKey(t,`VERCEL_OIDC_TOKEN`)]),r=e??n;r!==void 0&&i.log.message(`This directory is not linked to a Vercel project yet — the model currently runs on credentials from ${r}.`)}else{let e=l.teamName===void 0?import_picocolors.default.bold(l.projectName):`${import_picocolors.default.bold(l.projectName)} in ${import_picocolors.default.bold(l.teamName)}`;try{if(await i.select({message:`This directory is already linked to\n${e}`,options:[{value:`relink`,label:`Link to another project`},{value:`dismiss`,label:`Dismiss`}]})===`dismiss`)return{kind:`cancelled`}}catch(e){if(e instanceof WizardCancelledError)return{kind:`cancelled`};throw e}}let u=inProjectSetupState(t,{kind:`unresolved`});if((await runInteractive([resolveProvisioning({asker:withAnswers({deploy:`vercel`})(interactiveAsker(i)),prompter:i,targetDirectory:t,mode:{headless:!1},adoptExistingLink:!1,projectSelection:o,deps:s.resolveProvisioning}),linkVercelProject({prompter:i,deps:s.linkProject}),detectAiGateway(),applyAiGatewayCredential({prompter:i,deps:s.applyAiGatewayCredential})],u,prompterSink(i),{snapshot:snapshotSetupState,signal:a})).kind===`cancelled`)return{kind:`cancelled`};let[d,f]=await Promise.all([s.findEnvFileWithKey(t,`VERCEL_OIDC_TOKEN`),s.findEnvFileWithKey(t,`AI_GATEWAY_API_KEY`)]);a?.throwIfAborted(),d===void 0&&f===void 0&&i.log.warning("Linked, but no model credential landed in an env file (VERCEL_OIDC_TOKEN or AI_GATEWAY_API_KEY). Run `vercel env pull` once the project has AI Gateway access.");let p={kind:`done`};return d===void 0?f!==void 0&&(p.credential=`AI_GATEWAY_API_KEY`):p.credential=`VERCEL_OIDC_TOKEN`,p}export{runLinkFlow};
1
+ import{__toESM}from"../../_virtual/_rolldown/runtime.js";import{require_picocolors}from"../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js";import{interactiveAsker,withAnswers}from"../ask.js";import{detectProjectIdentity}from"../project-resolution.js";import{snapshotSetupState}from"../state.js";import{WizardCancelledError}from"../step.js";import{detectAiGateway,findEnvFileWithKey}from"../boxes/detect-ai-gateway.js";import{applyAiGatewayCredential}from"../boxes/apply-ai-gateway-credential.js";import{linkVercelProject}from"../boxes/link-project.js";import{resolveProvisioning}from"../boxes/resolve-provisioning.js";import{runInteractive}from"../runner.js";import{inProjectSetupState,prompterSink}from"./in-project.js";var import_picocolors=__toESM(require_picocolors(),1);async function runLinkFlow(e){let{appRoot:t,prompter:i,signal:a,projectSelection:o=`existing-only`}=e,s={detectProjectIdentity,findEnvFileWithKey,...e.deps},c=i.log.spinner?.(`Checking the current Vercel link...`),l;try{l=await s.detectProjectIdentity(t,{signal:a}),a?.throwIfAborted()}finally{c?.stop()}if(l===void 0){let[e,n]=await Promise.all([s.findEnvFileWithKey(t,`AI_GATEWAY_API_KEY`),s.findEnvFileWithKey(t,`VERCEL_OIDC_TOKEN`)]),r=e??n;r!==void 0&&i.log.message(`This directory is not linked to a Vercel project yet — the model currently runs on credentials from ${r}.`)}else{let e=l.teamName===void 0?import_picocolors.default.bold(l.projectName):`${import_picocolors.default.bold(l.projectName)} in ${import_picocolors.default.bold(l.teamName)}`;try{if(await i.select({message:`This directory is already linked to\n${e}`,options:[{value:`relink`,label:`Link to another project`},{value:`dismiss`,label:`Dismiss`}]})===`dismiss`)return{kind:`cancelled`}}catch(e){if(e instanceof WizardCancelledError)return{kind:`cancelled`};throw e}}let u=inProjectSetupState(t,{kind:`unresolved`});if((await runInteractive([resolveProvisioning({asker:withAnswers({deploy:`vercel`})(interactiveAsker(i)),prompter:i,targetDirectory:t,mode:{headless:!1},adoptExistingLink:!1,projectSelection:o,deps:s.resolveProvisioning}),linkVercelProject({prompter:i,deps:s.linkProject}),detectAiGateway(),applyAiGatewayCredential({prompter:i,deps:s.applyAiGatewayCredential})],u,prompterSink(i),{snapshot:snapshotSetupState,signal:a})).kind===`cancelled`)return{kind:`cancelled`};let[d,f]=await Promise.all([s.findEnvFileWithKey(t,`VERCEL_OIDC_TOKEN`),s.findEnvFileWithKey(t,`AI_GATEWAY_API_KEY`)]);a?.throwIfAborted(),d===void 0&&f===void 0&&i.log.warning("Linked, but no model credential landed in an env file (VERCEL_OIDC_TOKEN or AI_GATEWAY_API_KEY). Run `vercel env pull` once the project has AI Gateway access.");let p={kind:`done`};return d===void 0?f!==void 0&&(p.credential=`AI_GATEWAY_API_KEY`):p.credential=`VERCEL_OIDC_TOKEN`,p}export{runLinkFlow};
@@ -0,0 +1,49 @@
1
+ import { createPromptCommandOutput } from "#setup/cli/index.js";
2
+ import { getVercelAuthStatus } from "#setup/vercel-project.js";
3
+ import type { Prompter } from "../prompter.js";
4
+ export type LoginFlowResult =
5
+ /** A `vercel whoami` already succeeds; nothing to do. */
6
+ {
7
+ kind: "already";
8
+ }
9
+ /** `vercel login` ran and the directory is now authenticated. */
10
+ | {
11
+ kind: "logged-in";
12
+ }
13
+ /** `vercel login` exited without leaving an authenticated session. */
14
+ | {
15
+ kind: "failed";
16
+ }
17
+ /** The Vercel CLI is not installed, so login cannot start. */
18
+ | {
19
+ kind: "cli-missing";
20
+ }
21
+ /** Vercel could not be reached, so login state could not be determined. */
22
+ | {
23
+ kind: "unavailable";
24
+ }
25
+ /** The user stopped waiting (Cancel / Esc) before login completed. */
26
+ | {
27
+ kind: "cancelled";
28
+ };
29
+ /** Injected for tests; defaults to the real auth probe and `vercel login`. */
30
+ export interface LoginFlowDeps {
31
+ getVercelAuthStatus: typeof getVercelAuthStatus;
32
+ runVercelLogin: (input: {
33
+ cwd: string;
34
+ onOutput: ReturnType<typeof createPromptCommandOutput>;
35
+ signal?: AbortSignal;
36
+ }) => Promise<boolean>;
37
+ }
38
+ /**
39
+ * THE LOGIN FLOW for the dev TUI's `/login`. Short-circuits when already
40
+ * authenticated; otherwise runs `vercel login` as a browser flow the TUI waits
41
+ * on (see {@link runVercelLoginWithControls}) and re-probes after, so a
42
+ * half-finished or abandoned login reports `failed`, never a false success.
43
+ */
44
+ export declare function runLoginFlow(input: {
45
+ appRoot: string;
46
+ prompter: Prompter;
47
+ signal?: AbortSignal;
48
+ deps?: Partial<LoginFlowDeps>;
49
+ }): Promise<LoginFlowResult>;
@@ -0,0 +1 @@
1
+ import{getVercelAuthStatus}from"#setup/vercel-project.js";import{createPromptCommandOutput}from"#setup/cli/index.js";import{runVercel}from"#setup/primitives/run-vercel.js";const defaultDeps={getVercelAuthStatus,runVercelLogin:({cwd:e,onOutput:t,signal:r})=>runVercel([`login`],{cwd:e,nonInteractive:!0,onOutput:t,timeoutMs:3e5,signal:r})};async function withSpinner(e,t,n){let r=e.log.spinner?.(t);try{return await n()}finally{r?.stop()}}async function runVercelLoginWithControls(e,t,n,r,i){if(r.awaitChoice===void 0)return withSpinner(r,`Opening Vercel login in your browser…`,()=>e.runVercelLogin({cwd:t,onOutput:n,signal:i}));let a=new AbortController,o=i?AbortSignal.any([i,a.signal]):a.signal,s=r.awaitChoice({status:`Logging in to Vercel…`,context:`Complete the login in your browser`,actions:[{value:`cancel`,label:`Cancel`}]}),c=e.runVercelLogin({cwd:t,onOutput:n,signal:o});try{let e=await Promise.race([c.then(e=>({via:`work`,ok:e})),s.choice.then(()=>({via:`choice`}))]);return e.via===`work`?e.ok:(a.abort(),await c.catch(()=>{}),`cancelled`)}finally{s.close()}}async function runLoginFlow(e){let{appRoot:n,prompter:i,signal:a}=e,o={...defaultDeps,...e.deps},s=createPromptCommandOutput(i.log),probeAuth=()=>o.getVercelAuthStatus(n,{signal:a}),c=await withSpinner(i,`Checking your Vercel login…`,probeAuth);switch(a?.throwIfAborted(),c){case`authenticated`:return{kind:`already`};case`cli-missing`:return{kind:`cli-missing`};case`unavailable`:return{kind:`unavailable`};case`logged-out`:break;default:return c}let l=await runVercelLoginWithControls(o,n,s,i,a);if(l===`cancelled`)return{kind:`cancelled`};if(!l)return{kind:`failed`};let u=await withSpinner(i,`Confirming your Vercel login…`,probeAuth);switch(a?.throwIfAborted(),u){case`authenticated`:return{kind:`logged-in`};case`logged-out`:return{kind:`failed`};case`cli-missing`:return{kind:`cli-missing`};case`unavailable`:return{kind:`unavailable`};default:return u}}export{runLoginFlow};
@@ -1 +1 @@
1
- import{__toESM}from"../../_virtual/_rolldown/runtime.js";import{require_picocolors}from"../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js";import{interactiveAsker}from"../ask.js";import{detectProjectIdentity}from"../project-resolution.js";import{snapshotSetupState}from"../state.js";import{WizardCancelledError}from"../step.js";import{findEnvFileWithKey}from"../boxes/detect-ai-gateway.js";import{fetchGatewayCatalog,selectModel}from"../boxes/select-model.js";import{runInteractive}from"../runner.js";import{inProjectSetupState,prompterSink}from"./in-project.js";import{runVercelFlow}from"./vercel.js";import{join}from"node:path";import{discoverAgent}from"#discover/discover-agent.js";import{inspectApplication}from"#services/inspect-application.js";import{formatLanguageModelGatewayId}from"#internal/runtime-model.js";import{createCompiledRuntimeModelCatalogLoader}from"#compiler/model-catalog.js";import{createStaticSourceChange}from"#source-change/static-source-change.js";var import_picocolors=__toESM(require_picocolors(),1);const MODEL_MENU_MESSAGE=``;function providerStatusHint(e,t=e=>e){return e.kind===`gateway-project`?`AI Gateway (Linked to ${e.teamName===void 0?t(e.projectName):`${t(e.projectName)} in ${t(e.teamName)}`})`:`AI Gateway (${e.envKey} in ${e.envFile})`}function modelMenuRows(e,t,n,r){let i;r?(i={value:`model`,label:`Change model`},e!==null&&(i.hint=e)):i={value:`model`,label:`Change model`,disabled:!0,description:`Set via an SDK model call in agent.ts; edit the source to change it`};let a;return a=n?.kind===`external`?{value:`provider`,label:`Change provider`,disabled:!0,description:`Disabled in external endpoint mode`}:t.kind===`unset`?{value:`provider`,label:import_picocolors.default.bold(import_picocolors.default.yellow(`Configure provider`)),hint:`Required to enable the agent`,accent:`warning`}:{value:`provider`,label:`Change provider`,hint:providerStatusHint(t,import_picocolors.default.bold)},[i,a,{value:`done`,label:`Done`}]}function applyModelNotice(e){switch(e.kind){case`changed`:return{tone:`success`,text:`Model changed to ${e.to}`};case`unchanged`:return{tone:`info`,text:`Model is already ${e.model}`};case`rejected`:return{tone:`warning`,text:e.message}}}function providerNotice(e){return e.kind===`unset`?{tone:`warning`,text:`Provider updated — no gateway credential detected yet.`}:{tone:`success`,text:`Connected to AI Gateway`}}async function detectModelProviderStatus(e,t={}){let[n,i,a]=await Promise.all([detectProjectIdentity(e,t),findEnvFileWithKey(e,`AI_GATEWAY_API_KEY`),findEnvFileWithKey(e,`VERCEL_OIDC_TOKEN`)]);if(n!==void 0){let e={kind:`gateway-project`,projectName:n.projectName};return n.teamName!==void 0&&(e.teamName=n.teamName),e}return i===void 0?a===void 0?{kind:`unset`}:{kind:`gateway-key`,envKey:`VERCEL_OIDC_TOKEN`,envFile:a}:{kind:`gateway-key`,envKey:`AI_GATEWAY_API_KEY`,envFile:i}}async function runModelFlow(e){let{appRoot:t,prompter:n,signal:r}=e,i={readCurrentModel:readCurrentAgentModel,applyModel:changeAgentModel,detectProviderStatus:detectModelProviderStatus,runVercelFlow,...e.deps};async function checkProject(e){let t=n.log.spinner?.(`Checking the project…`);try{return await e()}finally{t?.stop()}}let detectProvider=()=>r===void 0?i.detectProviderStatus(t):i.detectProviderStatus(t,{signal:r}),[{id:o,routing:s,editable:c},l]=await checkProject(()=>Promise.all([i.readCurrentModel(t),detectProvider()]));r?.throwIfAborted();let u,d,p,m,h=s?.kind===`external`?{tone:`warning`,text:"`agent.ts` specifies a model provider directly. In-TUI configuration is restricted to AI Gateway endpoints."}:void 0,g=l.kind===`unset`&&s?.kind!==`external`?`provider`:c?`model`:s?.kind===`external`?`done`:`provider`;for(;;){let e;try{e=await n.select({message:``,options:modelMenuRows(o,l,s,c),hintLayout:`stacked`,initialValue:g,notices:[h,p,m].filter(e=>e!==void 0)})}catch(e){if(!(e instanceof WizardCancelledError))throw e;break}if(e===`done`)break;if(e===`model`){let e=await pickModelFromCatalog({appRoot:t,prompter:n,current:o,signal:r,deps:i.selectModel});e===void 0?g=`model`:(r?.throwIfAborted(),u=await i.applyModel({appRoot:t,slug:e}),r?.throwIfAborted(),p=applyModelNotice(u),u.kind===`changed`&&(o=u.to),g=`done`);continue}let f=await i.runVercelFlow({appRoot:t,prompter:n,signal:r});if(r?.throwIfAborted(),f.kind===`cancelled`){g=`provider`;continue}if(`outcome`in f){g=`done`;continue}l=await checkProject(detectProvider),r?.throwIfAborted(),d={status:l},f.credential!==void 0&&(d.credential=f.credential),m=providerNotice(l),g=`done`}if(u===void 0&&d===void 0)return{kind:`cancelled`};let _={kind:`done`};return u!==void 0&&(_.modelMessage=formatApplyModelOutcome(u)),d!==void 0&&(_.providerOutcome=d),_}async function pickModelFromCatalog(e){let{appRoot:t,prompter:r,current:a,signal:o}=e,f=e.deps?.fetchModels??fetchGatewayCatalog,p={asker:interactiveAsker(r),deps:{fetchModels:async e=>{let t=r.log.spinner?.(`Loading the model catalog...`);try{return await f(e)}finally{t?.stop()}}}};a!==null&&(p.defaultModel=a);let m=await runInteractive([selectModel(p)],inProjectSetupState(t,{kind:`unresolved`}),prompterSink(r),{snapshot:snapshotSetupState,signal:o});return m.kind===`cancelled`?void 0:m.state.modelId}function formatApplyModelOutcome(e){switch(e.kind){case`changed`:return`Model changed to ${import_picocolors.default.bold(e.to)}. Live on your next prompt.`;case`unchanged`:return`Model is already \`${e.model}\`.`;case`rejected`:return e.message}}async function changeAgentModel(e){let{appRoot:t,slug:n}=e,r=await validateModelSlug(t,n);if(r!==null)return{kind:`rejected`,message:r};let{manifest:i}=await discoverAgent({agentRoot:join(t,`agent`),appRoot:t}),a=await createStaticSourceChange(i).updateModelName(n);return a.kind===`bail`?{kind:`rejected`,message:`Couldn't edit ${a.at.logicalPath}: ${a.reason}. Change \`model\` by hand.`}:a.from===a.to?{kind:`unchanged`,model:a.to}:{kind:`changed`,to:a.to}}async function validateModelSlug(e,t){if(!t.includes(`/`))return`\`${t}\` isn't a provider/model id (e.g. anthropic/claude-sonnet-4.6).`;let n=createCompiledRuntimeModelCatalogLoader(e);try{if(await n.getModelLimits(formatLanguageModelGatewayId(t))===null)return`I couldn't confirm \`${t}\` in the AI Gateway model catalog, so I didn't change agent.ts.`}catch{return null}return null}async function readCurrentAgentModel(e){try{let{compiledState:t}=await inspectApplication(e),n=t?.manifest.config.model;return{id:n?.id??null,routing:n?.routing??null,editable:n!==void 0&&n.source===void 0}}catch{return{id:null,routing:null,editable:!1}}}async function modelChangeRefusalForUneditableModel(e){let{editable:t,routing:n}=await readCurrentAgentModel(e);return t?null:`Model is set via ${n?.kind===`external`?`the external provider \`${n.provider}\``:`an SDK model call`} in agent.ts, not a string literal; /model can't rewrite it. Edit \`model\` in agent.ts.`}export{MODEL_MENU_MESSAGE,changeAgentModel,detectModelProviderStatus,formatApplyModelOutcome,modelChangeRefusalForUneditableModel,runModelFlow};
1
+ import{__toESM}from"../../_virtual/_rolldown/runtime.js";import{require_picocolors}from"../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js";import{interactiveAsker}from"../ask.js";import{detectProjectIdentity}from"../project-resolution.js";import{snapshotSetupState}from"../state.js";import{WizardCancelledError}from"../step.js";import{findEnvFileWithKey}from"../boxes/detect-ai-gateway.js";import{fetchGatewayCatalog,selectModel}from"../boxes/select-model.js";import{runInteractive}from"../runner.js";import{inProjectSetupState,prompterSink}from"./in-project.js";import{runVercelFlow}from"./vercel.js";import{join}from"node:path";import{discoverAgent}from"#discover/discover-agent.js";import{inspectApplication}from"#services/inspect-application.js";import{formatLanguageModelGatewayId}from"#internal/runtime-model.js";import{createCompiledRuntimeModelCatalogLoader}from"#compiler/model-catalog.js";import{createStaticSourceChange}from"#source-change/static-source-change.js";var import_picocolors=__toESM(require_picocolors(),1);const MODEL_MENU_MESSAGE=``;function providerStatusHint(e,t=e=>e){return e.kind===`gateway-project`?`AI Gateway (Linked to ${e.teamName===void 0?t(e.projectName):`${t(e.projectName)} in ${t(e.teamName)}`})`:`AI Gateway (${e.envKey} in ${e.envFile})`}function modelMenuRows(e,t,n,r){let i;r?(i={value:`model`,label:`Change model`},e!==null&&(i.hint=e)):i={value:`model`,label:`Change model`,disabled:!0,description:`Set via an SDK model call in agent.ts; edit the source to change it`};let a;return a=n?.kind===`external`?{value:`provider`,label:`Change provider`,disabled:!0,description:`Disabled in external endpoint mode`}:t.kind===`unset`?{value:`provider`,label:import_picocolors.default.bold(import_picocolors.default.yellow(`Configure provider`)),hint:`Required to enable the agent`,accent:`warning`}:{value:`provider`,label:`Change provider`,hint:providerStatusHint(t,import_picocolors.default.bold)},[i,a,{value:`done`,label:`Done`}]}function applyModelNotice(e){switch(e.kind){case`changed`:return{tone:`success`,text:`Model changed to ${e.to}`};case`unchanged`:return{tone:`info`,text:`Model is already ${e.model}`};case`rejected`:return{tone:`warning`,text:e.message}}}function providerNotice(e){return e.kind===`unset`?{tone:`warning`,text:`Provider updated — no gateway credential detected yet.`}:{tone:`success`,text:`Connected to AI Gateway`}}async function detectModelProviderStatus(e,t={}){let[n,i,a]=await Promise.all([detectProjectIdentity(e,t),findEnvFileWithKey(e,`AI_GATEWAY_API_KEY`),findEnvFileWithKey(e,`VERCEL_OIDC_TOKEN`)]);if(n!==void 0){let e={kind:`gateway-project`,projectName:n.projectName};return n.teamName!==void 0&&(e.teamName=n.teamName),e}return i===void 0?a===void 0?{kind:`unset`}:{kind:`gateway-key`,envKey:`VERCEL_OIDC_TOKEN`,envFile:a}:{kind:`gateway-key`,envKey:`AI_GATEWAY_API_KEY`,envFile:i}}async function runModelFlow(e){let{appRoot:t,prompter:n,signal:r}=e,i={readCurrentModel:readCurrentAgentModel,applyModel:changeAgentModel,detectProviderStatus:detectModelProviderStatus,runVercelFlow,...e.deps};async function checkProject(e){let t=n.log.spinner?.(`Checking the project…`);try{return await e()}finally{t?.stop()}}let detectProvider=()=>i.detectProviderStatus(t,{signal:r}),[{id:o,routing:s,editable:c},l]=await checkProject(()=>Promise.all([i.readCurrentModel(t),detectProvider()]));r?.throwIfAborted();let u,d,p,m,h=s?.kind===`external`?{tone:`warning`,text:"`agent.ts` specifies a model provider directly. In-TUI configuration is restricted to AI Gateway endpoints."}:void 0,g=l.kind===`unset`&&s?.kind!==`external`?`provider`:c?`model`:s?.kind===`external`?`done`:`provider`;for(;;){let e;try{e=await n.select({message:``,options:modelMenuRows(o,l,s,c),hintLayout:`stacked`,initialValue:g,notices:[h,p,m].filter(e=>e!==void 0)})}catch(e){if(!(e instanceof WizardCancelledError))throw e;break}if(e===`done`)break;if(e===`model`){let e=await pickModelFromCatalog({appRoot:t,prompter:n,current:o,signal:r,deps:i.selectModel});e===void 0?g=`model`:(r?.throwIfAborted(),u=await i.applyModel({appRoot:t,slug:e}),r?.throwIfAborted(),p=applyModelNotice(u),u.kind===`changed`&&(o=u.to),g=`done`);continue}let f=await i.runVercelFlow({appRoot:t,prompter:n,signal:r});if(r?.throwIfAborted(),f.kind===`cancelled`){g=`provider`;continue}if(`outcome`in f){g=`done`;continue}l=await checkProject(detectProvider),r?.throwIfAborted(),d={status:l},f.credential!==void 0&&(d.credential=f.credential),m=providerNotice(l),g=`done`}if(u===void 0&&d===void 0)return{kind:`cancelled`};let _={kind:`done`};return u!==void 0&&(_.modelMessage=formatApplyModelOutcome(u)),d!==void 0&&(_.providerOutcome=d),_}async function pickModelFromCatalog(e){let{appRoot:t,prompter:r,current:a,signal:o}=e,f=e.deps?.fetchModels??fetchGatewayCatalog,p={asker:interactiveAsker(r),deps:{fetchModels:async e=>{let t=r.log.spinner?.(`Loading the model catalog...`);try{return await f(e)}finally{t?.stop()}}}};a!==null&&(p.defaultModel=a);let m=await runInteractive([selectModel(p)],inProjectSetupState(t,{kind:`unresolved`}),prompterSink(r),{snapshot:snapshotSetupState,signal:o});return m.kind===`cancelled`?void 0:m.state.modelId}function formatApplyModelOutcome(e){switch(e.kind){case`changed`:return`Model changed to ${import_picocolors.default.bold(e.to)}. Live on your next prompt.`;case`unchanged`:return`Model is already \`${e.model}\`.`;case`rejected`:return e.message}}async function changeAgentModel(e){let{appRoot:t,slug:n}=e,r=await validateModelSlug(t,n);if(r!==null)return{kind:`rejected`,message:r};let{manifest:i}=await discoverAgent({agentRoot:join(t,`agent`),appRoot:t}),a=await createStaticSourceChange(i).updateModelName(n);return a.kind===`bail`?{kind:`rejected`,message:`Couldn't edit ${a.at.logicalPath}: ${a.reason}. Change \`model\` by hand.`}:a.from===a.to?{kind:`unchanged`,model:a.to}:{kind:`changed`,to:a.to}}async function validateModelSlug(e,t){if(!t.includes(`/`))return`\`${t}\` isn't a provider/model id (e.g. anthropic/claude-sonnet-4.6).`;let n=createCompiledRuntimeModelCatalogLoader(e);try{if(await n.getModelLimits(formatLanguageModelGatewayId(t))===null)return`I couldn't confirm \`${t}\` in the AI Gateway model catalog, so I didn't change agent.ts.`}catch{return null}return null}async function readCurrentAgentModel(e){try{let{compiledState:t}=await inspectApplication(e),n=t?.manifest.config.model;return{id:n?.id??null,routing:n?.routing??null,editable:n!==void 0&&n.source===void 0}}catch{return{id:null,routing:null,editable:!1}}}async function modelChangeRefusalForUneditableModel(e){let{editable:t,routing:n}=await readCurrentAgentModel(e);return t?null:`Model is set via ${n?.kind===`external`?`the external provider \`${n.provider}\``:`an SDK model call`} in agent.ts, not a string literal; /model can't rewrite it. Edit \`model\` in agent.ts.`}export{MODEL_MENU_MESSAGE,changeAgentModel,detectModelProviderStatus,formatApplyModelOutcome,modelChangeRefusalForUneditableModel,runModelFlow};
@@ -1,6 +1,7 @@
1
1
  import { appendEnv } from "../append-env.js";
2
2
  import type { Prompter } from "../prompter.js";
3
3
  import { validateGatewayApiKey } from "../validate-gateway-key.js";
4
+ import { getVercelAuthStatus } from "../vercel-project.js";
4
5
  import { runLinkFlow, type LinkFlowResult } from "./link.js";
5
6
  export declare const PROVIDER_QUESTION = "Which model provider do you want to use?";
6
7
  export declare const CONNECTION_QUESTION = "How do you want to connect to AI Gateway?";
@@ -8,6 +9,7 @@ export declare const EXTERNAL_PROVIDER_INSTRUCTIONS_TITLE = "Using another model
8
9
  export declare const EXTERNAL_PROVIDER_INSTRUCTIONS: readonly string[];
9
10
  /** Injected for tests; defaults to the real link flow, env write, and key check. */
10
11
  export interface VercelFlowDeps {
12
+ getVercelAuthStatus: typeof getVercelAuthStatus;
11
13
  runLinkFlow: typeof runLinkFlow;
12
14
  appendEnv: typeof appendEnv;
13
15
  validateGatewayApiKey: typeof validateGatewayApiKey;
@@ -1,2 +1,2 @@
1
- import{__toESM}from"../../_virtual/_rolldown/runtime.js";import{require_picocolors}from"../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js";import{appendEnv}from"../append-env.js";import{WizardCancelledError}from"../step.js";import{runLinkFlow}from"./link.js";import{validateGatewayApiKey}from"../validate-gateway-key.js";import{join}from"node:path";var import_picocolors=__toESM(require_picocolors(),1);const AI_GATEWAY_ENV_KEY=`AI_GATEWAY_API_KEY`,ENV_FILE_NAME=`.env.local`,PROVIDER_QUESTION=`Which model provider do you want to use?`,CONNECTION_QUESTION=`How do you want to connect to AI Gateway?`,EXTERNAL_PROVIDER_INSTRUCTIONS_TITLE=`Using another model provider`,EXTERNAL_PROVIDER_INSTRUCTIONS=[`Set your provider's API key in ${ENV_FILE_NAME} — e.g. ANTHROPIC_API_KEY or OPENAI_API_KEY.`,'In agent/agent.ts, set `model` to a provider-authored model — e.g. `anthropic("claude-opus-4.8")` from `@ai-sdk/anthropic`.',`See https://beta.eve.dev/docs/agent-config for details.`,"A running `eve dev` reloads env files automatically — no restart needed."];async function runVercelFlow(e){let{appRoot:t,prompter:a,signal:o}=e,s={runLinkFlow,appendEnv,validateGatewayApiKey,...e.deps},c,l;try{c=await a.select({message:PROVIDER_QUESTION,options:[{value:`gateway`,label:`Vercel AI Gateway`,hint:`one key, every model`},{value:`other`,label:`Something else`,hint:`use your own provider credentials`}],hintLayout:`stacked`}),c===`gateway`&&(l=await a.select({message:CONNECTION_QUESTION,options:[{value:`project`,label:`Connect via a project`,hint:`vercel link + env pull`},{value:`own-key`,label:`Use my own key`,hint:`paste an ${AI_GATEWAY_ENV_KEY}`}],hintLayout:`stacked`}))}catch(e){if(e instanceof WizardCancelledError)return{kind:`cancelled`};throw e}if(c===`other`)return a.acknowledge?await a.acknowledge({message:EXTERNAL_PROVIDER_INSTRUCTIONS_TITLE,lines:EXTERNAL_PROVIDER_INSTRUCTIONS}):a.note(EXTERNAL_PROVIDER_INSTRUCTIONS.join(`
1
+ import{__toESM}from"../../_virtual/_rolldown/runtime.js";import{require_picocolors}from"../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js";import{appendEnv}from"../append-env.js";import{WizardCancelledError}from"../step.js";import{getVercelAuthStatus}from"../vercel-project.js";import{runLinkFlow}from"./link.js";import{validateGatewayApiKey}from"../validate-gateway-key.js";import{join}from"node:path";var import_picocolors=__toESM(require_picocolors(),1);const AI_GATEWAY_ENV_KEY=`AI_GATEWAY_API_KEY`,ENV_FILE_NAME=`.env.local`,PROVIDER_QUESTION=`Which model provider do you want to use?`,CONNECTION_QUESTION=`How do you want to connect to AI Gateway?`,EXTERNAL_PROVIDER_INSTRUCTIONS_TITLE=`Using another model provider`,EXTERNAL_PROVIDER_INSTRUCTIONS=[`Set your provider's API key in ${ENV_FILE_NAME} — e.g. ANTHROPIC_API_KEY or OPENAI_API_KEY.`,'In agent/agent.ts, set `model` to a provider-authored model — e.g. `anthropic("claude-opus-4.8")` from `@ai-sdk/anthropic`.',`See https://beta.eve.dev/docs/agent-config for details.`,"A running `eve dev` reloads env files automatically — no restart needed."];function projectConnectionOption(e){let t={value:`project`,label:`Connect via a project`,hint:`vercel link + env pull`};switch(e){case`authenticated`:return t;case`cli-missing`:return{...t,disabled:!0,disabledReason:`Vercel CLI not found, see /vc`,disabledReasonTone:`warning`};case`logged-out`:return{...t,disabled:!0,disabledReason:`Log in to Vercel first, see /login`,disabledReasonTone:`warning`};case`unavailable`:return{...t,disabled:!0,disabledReason:`Couldn't reach Vercel, check your connection`,disabledReasonTone:`warning`};default:return e}}async function runVercelFlow(e){let{appRoot:t,prompter:a,signal:o}=e,s={getVercelAuthStatus,runLinkFlow,appendEnv,validateGatewayApiKey,...e.deps},c,l;try{if(c=await a.select({message:PROVIDER_QUESTION,options:[{value:`gateway`,label:`Vercel AI Gateway`,hint:`one key, every model`},{value:`other`,label:`Something else`,hint:`use your own provider credentials`}],hintLayout:`stacked`}),c===`gateway`){let e=a.log.spinner?.(`Checking your Vercel login…`),n;try{n=await s.getVercelAuthStatus(t,{signal:o}),o?.throwIfAborted()}finally{e?.stop()}l=await a.select({message:CONNECTION_QUESTION,options:[projectConnectionOption(n),{value:`own-key`,label:`Use my own key`,hint:`paste an ${AI_GATEWAY_ENV_KEY}`}],hintLayout:`stacked`})}}catch(e){if(e instanceof WizardCancelledError)return{kind:`cancelled`};throw e}if(c===`other`)return a.acknowledge?await a.acknowledge({message:EXTERNAL_PROVIDER_INSTRUCTIONS_TITLE,lines:EXTERNAL_PROVIDER_INSTRUCTIONS}):a.note(EXTERNAL_PROVIDER_INSTRUCTIONS.join(`
2
2
  `),EXTERNAL_PROVIDER_INSTRUCTIONS_TITLE),{kind:`done`,outcome:`external-provider`};if(l===`own-key`)for(;;){let e;try{e=await a.password({message:`Enter your ${AI_GATEWAY_ENV_KEY}`,validate:e=>e.trim().length===0?`API key cannot be empty.`:void 0})}catch(e){if(e instanceof WizardCancelledError)return{kind:`cancelled`};throw e}o?.throwIfAborted();let n=e.trim(),r=a.log.spinner?.(`Validating…`),i;try{i=await s.validateGatewayApiKey(n,o)}finally{r?.stop()}if(o?.throwIfAborted(),i.kind===`invalid`){a.log.error(`${i.message} Check the key and try again, or Esc to cancel.`);continue}return i.kind===`inconclusive`?a.log.warning(`Couldn't reach the gateway to validate (${i.message}). Saving the key anyway.`):a.log.success(`${import_picocolors.default.green(`✓`)} ${import_picocolors.default.bold(`Valid key`)}`),await s.appendEnv(join(t,ENV_FILE_NAME),{[AI_GATEWAY_ENV_KEY]:n},{force:!0}),o?.throwIfAborted(),a.log.success(`Saved ${AI_GATEWAY_ENV_KEY} to ${ENV_FILE_NAME}.`),{kind:`done`,credential:AI_GATEWAY_ENV_KEY}}else return await s.runLinkFlow({appRoot:t,prompter:a,signal:o,projectSelection:`create-or-link`})}export{CONNECTION_QUESTION,EXTERNAL_PROVIDER_INSTRUCTIONS,EXTERNAL_PROVIDER_INSTRUCTIONS_TITLE,PROVIDER_QUESTION,runVercelFlow};
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Environment variables `@vercel/detect-agent@1.2.3` reads as launch markers.
3
+ *
4
+ * Two consumers share this list. Tests that assert a human path delete these
5
+ * from the child environment, because the test runner itself is often launched
6
+ * by a coding agent and the markers would leak into spawned CLIs. And every
7
+ * `vercel` subprocess eve spawns strips them ({@link withoutCodingAgentMarkers}),
8
+ * so the Vercel CLI never sees an agent it would react to — eve drives it
9
+ * explicitly (stdin, flags), and an inherited marker has been observed to turn a
10
+ * read-only `vercel whoami` into a login attempt. The list lives here as the one
11
+ * place that knows the dependency's internals; revisit it when the pinned
12
+ * version changes. (The package also probes `/opt/.devin`, which cannot be
13
+ * masked through the environment.)
14
+ */
15
+ export declare const CODING_AGENT_ENV_MARKERS: readonly string[];
16
+ /** A copy of `env` with the coding-agent launch markers removed. */
17
+ export declare function withoutCodingAgentMarkers(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
@@ -0,0 +1 @@
1
+ const CODING_AGENT_ENV_MARKERS=[`AI_AGENT`,`ANTIGRAVITY_AGENT`,`AUGMENT_AGENT`,`CLAUDECODE`,`CLAUDE_CODE`,`CLAUDE_CODE_IS_COWORK`,`CODEX_CI`,`CODEX_SANDBOX`,`CODEX_THREAD_ID`,`COPILOT_ALLOW_ALL`,`COPILOT_GITHUB_TOKEN`,`COPILOT_MODEL`,`CURSOR_AGENT`,`CURSOR_EXTENSION_HOST_ROLE`,`CURSOR_TRACE_ID`,`GEMINI_CLI`,`OPENCODE_CLIENT`,`REPL_ID`];function withoutCodingAgentMarkers(e){let t={...e};for(let e of CODING_AGENT_ENV_MARKERS)delete t[e];return t}export{CODING_AGENT_ENV_MARKERS,withoutCodingAgentMarkers};
@@ -1,8 +1,8 @@
1
- import{pathExists}from"../../path-exists.js";import{dirname,extname,join,resolve}from"node:path";import{existsSync,realpathSync}from"node:fs";import{readFile,writeFile}from"node:fs/promises";const PNPM_WORKSPACE_PATH=`pnpm-workspace.yaml`,PNPM_WORKSPACE_MEMBERSHIP_ARGUMENTS=[`list`,`--depth`,`-1`,`--json`],PNPM_WORKSPACE_CONTENT=[`minimumReleaseAgeExclude:`,` - eve`,`allowBuilds:`,` sharp: false`,`# Compatibility for Eve releases with an incomplete runtime manifest.`,`packageExtensions:`,` "eve@>=0.6.0-beta.13 <=0.7.0":`,` dependencies:`,` oxc-parser: 0.134.0`,``].join(`
1
+ import{pathExists}from"../../path-exists.js";import{existsSync,realpathSync}from"node:fs";import{dirname,extname,join,resolve}from"node:path";import{readFile,writeFile}from"node:fs/promises";const PNPM_WORKSPACE_PATH=`pnpm-workspace.yaml`,PNPM_WORKSPACE_MEMBERSHIP_ARGUMENTS=[`list`,`--depth`,`-1`,`--json`],PNPM_WORKSPACE_CONTENT=[`minimumReleaseAgeExclude:`,` - eve`,`allowBuilds:`,` sharp: false`,`# Compatibility for Eve releases with an incomplete runtime manifest.`,`packageExtensions:`,` "eve@>=0.6.0-beta.13 <=0.7.0":`,` dependencies:`,` oxc-parser: 0.134.0`,``].join(`
2
2
  `),EVE_RELEASE_AGE_EXCLUSION=` - eve`,SHARP_BUILD_POLICY=` sharp: false`;function findYamlBlockEnd(e,t){let n=t+1;for(;n<e.length;){let t=e[n]??``;if(t.length>0&&!t.startsWith(` `)&&!t.startsWith(` `))break;n+=1}return n}function withSharpBuildPolicy(e){let t=e.endsWith(`
3
3
  `)?e:`${e}\n`,n=t.split(`
4
4
  `),r=n.findIndex(e=>e===`allowBuilds:`);if(r<0)return`${t.trim().length===0?``:`${t}\n`}allowBuilds:\n${SHARP_BUILD_POLICY}\n`;let i=findYamlBlockEnd(n,r);if(n.slice(r+1,i).some(e=>/^\s+sharp:/.test(e)))return e;let a=i;for(;a>r+1&&n[a-1]===``;)--a;return n.splice(a,0,SHARP_BUILD_POLICY),n.join(`
5
5
  `)}function withExperimentalEveReleaseAgeExclusion(e){let t=e.endsWith(`
6
6
  `)?e:`${e}\n`,n=t.split(`
7
7
  `),r=n.findIndex(e=>e===`minimumReleaseAgeExclude:`);if(r<0)return`${t.trim().length===0?``:`${t}\n`}minimumReleaseAgeExclude:\n${EVE_RELEASE_AGE_EXCLUSION}\n`;let i=findYamlBlockEnd(n,r);if(n.slice(r+1,i).some(e=>e.trim()===`- eve`))return e;let a=i;for(;a>r+1&&n[a-1]===``;)--a;return n.splice(a,0,EVE_RELEASE_AGE_EXCLUSION),n.join(`
8
- `)}async function ensurePnpmWorkspacePolicy(t){if(!await pathExists(t))return await writeFile(t,PNPM_WORKSPACE_CONTENT,`utf8`),`written`;let n=await readFile(t,`utf8`),r=withExperimentalEveReleaseAgeExclusion(withSharpBuildPolicy(n));return r===n?`skipped`:(await writeFile(t,r,`utf8`),`written`)}function hasAncestorPnpmWorkspace(e){let n=dirname(resolve(e));for(;;){if(existsSync(join(n,`pnpm-workspace.yaml`)))return!0;let e=dirname(n);if(e===n)return!1;n=e}}function pnpmWorkspaceClaimsProject(e,t){let n;try{n=JSON.parse(e)}catch{return}if(!Array.isArray(n)||n.length===0)return;let canonicalPath=e=>{let t=resolve(e);try{return realpathSync.native(t)}catch{return t}},r=canonicalPath(t),a=!1;for(let e of n){if(typeof e!=`object`||!e)continue;let t=e.path;if(typeof t==`string`&&(a=!0,canonicalPath(t)===r))return!0}return a?!1:void 0}const pnpmPackageManager={kind:`pnpm`,scaffoldFiles:{[PNPM_WORKSPACE_PATH]:PNPM_WORKSPACE_CONTENT},async applyProjectConfiguration(e){let t=join(e,PNPM_WORKSPACE_PATH);return await ensurePnpmWorkspacePolicy(t)===`written`?{filesSkipped:[],filesWritten:[t]}:{filesSkipped:[t],filesWritten:[]}},devArguments:()=>[`exec`,`eve`,`dev`],installArguments:e=>[`install`,`--no-frozen-lockfile`,...e.bypassMinimumReleaseAge===!0?[`--config.minimum-release-age=0`]:[],...e.ignoreWorkspace===!0?[`--ignore-workspace`]:[]],prepareArguments:(e,t)=>[`--dir`,e,...t],resolveInvocation(e){let t=process.env.npm_execpath;if(t!==void 0&&t.toLowerCase().includes(`pnpm`)){let r=extname(t).toLowerCase();return r===`.cjs`||r===`.js`?{args:[t,...e],command:process.execPath}:{args:e,command:t,shell:process.platform===`win32`}}if(process.env.npm_config_user_agent?.toLowerCase().startsWith(`pnpm/`))return{args:e,command:`pnpm`,shell:process.platform===`win32`};let i=process.env.PNPM_HOME;if(i!==void 0){let t=join(i,process.platform===`win32`?`pnpm.CMD`:`pnpm`);if(existsSync(t))return{args:e,command:t,shell:process.platform===`win32`}}return{args:e,command:`pnpm`}}};export{PNPM_WORKSPACE_CONTENT,PNPM_WORKSPACE_MEMBERSHIP_ARGUMENTS,PNPM_WORKSPACE_PATH,hasAncestorPnpmWorkspace,pnpmPackageManager,pnpmWorkspaceClaimsProject};
8
+ `)}async function ensurePnpmWorkspacePolicy(t){if(!await pathExists(t))return await writeFile(t,PNPM_WORKSPACE_CONTENT,`utf8`),`written`;let n=await readFile(t,`utf8`),r=withExperimentalEveReleaseAgeExclusion(withSharpBuildPolicy(n));return r===n?`skipped`:(await writeFile(t,r,`utf8`),`written`)}function hasAncestorPnpmWorkspace(e){let n=dirname(resolve(e));for(;;){if(existsSync(join(n,`pnpm-workspace.yaml`)))return!0;let e=dirname(n);if(e===n)return!1;n=e}}function pnpmWorkspaceClaimsProject(e,t){let r;try{r=JSON.parse(e)}catch{return}if(!Array.isArray(r)||r.length===0)return;let canonicalPath=e=>{let t=resolve(e);try{return realpathSync.native(t)}catch{return t}},i=canonicalPath(t),a=!1;for(let e of r){if(typeof e!=`object`||!e)continue;let t=e.path;if(typeof t==`string`&&(a=!0,canonicalPath(t)===i))return!0}return a?!1:void 0}const pnpmPackageManager={kind:`pnpm`,scaffoldFiles:{[PNPM_WORKSPACE_PATH]:PNPM_WORKSPACE_CONTENT},async applyProjectConfiguration(e){let t=join(e,PNPM_WORKSPACE_PATH);return await ensurePnpmWorkspacePolicy(t)===`written`?{filesSkipped:[],filesWritten:[t]}:{filesSkipped:[t],filesWritten:[]}},devArguments:()=>[`exec`,`eve`,`dev`],installArguments:e=>[`install`,`--no-frozen-lockfile`,...e.bypassMinimumReleaseAge===!0?[`--config.minimum-release-age=0`]:[],...e.ignoreWorkspace===!0?[`--ignore-workspace`]:[]],prepareArguments:(e,t)=>[`--dir`,e,...t],resolveInvocation(e){let n=process.env.npm_execpath;if(n!==void 0&&n.toLowerCase().includes(`pnpm`)){let t=extname(n).toLowerCase();return t===`.cjs`||t===`.js`?{args:[n,...e],command:process.execPath}:{args:e,command:n,shell:process.platform===`win32`}}if(process.env.npm_config_user_agent?.toLowerCase().startsWith(`pnpm/`))return{args:e,command:`pnpm`,shell:process.platform===`win32`};let r=process.env.PNPM_HOME;if(r!==void 0){let n=join(r,process.platform===`win32`?`pnpm.CMD`:`pnpm`);if(existsSync(n))return{args:e,command:n,shell:process.platform===`win32`}}return{args:e,command:`pnpm`}}};export{PNPM_WORKSPACE_CONTENT,PNPM_WORKSPACE_MEMBERSHIP_ARGUMENTS,PNPM_WORKSPACE_PATH,hasAncestorPnpmWorkspace,pnpmPackageManager,pnpmWorkspaceClaimsProject};
@@ -7,6 +7,12 @@ export interface RunPackageManagerOptions {
7
7
  onOutput?: ProcessOutputHandler;
8
8
  /** Aborts the package-manager subprocess when setup is interrupted. */
9
9
  signal?: AbortSignal;
10
+ /**
11
+ * Closes stdin so the child cannot prompt — required when a repainting TUI
12
+ * owns the terminal in raw mode, where an inherited stdin would let the child
13
+ * contend for keystrokes.
14
+ */
15
+ nonInteractive?: boolean;
10
16
  }
11
17
  /** @deprecated Use {@link RunPackageManagerOptions}. */
12
18
  export type RunPnpmOptions = RunPackageManagerOptions;
@@ -1 +1 @@
1
- import{createProcessOutputBuffer}from"../process-output.js";import{armProcessAbort}from"../process-abort.js";import{PNPM_WORKSPACE_MEMBERSHIP_ARGUMENTS,hasAncestorPnpmWorkspace,pnpmWorkspaceClaimsProject}from"./pnpm.js";import{getPackageManagerStrategy}from"./index.js";import{spawn}from"node:child_process";function spawnPackageManager(n,r,i,s={}){return s.signal?.aborted===!0?Promise.resolve(!1):new Promise(c=>{let l=getPackageManagerStrategy(n),u=l.prepareArguments(r,i),d=l.resolveInvocation(u),f=s.onOutput&&createProcessOutputBuffer(s.onOutput),p=spawn(d.command,[...d.args],{cwd:r,stdio:s.onOutput?[`inherit`,`pipe`,`pipe`]:`inherit`,shell:d.shell,signal:s.signal}),m=armProcessAbort(p,s.signal);p.stdout?.on(`data`,e=>f?.write(`stdout`,e)),p.stderr?.on(`data`,e=>f?.write(`stderr`,e));let h=!1;function settle(e){h||(h=!0,f?.flush(),c(e))}function reportFailure(e){s.onOutput?s.onOutput({stream:`stderr`,text:e}):process.stderr.write(`\n${e}\n`)}p.on(`error`,e=>{s.signal?.aborted===!0||e.name===`AbortError`||(e.code===`ENOENT`?(m(),reportFailure(`${n} not found. Install it before running this step.`),settle(!1)):(m(),reportFailure(`${n} ${i.join(` `)} failed: ${e.message}`),settle(!1)))}),p.on(`close`,e=>{m(),settle(s.signal?.aborted===!0?!1:e===0)})})}function capturePackageManager(n,r,i,s){return s.signal?.aborted===!0?Promise.resolve({ok:!1,stdout:``}):new Promise(c=>{let l=getPackageManagerStrategy(n),u=l.prepareArguments(r,i),d=l.resolveInvocation(u),f=spawn(d.command,[...d.args],{cwd:r,stdio:[`ignore`,`pipe`,`pipe`],shell:d.shell,signal:s.signal}),p=armProcessAbort(f,s.signal),m=[],h=s.onOutput&&createProcessOutputBuffer(s.onOutput);f.stdout?.on(`data`,e=>m.push(e)),f.stderr?.on(`data`,e=>h?.write(`stderr`,e));let g=!1;function settle(e){g||(g=!0,h?.flush(),c({ok:e,stdout:Buffer.concat(m).toString(`utf8`)}))}function reportFailure(e){s.onOutput?s.onOutput({stream:`stderr`,text:e}):process.stderr.write(`\n${e}\n`)}f.on(`error`,e=>{s.signal?.aborted===!0||e.name===`AbortError`||(p(),reportFailure(e.code===`ENOENT`?`${n} not found. Install it before running this step.`:`${n} ${i.join(` `)} failed: ${e.message}`),settle(!1))}),f.on(`close`,e=>{p(),!g&&e!==0&&s.signal?.aborted!==!0&&reportFailure(`${n} ${i.join(` `)} exited with code ${e??`unknown`}.`),settle(s.signal?.aborted===!0?!1:e===0)})})}async function runPackageManagerInstall(e,t,o={}){let s=getPackageManagerStrategy(e),c=o;if(e===`pnpm`&&o.ignoreWorkspace!==!0&&hasAncestorPnpmWorkspace(t)){let r=await capturePackageManager(e,t,PNPM_WORKSPACE_MEMBERSHIP_ARGUMENTS,o);if(!r.ok)return!1;let a=pnpmWorkspaceClaimsProject(r.stdout,t);if(a===void 0)return o.onOutput?.({stream:`stderr`,text:`Could not determine whether the ancestor pnpm workspace includes this project.`}),!1;a||(c={...o,ignoreWorkspace:!0})}return spawnPackageManager(e,t,s.installArguments(c),o)}function eveDevArguments(e){return getPackageManagerStrategy(e).devArguments()}function spawnPnpm(e,t,n={}){return spawnPackageManager(`pnpm`,e,t,n)}function runPnpmInstall(e,t={}){return runPackageManagerInstall(`pnpm`,e,t)}export{eveDevArguments,runPackageManagerInstall,runPnpmInstall,spawnPackageManager,spawnPnpm};
1
+ import{createProcessOutputBuffer}from"../process-output.js";import{armProcessAbort}from"../process-abort.js";import{PNPM_WORKSPACE_MEMBERSHIP_ARGUMENTS,hasAncestorPnpmWorkspace,pnpmWorkspaceClaimsProject}from"./pnpm.js";import{getPackageManagerStrategy}from"./index.js";import{spawn}from"node:child_process";function stdioForRun(e){return e.onOutput?[e.nonInteractive?`ignore`:`inherit`,`pipe`,`pipe`]:e.nonInteractive?[`ignore`,`inherit`,`inherit`]:`inherit`}function spawnPackageManager(n,r,i,s={}){return s.signal?.aborted===!0?Promise.resolve(!1):new Promise(c=>{let l=getPackageManagerStrategy(n),u=l.prepareArguments(r,i),d=l.resolveInvocation(u),f=s.onOutput&&createProcessOutputBuffer(s.onOutput),p=spawn(d.command,[...d.args],{cwd:r,stdio:stdioForRun(s),shell:d.shell,signal:s.signal}),m=armProcessAbort(p,s.signal);p.stdout?.on(`data`,e=>f?.write(`stdout`,e)),p.stderr?.on(`data`,e=>f?.write(`stderr`,e));let h=!1;function settle(e){h||(h=!0,f?.flush(),c(e))}function reportFailure(e){s.onOutput?s.onOutput({stream:`stderr`,text:e}):process.stderr.write(`\n${e}\n`)}p.on(`error`,e=>{s.signal?.aborted===!0||e.name===`AbortError`||(e.code===`ENOENT`?(m(),reportFailure(`${n} not found. Install it before running this step.`),settle(!1)):(m(),reportFailure(`${n} ${i.join(` `)} failed: ${e.message}`),settle(!1)))}),p.on(`close`,e=>{m(),settle(s.signal?.aborted===!0?!1:e===0)})})}function capturePackageManager(n,r,i,s){return s.signal?.aborted===!0?Promise.resolve({ok:!1,stdout:``}):new Promise(c=>{let l=getPackageManagerStrategy(n),u=l.prepareArguments(r,i),d=l.resolveInvocation(u),f=spawn(d.command,[...d.args],{cwd:r,stdio:[`ignore`,`pipe`,`pipe`],shell:d.shell,signal:s.signal}),p=armProcessAbort(f,s.signal),m=[],h=s.onOutput&&createProcessOutputBuffer(s.onOutput);f.stdout?.on(`data`,e=>m.push(e)),f.stderr?.on(`data`,e=>h?.write(`stderr`,e));let g=!1;function settle(e){g||(g=!0,h?.flush(),c({ok:e,stdout:Buffer.concat(m).toString(`utf8`)}))}function reportFailure(e){s.onOutput?s.onOutput({stream:`stderr`,text:e}):process.stderr.write(`\n${e}\n`)}f.on(`error`,e=>{s.signal?.aborted===!0||e.name===`AbortError`||(p(),reportFailure(e.code===`ENOENT`?`${n} not found. Install it before running this step.`:`${n} ${i.join(` `)} failed: ${e.message}`),settle(!1))}),f.on(`close`,e=>{p(),!g&&e!==0&&s.signal?.aborted!==!0&&reportFailure(`${n} ${i.join(` `)} exited with code ${e??`unknown`}.`),settle(s.signal?.aborted===!0?!1:e===0)})})}async function runPackageManagerInstall(e,t,o={}){let s=getPackageManagerStrategy(e),c=o;if(e===`pnpm`&&o.ignoreWorkspace!==!0&&hasAncestorPnpmWorkspace(t)){let r=await capturePackageManager(e,t,PNPM_WORKSPACE_MEMBERSHIP_ARGUMENTS,o);if(!r.ok)return!1;let a=pnpmWorkspaceClaimsProject(r.stdout,t);if(a===void 0)return o.onOutput?.({stream:`stderr`,text:`Could not determine whether the ancestor pnpm workspace includes this project.`}),!1;a||(c={...o,ignoreWorkspace:!0})}return spawnPackageManager(e,t,s.installArguments(c),o)}function eveDevArguments(e){return getPackageManagerStrategy(e).devArguments()}function spawnPnpm(e,t,n={}){return spawnPackageManager(`pnpm`,e,t,n)}function runPnpmInstall(e,t={}){return runPackageManagerInstall(`pnpm`,e,t)}export{eveDevArguments,runPackageManagerInstall,runPnpmInstall,spawnPackageManager,spawnPnpm};
@@ -3,7 +3,7 @@ import { type ProcessOutputHandler } from "./process-output.js";
3
3
  export interface RunVercelOptions {
4
4
  cwd: string;
5
5
  extraEnv?: Readonly<Record<string, string>>;
6
- /** Run with stdin closed so an automation path cannot stop on a prompt. */
6
+ /** Pass `--non-interactive` and close stdin so automation cannot stop on a prompt. */
7
7
  nonInteractive?: boolean;
8
8
  /** Streams command output to a parent-owned renderer instead of writing outside it. */
9
9
  onOutput?: ProcessOutputHandler;
@@ -1 +1 @@
1
- import{createProcessOutputBuffer}from"./process-output.js";import{armProcessAbort}from"./process-abort.js";import{dirname,join,resolve}from"node:path";import{spawn}from"node:child_process";import{accessSync,constants,existsSync,statSync}from"node:fs";const CONNECT_FEATURE_FLAG_ENV={FF_CONNECT_ENABLED:`1`},VERCEL_NOT_FOUND_MESSAGE=`Vercel CLI not found. Install with: npm i -g vercel@latest`;function buildSpawnEnv(e){return{...process.env,...CONNECT_FEATURE_FLAG_ENV,...e}}function existingDir(e){let t=resolve(e);for(;!existsSync(t);){let e=dirname(t);if(e===t)break;t=e}return t}function armDeadline(e,t,n){if(t===void 0)return()=>{};let r=setTimeout(()=>{n(),e.kill(`SIGTERM`);let t=setTimeout(()=>e.kill(`SIGKILL`),5e3);t.unref(),e.once(`close`,()=>clearTimeout(t))},t);return r.unref(),()=>clearTimeout(r)}function timeoutMessage(e,t){return`vercel ${e.join(` `)} timed out after ${Math.round(t/1e3)}s and was aborted.`}function abortMessage(e){return`vercel ${e.join(` `)} was aborted.`}function isAbortError(e,t){return t?.aborted===!0||e.name===`AbortError`||e.code===`ABORT_ERR`}function ancestorDirectories(e){let t=[],r=resolve(e);for(;;){t.push(r);let e=dirname(r);if(e===r)return t;r=e}}function findExecutable(e){try{if(accessSync(e,constants.F_OK|constants.X_OK),statSync(e).isFile())return e}catch{return}}function findLocalVercel(e){for(let t of ancestorDirectories(e)){let e=findExecutable(join(t,`node_modules`,`.bin`,`vercel`));if(e!==void 0)return e}}function resolveVercelInvocation(e){let t=findLocalVercel(e);return t===void 0?{command:`vercel`,commandArgs:[]}:{command:t,commandArgs:[]}}function stdioForRun(e){return e.onOutput?[e.nonInteractive?`ignore`:`inherit`,`pipe`,`pipe`]:e.nonInteractive?[`ignore`,`pipe`,`pipe`]:`inherit`}async function runVercel(n,r){return r.signal?.aborted===!0?!1:new Promise(i=>{let a=existingDir(r.cwd),o=resolveVercelInvocation(a),s=r.onOutput&&createProcessOutputBuffer(r.onOutput),c=spawn(o.command,[...o.commandArgs,...n],{cwd:a,stdio:stdioForRun(r),env:buildSpawnEnv(r.extraEnv??{}),signal:r.signal}),l=armProcessAbort(c,r.signal);c.stdout?.on(`data`,e=>s?.write(`stdout`,e)),c.stderr?.on(`data`,e=>s?.write(`stderr`,e));let u=!1;function settle(e){u||(u=!0,s?.flush(),i(e))}function reportFailure(e){r.onOutput?r.onOutput({stream:`stderr`,text:e}):process.stderr.write(`\n${e}\n`)}let d=armDeadline(c,r.timeoutMs,()=>{reportFailure(timeoutMessage(n,r.timeoutMs??0)),settle(!1)});c.on(`error`,e=>{isAbortError(e,r.signal)||(e.code===`ENOENT`?(l(),d(),reportFailure(VERCEL_NOT_FOUND_MESSAGE),settle(!1)):(l(),d(),reportFailure(`vercel ${n.join(` `)} failed: ${e.message}`),settle(!1)))}),c.on(`close`,e=>{if(l(),d(),r.signal?.aborted===!0){settle(!1);return}!u&&e!==0&&e!==null&&(s?.flush(),reportFailure(`vercel ${n.join(` `)} exited with code ${e}.`)),settle(e===0)})})}async function runVercelCaptureStdout(n,r){return r.signal?.aborted===!0?{ok:!1,stdout:``}:new Promise(i=>{let a=existingDir(r.cwd),o=resolveVercelInvocation(a),s=r.onOutput&&createProcessOutputBuffer(r.onOutput),c=spawn(o.command,[...o.commandArgs,...n],{cwd:a,stdio:[r.nonInteractive?`ignore`:`inherit`,`pipe`,r.onOutput?`pipe`:`inherit`],env:buildSpawnEnv(r.extraEnv??{}),signal:r.signal}),l=armProcessAbort(c,r.signal),u=[];c.stdout?.on(`data`,e=>u.push(e.toString(`utf8`))),c.stderr?.on(`data`,e=>s?.write(`stderr`,e));let d=!1;function settle(e){d||(d=!0,s?.flush(),i({ok:e,stdout:u.join(``)}))}function reportFailure(e){r.onOutput?r.onOutput({stream:`stderr`,text:e}):process.stderr.write(`\n${e}\n`)}let f=armDeadline(c,r.timeoutMs,()=>{reportFailure(timeoutMessage(n,r.timeoutMs??0)),settle(!1)});c.on(`error`,e=>{isAbortError(e,r.signal)||(l(),f(),reportFailure(e.code===`ENOENT`?VERCEL_NOT_FOUND_MESSAGE:`vercel ${n.join(` `)} failed: ${e.message}`),settle(!1))}),c.on(`close`,e=>{if(l(),f(),r.signal?.aborted===!0){settle(!1);return}!d&&e!==0&&e!==null&&reportFailure(`vercel ${n.join(` `)} exited with code ${e}.`),settle(e===0)})})}async function captureVercel(n,r){return r.signal?.aborted===!0?{ok:!1,failure:{errno:`ABORT_ERR`,stdout:``,stderr:``,message:abortMessage(n)}}:new Promise(i=>{let a=existingDir(r.cwd),o=resolveVercelInvocation(a),s=r.onOutput&&createProcessOutputBuffer(r.onOutput),c=spawn(o.command,[...o.commandArgs,...n],{cwd:a,stdio:[`ignore`,`pipe`,`pipe`],env:buildSpawnEnv(r.extraEnv??{}),signal:r.signal}),l=armProcessAbort(c,r.signal),u=[],d=[];c.stdout?.on(`data`,e=>u.push(e.toString(`utf8`))),c.stderr?.on(`data`,e=>{d.push(e.toString(`utf8`)),s?.write(`stderr`,e)});let f=!1;function fail(e,t=!0){f||(f=!0,s?.flush(),t&&r.onOutput?.({stream:`stderr`,text:e.message}),i({ok:!1,failure:e}))}function succeed(){f||(f=!0,s?.flush(),i({ok:!0,stdout:u.join(``)}))}let p=armDeadline(c,r.timeoutMs,()=>{fail({code:null,stdout:u.join(``),stderr:d.join(``),message:timeoutMessage(n,r.timeoutMs??0)})});c.on(`error`,e=>{isAbortError(e,r.signal)||(l(),p(),fail({errno:e.code,stdout:u.join(``),stderr:d.join(``),message:e.code===`ENOENT`?VERCEL_NOT_FOUND_MESSAGE:`vercel ${n.join(` `)} failed: ${e.message}`}))}),c.on(`close`,e=>{if(l(),p(),r.signal?.aborted===!0){fail({errno:`ABORT_ERR`,stdout:u.join(``),stderr:d.join(``),message:abortMessage(n)},!1);return}if(e!==0&&e!==null){fail({code:e,stdout:u.join(``),stderr:d.join(``),message:`vercel ${n.join(` `)} exited with code ${e}.`});return}succeed()})})}export{captureVercel,runVercel,runVercelCaptureStdout};
1
+ import{withoutCodingAgentMarkers}from"./coding-agent-env.js";import{createProcessOutputBuffer}from"./process-output.js";import{armProcessAbort}from"./process-abort.js";import{accessSync,constants,existsSync,statSync}from"node:fs";import{dirname,join,resolve}from"node:path";import{spawn}from"node:child_process";const CONNECT_FEATURE_FLAG_ENV={FF_CONNECT_ENABLED:`1`},VERCEL_NOT_FOUND_MESSAGE=`Vercel CLI not found. Install with: npm i -g vercel@latest`;function buildSpawnEnv(t){return{...withoutCodingAgentMarkers(process.env),...CONNECT_FEATURE_FLAG_ENV,...t}}function commandArgs(e,t){return!t||e.includes(`--non-interactive`)?e:[...e,`--non-interactive`]}function existingDir(e){let t=resolve(e);for(;!existsSync(t);){let e=dirname(t);if(e===t)break;t=e}return t}function armDeadline(e,t,n){if(t===void 0)return()=>{};let r=setTimeout(()=>{n(),e.kill(`SIGTERM`);let t=setTimeout(()=>e.kill(`SIGKILL`),5e3);t.unref(),e.once(`close`,()=>clearTimeout(t))},t);return r.unref(),()=>clearTimeout(r)}function timeoutMessage(e,t){return`vercel ${e.join(` `)} timed out after ${Math.round(t/1e3)}s and was aborted.`}function abortMessage(e){return`vercel ${e.join(` `)} was aborted.`}function isAbortError(e,t){return t?.aborted===!0||e.name===`AbortError`||e.code===`ABORT_ERR`}function ancestorDirectories(e){let t=[],n=resolve(e);for(;;){t.push(n);let e=dirname(n);if(e===n)return t;n=e}}function findExecutable(e){try{if(accessSync(e,constants.F_OK|constants.X_OK),statSync(e).isFile())return e}catch{return}}function findLocalVercel(e){for(let t of ancestorDirectories(e)){let e=findExecutable(join(t,`node_modules`,`.bin`,`vercel`));if(e!==void 0)return e}}function resolveVercelInvocation(e){let t=findLocalVercel(e);return t===void 0?{command:`vercel`,commandArgs:[]}:{command:t,commandArgs:[]}}function stdioForRun(e){return e.onOutput?[e.nonInteractive?`ignore`:`inherit`,`pipe`,`pipe`]:e.nonInteractive?[`ignore`,`pipe`,`pipe`]:`inherit`}async function runVercel(e,r){return r.signal?.aborted===!0?!1:new Promise(i=>{let a=existingDir(r.cwd),o=resolveVercelInvocation(a),s=r.onOutput&&createProcessOutputBuffer(r.onOutput),c=spawn(o.command,[...o.commandArgs,...commandArgs(e,r.nonInteractive)],{cwd:a,stdio:stdioForRun(r),env:buildSpawnEnv(r.extraEnv??{}),signal:r.signal}),l=armProcessAbort(c,r.signal);c.stdout?.on(`data`,e=>s?.write(`stdout`,e)),c.stderr?.on(`data`,e=>s?.write(`stderr`,e));let u=!1;function settle(e){u||(u=!0,s?.flush(),i(e))}function reportFailure(e){r.onOutput?r.onOutput({stream:`stderr`,text:e}):process.stderr.write(`\n${e}\n`)}let d=armDeadline(c,r.timeoutMs,()=>{reportFailure(timeoutMessage(e,r.timeoutMs??0)),settle(!1)});c.on(`error`,t=>{isAbortError(t,r.signal)||(t.code===`ENOENT`?(l(),d(),reportFailure(VERCEL_NOT_FOUND_MESSAGE),settle(!1)):(l(),d(),reportFailure(`vercel ${e.join(` `)} failed: ${t.message}`),settle(!1)))}),c.on(`close`,t=>{if(l(),d(),r.signal?.aborted===!0){settle(!1);return}!u&&t!==0&&t!==null&&(s?.flush(),reportFailure(`vercel ${e.join(` `)} exited with code ${t}.`)),settle(t===0)})})}async function runVercelCaptureStdout(e,r){return r.signal?.aborted===!0?{ok:!1,stdout:``}:new Promise(i=>{let a=existingDir(r.cwd),o=resolveVercelInvocation(a),s=r.onOutput&&createProcessOutputBuffer(r.onOutput),c=spawn(o.command,[...o.commandArgs,...commandArgs(e,r.nonInteractive)],{cwd:a,stdio:[r.nonInteractive?`ignore`:`inherit`,`pipe`,r.onOutput?`pipe`:`inherit`],env:buildSpawnEnv(r.extraEnv??{}),signal:r.signal}),l=armProcessAbort(c,r.signal),u=[];c.stdout?.on(`data`,e=>u.push(e.toString(`utf8`))),c.stderr?.on(`data`,e=>s?.write(`stderr`,e));let d=!1;function settle(e){d||(d=!0,s?.flush(),i({ok:e,stdout:u.join(``)}))}function reportFailure(e){r.onOutput?r.onOutput({stream:`stderr`,text:e}):process.stderr.write(`\n${e}\n`)}let f=armDeadline(c,r.timeoutMs,()=>{reportFailure(timeoutMessage(e,r.timeoutMs??0)),settle(!1)});c.on(`error`,t=>{isAbortError(t,r.signal)||(l(),f(),reportFailure(t.code===`ENOENT`?VERCEL_NOT_FOUND_MESSAGE:`vercel ${e.join(` `)} failed: ${t.message}`),settle(!1))}),c.on(`close`,t=>{if(l(),f(),r.signal?.aborted===!0){settle(!1);return}!d&&t!==0&&t!==null&&reportFailure(`vercel ${e.join(` `)} exited with code ${t}.`),settle(t===0)})})}async function captureVercel(e,r){return r.signal?.aborted===!0?{ok:!1,failure:{errno:`ABORT_ERR`,stdout:``,stderr:``,message:abortMessage(e)}}:new Promise(i=>{let a=existingDir(r.cwd),o=resolveVercelInvocation(a),s=r.onOutput&&createProcessOutputBuffer(r.onOutput),c=spawn(o.command,[...o.commandArgs,...commandArgs(e,r.nonInteractive)],{cwd:a,stdio:[`ignore`,`pipe`,`pipe`],env:buildSpawnEnv(r.extraEnv??{}),signal:r.signal}),l=armProcessAbort(c,r.signal),u=[],d=[];c.stdout?.on(`data`,e=>u.push(e.toString(`utf8`))),c.stderr?.on(`data`,e=>{d.push(e.toString(`utf8`)),s?.write(`stderr`,e)});let f=!1;function fail(e,t=!0){f||(f=!0,s?.flush(),t&&r.onOutput?.({stream:`stderr`,text:e.message}),i({ok:!1,failure:e}))}function succeed(){f||(f=!0,s?.flush(),i({ok:!0,stdout:u.join(``)}))}let p=armDeadline(c,r.timeoutMs,()=>{fail({code:null,stdout:u.join(``),stderr:d.join(``),message:timeoutMessage(e,r.timeoutMs??0)})});c.on(`error`,t=>{isAbortError(t,r.signal)||(l(),p(),fail({errno:t.code,stdout:u.join(``),stderr:d.join(``),message:t.code===`ENOENT`?VERCEL_NOT_FOUND_MESSAGE:`vercel ${e.join(` `)} failed: ${t.message}`}))}),c.on(`close`,t=>{if(l(),p(),r.signal?.aborted===!0){fail({errno:`ABORT_ERR`,stdout:u.join(``),stderr:d.join(``),message:abortMessage(e)},!1);return}if(t!==0&&t!==null){fail({code:t,stdout:u.join(``),stderr:d.join(``),message:`vercel ${e.join(` `)} exited with code ${t}.`});return}succeed()})})}export{captureVercel,runVercel,runVercelCaptureStdout};
@@ -1,4 +1,4 @@
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";
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.2`,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__",
@@ -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__`}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};
1
+ import{existsSync,readFileSync,realpathSync}from"node:fs";import{dirname,join}from"node:path";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 n=join(o,`package.json`);if(existsSync(n)&&JSON.parse(readFileSync(n,`utf8`)).name===`eve`)return o;let a=dirname(o);if(a===o)return;o=a}}function findWorkspaceManifest(t){let n=t;for(;;){let t=join(n,`pnpm-workspace.yaml`);if(existsSync(t))return t;let a=dirname(n);if(a===n)return;n=a}}function readCatalogVersion(e,n){let r=readFileSync(e,`utf8`).split(/\r?\n/),i=!1;for(let e of r){if(/^catalog:\s*$/.test(e)){i=!0;continue}if(!i)continue;if(/^\S/.test(e))break;let t=e.match(/^\s+(?:"([^"]+)"|([\w@/.-]+)):\s*"([^"]+)"/);if(t&&(t[1]??t[2])===n)return t[3]}}function resolveTokenFromDevTree(n){let r=TOKEN_SOURCES[n];if(r!==void 0)try{let n=findEvePackageRoot();if(n===void 0||!existsSync(join(n,`scripts/stamp-version-tokens.mjs`)))return;if(r.kind===`eve-version`){let e=JSON.parse(readFileSync(join(n,`package.json`),`utf8`));return typeof e.version==`string`?e.version:void 0}if(r.kind===`eve-node-engine`){let e=JSON.parse(readFileSync(join(n,`package.json`),`utf8`)).engines?.node;return typeof e==`string`?e:void 0}let a=findWorkspaceManifest(n);return a===void 0?void 0:readCatalogVersion(a,r.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};
@@ -0,0 +1,41 @@
1
+ import type { ProcessOutputHandler } from "#setup/primitives/process-output.js";
2
+ import type { captureVercel, runVercelCaptureStdout } from "#setup/primitives/run-vercel.js";
3
+ import { type SlackConnectorRef, type SlackWorkspaceConnection } from "./slack-connect.js";
4
+ export interface SlackConnectorCreateDeps {
5
+ captureVercel: typeof captureVercel;
6
+ runVercelCaptureStdout: typeof runVercelCaptureStdout;
7
+ delay?: (ms: number, signal?: AbortSignal) => Promise<void>;
8
+ now?: () => number;
9
+ }
10
+ export type SlackConnectorCreateResult = {
11
+ state: "created";
12
+ via: "cli";
13
+ ref: SlackConnectorRef;
14
+ } | {
15
+ state: "created";
16
+ via: "workspace";
17
+ ref: SlackConnectorRef;
18
+ workspace: SlackWorkspaceConnection;
19
+ } | {
20
+ state: "failed";
21
+ } | {
22
+ state: "unresolved";
23
+ };
24
+ type Phase = <T>(message: string, task: () => Promise<T>) => Promise<T>;
25
+ /**
26
+ * Waits for either the CLI's final browser result or connector metadata proving
27
+ * that Slack connected the workspace. A connector progress event establishes
28
+ * ownership only; the exact detail endpoint establishes workspace completion.
29
+ */
30
+ export declare function createSlackConnector(input: {
31
+ deps: SlackConnectorCreateDeps;
32
+ projectRoot: string;
33
+ orgId: string | undefined;
34
+ slug: string;
35
+ onOutput: ProcessOutputHandler;
36
+ signal: AbortSignal | undefined;
37
+ phase: Phase;
38
+ onCreated: (ref: SlackConnectorRef) => void;
39
+ waitForWorkspace: (ref: SlackConnectorRef, signal: AbortSignal) => Promise<SlackWorkspaceConnection | undefined>;
40
+ }): Promise<SlackConnectorCreateResult>;
41
+ export {};
@@ -0,0 +1 @@
1
+ import{parseCreatedSlackConnector}from"./slack-connect.js";import{CONNECT_LOOKUP_TIMEOUT_MS,fetchSlackConnectorDetails}from"./slack-connect-lifecycle.js";import{setTimeout}from"node:timers/promises";import{performance}from"node:perf_hooks";const CREATED_CONNECTOR_PROGRESS=/\bConnector created:\s*(scl_[A-Za-z0-9]+)\b/,realDelay=(e,t)=>setTimeout(e,void 0,{signal:t}),monotonicNow=()=>performance.now();async function pollCreatedSlackConnector(e,r,i,a,o,s){let c=e.delay??realDelay,l=e.now??monotonicNow,u=l()+CONNECT_LOOKUP_TIMEOUT_MS;for(;;){s.throwIfAborted();let t=u-l();if(t<=0)return;let d=await fetchSlackConnectorDetails({deps:e,projectRoot:r,connectorId:i,orgId:a,onOutput:o,timeoutMs:Math.min(1e4,t),signal:s});if(s.throwIfAborted(),d.state===`found`)return d.details.ref;let f=u-l();if(f<=0)return;await c(Math.min(3e3,f),s)}}async function createSlackConnector(t){let n=new AbortController,r=new AbortController,i=new AbortController,o=t.signal?AbortSignal.any([t.signal,n.signal]):n.signal,s=t.signal?AbortSignal.any([t.signal,r.signal]):r.signal,c=t.signal?AbortSignal.any([t.signal,i.signal]):i.signal,l=!1,reportCreated=e=>{l||(l=!0,t.onCreated(e))},u,d,f=new Promise((e,t)=>{u=e,d=t}),p,m,startWorkspaceLookup=e=>{m===void 0&&(m=t.waitForWorkspace(e,c).catch(e=>{if(!(i.signal.aborted&&t.signal?.aborted!==!0))throw e}),m.then(t=>{t!==void 0&&u({ref:e,workspace:t})},d))},createOutput=e=>{t.onOutput(e);let n=e.text.match(CREATED_CONNECTOR_PROGRESS)?.[1];n===void 0||p!==void 0||(p=pollCreatedSlackConnector(t.deps,t.projectRoot,n,t.orgId,t.onOutput,s).catch(e=>{if(!(r.signal.aborted&&t.signal?.aborted!==!0))throw e}),p.then(e=>{e!==void 0&&(reportCreated(e),startWorkspaceLookup(e))},d))},h=t.phase(`Waiting for Slack setup to finish...`,()=>t.deps.runVercelCaptureStdout([`connect`,`create`,`slack`,`--triggers`,`--name`,t.slug,`-F`,`json`],{cwd:t.projectRoot,nonInteractive:!0,onOutput:createOutput,timeoutMs:6e5,signal:o})),g;try{g=await Promise.race([h.then(e=>({via:`cli`,result:e})),f.then(e=>({via:`workspace`,...e}))])}catch(e){throw r.abort(),i.abort(),await Promise.allSettled([p,m].filter(e=>e!==void 0)),e}if(g.via===`workspace`)return n.abort(),await h,t.signal?.throwIfAborted(),{state:`created`,via:`workspace`,ref:g.ref,workspace:g.workspace};if(!g.result.ok)return p!==void 0&&await p,i.abort(),m!==void 0&&await m,t.signal?.throwIfAborted(),{state:`failed`};let _=parseCreatedSlackConnector(g.result.stdout);if(_!==void 0)return reportCreated(_),r.abort(),i.abort(),p!==void 0&&await p,m!==void 0&&await m,t.signal?.throwIfAborted(),{state:`created`,via:`cli`,ref:_};let v=p===void 0?void 0:await p;return i.abort(),m!==void 0&&await m,t.signal?.throwIfAborted(),v===void 0?{state:`unresolved`}:{state:`created`,via:`cli`,ref:v}}export{createSlackConnector};
@@ -1,8 +1,13 @@
1
1
  import { createPromptCommandOutput, type ChannelSetupLog } from "#setup/cli/index.js";
2
2
  import { captureVercel, runVercel } from "#setup/primitives/run-vercel.js";
3
- import { type RawSlackConnector, type SlackConnectorRef } from "./slack-connect.js";
3
+ import { z } from "zod";
4
+ import { type RawSlackConnector, type SlackConnectorDetails, type SlackConnectorRef, type SlackWorkspaceConnection } from "./slack-connect.js";
4
5
  export declare const CONNECT_LOOKUP_TIMEOUT_MS = 60000;
5
6
  export declare const CONNECT_MUTATION_TIMEOUT_MS: number;
7
+ declare const VercelProjectLinkSchema: z.ZodObject<{
8
+ projectId: z.ZodString;
9
+ orgId: z.ZodString;
10
+ }, z.core.$strip>;
6
11
  /** Connect subprocess operations needed to inventory and remove Slack connectors. */
7
12
  export interface SlackConnectLifecycleDeps {
8
13
  captureVercel: typeof captureVercel;
@@ -32,8 +37,10 @@ export interface SlackConnectorCleanupContext {
32
37
  }
33
38
  /** Reads and validates the account-level Slack connector inventory. */
34
39
  export declare function listSlackConnectors(deps: SlackConnectLifecycleDeps, projectRoot: string, onOutput: CommandOutput, signal?: AbortSignal): Promise<SlackConnectorInventory>;
35
- /** Reads the linked Vercel project id from the on-disk `.vercel/project.json`. */
36
- export declare function readProjectId(projectRoot: string): Promise<string | undefined>;
40
+ /** Project and team identifiers from a valid on-disk Vercel link. */
41
+ export type VercelProjectLink = z.infer<typeof VercelProjectLinkSchema>;
42
+ /** Reads the linked Vercel project and team ids from `.vercel/project.json`. */
43
+ export declare function readProjectLink(projectRoot: string): Promise<VercelProjectLink | undefined>;
37
44
  export type SlackConnectorLookup = {
38
45
  state: "found";
39
46
  connector: SlackConnectorRef;
@@ -67,20 +74,42 @@ export type SlackConnectorAttachmentResult = {
67
74
  * rather than silently left pointing at the wrong place.
68
75
  */
69
76
  export declare function attachSlackConnector(deps: SlackConnectLifecycleDeps, projectRoot: string, ref: SlackConnectorRef, onOutput: CommandOutput, signal?: AbortSignal): Promise<SlackConnectorAttachmentResult>;
70
- export type InstallationLookup = {
71
- state: "installed";
72
- info: {
73
- workspaceUrl: string;
74
- workspaceName?: string;
75
- };
77
+ export type SlackWorkspaceLookup = {
78
+ state: "connected";
79
+ workspace: SlackWorkspaceConnection;
76
80
  } | {
77
81
  state: "pending";
78
82
  } | {
79
83
  state: "failed";
80
84
  message: string;
81
85
  };
82
- /** Fetches the Slack workspace installation for a connector, if one exists yet. */
83
- export declare function fetchInstallationInfo(deps: SlackConnectLifecycleDeps, projectRoot: string, connectorId: string, onOutput: CommandOutput, timeoutMs: number, signal?: AbortSignal): Promise<InstallationLookup>;
86
+ export type SlackConnectorDetailsLookup = {
87
+ state: "found";
88
+ details: SlackConnectorDetails;
89
+ } | {
90
+ state: "failed";
91
+ message: string;
92
+ };
93
+ /** Fetches and validates one team-scoped connector detail payload. */
94
+ export declare function fetchSlackConnectorDetails(input: {
95
+ deps: Pick<SlackConnectLifecycleDeps, "captureVercel">;
96
+ projectRoot: string;
97
+ connectorId: string;
98
+ orgId: string | undefined;
99
+ onOutput: CommandOutput;
100
+ timeoutMs: number;
101
+ signal?: AbortSignal;
102
+ }): Promise<SlackConnectorDetailsLookup>;
103
+ /** Fetches the Slack workspace connected to a connector, if one exists yet. */
104
+ export declare function fetchSlackWorkspace(input: {
105
+ deps: Pick<SlackConnectLifecycleDeps, "captureVercel">;
106
+ projectRoot: string;
107
+ connectorId: string;
108
+ orgId: string | undefined;
109
+ onOutput: CommandOutput;
110
+ timeoutMs: number;
111
+ signal?: AbortSignal;
112
+ }): Promise<SlackWorkspaceLookup>;
84
113
  /**
85
114
  * Removes the exact connector returned by `connect create`. When no UID was
86
115
  * returned, ownership cannot be proven: a concurrent or eventually-consistent