eve 0.12.3 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/src/cli/commands/deploy.js +1 -1
  3. package/dist/src/cli/commands/init.js +1 -1
  4. package/dist/src/cli/commands/link.d.ts +2 -2
  5. package/dist/src/cli/commands/link.js +1 -1
  6. package/dist/src/cli/dev/tui/setup-flow.d.ts +5 -0
  7. package/dist/src/cli/dev/tui/setup-panel.d.ts +4 -1
  8. package/dist/src/cli/dev/tui/setup-panel.js +1 -1
  9. package/dist/src/cli/dev/tui/setup-selection-input.d.ts +2 -1
  10. package/dist/src/cli/dev/tui/setup-selection-input.js +2 -2
  11. package/dist/src/cli/dev/tui/terminal-renderer.js +2 -2
  12. package/dist/src/cli/dev/tui/tui-prompter.js +1 -1
  13. package/dist/src/execution/durable-session-store.d.ts +3 -2
  14. package/dist/src/execution/node-step.js +1 -1
  15. package/dist/src/execution/session.d.ts +4 -10
  16. package/dist/src/execution/session.js +2 -2
  17. package/dist/src/execution/tool-auth.d.ts +16 -39
  18. package/dist/src/execution/tool-auth.js +1 -1
  19. package/dist/src/execution/workflow-steps.js +1 -1
  20. package/dist/src/internal/application/package.js +1 -1
  21. package/dist/src/internal/nitro/routes/agent-info/build-agent-info-response.js +1 -1
  22. package/dist/src/public/channels/github/api.d.ts +5 -0
  23. package/dist/src/public/channels/github/api.js +1 -1
  24. package/dist/src/public/channels/github/dispatch.js +1 -1
  25. package/dist/src/public/channels/github/pr-context.d.ts +10 -0
  26. package/dist/src/public/channels/github/pr-context.js +2 -2
  27. package/dist/src/public/definitions/tool.d.ts +3 -48
  28. package/dist/src/public/definitions/tool.js +1 -1
  29. package/dist/src/runtime/resolve-tool.js +1 -1
  30. package/dist/src/runtime/types.d.ts +0 -10
  31. package/dist/src/setup/boxes/link-project.d.ts +8 -14
  32. package/dist/src/setup/boxes/link-project.js +1 -1
  33. package/dist/src/setup/boxes/resolve-provisioning.d.ts +2 -1
  34. package/dist/src/setup/boxes/resolve-provisioning.js +1 -1
  35. package/dist/src/setup/cli/select-component.d.ts +7 -1
  36. package/dist/src/setup/cli/select-component.js +1 -1
  37. package/dist/src/setup/cli/select-option-codec.d.ts +1 -0
  38. package/dist/src/setup/cli/select-option-codec.js +1 -1
  39. package/dist/src/setup/cli/select-state.d.ts +14 -1
  40. package/dist/src/setup/cli/select-state.js +1 -1
  41. package/dist/src/setup/flows/model.d.ts +2 -2
  42. package/dist/src/setup/index.d.ts +1 -1
  43. package/dist/src/setup/package-manager.d.ts +2 -1
  44. package/dist/src/setup/package-manager.js +1 -1
  45. package/dist/src/setup/primitives/pm/index.d.ts +1 -1
  46. package/dist/src/setup/primitives/pm/pnpm.d.ts +11 -1
  47. package/dist/src/setup/primitives/pm/pnpm.js +5 -2
  48. package/dist/src/setup/primitives/pm/types.d.ts +10 -1
  49. package/dist/src/setup/project-resolution.d.ts +9 -6
  50. package/dist/src/setup/project-resolution.js +1 -1
  51. package/dist/src/setup/prompter.d.ts +13 -0
  52. package/dist/src/setup/prompter.js +1 -1
  53. package/dist/src/setup/scaffold/create/add-to-project.js +1 -1
  54. package/dist/src/setup/scaffold/create/project.d.ts +8 -0
  55. package/dist/src/setup/scaffold/create/project.js +8 -7
  56. package/dist/src/setup/scaffold/update/channels.d.ts +8 -0
  57. package/dist/src/setup/scaffold/update/channels.js +2 -2
  58. package/dist/src/setup/scaffold/update/package-json.d.ts +3 -0
  59. package/dist/src/setup/scaffold/update/package-json.js +1 -1
  60. package/dist/src/setup/scaffold/workspace-glob.d.ts +5 -0
  61. package/dist/src/setup/scaffold/workspace-glob.js +1 -0
  62. package/dist/src/setup/scaffold/workspace-root.d.ts +29 -0
  63. package/dist/src/setup/scaffold/workspace-root.js +1 -0
  64. package/dist/src/setup/state.d.ts +7 -2
  65. package/dist/src/setup/vercel-api-failure.d.ts +9 -0
  66. package/dist/src/setup/vercel-api-failure.js +1 -0
  67. package/dist/src/setup/vercel-deployment.js +1 -1
  68. package/dist/src/setup/vercel-project-api.d.ts +25 -0
  69. package/dist/src/setup/vercel-project-api.js +1 -0
  70. package/dist/src/setup/vercel-project.d.ts +9 -51
  71. package/dist/src/setup/vercel-project.js +1 -1
  72. package/docs/concepts/execution-model-and-durability.md +2 -0
  73. package/docs/guides/auth-and-route-protection.md +2 -4
  74. package/docs/guides/dev-tui.md +1 -1
  75. package/docs/reference/cli.md +1 -1
  76. package/docs/reference/typescript-api.md +0 -2
  77. package/package.json +1 -1
@@ -37,7 +37,7 @@ export interface ArgsHeadlessProject {
37
37
  skipVercel?: boolean;
38
38
  /** Vercel team slug (scope). Undefined = the current vercel scope. */
39
39
  team?: string;
40
- /** Existing project slug to link. Undefined = create a new project named after the agent. */
40
+ /** Existing project name or ID to link. Undefined = create a project named after the agent. */
41
41
  project?: string;
42
42
  }
43
43
  /**
@@ -61,6 +61,11 @@ export type ProvisioningMode = {
61
61
  } | {
62
62
  headless: false;
63
63
  };
64
+ /** Stable identity of an existing Vercel project selected for linking. */
65
+ export interface VercelProjectIdentity {
66
+ projectId: string;
67
+ projectName: string;
68
+ }
64
69
  /**
65
70
  * Resolved project decision, fully concrete. The variant determines whether
66
71
  * the flow creates a project, links an existing one, or avoids Vercel project
@@ -74,7 +79,7 @@ export type ResolvedVercelProject = {
74
79
  team: string;
75
80
  } | {
76
81
  kind: "existing";
77
- project: string;
82
+ project: VercelProjectIdentity;
78
83
  team: string;
79
84
  };
80
85
  /** A concrete project to ensure exists and link. */
@@ -0,0 +1,9 @@
1
+ import type { VercelCaptureFailure, VercelCaptureResult } from "#setup/primitives/index.js";
2
+ /** Treats a structured API error as a failure even when `vercel api --raw` exits zero. */
3
+ export declare function normalizeVercelApiResult(result: VercelCaptureResult): VercelCaptureResult;
4
+ /** Whether a Vercel API failure proves that the requested resource does not exist. */
5
+ export declare function isNotFoundApiFailure(failure: VercelCaptureFailure): boolean;
6
+ /** Whether a Vercel API failure proves that the requested resource already exists. */
7
+ export declare function isConflictApiFailure(failure: VercelCaptureFailure): boolean;
8
+ /** Whether a scoped Vercel API request was denied. */
9
+ export declare function isForbiddenApiFailure(failure: VercelCaptureFailure): boolean;
@@ -0,0 +1 @@
1
+ import{number,object,string,union}from"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/schemas.js";import"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.js";const VercelApiErrorSchema=object({error:object({code:union([string(),number()]).optional(),message:string().optional()}).optional()});function apiErrorFromStdout(e){try{let t=VercelApiErrorSchema.safeParse(JSON.parse(e));return t.success?t.data.error:void 0}catch{return}}function apiFailureText(e){let t=apiErrorFromStdout(e.stdout);return`${String(t?.code??``)} ${t?.message??``} ${e.stderr}`.toLowerCase()}function normalizeVercelApiResult(e){if(!e.ok)return e;let t=apiErrorFromStdout(e.stdout);if(t===void 0)return e;let n=t.message??(t.code===void 0?void 0:String(t.code));return{ok:!1,failure:{stdout:e.stdout,stderr:``,message:`Vercel API request failed${n===void 0?``:`: ${n}`}.`}}}function isNotFoundApiFailure(e){return/(^|\W)(404|not_found)(\W|$)|not found/.test(apiFailureText(e))}function isConflictApiFailure(e){return/(^|\W)(409|conflict)(\W|$)|already exists/.test(apiFailureText(e))}function isForbiddenApiFailure(e){return/(^|\W)(403|forbidden|not_authorized|team_unauthorized|sso|saml)(\W|$)|not authorized/.test(apiFailureText(e))}export{isConflictApiFailure,isForbiddenApiFailure,isNotFoundApiFailure,normalizeVercelApiResult};
@@ -1 +1 @@
1
- import{number,object,string,union}from"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/schemas.js";import"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.js";import{projectReferenceFromEnvironment,readProjectLink}from"#setup/project-resolution.js";import{captureVercel}from"#setup/primitives/index.js";const VercelDeploymentSchema=object({projectId:string().min(1),name:string().min(1),target:string().nullable().optional(),customEnvironment:object({slug:string().min(1)}).nullable().optional()}),VercelApiErrorSchema=object({error:object({code:union([string(),number()]).optional(),message:string().optional()})}),verifiedVercelTargetBrand=Symbol(`VerifiedVercelTarget`),defaultDeps={captureVercel,readProjectLink};function isNotFoundApiFailure(e){if(e.code===404)return!0;try{let t=VercelApiErrorSchema.safeParse(JSON.parse(e.stdout));if(!t.success)return!1;let n=String(t.data.error.code??``).toLowerCase(),r=t.data.error.message?.toLowerCase()??``;return n===`404`||n===`not_found`||r.includes(`not found`)}catch{return!1}}function environmentForDeployment(e){return e.customEnvironment!==null&&e.customEnvironment!==void 0?e.customEnvironment.slug:e.target===`production`?`production`:`preview`}async function resolveVercelDeployment(e){let t={...defaultDeps,...e.deps},n=e.source??projectReferenceFromEnvironment(process.env)??await t.readProjectLink(e.workspaceRoot);if(n===void 0)return{kind:`unscoped`};let r=await t.captureVercel([`api`,`/v13/deployments/${encodeURIComponent(e.host)}`,`--scope`,n.orgId,`--raw`],{cwd:e.workspaceRoot,nonInteractive:!0,signal:e.signal,timeoutMs:1e4});if(!r.ok)return e.signal?.aborted===!0||r.failure.errno===`ABORT_ERR`?{kind:`cancelled`}:isNotFoundApiFailure(r.failure)?{kind:`not-found`}:{kind:`failed`,failure:{cause:`vercel`,failure:r.failure}};let i;try{i=JSON.parse(r.stdout)}catch{return{kind:`failed`,failure:{cause:`invalid-json`,message:`Vercel returned invalid deployment JSON.`}}}let a=VercelDeploymentSchema.safeParse(i);if(!a.success)return{kind:`failed`,failure:{cause:`invalid-shape`,message:`Vercel returned an invalid deployment response.`}};if(a.data.projectId!==n.projectId)return{kind:`project-mismatch`,expectedProjectId:n.projectId,actualProjectId:a.data.projectId};let o=`https://${new URL(`https://${e.host}`).host}`;return{kind:`resolved`,target:{[verifiedVercelTargetBrand]:!0,origin:o,deployment:{provider:`vercel`,ownerId:n.orgId,projectId:a.data.projectId,projectName:a.data.name,environment:environmentForDeployment(a.data)}}}}export{resolveVercelDeployment};
1
+ import{object,string}from"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/schemas.js";import"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.js";import{isNotFoundApiFailure,normalizeVercelApiResult}from"./vercel-api-failure.js";import{projectReferenceFromEnvironment,readProjectLink}from"#setup/project-resolution.js";import{captureVercel}from"#setup/primitives/index.js";const VercelDeploymentSchema=object({projectId:string().min(1),name:string().min(1),target:string().nullable().optional(),customEnvironment:object({slug:string().min(1)}).nullable().optional()}),verifiedVercelTargetBrand=Symbol(`VerifiedVercelTarget`),defaultDeps={captureVercel,readProjectLink};function environmentForDeployment(e){return e.customEnvironment!==null&&e.customEnvironment!==void 0?e.customEnvironment.slug:e.target===`production`?`production`:`preview`}async function resolveVercelDeployment(e){let t={...defaultDeps,...e.deps},n=e.source??projectReferenceFromEnvironment(process.env)??await t.readProjectLink(e.workspaceRoot);if(n===void 0)return{kind:`unscoped`};let r=normalizeVercelApiResult(await t.captureVercel([`api`,`/v13/deployments/${encodeURIComponent(e.host)}`,`--scope`,n.orgId,`--raw`],{cwd:e.workspaceRoot,nonInteractive:!0,signal:e.signal,timeoutMs:1e4}));if(!r.ok)return e.signal?.aborted===!0||r.failure.errno===`ABORT_ERR`?{kind:`cancelled`}:isNotFoundApiFailure(r.failure)?{kind:`not-found`}:{kind:`failed`,failure:{cause:`vercel`,failure:r.failure}};let i;try{i=JSON.parse(r.stdout)}catch{return{kind:`failed`,failure:{cause:`invalid-json`,message:`Vercel returned invalid deployment JSON.`}}}let a=VercelDeploymentSchema.safeParse(i);if(!a.success)return{kind:`failed`,failure:{cause:`invalid-shape`,message:`Vercel returned an invalid deployment response.`}};if(a.data.projectId!==n.projectId)return{kind:`project-mismatch`,expectedProjectId:n.projectId,actualProjectId:a.data.projectId};let o=`https://${new URL(`https://${e.host}`).host}`;return{kind:`resolved`,target:{[verifiedVercelTargetBrand]:!0,origin:o,deployment:{provider:`vercel`,ownerId:n.orgId,projectId:a.data.projectId,projectName:a.data.name,environment:environmentForDeployment(a.data)}}}}export{resolveVercelDeployment};
@@ -0,0 +1,25 @@
1
+ import { type VercelCaptureFailure } from "#setup/primitives/index.js";
2
+ import { z } from "zod";
3
+ import type { VercelProjectOperationOptions } from "./project-resolution.js";
4
+ export type { VercelProjectOperationOptions };
5
+ declare const VercelTeamListEntrySchema: z.ZodObject<{
6
+ name: z.ZodString;
7
+ slug: z.ZodString;
8
+ current: z.ZodBoolean;
9
+ }, z.core.$strip>;
10
+ type VercelTeamListEntry = z.infer<typeof VercelTeamListEntrySchema>;
11
+ declare const VercelProjectListEntrySchema: z.ZodObject<{
12
+ name: z.ZodString;
13
+ id: z.ZodString;
14
+ }, z.core.$strip>;
15
+ export type VercelProjectListEntry = z.infer<typeof VercelProjectListEntrySchema>;
16
+ /** Parses one JSON response captured from the Vercel CLI. */
17
+ export declare function parseVercelJson(stdout: string, description: string): unknown;
18
+ /** Converts a scoped API denial into the Vercel re-authentication action. */
19
+ export declare function requireVercelTeamAccess(failure: VercelCaptureFailure): never;
20
+ /** Lists every Vercel scope available to the current CLI user. */
21
+ export declare function listTeams(projectRoot: string, options?: VercelProjectOperationOptions): Promise<VercelTeamListEntry[]>;
22
+ /** Lists the 20 most recent Vercel projects in one account scope. */
23
+ export declare function listRecentProjects(projectRoot: string, team: string, options?: VercelProjectOperationOptions): Promise<VercelProjectListEntry[]>;
24
+ /** Searches every matching Vercel project page in one account scope. */
25
+ export declare function searchProjects(projectRoot: string, team: string, query: string, options?: VercelProjectOperationOptions): Promise<VercelProjectListEntry[]>;
@@ -0,0 +1 @@
1
+ import{array,boolean,number,object,string}from"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/schemas.js";import"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.js";import{isForbiddenApiFailure}from"./vercel-api-failure.js";import{captureVercel}from"#setup/primitives/index.js";import{HumanActionRequiredError}from"#setup/human-action.js";const VercelTeamListEntrySchema=object({name:string(),slug:string(),current:boolean()}),VercelProjectListEntrySchema=object({name:string(),id:string()}),VercelPaginationSchema=object({next:number().int().nonnegative().nullable().optional()}),VercelTeamPageSchema=object({teams:array(VercelTeamListEntrySchema),pagination:VercelPaginationSchema.optional()}).transform(e=>({items:e.teams,next:e.pagination?.next??void 0})),VercelProjectPageSchema=object({projects:array(VercelProjectListEntrySchema),pagination:VercelPaginationSchema.optional()}).transform(e=>({items:e.projects,next:e.pagination?.next??void 0}));function parseVercelJson(e,t){try{return JSON.parse(e)}catch{throw Error(`Could not parse ${t} JSON from Vercel CLI output.`)}}async function drainPages(e,t,n){let r=new Map,i=new Set,a;for(;;){let o=await n(a);for(let e of o.items)r.set(t(e),e);if(o.next===void 0)return[...r.values()];if(i.has(o.next))throw Error(`Vercel returned a repeated pagination cursor for ${e}.`);i.add(o.next),a=o.next}}function requireVercelTeamAccess(e){let t=e.stderr.trim();throw new HumanActionRequiredError({kind:`vercel-forbidden`,command:`vercel login`,reason:`Vercel denied access to this scope.${t?` ${t}`:``} Re-authenticate (for example to complete a team's SSO) or switch to a team you can access.`})}async function fetchTeamPage(e,t,n){let r=[`teams`,`ls`,`--format`,`json`];n!==void 0&&r.push(`--next`,String(n));let i=await captureVercel(r,{cwd:e,signal:t.signal});if(t.signal?.throwIfAborted(),!i.ok)throw isForbiddenApiFailure(i.failure)&&requireVercelTeamAccess(i.failure),Error(`Could not list Vercel teams. ${i.failure.message}`);let s=VercelTeamPageSchema.safeParse(parseVercelJson(i.stdout,`teams`));if(!s.success)throw Error(`Could not read teams from Vercel CLI JSON output.`);return s.data}async function listTeams(e,t={}){return drainPages(`Vercel teams`,e=>e.slug,n=>fetchTeamPage(e,t,n))}async function fetchProjectPage(e,t,n){let r=[`project`,`ls`,`--format`,`json`,`--scope`,t];n.search!==void 0&&r.push(`--filter`,n.search),n.next!==void 0&&r.push(`--next`,String(n.next));let i=await captureVercel(r,{cwd:e,signal:n.signal,timeoutMs:15e3});if(n.signal?.throwIfAborted(),!i.ok)throw isForbiddenApiFailure(i.failure)&&requireVercelTeamAccess(i.failure),Error(`Could not list Vercel projects in ${t}. ${i.failure.message}`);let s=VercelProjectPageSchema.safeParse(parseVercelJson(i.stdout,`projects`));if(!s.success)throw Error(`Could not read projects from Vercel CLI JSON output.`);return s.data}async function listRecentProjects(e,t,n={}){return(await fetchProjectPage(e,t,n)).items}async function searchProjects(e,t,n,r={}){let i=n.trim();if(i.length===0)throw Error(`Project search query cannot be empty.`);return drainPages(`project search in ${t}`,e=>e.id,n=>fetchProjectPage(e,t,{...r,search:i,next:n}))}export{listRecentProjects,listTeams,parseVercelJson,requireVercelTeamAccess,searchProjects};
@@ -1,28 +1,9 @@
1
1
  import { createPromptCommandOutput } from "#setup/cli/index.js";
2
2
  import { type VercelCaptureFailure } from "#setup/primitives/index.js";
3
- import { z } from "zod";
4
- import type { ProjectResolution } from "./project-resolution.js";
3
+ import { type ProjectResolution } from "./project-resolution.js";
5
4
  import type { Prompter } from "./prompter.js";
6
- import type { ResolvedVercelProjectSpec } from "./state.js";
7
- declare const VercelTeamListEntrySchema: z.ZodObject<{
8
- name: z.ZodString;
9
- slug: z.ZodString;
10
- current: z.ZodBoolean;
11
- }, z.core.$strip>;
12
- type VercelTeamListEntry = z.infer<typeof VercelTeamListEntrySchema>;
13
- declare const VercelProjectListEntrySchema: z.ZodObject<{
14
- name: z.ZodString;
15
- id: z.ZodString;
16
- }, z.core.$strip>;
17
- type VercelProjectListEntry = z.infer<typeof VercelProjectListEntrySchema>;
18
- declare const VercelProjectReferenceSchema: z.ZodObject<{
19
- id: z.ZodString;
20
- name: z.ZodString;
21
- }, z.core.$strip>;
22
- type VercelProjectReference = z.infer<typeof VercelProjectReferenceSchema>;
23
- export interface VercelProjectOperationOptions {
24
- signal?: AbortSignal;
25
- }
5
+ import type { ResolvedVercelProjectSpec, VercelProjectIdentity } from "./state.js";
6
+ import { type VercelProjectOperationOptions } from "./vercel-project-api.js";
26
7
  export interface PickProjectOptions extends VercelProjectOperationOptions {
27
8
  /** Whether an empty project list may fall back to entering a name to create. */
28
9
  allowCreateWhenEmpty?: boolean;
@@ -30,12 +11,8 @@ export interface PickProjectOptions extends VercelProjectOperationOptions {
30
11
  export declare function unresolvedProject(): ProjectResolution;
31
12
  /** Resolves the linked project id from a resolution, if any. */
32
13
  export declare function projectIdFromResolution(project: ProjectResolution): string | undefined;
33
- /** Lists the Vercel scopes available to the current CLI user. */
34
- export declare function listTeams(projectRoot: string, options?: VercelProjectOperationOptions): Promise<VercelTeamListEntry[]>;
35
- /** Lists Vercel projects available under an explicit team or personal scope. */
36
- export declare function listProjects(projectRoot: string, team: string, options?: VercelProjectOperationOptions): Promise<VercelProjectListEntry[]>;
37
14
  /** Resolves one project by exact name or id through the Vercel API. */
38
- export declare function resolveProjectByNameOrId(projectRoot: string, team: string, projectNameOrId: string, options?: VercelProjectOperationOptions): Promise<VercelProjectReference | null>;
15
+ export declare function resolveProjectByNameOrId(projectRoot: string, team: string, projectNameOrId: string, options?: VercelProjectOperationOptions): Promise<VercelProjectIdentity | null>;
39
16
  export declare function assertNewProjectNameAvailable(projectRoot: string, team: string, projectName: string, options?: VercelProjectOperationOptions): Promise<void>;
40
17
  /**
41
18
  * Throws the login action. When the underlying `vercel whoami` failure is
@@ -63,14 +40,6 @@ export type VercelAuthStatus = "authenticated" | "logged-out" | "cli-missing" |
63
40
  /** Returns the user-facing reason Vercel-backed setup is unavailable. */
64
41
  export declare function vercelAuthBlockerReason(authStatus: VercelAuthStatus): string | undefined;
65
42
  export declare function getVercelAuthStatus(projectRoot: string, options?: VercelProjectOperationOptions): Promise<VercelAuthStatus>;
66
- /**
67
- * Throws the re-auth action for a forbidden scope. The session is logged in,
68
- * but a scoped command was denied — the SSO/SAML or non-membership case. The
69
- * remedy is still `vercel login` (it completes the team's SSO and refreshes the
70
- * token), so the dev TUI routes it to `/login`; the reason names the membership
71
- * fallback for the case re-auth cannot fix.
72
- */
73
- export declare function requireVercelTeamAccess(failure: VercelCaptureFailure): never;
74
43
  /**
75
44
  * Ensures Vercel authentication before any provisioning. `vercel whoami` exits
76
45
  * non-zero when not logged in; any other failure (a missing CLI, a transient
@@ -106,25 +75,14 @@ export declare function validateTeam(prompter: Prompter, projectRoot: string, te
106
75
  * user filters and chooses from the list with a single-selection picker.
107
76
  */
108
77
  export declare function pickTeam(prompter: Prompter, projectRoot: string, presetTeam: string | undefined, options?: VercelProjectOperationOptions): Promise<string>;
109
- /**
110
- * A picked Vercel project. `exists` distinguishes a project the user selected
111
- * from the existing list (link it) from a name they typed because none exist
112
- * yet (create it), so the caller can build the right `new` vs `existing` plan.
113
- */
114
- export interface ArgsPickedProject {
115
- /** Project slug: an existing project's name, or a name to create. */
116
- project: string;
117
- /** True for a selected existing project; false for a typed-in name to create. */
118
- exists: boolean;
119
- }
120
78
  /** Picks an existing project under a team, or a name to create when none exist. */
121
- export declare function pickProject(prompter: Prompter, projectRoot: string, team: string, options?: PickProjectOptions): Promise<ArgsPickedProject>;
79
+ export declare function pickProject(prompter: Prompter, projectRoot: string, team: string, options?: PickProjectOptions): Promise<ResolvedVercelProjectSpec>;
122
80
  /** Returns a project name for a new Vercel project, prompting when the default exists. */
123
81
  export declare function pickNewProjectName(prompter: Prompter, projectRoot: string, team: string, defaultProjectName: string, options?: VercelProjectOperationOptions): Promise<string>;
124
82
  /**
125
83
  * Ensures the concrete project exists (creating it for a `new` plan) and links
126
- * this directory to it. Pure executor: it acts on a fully-resolved spec and
127
- * never prompts for a team or project. Returns whether the link succeeded.
84
+ * this directory to it. Acts on a fully-resolved spec — never prompts for a
85
+ * team or project. Returns the linked project, or undefined if `vercel link`
86
+ * did not complete.
128
87
  */
129
- export declare function linkProject(prompter: Prompter, projectRoot: string, spec: ResolvedVercelProjectSpec, onOutput: ReturnType<typeof createPromptCommandOutput>, options?: VercelProjectOperationOptions): Promise<boolean>;
130
- export {};
88
+ export declare function linkProject(prompter: Prompter, projectRoot: string, spec: ResolvedVercelProjectSpec, onOutput: ReturnType<typeof createPromptCommandOutput>, options?: VercelProjectOperationOptions): Promise<VercelProjectIdentity | undefined>;
@@ -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{boolean,object,record,string,unknown}from"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/schemas.js";import"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.js";import{withSpinner}from"./with-spinner.js";import{hasVercelHostFramework}from"#setup/scaffold/index.js";import{captureVercel,runVercel}from"#setup/primitives/index.js";import{HumanActionRequiredError}from"#setup/human-action.js";import{whimsyFor}from"#setup/cli/index.js";var import_picocolors=__toESM(require_picocolors(),1);const JsonObjectSchema=record(string(),unknown()),VercelTeamListEntrySchema=object({name:string(),slug:string(),current:boolean()}),VercelProjectListEntrySchema=object({name:string(),id:string()}),VercelProjectReferenceSchema=object({id:string(),name:string()}),VercelApiErrorSchema=object({error:object({code:string().optional(),message:string().optional()}).optional()});function unresolvedProject(){return{kind:`unresolved`}}function projectIdFromResolution(e){return e.kind===`unresolved`?void 0:e.projectId}function parseJson(e,t){try{return JSON.parse(e)}catch{throw Error(`Could not parse ${t} JSON from Vercel CLI output.`)}}function parseVercelJsonList(e,t,n){let r=parseJson(e,t),i=JsonObjectSchema.safeParse(r);if(!i.success)throw Error(`Could not read ${t} from Vercel CLI JSON output.`);let a=i.data[t];if(!Array.isArray(a))throw Error(`Vercel CLI JSON output did not include ${t}.`);let o=[];for(let e of a){let t=n.safeParse(e);t.success&&o.push(t.data)}return o}function parseTeamList(e){return e===void 0?[]:parseVercelJsonList(e,`teams`,VercelTeamListEntrySchema)}async function listTeams(e,t={}){let n=await captureVercel([`teams`,`ls`,`--format`,`json`],{cwd:e,signal:t.signal});if(!n.ok)throw isForbiddenApiFailure(n.failure)&&requireVercelTeamAccess(n.failure),Error(`Could not list Vercel teams. ${n.failure.message}`);return parseTeamList(n.stdout)}function parseProjectList(e){return e===void 0?[]:parseVercelJsonList(e,`projects`,VercelProjectListEntrySchema)}async function listProjects(e,t,n={}){let r=await captureVercel([`project`,`ls`,`--format`,`json`,`--scope`,t],{cwd:e,signal:n.signal});if(!r.ok)throw isForbiddenApiFailure(r.failure)&&requireVercelTeamAccess(r.failure),Error(`Could not list Vercel projects in ${t}. ${r.failure.message}`);return parseProjectList(r.stdout)}function isNotFoundApiFailure(e){if(e.code===404)return!0;let t=VercelApiErrorSchema.safeParse(safeParseJson(e.stdout)),n=t.success?t.data.error:void 0,r=`${n?.code??``} ${n?.message??``} ${e.stderr}`.toLowerCase();return r.includes(`not_found`)||r.includes(`not found`)||r.includes(`404`)}function isConflictApiFailure(e){let t=VercelApiErrorSchema.safeParse(safeParseJson(e.stdout)),n=t.success?t.data.error:void 0,r=`${n?.code??``} ${n?.message??``} ${e.stdout} ${e.stderr}`.toLowerCase();return r.includes(`409`)||r.includes(`conflict`)||r.includes(`already exists`)}function isForbiddenApiFailure(e){let t=VercelApiErrorSchema.safeParse(safeParseJson(e.stdout)),n=t.success?t.data.error:void 0,r=`${n?.code??``} ${n?.message??``} ${e.stdout} ${e.stderr}`.toLowerCase();return r.includes(`403`)||r.includes(`forbidden`)||r.includes(`not_authorized`)||r.includes(`not authorized`)||r.includes(`sso`)||r.includes(`saml`)}function safeParseJson(e){try{return JSON.parse(e)}catch{return}}function parseProjectReference(e,t){let n=VercelProjectReferenceSchema.safeParse(parseJson(e,t));if(!n.success)throw Error(`Could not read Vercel project identity from ${t}.`);return n.data}async function resolveProjectByNameOrId(e,t,n,r={}){let i=await captureVercel([`api`,`/v9/projects/${encodeURIComponent(n)}`,`--scope`,t,`--raw`],{cwd:e,signal:r.signal});if(i.ok)return parseProjectReference(i.stdout,`project ${n}`);if(isNotFoundApiFailure(i.failure))return null;throw isForbiddenApiFailure(i.failure)&&requireVercelTeamAccess(i.failure),Error(`Could not resolve project "${n}" in ${t}. ${i.failure.message}`)}async function createProject(e,t,n,r,i){let a=[`api`,`/v10/projects`,`--scope`,t,`--method`,`POST`,`--raw-field`,`name=${n}`];await hasVercelHostFramework(e)||a.push(`--raw-field`,`framework=eve`),a.push(`--raw`);let o=await captureVercel(a,{cwd:e,onOutput:r,signal:i.signal});if(o.ok)return parseProjectReference(o.stdout,`created project ${n}`);throw isConflictApiFailure(o.failure)?Error(projectNameCollisionMessage(n,t)):(isForbiddenApiFailure(o.failure)&&requireVercelTeamAccess(o.failure),Error(`Could not create Vercel project "${n}" in ${t}. ${o.failure.message}`))}function projectNameCollisionMessage(e,t){return`Vercel project "${e}" already exists in ${t}. Pass --project ${e} to link it, or choose a different project name.`}async function assertNewProjectNameAvailable(e,t,n,r={}){if(await resolveProjectByNameOrId(e,t,n,r)!==null)throw Error(projectNameCollisionMessage(n,t))}function requireVercelLogin(e){let t=`Provisioning a Vercel project requires you to be logged in to Vercel.`,n=e?.stderr.trim();throw new HumanActionRequiredError({kind:`vercel-login`,command:`vercel login`,reason:e?`${t} The Vercel CLI check did not succeed: ${e.message}${n?` ${n}`:``}`:t})}function probeWhoami(e,t){return captureVercel([`whoami`],{cwd:e,signal:t.signal,timeoutMs:1e4})}function isLoggedOutFailure(e){let t=`${e.stdout} ${e.stderr}`.toLowerCase();return t.includes(`credentials`)||t.includes(`not authenticated`)||t.includes(`not logged in`)}function requireVercelAuth(e){if(e.errno===`ENOENT`)throw new HumanActionRequiredError({kind:`vercel-cli-missing`,command:`npm i -g vercel@latest`,reason:e.message});isLoggedOutFailure(e)&&requireVercelLogin(e);let t=e.stderr.trim();throw Error(`Couldn't verify your Vercel login: ${e.message}${t?` ${t}`:``}`)}function vercelAuthBlockerReason(e){switch(e){case`authenticated`:return;case`cli-missing`:return`Vercel CLI not found, see /vc`;case`logged-out`:return`Log in to Vercel first, see /login`;case`unavailable`:return`Couldn't reach Vercel, check your connection`;default:return e}}async function getVercelAuthStatus(e,t={}){let n=await probeWhoami(e,t);return t.signal?.throwIfAborted(),n.ok?`authenticated`:n.failure.errno===`ENOENT`?`cli-missing`:isLoggedOutFailure(n.failure)?`logged-out`:`unavailable`}function requireVercelTeamAccess(e){let t=e.stderr.trim();throw new HumanActionRequiredError({kind:`vercel-forbidden`,command:`vercel login`,reason:`Vercel denied access to this scope.${t?` ${t}`:``} Re-authenticate (for example to complete a team's SSO) or switch to a team you can access.`})}async function requireAuth(e,t,n={}){let check=async()=>{let t=await probeWhoami(e,n);n.signal?.throwIfAborted(),t.ok||requireVercelAuth(t.failure)};if(t===void 0){await check();return}await withSpinner(t,whimsyFor(`auth`),check)}async function isVercelAuthenticated(e,t={}){return await getVercelAuthStatus(e,t)===`authenticated`}async function whoamiScope(e,t){let n=await probeWhoami(e,t);return t.signal?.throwIfAborted(),n.ok||requireVercelAuth(n.failure),n.stdout.trim()}async function resolveTeam(e,t,n={}){return t===void 0?(await listTeams(e,n)).find(e=>e.current)?.slug??await whoamiScope(e,n):t}async function validateTeam(e,t,n,r={}){if(n===void 0)return;let i=await listTeams(t,r);if(i.length>0&&!i.some(e=>e.slug===n))throw Error(`Team "${n}" was not found in \`vercel teams ls\`. Pass a valid team slug or omit --team.`)}async function pickTeam(e,t,n,r={}){if(n!==void 0)return await validateTeam(e,t,n,r),resolveTeam(t,n,r);let i=await withSpinner(e,whimsyFor(`teams`),()=>listTeams(t,r));return i.length<=1?i.find(e=>e.current)?.slug??await whoamiScope(t,r):e.select({message:`Select your team`,search:!0,placeholder:`type to search teams`,options:i.map(e=>({value:e.slug,label:e.current?`${e.name} (current)`:e.name})),initialValue:i.find(e=>e.current)?.slug})}async function pickProject(e,t,n,r={}){let i=await withSpinner(e,whimsyFor(`projects`,n),()=>listProjects(t,n,r));if(i.length===0){if(r.allowCreateWhenEmpty===!1)throw Error(`No existing Vercel projects found in ${n}. Create one in Vercel, then try again.`);return{project:await e.text({message:`No projects found in ${n}. Enter a project name to create`,validate:e=>e.trim().length===0?`Project name cannot be empty.`:void 0}),exists:!1}}return{project:await e.select({message:`Project to link`,search:!0,placeholder:`type to filter projects`,options:i.map(e=>({value:e.name,label:e.name}))}),exists:!0}}async function pickNewProjectName(e,t,n,r,i={}){let a=await withSpinner(e,whimsyFor(`project-name`,n),()=>resolveProjectByNameOrId(t,n,r.trim(),i)),o=r.trim();for(;a!==null;)o=(await e.text({message:`New project name`,defaultValue:`${o}-2`,notices:[{tone:`warning`,text:`${import_picocolors.default.yellow(`Project named`)} '${import_picocolors.default.blue(o)}' ${import_picocolors.default.yellow(`already exists in`)} '${import_picocolors.default.blue(n)}'`}],validate:e=>{if(e.trim().length===0)return`Project name cannot be empty.`}})).trim(),a=await resolveProjectByNameOrId(t,n,o,i);return o}async function linkProject(e,t,n,r,i={}){let a=[`--scope`,n.team],o;if(n.kind===`new`)o=await withSpinner(e,`Creating Vercel project "${n.project}" in ${n.team}...`,async()=>(await assertNewProjectNameAvailable(t,n.team,n.project,i),createProject(t,n.team,n.project,r,i)));else{let e=await resolveProjectByNameOrId(t,n.team,n.project,i);if(e===null)throw Error(`Vercel project "${n.project}" was not found in ${n.team}.`);o=e}return withSpinner(e,`Linking this directory to Vercel project "${o.name}"...`,()=>runVercel([`link`,`--project`,o.id,...a,`--yes`],{cwd:t,onOutput:r,nonInteractive:!0,signal:i.signal}))}export{assertNewProjectNameAvailable,getVercelAuthStatus,isVercelAuthenticated,linkProject,listProjects,listTeams,pickNewProjectName,pickProject,pickTeam,projectIdFromResolution,requireAuth,requireVercelAuth,requireVercelLogin,requireVercelTeamAccess,resolveProjectByNameOrId,resolveTeam,unresolvedProject,validateTeam,vercelAuthBlockerReason};
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{object,string}from"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/schemas.js";import"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.js";import{assertNoLegacyProjectLinkDirectory}from"./project-resolution.js";import{withSpinner}from"./with-spinner.js";import{isConflictApiFailure,isForbiddenApiFailure,isNotFoundApiFailure,normalizeVercelApiResult}from"./vercel-api-failure.js";import{listRecentProjects,listTeams,parseVercelJson,requireVercelTeamAccess,searchProjects}from"./vercel-project-api.js";import{hasVercelHostFramework}from"#setup/scaffold/index.js";import{captureVercel,runVercel}from"#setup/primitives/index.js";import{HumanActionRequiredError}from"#setup/human-action.js";import{whimsyFor}from"#setup/cli/index.js";var import_picocolors=__toESM(require_picocolors(),1);const VercelProjectReferenceSchema=object({id:string().min(1),name:string().min(1)});function unresolvedProject(){return{kind:`unresolved`}}function projectIdFromResolution(e){return e.kind===`unresolved`?void 0:e.projectId}function parseProjectReference(e,t){let n=VercelProjectReferenceSchema.safeParse(parseVercelJson(e,t));if(!n.success)throw Error(`Could not read Vercel project identity from ${t}.`);return{projectId:n.data.id,projectName:n.data.name}}async function resolveProjectByNameOrId(e,t,n,r={}){let i=normalizeVercelApiResult(await captureVercel([`api`,`/v9/projects/${encodeURIComponent(n)}`,`--scope`,t,`--raw`],{cwd:e,signal:r.signal}));if(i.ok)return parseProjectReference(i.stdout,`project ${n}`);if(isNotFoundApiFailure(i.failure))return null;throw isForbiddenApiFailure(i.failure)&&requireVercelTeamAccess(i.failure),Error(`Could not resolve project "${n}" in ${t}. ${i.failure.message}`)}async function createProject(e,t,n,r,i){let a=[`api`,`/v10/projects`,`--scope`,t,`--method`,`POST`,`--raw-field`,`name=${n}`];await hasVercelHostFramework(e)||a.push(`--raw-field`,`framework=eve`),a.push(`--raw`);let c=normalizeVercelApiResult(await captureVercel(a,{cwd:e,onOutput:r,signal:i.signal}));if(c.ok)return parseProjectReference(c.stdout,`created project ${n}`);throw isConflictApiFailure(c.failure)?Error(projectNameCollisionMessage(n,t)):(isForbiddenApiFailure(c.failure)&&requireVercelTeamAccess(c.failure),Error(`Could not create Vercel project "${n}" in ${t}. ${c.failure.message}`))}function projectNameCollisionMessage(e,t){return`Vercel project "${e}" already exists in ${t}. Pass --project ${e} to link it, or choose a different project name.`}async function assertNewProjectNameAvailable(e,t,n,r={}){if(await resolveProjectByNameOrId(e,t,n,r)!==null)throw Error(projectNameCollisionMessage(n,t))}function requireVercelLogin(e){let t=`Provisioning a Vercel project requires you to be logged in to Vercel.`,n=e?.stderr.trim();throw new HumanActionRequiredError({kind:`vercel-login`,command:`vercel login`,reason:e?`${t} The Vercel CLI check did not succeed: ${e.message}${n?` ${n}`:``}`:t})}function probeWhoami(e,t){return captureVercel([`whoami`],{cwd:e,signal:t.signal,timeoutMs:1e4})}function isLoggedOutFailure(e){let t=`${e.stdout} ${e.stderr}`.toLowerCase();return t.includes(`credentials`)||t.includes(`not authenticated`)||t.includes(`not logged in`)}function requireVercelAuth(e){if(e.errno===`ENOENT`)throw new HumanActionRequiredError({kind:`vercel-cli-missing`,command:`npm i -g vercel@latest`,reason:e.message});isLoggedOutFailure(e)&&requireVercelLogin(e);let t=e.stderr.trim();throw Error(`Couldn't verify your Vercel login: ${e.message}${t?` ${t}`:``}`)}function vercelAuthBlockerReason(e){switch(e){case`authenticated`:return;case`cli-missing`:return`Vercel CLI not found, see /vc`;case`logged-out`:return`Log in to Vercel first, see /login`;case`unavailable`:return`Couldn't reach Vercel, check your connection`;default:return e}}async function getVercelAuthStatus(e,t={}){let n=await probeWhoami(e,t);return t.signal?.throwIfAborted(),n.ok?`authenticated`:n.failure.errno===`ENOENT`?`cli-missing`:isLoggedOutFailure(n.failure)?`logged-out`:`unavailable`}async function requireAuth(e,t,n={}){let check=async()=>{let t=await probeWhoami(e,n);n.signal?.throwIfAborted(),t.ok||requireVercelAuth(t.failure)};if(t===void 0){await check();return}await withSpinner(t,whimsyFor(`auth`),check)}async function isVercelAuthenticated(e,t={}){return await getVercelAuthStatus(e,t)===`authenticated`}async function whoamiScope(e,t){let n=await probeWhoami(e,t);return t.signal?.throwIfAborted(),n.ok||requireVercelAuth(n.failure),n.stdout.trim()}async function resolveTeam(e,t,n={}){return t===void 0?(await listTeams(e,n)).find(e=>e.current)?.slug??await whoamiScope(e,n):t}async function validateTeam(e,t,n,r={}){if(n===void 0)return;let i=await listTeams(t,r);if(i.length>0&&!i.some(e=>e.slug===n))throw Error(`Team "${n}" was not found in \`vercel teams ls\`. Pass a valid team slug or omit --team.`)}async function pickTeam(e,t,n,r={}){if(n!==void 0)return await validateTeam(e,t,n,r),resolveTeam(t,n,r);let i=await withSpinner(e,whimsyFor(`teams`),()=>listTeams(t,r));return i.length<=1?i.find(e=>e.current)?.slug??await whoamiScope(t,r):e.select({message:`Select your team`,search:!0,placeholder:`type to search teams`,options:i.map(e=>({value:e.slug,label:e.current?`${e.name} (current)`:e.name})),initialValue:i.find(e=>e.current)?.slug})}const SEARCH_PROJECT_PREFIX=`\0search-project:`;function appendProjects(e,t){return[...new Map([...e,...t].map(e=>[e.id,e])).values()]}async function pickProject(e,t,n,r={}){let i=await withSpinner(e,whimsyFor(`projects`,n),()=>listRecentProjects(t,n,r));if(i.length===0){if(r.allowCreateWhenEmpty===!1)throw Error(`No existing Vercel projects found in ${n}. Create one in Vercel, then try again.`);return{kind:`new`,project:await e.text({message:`No projects found in ${n}. Enter a project name to create`,validate:e=>e.trim().length===0?`Project name cannot be empty.`:void 0}),team:n}}for(;;){let o=await e.select({message:`Project to link`,search:!0,placeholder:`type to filter projects`,searchAction:{label:e=>`Search for '${e}'`,value:e=>`${SEARCH_PROJECT_PREFIX}${e}`,load:async e=>{let a=await searchProjects(t,n,e,{signal:r.signal});return i=appendProjects(i,a),i.map(e=>({value:e.id,label:e.name}))}},options:i.map(e=>({value:e.id,label:e.name})),initialValue:i[0]?.id}),s=o.startsWith(SEARCH_PROJECT_PREFIX)?o.slice(16):void 0;if(s===void 0){let e=i.find(e=>e.id===o);if(e===void 0)throw Error(`Selected Vercel project is not available.`);return{kind:`existing`,project:{projectId:e.id,projectName:e.name},team:n}}let c=await withSpinner(e,`Searching ${n} for "${s}"...`,()=>searchProjects(t,n,s,{signal:r.signal}));if(c.length===0){e.note(`No projects matched "${s}" in ${n}.`);continue}i=appendProjects(i,c)}}async function pickNewProjectName(e,t,n,r,i={}){let o=await withSpinner(e,whimsyFor(`project-name`,n),()=>resolveProjectByNameOrId(t,n,r.trim(),i)),s=r.trim();for(;o!==null;)s=(await e.text({message:`New project name`,defaultValue:`${s}-2`,notices:[{tone:`warning`,text:`${import_picocolors.default.yellow(`Project named`)} '${import_picocolors.default.blue(s)}' ${import_picocolors.default.yellow(`already exists in`)} '${import_picocolors.default.blue(n)}'`}],validate:e=>{if(e.trim().length===0)return`Project name cannot be empty.`}})).trim(),o=await resolveProjectByNameOrId(t,n,s,i);return s}async function linkProject(e,t,n,r,o={}){await assertNoLegacyProjectLinkDirectory(t);let s=[`--scope`,n.team],c;return c=n.kind===`new`?await withSpinner(e,`Creating Vercel project "${n.project}" in ${n.team}...`,async()=>(await assertNewProjectNameAvailable(t,n.team,n.project,o),createProject(t,n.team,n.project,r,o))):n.project,await withSpinner(e,`Linking this directory to Vercel project "${c.projectName}"...`,()=>runVercel([`link`,`--project`,c.projectId,...s,`--yes`],{cwd:t,onOutput:r,nonInteractive:!0,signal:o.signal}))?c:void 0}export{assertNewProjectNameAvailable,getVercelAuthStatus,isVercelAuthenticated,linkProject,pickNewProjectName,pickProject,pickTeam,projectIdFromResolution,requireAuth,requireVercelAuth,requireVercelLogin,resolveProjectByNameOrId,resolveTeam,unresolvedProject,validateTeam,vercelAuthBlockerReason};
@@ -17,6 +17,8 @@ Every turn runs as a durable workflow, built on the open-source [Workflow SDK](h
17
17
 
18
18
  The Workflow SDK is not inherently tied to Vercel. In local development and in a self-deployed `eve start` process, eve uses the SDK's local world by default; that world persists workflow runs on disk, normally under `.workflow-data`, and dispatches through the same Nitro-hosted workflow routes. On Vercel, the same workflow code runs against Vercel Workflow instead, which adds platform features such as latest production deployment routing and dashboard run metadata.
19
19
 
20
+ When a Vercel production deployment changes, the next model turn in an existing session uses that deployment's current instructions, model, and tools. The durable session keeps its conversation history and authored state, so identity-based channels such as Telegram private chats and Twilio phone-number conversations adopt agent updates without requiring a new session.
21
+
20
22
  Nitro hosts the HTTP routes and workflow entrypoints. It does not supply the workflow state store or the sandbox runtime. Those are separate adapters: Workflow uses the active world implementation, and Sandbox uses the backend from `agent/sandbox` or `defaultBackend()`.
21
23
 
22
24
  For advanced self-hosted deployments, the root `agent.ts` can select the installed Workflow world package to use with `experimental.workflow.world`:
@@ -313,16 +313,14 @@ const githubAuth = connect({
313
313
 
314
314
  The tool's `ctx` exposes provider-scoped auth accessors:
315
315
 
316
- - `ctx.getToken(provider, options?)` resolves an inline provider such as `connect("github/myagent")`. It uses the same cache, callback, and sign-in machinery as connection auth, scoped to that provider instead of the tool's legacy top-level `auth`.
316
+ - `ctx.getToken(provider, options?)` resolves an inline provider such as `connect("github/myagent")`. It uses the same cache, callback, and sign-in machinery as connection auth, scoped to that provider's tool-qualified auth key.
317
317
  - `ctx.requireAuth(provider, options?)` evicts the cached token for that inline provider and starts a fresh authorization challenge. Use it after a downstream `401` rejects a token returned by `ctx.getToken(provider)`.
318
318
 
319
319
  Throw `ConnectionAuthorizationRequiredError` from an inline provider's `getToken` to trigger the consent flow for that provider. If a downstream request later rejects an already-resolved token, call `ctx.requireAuth(provider)` to evict and re-authorize it.
320
320
 
321
321
  Vercel Connect providers usually supply their own display name in the authorization challenge. Set `displayName` in the inline options only when you need to override what users see, for example `ctx.getToken(customAuth, { displayName: "Salesforce" })`. It is presentation-only.
322
322
 
323
- Inline providers derive a stable tool-qualified auth key from Vercel Connect metadata when available. If you pass multiple custom providers that do not carry provider metadata, give each one an explicit auth key, for example `ctx.getToken(auth, { authKey: "github" })`. This `authKey` controls Eve's cache and callback keys; it is not an OAuth scope.
324
-
325
- Older tools may still declare a top-level `auth` field and call `ctx.getToken()` or `ctx.requireAuth()` without arguments. That compatibility path is deprecated; prefer inline providers for new tools.
323
+ Inline providers derive a stable tool-qualified auth key from Vercel Connect metadata when available. If you pass multiple custom providers that do not carry provider metadata, give each one an explicit auth key, for example `ctx.getToken(auth, { authKey: "github" })`. This `authKey` controls eve's cache and callback keys; it is not an OAuth scope.
326
324
 
327
325
  ## What to read next
328
326
 
@@ -48,7 +48,7 @@ Each command echoes as an invocation line, asks through a bordered panel that ta
48
48
 
49
49
  Bare `/model` opens the configure menu. When no provider is configured, it opens the provider questions directly; Esc returns to the configure menu. "Change model" runs the same searchable model picker setup uses (the Vercel AI Gateway catalog, pre-selected on the model the runtime is serving). A model change is written into your agent's authored source, and the command reports success only after eve confirms the new id. `/model <provider/model-id>` applies one directly, skipping the menu.
50
50
 
51
- The provider row opens the provider questions: which model provider to use, and how to connect. Picking something other than Vercel AI Gateway shows wiring instructions for your own provider and stops there, leaving any existing setup untouched. For Vercel AI Gateway, you either paste your own `AI_GATEWAY_API_KEY` (saved straight to `.env.local`) or connect via a project. Connecting via a project asks for a Vercel team, opens that team's existing-project list (picking again re-links), then pulls the project's environment so an AI Gateway credential lands in `.env.local`. The dev TUI reloads env files, re-reads the runtime's model endpoint, and clears the setup warning automatically; no restart is needed.
51
+ The provider row opens the provider questions: which model provider to use, and how to connect. Picking something other than Vercel AI Gateway shows wiring instructions for your own provider and stops there, leaving any existing setup untouched. For Vercel AI Gateway, you either paste your own `AI_GATEWAY_API_KEY` (saved straight to `.env.local`) or connect via a project. Connecting via a project asks for a Vercel team, opens that team's recent projects, and lets you search all projects for older matches. Vercel links the selected project, eve verifies its project ID, then pulls its environment into `.env.local`. The dev TUI reloads env files, re-reads the runtime's model endpoint, and clears the setup warning automatically; no restart is needed.
52
52
 
53
53
  The provider row demands attention (a bold yellow "Configure provider" with "Required to enable the agent") until a link or gateway credential is detected, then names the connection afterward (for example "AI Gateway (Linked to my-project in my-team)"). Each action's latest outcome stays visible beneath the menu (for example "✓ Model changed to openai/gpt-5.5"). When a turn fails because AI Gateway authentication is missing or stale, the error points you at `/model` directly.
54
54
 
@@ -119,7 +119,7 @@ Local dev keeps immutable runtime source snapshots under `.eve/dev-runtime/snaps
119
119
  eve link
120
120
  ```
121
121
 
122
- Links the current directory to an existing Vercel project. You select a team and then a project, and eve pulls the project's environment so an AI Gateway credential (`VERCEL_OIDC_TOKEN` or `AI_GATEWAY_API_KEY`) lands in `.env.local`, then verifies one actually did. Running it again re-links: the pickers always run, and the new choice wins. The command is interactive only; in CI, use `vercel link --project <name> --yes` instead. A running `eve dev` reloads env files automatically, so you don't need to restart after the pull.
122
+ Links the current directory to an existing Vercel project. You select a team and then one of its recent projects; type a project name and choose **Search for '<name>'** to search the rest of that team's projects. Vercel links the selected project, eve verifies its project ID, and then pulls the project's environment so an AI Gateway credential (`VERCEL_OIDC_TOKEN` or `AI_GATEWAY_API_KEY`) lands in `.env.local`. Running it again re-links: the pickers always run, and the new choice wins. The command is interactive only; in CI, use `vercel link --project <name> --yes --non-interactive` instead. A running `eve dev` reloads env files automatically, so you don't need to restart after the pull.
123
123
 
124
124
  ## `eve deploy`
125
125
 
@@ -63,8 +63,6 @@ A few non-`define*` helpers round out the set: `disableTool` and `ExperimentalWo
63
63
  | `ctx.getSkill(identifier)` | Handle for a named skill visible to the current agent |
64
64
  | `ctx.getToken(provider)` | Resolve a bearer token for an inline auth provider such as `connect("...")` |
65
65
  | `ctx.requireAuth(provider)` | Evict and re-authorize an inline provider, commonly after a downstream `401` |
66
- | `ctx.getToken()` | Deprecated compatibility path for a tool's legacy top-level `auth` |
67
- | `ctx.requireAuth()` | Deprecated compatibility path for a tool's legacy top-level `auth` |
68
66
 
69
67
  ## Imports at a glance
70
68
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eve",
3
- "version": "0.12.3",
3
+ "version": "0.13.1",
4
4
  "private": false,
5
5
  "description": "Filesystem-first framework for durable backend AI agents that run anywhere.",
6
6
  "keywords": [