eve 0.24.3 → 0.24.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +35 -0
- package/dist/src/channel/adapter.d.ts +4 -2
- package/dist/src/channel/adapter.js +1 -1
- package/dist/src/channel/session.d.ts +5 -1
- package/dist/src/channel/types.d.ts +20 -6
- package/dist/src/chunks/{use-eve-agent-dEGV09g_.js → use-eve-agent-8rerxDHY.js} +74 -10
- package/dist/src/chunks/{use-eve-agent-CFBTHlPx.js → use-eve-agent-DhgdHzDG.js} +74 -10
- package/dist/src/cli/commands/build.d.ts +14 -0
- package/dist/src/cli/commands/build.js +1 -0
- package/dist/src/cli/commands/channels.js +1 -1
- package/dist/src/cli/commands/link.d.ts +6 -5
- package/dist/src/cli/commands/link.js +1 -1
- package/dist/src/cli/dev/tui/runner.d.ts +2 -2
- package/dist/src/cli/dev/tui/runner.js +1 -1
- package/dist/src/cli/run.d.ts +3 -2
- package/dist/src/cli/run.js +1 -1
- package/dist/src/client/index.d.ts +2 -2
- package/dist/src/client/message-reducer.js +1 -1
- package/dist/src/client/ndjson.js +1 -1
- package/dist/src/client/open-stream.d.ts +3 -2
- package/dist/src/client/open-stream.js +1 -1
- package/dist/src/client/session-utils.js +1 -1
- package/dist/src/client/session.d.ts +19 -5
- package/dist/src/client/session.js +1 -1
- package/dist/src/client/types.d.ts +11 -2
- package/dist/src/compiled/.vendor-stamp.json +5 -5
- package/dist/src/compiled/@workflow/core/index.js +2 -2
- package/dist/src/compiled/@workflow/core/runtime/helpers.d.ts +55 -0
- package/dist/src/compiled/@workflow/core/runtime/run-id-time.d.ts +9 -0
- package/dist/src/compiled/@workflow/core/runtime/step-executor.d.ts +2 -0
- package/dist/src/compiled/@workflow/core/runtime/step-latency.d.ts +70 -4
- package/dist/src/compiled/@workflow/core/runtime/suspension-handler.d.ts +10 -1
- package/dist/src/compiled/@workflow/core/runtime.js +3 -3
- package/dist/src/compiled/@workflow/core/step/context-storage.d.ts +6 -0
- package/dist/src/compiled/@workflow/core/telemetry/semantic-conventions.d.ts +25 -0
- package/dist/src/compiled/@workflow/core/version.d.ts +1 -1
- package/dist/src/compiled/@workflow/core/workflow.js +1 -1
- package/dist/src/compiled/@workflow/errors/index.d.ts +16 -0
- package/dist/src/compiled/@workflow/errors/index.js +1 -1
- package/dist/src/compiled/@workflow/world/attributes.d.ts +7 -0
- package/dist/src/compiled/@workflow/world/events.d.ts +16 -0
- package/dist/src/compiled/@workflow/world/index.d.ts +1 -1
- package/dist/src/compiled/@workflow/world-local/index.js +3 -3
- package/dist/src/compiled/@workflow/world-vercel/index.js +16 -16
- package/dist/src/compiled/_chunks/workflow/attribute-changes-DXbmITuI.js +20 -0
- package/dist/src/compiled/_chunks/workflow/{dist-DpDDcpTl.js → dist-BYo8Gno2.js} +1 -1
- package/dist/src/compiled/_chunks/workflow/{dist-Blxnyb7-.js → dist-CSfKNxQW.js} +1 -1
- package/dist/src/compiled/_chunks/workflow/resume-hook-DvvgYsRt.js +1 -0
- package/dist/src/compiled/_chunks/workflow/run-BdvQmV5a.js +1 -0
- package/dist/src/compiled/_chunks/workflow/run-id-BdE0MZz9.js +1 -0
- package/dist/src/compiled/_chunks/workflow/sleep-DzxrwWTs.js +1 -0
- package/dist/src/discover/filesystem.js +1 -1
- package/dist/src/evals/assertions/run.d.ts +3 -3
- package/dist/src/evals/context.js +1 -1
- package/dist/src/evals/index.d.ts +2 -1
- package/dist/src/evals/match.d.ts +4 -0
- package/dist/src/evals/match.js +1 -1
- package/dist/src/evals/runner/derive-run-facts.js +1 -1
- package/dist/src/evals/session.d.ts +10 -2
- package/dist/src/evals/session.js +1 -1
- package/dist/src/evals/target.js +1 -1
- package/dist/src/evals/types.d.ts +52 -2
- package/dist/src/execution/cancel-descendant-turns-step.d.ts +6 -0
- package/dist/src/execution/cancel-descendant-turns-step.js +1 -0
- package/dist/src/execution/create-session-step.js +1 -1
- package/dist/src/execution/dispatch-runtime-actions-step.js +1 -1
- package/dist/src/execution/dispatch-workflow-runtime-actions-step.js +1 -1
- package/dist/src/execution/durable-session-migrations/turn-workflow.d.ts +1 -0
- package/dist/src/execution/durable-session-migrations/turn-workflow.js +1 -1
- package/dist/src/execution/next-driver-action.d.ts +7 -0
- package/dist/src/execution/node-step.js +1 -1
- package/dist/src/execution/remote-agent-dispatch.d.ts +6 -0
- package/dist/src/execution/remote-agent-dispatch.js +1 -1
- package/dist/src/execution/settle-cancelled-turn-step.d.ts +16 -0
- package/dist/src/execution/settle-cancelled-turn-step.js +1 -0
- package/dist/src/execution/subagent-event-proxy-step.js +1 -1
- package/dist/src/execution/subagent-hitl-proxy.js +1 -1
- package/dist/src/execution/terminal-session-failure-step.d.ts +6 -0
- package/dist/src/execution/terminal-session-failure-step.js +1 -0
- package/dist/src/execution/turn-cancellation-control.d.ts +27 -0
- package/dist/src/execution/turn-cancellation-control.js +1 -0
- package/dist/src/execution/turn-cancellation-token.d.ts +9 -0
- package/dist/src/execution/turn-cancellation-token.js +1 -0
- package/dist/src/execution/turn-dispatch.d.ts +14 -1
- package/dist/src/execution/turn-dispatch.js +1 -1
- package/dist/src/execution/turn-execution-cursor.d.ts +2 -1
- package/dist/src/execution/turn-execution-cursor.js +1 -1
- package/dist/src/execution/turn-workflow.d.ts +9 -1
- package/dist/src/execution/turn-workflow.js +1 -1
- package/dist/src/execution/workflow-entry.js +1 -1
- package/dist/src/execution/workflow-runtime.d.ts +3 -1
- package/dist/src/execution/workflow-runtime.js +1 -1
- package/dist/src/execution/workflow-steps.d.ts +8 -6
- package/dist/src/execution/workflow-steps.js +1 -1
- package/dist/src/harness/active-turn-id.d.ts +11 -0
- package/dist/src/harness/active-turn-id.js +1 -0
- package/dist/src/harness/advertised-tools.js +1 -1
- package/dist/src/harness/cancelled-turn-emission.d.ts +11 -0
- package/dist/src/harness/cancelled-turn-emission.js +1 -0
- package/dist/src/harness/emission.d.ts +4 -2
- package/dist/src/harness/emission.js +1 -1
- package/dist/src/harness/execute-tool.d.ts +0 -1
- package/dist/src/harness/proxy-input-requests.d.ts +5 -0
- package/dist/src/harness/proxy-input-requests.js +1 -1
- package/dist/src/harness/runtime-actions.d.ts +16 -12
- package/dist/src/harness/runtime-actions.js +1 -1
- package/dist/src/harness/session-limit-enforcement.js +1 -1
- package/dist/src/harness/tool-loop.js +2 -2
- package/dist/src/internal/application/build-profile.d.ts +64 -0
- package/dist/src/internal/application/build-profile.js +1 -0
- package/dist/src/internal/application/compiled-artifacts.js +3 -2
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/authored-module-loader.d.ts +10 -0
- package/dist/src/internal/authored-module-loader.js +3 -3
- package/dist/src/internal/authored-module-map-loader.js +1 -1
- package/dist/src/internal/bundler/nitro-rolldown.d.ts +18 -2
- package/dist/src/internal/bundler/nitro-rolldown.js +1 -1
- package/dist/src/internal/materialized-authored-modules.d.ts +2 -4
- package/dist/src/internal/materialized-authored-modules.js +1 -1
- package/dist/src/internal/nitro/dev-runtime-artifacts.js +1 -1
- package/dist/src/internal/nitro/dev-runtime-source-snapshot-copy.js +1 -1
- package/dist/src/internal/nitro/host/build-application.js +1 -1
- package/dist/src/internal/nitro/host/dev-authored-source-watcher.js +1 -1
- package/dist/src/internal/nitro/host/types.d.ts +2 -0
- package/dist/src/internal/nitro/routes/agent-info/build-agent-info-response-from-manifest.js +1 -1
- package/dist/src/internal/nitro/routes/agent-info/build-agent-info-response.d.ts +7 -1
- package/dist/src/internal/nitro/routes/agent-info/build-agent-info-response.js +1 -1
- package/dist/src/internal/nitro/routes/channel-dispatch.js +1 -1
- package/dist/src/internal/nitro/routes/channel-route-context.d.ts +3 -0
- package/dist/src/internal/nitro/routes/channel-route-context.js +1 -1
- package/dist/src/internal/nitro/routes/runtime-stack.js +1 -1
- package/dist/src/internal/nitro/routes/schedule-task.js +1 -1
- package/dist/src/internal/workflow/development-world-client.js +1 -1
- package/dist/src/internal/workflow/development-world-server.js +1 -1
- package/dist/src/internal/workflow/local-world-data-directory.d.ts +2 -0
- package/dist/src/internal/workflow/local-world-data-directory.js +1 -0
- package/dist/src/internal/workflow-bundle/builder-support.js +3 -3
- package/dist/src/internal/workflow-bundle/builder.js +2 -2
- package/dist/src/internal/workflow-bundle/vercel-workflow-output.js +1 -1
- package/dist/src/protocol/cancel-turn.d.ts +11 -0
- package/dist/src/protocol/cancel-turn.js +1 -0
- package/dist/src/protocol/message.d.ts +23 -3
- package/dist/src/protocol/message.js +2 -2
- package/dist/src/protocol/routes.d.ts +10 -0
- package/dist/src/protocol/routes.js +1 -1
- package/dist/src/public/channels/discord/discordChannel.d.ts +1 -0
- package/dist/src/public/channels/eve.d.ts +2 -1
- package/dist/src/public/channels/eve.js +2 -2
- package/dist/src/public/channels/github/githubChannel.d.ts +1 -0
- package/dist/src/public/channels/linear/api.d.ts +0 -1
- package/dist/src/public/channels/linear/api.js +17 -22
- package/dist/src/public/channels/linear/linearChannel.d.ts +1 -0
- package/dist/src/public/channels/linear/linearChannel.js +1 -1
- package/dist/src/public/channels/slack/slackChannel.d.ts +1 -0
- package/dist/src/public/channels/teams/teamsChannel.d.ts +1 -0
- package/dist/src/public/channels/telegram/telegramChannel.d.ts +1 -0
- package/dist/src/public/channels/twilio/twilioChannel.d.ts +1 -0
- package/dist/src/public/definitions/channel.d.ts +25 -14
- package/dist/src/public/definitions/channel.js +1 -1
- package/dist/src/public/next/index.js +1 -1
- package/dist/src/public/next/resolve-eve-binary.d.ts +12 -0
- package/dist/src/public/next/resolve-eve-binary.js +1 -0
- package/dist/src/runtime/agent/mock-model-adapter.js +1 -1
- package/dist/src/runtime/framework-tools/agent.d.ts +13 -0
- package/dist/src/runtime/framework-tools/agent.js +1 -0
- package/dist/src/runtime/framework-tools/index.d.ts +7 -2
- package/dist/src/runtime/framework-tools/index.js +1 -1
- package/dist/src/runtime/resolve-agent-graph.js +1 -1
- package/dist/src/runtime/types.d.ts +2 -1
- package/dist/src/services/dev-client/runtime-artifacts.d.ts +2 -2
- package/dist/src/services/dev-client.d.ts +10 -18
- package/dist/src/services/dev-client.js +1 -1
- package/dist/src/setup/boxes/reconcile-host-framework-preset.d.ts +26 -0
- package/dist/src/setup/boxes/reconcile-host-framework-preset.js +1 -0
- package/dist/src/setup/boxes/resolve-provisioning.js +1 -1
- package/dist/src/setup/index.js +1 -1
- package/dist/src/setup/scaffold/create/add-to-project.js +1 -1
- package/dist/src/setup/scaffold/create/extension.js +0 -1
- package/dist/src/setup/scaffold/create/project.js +2 -4
- package/dist/src/setup/scaffold/index.d.ts +1 -1
- package/dist/src/setup/scaffold/index.js +1 -1
- package/dist/src/setup/scaffold/update/channels.d.ts +7 -1
- package/dist/src/setup/scaffold/update/channels.js +2 -2
- package/dist/src/setup/scaffold/update/connections.js +3 -3
- package/dist/src/setup/vercel-project-framework.d.ts +12 -0
- package/dist/src/setup/vercel-project-framework.js +1 -1
- package/dist/src/shared/continuation-token.d.ts +2 -0
- package/dist/src/shared/continuation-token.js +1 -0
- package/dist/src/svelte/index.js +1 -1
- package/dist/src/svelte/use-eve-agent.js +1 -1
- package/dist/src/vue/index.js +1 -1
- package/dist/src/vue/use-eve-agent.js +1 -1
- package/docs/channels/eve.mdx +11 -1
- package/docs/concepts/default-harness.md +2 -0
- package/docs/concepts/execution-model-and-durability.md +1 -1
- package/docs/concepts/sessions-runs-and-streaming.md +24 -4
- package/docs/evals/assertions.mdx +2 -2
- package/docs/evals/cases.mdx +31 -0
- package/docs/evals/overview.mdx +1 -1
- package/docs/evals/targets.mdx +2 -1
- package/docs/guides/client/continuations.mdx +16 -1
- package/docs/guides/client/streaming.mdx +31 -2
- package/docs/guides/deployment.md +1 -1
- package/docs/guides/frontend/overview.mdx +4 -2
- package/docs/guides/frontend/use-eve-agent-svelte.mdx +2 -2
- package/docs/guides/frontend/use-eve-agent-vue.mdx +2 -2
- package/docs/guides/remote-agents.md +2 -0
- package/docs/reference/cli.md +16 -3
- package/docs/subagents.mdx +10 -0
- package/package.json +6 -6
- package/dist/src/compiled/_chunks/workflow/attribute-changes-MGTOG_uX.js +0 -20
- package/dist/src/compiled/_chunks/workflow/resume-hook-DHP5ql3-.js +0 -1
- package/dist/src/compiled/_chunks/workflow/run-D8hv1ptT.js +0 -1
- package/dist/src/compiled/_chunks/workflow/sleep-uA9pS-PT.js +0 -1
|
@@ -1,50 +1,42 @@
|
|
|
1
1
|
import type { UserContent } from "ai";
|
|
2
|
-
import type { ClientSession } from "#client/session.js";
|
|
3
2
|
import type { InputResponse } from "#runtime/input/types.js";
|
|
4
3
|
/**
|
|
5
|
-
* Tracks local dev runtime-artifact revisions
|
|
6
|
-
*
|
|
7
|
-
* input-response resumes.
|
|
4
|
+
* Tracks local dev runtime-artifact revisions so callers can refresh their
|
|
5
|
+
* presentation before delivering the next turn.
|
|
8
6
|
*/
|
|
9
|
-
export interface
|
|
7
|
+
export interface DevelopmentRuntimeArtifactRefresher {
|
|
10
8
|
/**
|
|
11
9
|
* Clears the remembered runtime-artifact revision.
|
|
12
10
|
*/
|
|
13
11
|
clear(): void;
|
|
14
12
|
/**
|
|
15
|
-
*
|
|
13
|
+
* Refreshes the artifact revision before a normal turn.
|
|
16
14
|
*/
|
|
17
15
|
refresh(input: {
|
|
18
|
-
readonly createSession: () => ClientSession;
|
|
19
16
|
readonly inputResponses?: readonly InputResponse[];
|
|
20
17
|
readonly message?: string | UserContent;
|
|
21
18
|
readonly onRuntimeArtifactsChanged?: (change: DevelopmentRuntimeArtifactChange) => void | Promise<void>;
|
|
22
|
-
|
|
23
|
-
}): Promise<ClientSession>;
|
|
19
|
+
}): Promise<void>;
|
|
24
20
|
/**
|
|
25
21
|
* Forces one rebuild after a local setup action wrote authored source.
|
|
26
22
|
*/
|
|
27
23
|
refreshAfterSourceChange(input: {
|
|
28
|
-
readonly createSession: () => ClientSession;
|
|
29
24
|
readonly onRuntimeArtifactsChanged?: (change: DevelopmentRuntimeArtifactChange) => void | Promise<void>;
|
|
30
|
-
|
|
31
|
-
}): Promise<ClientSession>;
|
|
25
|
+
}): Promise<void>;
|
|
32
26
|
/**
|
|
33
27
|
* Checks for a runtime-artifact revision change while the UI is idle.
|
|
34
28
|
*/
|
|
35
29
|
refreshIdle(input: {
|
|
36
|
-
readonly createSession: () => ClientSession;
|
|
37
30
|
readonly onRuntimeArtifactsChanged?: (change: DevelopmentRuntimeArtifactChange) => void | Promise<void>;
|
|
38
|
-
|
|
39
|
-
}): Promise<ClientSession>;
|
|
31
|
+
}): Promise<void>;
|
|
40
32
|
}
|
|
41
33
|
export interface DevelopmentRuntimeArtifactChange {
|
|
42
34
|
readonly previousRevision: string;
|
|
43
35
|
readonly revision: string;
|
|
44
36
|
}
|
|
45
37
|
/**
|
|
46
|
-
* Creates a revision-aware local dev
|
|
38
|
+
* Creates a revision-aware local dev runtime-artifact refresher.
|
|
47
39
|
*/
|
|
48
|
-
export declare function
|
|
40
|
+
export declare function createDevelopmentRuntimeArtifactRefresher(input: {
|
|
49
41
|
readonly serverUrl: string;
|
|
50
|
-
}):
|
|
42
|
+
}): DevelopmentRuntimeArtifactRefresher;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isLocalDevelopmentServerUrl}from"#services/dev-client/local-host.js";import{readDevelopmentRuntimeArtifactsRevision,rebuildDevelopmentRuntimeArtifacts}from"#services/dev-client/runtime-artifacts.js";var
|
|
1
|
+
import{isLocalDevelopmentServerUrl}from"#services/dev-client/local-host.js";import{readDevelopmentRuntimeArtifactsRevision,rebuildDevelopmentRuntimeArtifacts}from"#services/dev-client/runtime-artifacts.js";var LocalDevelopmentRuntimeArtifactRefresher=class{#e;#t;#n;constructor(t){this.#e=isLocalDevelopmentServerUrl(t.serverUrl),this.#t=t.serverUrl}clear(){this.#n=void 0}async refresh(e){shouldRefreshRuntimeArtifactsForTurn(e)&&await this.#r({...e,rebuild:!0})}async refreshIdle(e){await this.#r({...e,rebuild:!1})}async refreshAfterSourceChange(e){await this.#r({...e,force:!0,rebuild:!0})}async#r(e){if(!this.#e)return;let n=(e.rebuild?await rebuildDevelopmentRuntimeArtifacts({force:e.force,serverUrl:this.#t}):void 0)??await readDevelopmentRuntimeArtifactsRevision({serverUrl:this.#t});if(n===void 0)return;let r=this.#n;r!==void 0&&r!==n&&await e.onRuntimeArtifactsChanged?.({previousRevision:r,revision:n}),this.#n=n}};function shouldRefreshRuntimeArtifactsForTurn(e){return e.message!==void 0&&(e.inputResponses?.length??0)===0}function createDevelopmentRuntimeArtifactRefresher(e){return new LocalDevelopmentRuntimeArtifactRefresher(e)}export{createDevelopmentRuntimeArtifactRefresher};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Prompter } from "../prompter.js";
|
|
2
|
+
import { type SetupState } from "../state.js";
|
|
3
|
+
import type { SetupBox } from "../step.js";
|
|
4
|
+
import { syncHostFrameworkPreset } from "../vercel-project-framework.js";
|
|
5
|
+
/** Injected for tests; defaults to the real framework-preset reconciliation. */
|
|
6
|
+
export interface ReconcileHostFrameworkPresetDeps {
|
|
7
|
+
syncHostFrameworkPreset: typeof syncHostFrameworkPreset;
|
|
8
|
+
}
|
|
9
|
+
export interface ReconcileHostFrameworkPresetOptions {
|
|
10
|
+
/** Streams reconciliation progress and the applied-change note. */
|
|
11
|
+
prompter: Prompter;
|
|
12
|
+
deps?: ReconcileHostFrameworkPresetDeps;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Aligns an already-linked Vercel project's Framework Preset with a newly-added
|
|
16
|
+
* web (Next.js) channel before the deploy box runs. A project created as a
|
|
17
|
+
* standalone agent keeps the `eve` preset, which would build the agent instead
|
|
18
|
+
* of the host app; the command already deploys on the user's behalf, so this
|
|
19
|
+
* corrects the preset directly (no confirmation) and notes the change.
|
|
20
|
+
*
|
|
21
|
+
* Runs only for an already-linked project — an unlinked directory links later
|
|
22
|
+
* inside the deploy box, where a fresh `vercel link` detects the framework. All
|
|
23
|
+
* effects live in {@link syncHostFrameworkPreset}, a no-op when the preset
|
|
24
|
+
* already matches.
|
|
25
|
+
*/
|
|
26
|
+
export declare function reconcileHostFrameworkPreset(options: ReconcileHostFrameworkPresetOptions): SetupBox<SetupState, null, null>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{isProjectResolved}from"../project-resolution.js";import{requireProjectPath}from"../state.js";import{syncHostFrameworkPreset}from"../vercel-project-framework.js";import{createPromptCommandOutput}from"#setup/cli/index.js";function reconcileHostFrameworkPreset(r){let i=r.deps??{syncHostFrameworkPreset};return{id:`reconcile-host-framework-preset`,shouldRun(t){return t.deploymentPending&&t.channelSelection.includes(`web`)&&isProjectResolved(t.project)},async gather(){return null},async perform({state:e,signal:n}){let a=requireProjectPath(e),o=createPromptCommandOutput(r.prompter.log);return await i.syncHostFrameworkPreset(r.prompter,a,o,{signal:n}),null},apply(e){return e}}}export{reconcileHostFrameworkPreset};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{select,text}from"../ask.js";import{detectProjectResolution,isProjectResolved,mergeProjectResolution}from"../project-resolution.js";import{withSpinner}from"../with-spinner.js";import{assertNewProjectNameAvailable,isVercelAuthenticated,pickNewProjectName,pickProject,pickTeam,requireAuth,resolveProjectByNameOrId,resolveTeam,validateTeam}from"../vercel-project.js";import{
|
|
1
|
+
import{select,text}from"../ask.js";import{detectProjectResolution,isProjectResolved,mergeProjectResolution}from"../project-resolution.js";import{withSpinner}from"../with-spinner.js";import{pathExists}from"../path-exists.js";import{assertNewProjectNameAvailable,isVercelAuthenticated,pickNewProjectName,pickProject,pickTeam,requireAuth,resolveProjectByNameOrId,resolveTeam,validateTeam}from"../vercel-project.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,resolveProjectByNameOrId},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 withSpinner(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;if(t.project===void 0)o={kind:`new`,project:e,team:i};else{let e=await u.resolveProjectByNameOrId(parent(),i,t.project,{signal:r});if(e===null)throw Error(`Vercel project "${t.project}" was not found in ${i}.`);o={kind:`existing`,project:e,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={signal:r,selectMessage:l.teamSelectMessage},n=await u.pickTeam(i,parent(),void 0,t),o=[{value:`new`,label:`Create a new project`,hint:`Name: ${a}`},{value:`link`,label:`Link an existing project`}],s=l.projectSelection!==`existing-only`&&l.prompter.selectEditable?await l.prompter.selectEditable({message:`Vercel project`,options:o,initialValue:`new`,editable:{value:`new`,defaultValue:a,formatHint:e=>`Name: ${e}`,validate:e=>e.trim().length===0?`Project name cannot be empty.`:void 0}}):void 0;if((l.projectSelection===`existing-only`?`link`:s?.value??await l.asker.ask(select({key:`vercel-project`,message:`Vercel project`,options:[{id:`new`,value:`new`,label:`Create a new project`,hint:`Name: ${a}`},{id:`link`,value:`link`,label:`Link an existing project`}],recommended:`new`,required:!0})))===`new`){let e=s?.kind===`edited`?s.text:a;return{vercelProject:{kind:`new`,project:await u.pickNewProjectName(i,parent(),n,e,{signal:r}),team:n},aiGateway:{kind:`inherit`},modelWiring:`gateway`}}return{vercelProject:await u.pickProject(i,parent(),n,{allowCreateWhenEmpty:l.projectSelection!==`existing-only`,signal:r}),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};
|
package/dist/src/setup/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{InteractionRequired}from"./ask.js";import{runVercel}from"./primitives/run-vercel.js";import{detectDeployment,detectProjectResolution,projectProductionUrlFromResolution}from"./project-resolution.js";import{provisionSlackbot,reconcileSlackUid}from"./slackbot.js";import{createDefaultSetupState,requireProjectPath,snapshotSetupState}from"./state.js";import{WizardCancelledError}from"./step.js";import{setupConnectionConnector}from"./connection-connector.js";import{linkProject,requireAuth,resolveProjectByNameOrId,resolveTeam}from"./vercel-project.js";import{runVercelEnvPull}from"./run-vercel-link.js";import{createPromptCommandOutput}from"./cli/command-output.js";import"./cli/index.js";import{runHeadless,runInteractive}from"./runner.js";import{HeadlessPromptError,createHeadlessPrompter,formatHeadlessEvent}from"./headless.js";import{createPrompter}from"./prompter.js";import{composeOnboardingBoxes}from"./onboarding.js";import{
|
|
1
|
+
import{InteractionRequired}from"./ask.js";import{runVercel}from"./primitives/run-vercel.js";import{detectDeployment,detectProjectResolution,projectProductionUrlFromResolution}from"./project-resolution.js";import{provisionSlackbot,reconcileSlackUid}from"./slackbot.js";import{createDefaultSetupState,requireProjectPath,snapshotSetupState}from"./state.js";import{WizardCancelledError}from"./step.js";import{setupConnectionConnector}from"./connection-connector.js";import{getPackageManagerStrategy}from"./primitives/pm/index.js";import{linkProject,requireAuth,resolveProjectByNameOrId,resolveTeam}from"./vercel-project.js";import{runVercelEnvPull}from"./run-vercel-link.js";import{createPromptCommandOutput}from"./cli/command-output.js";import"./cli/index.js";import{runHeadless,runInteractive}from"./runner.js";import{HeadlessPromptError,createHeadlessPrompter,formatHeadlessEvent}from"./headless.js";import{createPrompter}from"./prompter.js";import{composeOnboardingBoxes}from"./onboarding.js";import{runPackageManagerInstall,runPnpmInstall,spawnPackageManager,spawnPnpm}from"./primitives/pm/run.js";import"./primitives/index.js";export{HeadlessPromptError,InteractionRequired,WizardCancelledError,composeOnboardingBoxes,createDefaultSetupState,createHeadlessPrompter,createPromptCommandOutput,createPrompter,detectDeployment,detectProjectResolution,formatHeadlessEvent,getPackageManagerStrategy,linkProject,projectProductionUrlFromResolution,provisionSlackbot,reconcileSlackUid,requireAuth,requireProjectPath,resolveProjectByNameOrId,resolveTeam,runHeadless,runInteractive,runPackageManagerInstall,runPnpmInstall,runVercel,runVercelEnvPull,setupConnectionConnector,snapshotSetupState,spawnPackageManager,spawnPnpm};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{pathExists,writeTextFile}from"../files.js";import{
|
|
1
|
+
import{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{patchPackageJson}from"../update/package-json.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{agentTemplateFiles,formatEveDependencySpecifier,resolveEvePackageContract}from"./project.js";import{join}from"node:path";import{readFile}from"node:fs/promises";const DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`,`optionalDependencies`,`peerDependencies`];function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function hasDeclaredDependency(e,t){if(!isJsonObject(e))return!1;for(let n of DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function addAgentToProject(i){let a=i.packageManager??`pnpm`,o=join(i.projectRoot,`package.json`);if(!await pathExists(o))throw Error(`Cannot add an eve agent to "${i.projectRoot}" because it has no package.json. Run \`eve init <name>\` to create a new project instead.`);let s=agentTemplateFiles(i.model),c=[];for(let t of Object.keys(s))await pathExists(join(i.projectRoot,t))&&c.push(t);if(c.length===0&&await pathExists(join(i.projectRoot,`agent`))&&c.push(`agent/`),c.length>0)throw Error(`Cannot add an eve agent to "${i.projectRoot}" because it already has: ${c.join(`, `)}.`);let l=resolveEvePackageContract(i.evePackage),u=resolveVersionToken(`aiPackageVersion`,i.aiPackageVersion??`^7.0.26`),d=resolveVersionToken(`connectPackageVersion`,i.connectPackageVersion??`0.2.2`),f=resolveVersionToken(`zodPackageVersion`,i.zodPackageVersion??`4.4.3`),p=[];for(let[e,n]of Object.entries(s)){let r=join(i.projectRoot,e);await writeTextFile(r,n),p.push(r)}let m=JSON.parse(await readFile(o,`utf8`)),h={"@vercel/connect":d,ai:u,eve:formatEveDependencySpecifier(l.version),zod:f},g={};for(let[e,t]of Object.entries(h))hasDeclaredDependency(m,e)||(g[e]=t);let _={};Object.keys(g).length>0&&(_.dependencies=g),isPackageManagerWorkspaceMember(a,i.projectRoot)||(_.nodeEngineRequirement=l.nodeEngine);let v=await patchPackageJson(o,_),y=(await patchWorkspaceRootPackageJson(a,i.projectRoot,{aiPackageVersion:u,nodeEngineRequirement:l.nodeEngine})).nodeEngineOverride??v.nodeEngineOverride;return await applyPackageManagerWorkspaceConfiguration({packageManager:a,projectRoot:i.projectRoot}),{filesWritten:p,dependenciesAdded:Object.keys(g).sort(),nodeEngineOverride:y}}export{addAgentToProject};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{pinnedNodeEngineMajor}from"../../node-engine.js";import{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{
|
|
1
|
+
import{pinnedNodeEngineMajor}from"../../node-engine.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.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.26`,DEFAULT_CONNECT_PACKAGE_VERSION=`0.2.2`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.24.5`,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_TYPESCRIPT_VERSION__`,t.typescriptPackageVersion).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__",
|
|
@@ -58,7 +58,6 @@ You are a helpful assistant.
|
|
|
58
58
|
.env*
|
|
59
59
|
.eve
|
|
60
60
|
.vercel
|
|
61
|
-
.workflow-data
|
|
62
61
|
.next
|
|
63
62
|
.output
|
|
64
63
|
.nitro
|
|
@@ -68,7 +67,6 @@ dist
|
|
|
68
67
|
`,".vercelignore":`node_modules
|
|
69
68
|
.env*
|
|
70
69
|
.eve
|
|
71
|
-
.workflow-data
|
|
72
70
|
.next
|
|
73
71
|
.output
|
|
74
72
|
.nitro
|
|
@@ -95,4 +93,4 @@ export default defineAgent({
|
|
|
95
93
|
},
|
|
96
94
|
},
|
|
97
95
|
});
|
|
98
|
-
`:BASE_AGENT_TEMPLATE,...SHARED_TEMPLATE_FILES,"package.json":packageJsonTemplate({includeRootOnlyFields:e.includeRootOnlyPackageJsonFields,packageManager:e.packageManager})}}async function assertCanCreateInPlace(e,
|
|
96
|
+
`:BASE_AGENT_TEMPLATE,...SHARED_TEMPLATE_FILES,"package.json":packageJsonTemplate({includeRootOnlyFields:e.includeRootOnlyPackageJsonFields,packageManager:e.packageManager})}}async function assertCanCreateInPlace(e,t){if(!await pathExists(e))return;let r=(await readdir(e)).filter(e=>!ALLOWED_CREATE_IN_PLACE_ENTRIES.has(e));if(r.length>0&&!t){let e=r.slice(0,5).join(`, `),t=r.length>5?`, and ${r.length-5} more`:``;throw Error(`Cannot create project in current directory because it is not empty. Found: ${e}${t}. Use an empty directory.`)}}async function scaffoldBaseProject(t){let s=resolve(t.targetDirectory??process.cwd(),t.projectName),c=t.projectName===`.`,l=t.overwriteExisting??!1,u=t.byokProvider??!1,d=t.packageManager??`pnpm`,f=resolveEvePackageContract(t.evePackage),p=pinnedNodeEngineMajor(f.nodeEngine),m=resolve(t.workspaceProbeDirectory??s),h=isPackageManagerWorkspaceMember(d,m);if(c)await assertCanCreateInPlace(s,l);else if(await pathExists(s))throw Error(`Cannot create project because "${s}" already exists.`);let g={appName:basename(s),model:t.model,eveVersion:f.version,aiPackageVersion:resolveVersionToken(`aiPackageVersion`,t.aiPackageVersion??`^7.0.26`),connectPackageVersion:resolveVersionToken(`connectPackageVersion`,t.connectPackageVersion??`0.2.2`),zodPackageVersion:resolveVersionToken(`zodPackageVersion`,t.zodPackageVersion??`4.4.3`),typescriptPackageVersion:resolveVersionToken(`typescriptPackageVersion`,t.typescriptPackageVersion??`7.0.2`),nodeTypesVersion:p,nodeEngine:p};await mkdir(s,{recursive:!0});for(let[e,i]of Object.entries(templateFiles({byokProvider:u,includeRootOnlyPackageJsonFields:!h,packageManager:d}))){let a=`${s}/${e}`,o=await pathExists(a);await writeTextFile(a,renderTemplate(i,g),{force:c&&l}),o&&await t.onOverwriteFile?.(a)}return await applyPackageManagerWorkspaceConfiguration({packageManager:d,projectRoot:s,workspaceProbeRoot:m,onWorkspaceRootMutation:t.onWorkspaceRootMutation}),await patchWorkspaceRootPackageJson(d,m,{aiPackageVersion:g.aiPackageVersion,nodeEngineRequirement:f.nodeEngine,onWorkspaceRootMutation:t.onWorkspaceRootMutation}),s}async function isEveProject(e){for(let n of SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS)try{return await stat(join(e,`agent`,`agent${n}`)),!0}catch{}return!1}export{CURRENT_DIRECTORY_PROJECT_NAME,DEFAULT_AI_PACKAGE_VERSION,DEFAULT_CONNECT_PACKAGE_VERSION,DEFAULT_EVE_PACKAGE_CONTRACT,DEFAULT_ZOD_PACKAGE_VERSION,ROOT_ONLY_PACKAGE_JSON_TEMPLATE_SUFFIX,agentTemplateFiles,byokProviderEnvVar,formatEveDependencySpecifier,isEveProject,modelProviderSlug,resolveEvePackageContract,scaffoldBaseProject};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { byokProviderEnvVar, CURRENT_DIRECTORY_PROJECT_NAME, isEveProject, scaffoldBaseProject, type EvePackageContract, type ScaffoldBaseProjectOptions, } from "./create/project.js";
|
|
2
2
|
export { scaffoldExtensionProject, type ScaffoldExtensionProjectOptions, } from "./create/extension.js";
|
|
3
|
-
export { DEFAULT_SLACK_CONNECTOR_SLUG, SLACK_CHANNEL_DEFAULT_ROUTE, deriveSlackConnectorSlug, ensureChannel, hasVercelHostFramework, isNextJsProject, listAuthoredChannels, normalizeSlackConnectorSlug, type ChannelKind, type ChannelMutationResult, type EnsureChannelOptions, type SlackConnectorSlug, type WebPackageVersions, } from "./update/channels.js";
|
|
3
|
+
export { DEFAULT_SLACK_CONNECTOR_SLUG, SLACK_CHANNEL_DEFAULT_ROUTE, deriveSlackConnectorSlug, ensureChannel, hasVercelHostFramework, isNextJsProject, listAuthoredChannels, normalizeSlackConnectorSlug, resolveVercelHostFrameworkPreset, type ChannelKind, type ChannelMutationResult, type EnsureChannelOptions, type SlackConnectorSlug, type WebPackageVersions, } from "./update/channels.js";
|
|
4
4
|
export { SCAFFOLDABLE_CHANNELS, type ScaffoldableChannel } from "./channels-catalog.js";
|
|
5
5
|
export { ensureConnection, ensureConnectionDependencies, listAuthoredConnections, type ConnectionInput, type ConnectionMutationAction, type ConnectionMutationResult, type EnsureConnectionOptions, type EnsureConnectionDependenciesOptions, } from "./update/connections.js";
|
|
6
6
|
export { catalogSlugs, CONNECTION_CATALOG, CUSTOM_CONNECTION_SLUG, effectiveProtocols, endpointForProtocol, getCatalogEntry, isValidConnectionSlug, SUPPORTED_PROTOCOLS, type ConnectionAuthSpec, type ConnectionCatalogEntry, type ConnectionProtocol, type CustomConnectionInput, type EnvHeader, type McpEndpoint, type OpenApiEndpoint, } from "./connections/catalog.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{CONNECTION_CATALOG,CUSTOM_CONNECTION_SLUG,SUPPORTED_PROTOCOLS,catalogSlugs,effectiveProtocols,endpointForProtocol,getCatalogEntry,isValidConnectionSlug}from"./connections/catalog.js";import{
|
|
1
|
+
import{CONNECTION_CATALOG,CUSTOM_CONNECTION_SLUG,SUPPORTED_PROTOCOLS,catalogSlugs,effectiveProtocols,endpointForProtocol,getCatalogEntry,isValidConnectionSlug}from"./connections/catalog.js";import{WriteFileExistsError}from"./files.js";import{CURRENT_DIRECTORY_PROJECT_NAME,byokProviderEnvVar,isEveProject,scaffoldBaseProject}from"./create/project.js";import{scaffoldExtensionProject}from"./create/extension.js";import{DEFAULT_SLACK_CONNECTOR_SLUG,SLACK_CHANNEL_DEFAULT_ROUTE,deriveSlackConnectorSlug,ensureChannel,hasVercelHostFramework,isNextJsProject,listAuthoredChannels,normalizeSlackConnectorSlug,resolveVercelHostFrameworkPreset}from"./update/channels.js";import{SCAFFOLDABLE_CHANNELS}from"./channels-catalog.js";import{ensureConnection,ensureConnectionDependencies,listAuthoredConnections}from"./update/connections.js";import{HumanActionRequiredError}from"../human-action.js";export{CONNECTION_CATALOG,CURRENT_DIRECTORY_PROJECT_NAME,CUSTOM_CONNECTION_SLUG,DEFAULT_SLACK_CONNECTOR_SLUG,HumanActionRequiredError,SCAFFOLDABLE_CHANNELS,SLACK_CHANNEL_DEFAULT_ROUTE,SUPPORTED_PROTOCOLS,WriteFileExistsError,byokProviderEnvVar,catalogSlugs,deriveSlackConnectorSlug,effectiveProtocols,endpointForProtocol,ensureChannel,ensureConnection,ensureConnectionDependencies,getCatalogEntry,hasVercelHostFramework,isEveProject,isNextJsProject,isValidConnectionSlug,listAuthoredChannels,listAuthoredConnections,normalizeSlackConnectorSlug,resolveVercelHostFrameworkPreset,scaffoldBaseProject,scaffoldExtensionProject};
|
|
@@ -64,10 +64,16 @@ type WebChannelMutationResult = WebChannelWrittenResult | WebChannelSkippedResul
|
|
|
64
64
|
* A missing `package.json` reads as "no app".
|
|
65
65
|
*/
|
|
66
66
|
export declare function isNextJsProject(projectRoot: string): Promise<boolean>;
|
|
67
|
+
/**
|
|
68
|
+
* The Vercel Framework Preset slug for the host framework a project declares, or
|
|
69
|
+
* `undefined` when it declares none (a missing `package.json` reads as none).
|
|
70
|
+
*/
|
|
71
|
+
export declare function resolveVercelHostFrameworkPreset(projectRoot: string): Promise<string | undefined>;
|
|
67
72
|
/**
|
|
68
73
|
* Whether the root app declares a Vercel framework that should own the
|
|
69
74
|
* top-level deployment while eve runs as a sibling service. These match Eve's
|
|
70
|
-
* current framework integrations: Next.js, Nuxt, and SvelteKit.
|
|
75
|
+
* current framework integrations: Next.js, Nuxt, and SvelteKit. Derived from
|
|
76
|
+
* {@link resolveVercelHostFrameworkPreset} so the two share one dependency list.
|
|
71
77
|
*/
|
|
72
78
|
export declare function hasVercelHostFramework(projectRoot: string): Promise<boolean>;
|
|
73
79
|
export declare function normalizeSlackConnectorSlug(input: string): SlackConnectorSlug;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{pinnedNodeEngineMajor}from"../../node-engine.js";import{
|
|
1
|
+
import{pinnedNodeEngineMajor}from"../../node-engine.js";import{getSupportedModuleBaseName,matchesSupportedModuleBaseName}from"./module-files.js";import{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{patchPackageJson}from"./package-json.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{WEB_APP_TEMPLATE_FILES,WEB_APP_TEMPLATE_PACKAGE_JSON}from"../create/web-template.js";import{DEFAULT_EVE_PACKAGE_CONTRACT,resolveEvePackageContract}from"../create/project.js";import{basename,join,resolve}from"node:path";import{readFile,readdir}from"node:fs/promises";const SLACK_CHANNEL_DEFAULT_ROUTE=`/eve/v1/slack`,DEFAULT_SLACK_CONNECTOR_SLUG=`my-agent`,NEXT_PACKAGE_NAME=`next`,PACKAGE_DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`],WEB_NEXT_CONFIG_PATH=`next.config.ts`,WEB_COMPETING_NEXT_CONFIG_PATHS=[`next.config.js`,`next.config.mjs`,WEB_NEXT_CONFIG_PATH,`next.config.mts`].filter(e=>e!==WEB_NEXT_CONFIG_PATH);function toSlackConnectorSlug(e){return e}function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}async function readPackageJsonObject(e){if(!await pathExists(e))return;let t=JSON.parse(await readFile(e,`utf8`));return isJsonObject(t)?t:void 0}async function readDependencyVersion(e,t){let n=await readPackageJsonObject(e);if(n===void 0||!isJsonObject(n.dependencies))return;let r=n.dependencies[t];return typeof r==`string`?r:void 0}function packageJsonHasDependency(e,t){for(let n of PACKAGE_DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function hasPackageDependency(e,t){let n=await readPackageJsonObject(e);return n!==void 0&&packageJsonHasDependency(n,t)}async function isNextJsProject(e){return hasPackageDependency(join(e,`package.json`),NEXT_PACKAGE_NAME)}const VERCEL_HOST_FRAMEWORK_PRESETS={"@sveltejs/kit":`sveltekit`,[NEXT_PACKAGE_NAME]:`nextjs`,nuxt:`nuxtjs`,nuxt3:`nuxtjs`,"nuxt-edge":`nuxtjs`,"nuxt-nightly":`nuxtjs`};async function resolveVercelHostFrameworkPreset(e){let t=await readPackageJsonObject(join(e,`package.json`));if(t!==void 0){for(let[e,n]of Object.entries(VERCEL_HOST_FRAMEWORK_PRESETS))if(packageJsonHasDependency(t,e))return n}}async function hasVercelHostFramework(e){return await resolveVercelHostFrameworkPreset(e)!==void 0}async function ensurePackageDependency(e,t,n){return!await pathExists(e)||await readDependencyVersion(e,t)===n?[]:(await patchPackageJson(e,{dependencies:{[t]:n}}),[{path:e,dependencies:[t],devDependencies:[],scripts:[]}])}function resolveWebPackageVersions(e){return{evePackage:e?.evePackage??DEFAULT_EVE_PACKAGE_CONTRACT,aiPackageVersion:e?.aiPackageVersion??`^7.0.26`,nextPackageVersion:e?.nextPackageVersion??`16.2.6`,reactPackageVersion:e?.reactPackageVersion??`19.2.6`,reactDomPackageVersion:e?.reactDomPackageVersion??`19.2.6`,streamdownPackageVersion:e?.streamdownPackageVersion??`2.5.0`,zodPackageVersion:e?.zodPackageVersion??`4.4.3`,typesReactPackageVersion:e?.typesReactPackageVersion??`19.2.15`,typesReactDomPackageVersion:e?.typesReactDomPackageVersion??`19.2.3`}}function formatEveDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}async function patchWebPackageJson(t,n,i,s,u){let f=join(t,`package.json`);if(!await pathExists(f))return{mutations:[]};let m=resolveEvePackageContract(s.evePackage),h=pinnedNodeEngineMajor(m.nodeEngine),g={...WEB_APP_TEMPLATE_PACKAGE_JSON.dependencies,ai:resolveVersionToken(`aiPackageVersion`,s.aiPackageVersion),eve:formatEveDependencySpecifier(m.version),next:resolveVersionToken(`nextPackageVersion`,s.nextPackageVersion),react:resolveVersionToken(`reactPackageVersion`,s.reactPackageVersion),"react-dom":resolveVersionToken(`reactDomPackageVersion`,s.reactDomPackageVersion),streamdown:resolveVersionToken(`streamdownPackageVersion`,s.streamdownPackageVersion),zod:resolveVersionToken(`zodPackageVersion`,s.zodPackageVersion)},_={...WEB_APP_TEMPLATE_PACKAGE_JSON.devDependencies,"@types/node":h,"@types/react":resolveVersionToken(`typesReactPackageVersion`,s.typesReactPackageVersion),"@types/react-dom":resolveVersionToken(`typesReactDomPackageVersion`,s.typesReactDomPackageVersion),typescript:`6.0.3`},v=WEB_APP_TEMPLATE_PACKAGE_JSON.scripts,y=isPackageManagerWorkspaceMember(n,i),b={dependencies:g,devDependencies:_,scripts:v};y||(b.nodeEngineRequirement=m.nodeEngine);let x=await patchPackageJson(f,b),S=(await patchWorkspaceRootPackageJson(n,i,{aiPackageVersion:g.ai,nodeEngineRequirement:m.nodeEngine,onWorkspaceRootMutation:u})).nodeEngineOverride??x.nodeEngineOverride;return{mutations:[{path:f,dependencies:Object.keys(g),devDependencies:Object.keys(_),scripts:Object.keys(v)}],nodeEngineOverride:S}}function normalizeSlackConnectorSlug(e){return toSlackConnectorSlug((e.trim().replace(/^@/,``).split(`/`).at(-1)??``).toLowerCase().replace(/[^a-z0-9_-]+/g,`-`).replace(/^[^a-z0-9]+/,``).replace(/[^a-z0-9]+$/,``).slice(0,100).replace(/[^a-z0-9]+$/,``)||`my-agent`)}async function deriveSlackConnectorSlug(e,t){if(t!==void 0&&t.length>0&&t!==`.`)return normalizeSlackConnectorSlug(t);try{let t=await readFile(join(e,`package.json`),`utf8`),n=JSON.parse(t);if(typeof n.name==`string`&&n.name.length>0)return normalizeSlackConnectorSlug(n.name)}catch{}return normalizeSlackConnectorSlug(basename(resolve(e))||`my-agent`)}function buildSlackTemplate(e){if(!e.startsWith(`slack/`)||e.length===6)throw Error(`Invalid Slack connector UID "${e}".`);return`import { connectSlackCredentials } from "@vercel/connect/eve";
|
|
2
2
|
import { slackChannel } from "eve/channels/slack";
|
|
3
3
|
|
|
4
4
|
export default slackChannel({
|
|
5
5
|
credentials: connectSlackCredentials(${JSON.stringify(e)}),
|
|
6
6
|
});
|
|
7
|
-
`}function renderWebAppTemplate(e,t){return e.replaceAll(`__EVE_INIT_APP_NAME__`,t).replaceAll(`__EVE_INIT_WITH_EVE_OPTIONS__`,``)}function
|
|
7
|
+
`}function renderWebAppTemplate(e,t){return e.replaceAll(`__EVE_INIT_APP_NAME__`,t).replaceAll(`__EVE_INIT_WITH_EVE_OPTIONS__`,``)}async function ensureWebVercelJson(e){return await pathExists(e)?`skipped`:(await writeTextFile(e,`${JSON.stringify({$schema:`https://openapi.vercel.sh/vercel.json`},null,2)}\n`,{force:!0}),`written`)}async function findCompetingNextConfigFiles(e){let t=[];for(let n of WEB_COMPETING_NEXT_CONFIG_PATHS){let i=join(e,n);await pathExists(i)&&t.push(i)}return t}async function ensureChannel(e){switch(e.kind){case`slack`:return ensureSlackChannel({...e,kind:`slack`});case`web`:return ensureWebChannel({...e,kind:`web`})}}async function ensureWebChannel(e){let t=join(e.projectRoot,`package.json`),n=await pathExists(join(e.projectRoot,`app/page.tsx`));if(!e.force&&await isNextJsProject(e.projectRoot))return{kind:`web`,action:`skipped`,skipReason:`nextjs-project`,filesWritten:[],filesSkipped:[t],packageJsonUpdated:[]};let a=resolveWebPackageVersions(e.webPackageVersions),o=e.packageManager??`pnpm`,c=resolve(e.workspaceProbeDirectory??e.projectRoot),l=await patchWebPackageJson(e.projectRoot,o,c,a,e.onWorkspaceRootMutation),d=[],f=[],p=[],g=[],_=basename(resolve(e.projectRoot));if(e.configureVercelServices??!0){let t=join(e.projectRoot,`vercel.json`);await ensureWebVercelJson(t)===`written`?d.push(t):g.push(t)}let v=await applyPackageManagerWorkspaceConfiguration({packageManager:o,projectRoot:e.projectRoot,workspaceProbeRoot:c,onWorkspaceRootMutation:e.onWorkspaceRootMutation});d.push(...v.filesWritten),g.push(...v.filesSkipped);for(let[t,n]of Object.entries(WEB_APP_TEMPLATE_FILES)){let a=join(e.projectRoot,t);if(t===`agent/channels/eve.ts`&&!e.force&&await pathExists(a)){g.push(a);continue}let o=await pathExists(a);await writeTextFile(a,renderWebAppTemplate(n,_),{force:!0}),d.push(a),o&&f.push(a)}p.push(...await findCompetingNextConfigFiles(e.projectRoot));let y=[...new Set(d)],b=[...new Set(g)].filter(e=>!y.includes(e)),x={kind:`web`,action:n?`overwritten`:`created`,filesWritten:y,filesSkipped:b,packageJsonUpdated:l.mutations};return f.length>0&&(x.filesOverwritten=f),p.length>0&&(x.competingNextConfigFiles=p),l.nodeEngineOverride!==void 0&&(x.nodeEngineOverride=l.nodeEngineOverride),x}async function ensureSlackChannel(e){let t=join(e.projectRoot,`agent/channels/slack.ts`),n=await pathExists(t);if(!e.force&&n)return{kind:`slack`,action:`skipped`,filesWritten:[],filesSkipped:[t],packageJsonUpdated:[]};let o=resolveVersionToken(`connectPackageVersion`,e.connectPackageVersion??`0.2.2`),s=await ensurePackageDependency(join(e.projectRoot,`package.json`),`@vercel/connect`,o),c=e.slackConnectorSlug??await deriveSlackConnectorSlug(e.projectRoot);await writeTextFile(t,buildSlackTemplate(e.slackConnectorUid??`slack/${c}`),{force:e.force});let l={kind:`slack`,action:n?`overwritten`:`created`,filesWritten:[t],filesSkipped:[],packageJsonUpdated:s,slackConnectorSlug:c};return n&&(l.filesOverwritten=[t]),l}async function listAuthoredChannels(e){let r=join(e,`agent/channels`),i;try{i=await readdir(r,{withFileTypes:!0})}catch(e){if(e.code===`ENOENT`)return[];throw e}let a=[];for(let e of i){if(e.isFile()){let n=getSupportedModuleBaseName(e.name);n!==null&&a.push(n);continue}if(e.isDirectory())try{(await readdir(join(r,e.name))).some(e=>matchesSupportedModuleBaseName(e,`connection`))&&a.push(e.name)}catch{}}return a.sort()}export{DEFAULT_SLACK_CONNECTOR_SLUG,SLACK_CHANNEL_DEFAULT_ROUTE,deriveSlackConnectorSlug,ensureChannel,hasVercelHostFramework,isNextJsProject,listAuthoredChannels,normalizeSlackConnectorSlug,resolveVercelHostFrameworkPreset};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{endpointForProtocol}from"../connections/catalog.js";import{
|
|
1
|
+
import{endpointForProtocol}from"../connections/catalog.js";import{getSupportedModuleBaseName,matchesSupportedModuleBaseName}from"./module-files.js";import{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{patchPackageJson}from"./package-json.js";import{join}from"node:path";import{readFile,readdir,writeFile}from"node:fs/promises";const DEFAULT_CONNECT_PACKAGE_VERSION=`0.2.2`,CONNECT_PACKAGE_NAME=`@vercel/connect`,USER_AUTHORED_CONNECTION_DIR=`agent/connections`;function resolveAuth(e){return e.auth??{kind:`none`}}function envKeysForAuth(e){switch(e.kind){case`bearer-env`:return[e.envVar];case`header`:return e.headers.map(e=>e.envVar);case`connect`:case`none`:return[]}}function authBlock(e){switch(e.kind){case`connect`:return` auth: connect("${e.connector}"),\n`;case`bearer-env`:return` auth: { getToken: async () => ({ token: process.env.${e.envVar}! }) },\n`;case`header`:return` headers: () => ({\n${e.headers.map(e=>` "${e.header}": process.env.${e.envVar}!,`).join(`
|
|
2
2
|
`)}\n }),\n`;case`none`:return``}}function renderMcpTemplate(e,t,n){return`${n.kind===`connect`?`import { connect } from "@vercel/connect/eve";
|
|
3
3
|
import { defineMcpClientConnection } from "eve/connections";
|
|
4
4
|
`:`import { defineMcpClientConnection } from "eve/connections";
|
|
@@ -15,7 +15,7 @@ export default defineOpenAPIConnection({
|
|
|
15
15
|
spec: "${e.spec}",
|
|
16
16
|
${i} description: "${t}",
|
|
17
17
|
${authBlock(n)}});
|
|
18
|
-
`}function renderTemplate(e,t,n,r){return e===`mcp`?renderMcpTemplate(t,n,r):renderOpenApiTemplate(t,n,r)}function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}async function ensureConnectDependency(e,
|
|
18
|
+
`}function renderTemplate(e,t,n,r){return e===`mcp`?renderMcpTemplate(t,n,r):renderOpenApiTemplate(t,n,r)}function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}async function ensureConnectDependency(e,t){if(!await pathExists(e))return[];let n=JSON.parse(await readFile(e,`utf8`));return(isJsonObject(n)&&isJsonObject(n.dependencies)?n.dependencies[CONNECT_PACKAGE_NAME]:void 0)===t?[]:(await patchPackageJson(e,{dependencies:{[CONNECT_PACKAGE_NAME]:t}}),[{path:e,dependencies:[CONNECT_PACKAGE_NAME],devDependencies:[],scripts:[]}])}async function ensureConnectionDependencies(e){let t=resolveVersionToken(`connectPackageVersion`,e.connectPackageVersion??DEFAULT_CONNECT_PACKAGE_VERSION);return ensureConnectDependency(join(e.projectRoot,`package.json`),t)}function envKeyPresent(e,t){return RegExp(`^\\s*(?:export\\s+)?${t}\\s*=`,`m`).test(e)}async function seedEnvPlaceholders(e,t){if(t.length===0)return[];let n=``;await pathExists(e)&&(n=await readFile(e,`utf8`));let i=t.filter(e=>!envKeyPresent(n,e));if(i.length===0)return[];let a=`${n.length>0&&!n.endsWith(`
|
|
19
19
|
`)?`
|
|
20
20
|
`:``}${i.map(e=>`${e}=`).join(`
|
|
21
|
-
`)}\n`;return await writeFile(e,
|
|
21
|
+
`)}\n`;return await writeFile(e,n+a,`utf8`),i}async function ensureConnection(t){let n=t.slug??t.entry.slug,o=resolveAuth(t.entry),s=endpointForProtocol(t.entry,t.protocol);if(s===null)throw Error(`Connection "${n}" is missing a ${t.protocol===`mcp`?`mcp.url`:`openapi.spec`} endpoint for protocol "${t.protocol}".`);let c=join(t.projectRoot,USER_AUTHORED_CONNECTION_DIR,`${n}.ts`),l=envKeysForAuth(o),u=await pathExists(c);if(!t.force&&u)return{slug:n,protocol:t.protocol,action:`skipped`,filePath:c,filesWritten:[],filesSkipped:[c],packageJsonUpdated:[],envKeysAdded:[],envKeysRequired:l};let d=[];if(o.kind===`connect`){let e=resolveVersionToken(`connectPackageVersion`,t.connectPackageVersion??DEFAULT_CONNECT_PACKAGE_VERSION);d.push(...await ensureConnectDependency(join(t.projectRoot,`package.json`),e))}await writeTextFile(c,renderTemplate(t.protocol,s,t.entry.description,o),{force:!0});let f=await seedEnvPlaceholders(join(t.projectRoot,`.env.local`),l),p={slug:n,protocol:t.protocol,action:u?`overwritten`:`created`,filePath:c,filesWritten:[c],filesSkipped:[],packageJsonUpdated:d,envKeysAdded:f,envKeysRequired:l};return u&&(p.filesOverwritten=[c]),p}async function listAuthoredConnections(e){let r=join(e,USER_AUTHORED_CONNECTION_DIR),i;try{i=await readdir(r,{withFileTypes:!0})}catch(e){if(e.code===`ENOENT`)return[];throw e}let a=[];for(let e of i){if(e.isFile()){let n=getSupportedModuleBaseName(e.name);n!==null&&a.push(n);continue}if(e.isDirectory())try{(await readdir(join(r,e.name))).some(e=>matchesSupportedModuleBaseName(e,`connection`))&&a.push(e.name)}catch{}}return a.sort()}export{ensureConnection,ensureConnectionDependencies,listAuthoredConnections};
|
|
@@ -7,4 +7,16 @@ export interface CreatedProjectFrameworkOptions extends VercelProjectOperationOp
|
|
|
7
7
|
/** Never prompt; ambiguous host framework detections fall back to the eve preset. */
|
|
8
8
|
headless?: boolean;
|
|
9
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* Best-effort alignment of a linked Vercel project's Framework Preset with the
|
|
12
|
+
* host framework the project declares on disk (e.g. Next.js).
|
|
13
|
+
*
|
|
14
|
+
* A project created as a standalone eve agent keeps the `eve` preset; adding a
|
|
15
|
+
* host framework via `eve channels add web` leaves it stale, so the deploy would
|
|
16
|
+
* build the agent instead of the host app. Since that command already deploys on
|
|
17
|
+
* the user's behalf, this switches the preset directly (no prompt) and notes the
|
|
18
|
+
* change. No host framework, an unlinked directory, or an already-correct preset
|
|
19
|
+
* is a no-op; a Vercel API failure warns rather than aborting the deploy.
|
|
20
|
+
*/
|
|
21
|
+
export declare function syncHostFrameworkPreset(prompter: Prompter, projectRoot: string, onOutput: ReturnType<typeof createPromptCommandOutput>, options: VercelProjectOperationOptions): Promise<void>;
|
|
10
22
|
export declare function ensureCreatedProjectFramework(prompter: Prompter, projectRoot: string, team: string, projectId: string, onOutput: ReturnType<typeof createPromptCommandOutput>, options: CreatedProjectFrameworkOptions): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
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{isForbiddenApiFailure,normalizeVercelApiResult}from"./vercel-api-failure.js";import{VERCEL_PROJECT_REQUEST_TIMEOUT_MS,parseVercelJson,requireVercelTeamAccess}from"./vercel-project-api.js";import{extname,join}from"node:path";import*as fs from"node:fs/promises";import{captureVercel}from"#setup/primitives/index.js";import"#setup/cli/index.js";const VercelProjectFrameworkSchema=object({framework:string().min(1).nullish()}),EVE_FRAMEWORK_INTEGRATIONS={nextjs:{label:`Next.js`,importSpecifier:`eve/next`},nuxt:{label:`Nuxt`,importSpecifier:`eve/nuxt`},nuxtjs:{label:`Nuxt`,importSpecifier:`eve/nuxt`},sveltekit:{label:`SvelteKit`,importSpecifier:`eve/sveltekit`}},FRAMEWORK_INTEGRATION_SOURCE_EXTENSIONS=new Set([`.cjs`,`.cts`,`.js`,`.json`,`.jsx`,`.mjs`,`.mts`,`.svelte`,`.ts`,`.tsx`,`.vue`]),FRAMEWORK_INTEGRATION_IGNORED_DIRECTORIES=new Set([`.eve`,`.git`,`.next`,`.nuxt`,`.output`,`.svelte-kit`,`.turbo`,`.vercel`,`build`,`coverage`,`dist`,`node_modules`]);function parseProjectFramework(e,t){let n=VercelProjectFrameworkSchema.safeParse(parseVercelJson(e,t));if(!n.success)throw Error(`Could not read Vercel project framework from ${t}.`);return n.data.framework??void 0}async function fetchProjectFramework(e,t,
|
|
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{readProjectLink}from"./project-resolution.js";import{isForbiddenApiFailure,normalizeVercelApiResult}from"./vercel-api-failure.js";import{VERCEL_PROJECT_REQUEST_TIMEOUT_MS,parseVercelJson,requireVercelTeamAccess}from"./vercel-project-api.js";import{resolveVercelHostFrameworkPreset}from"./scaffold/update/channels.js";import"./scaffold/index.js";import{extname,join}from"node:path";import*as fs from"node:fs/promises";import{captureVercel}from"#setup/primitives/index.js";import"#setup/cli/index.js";const VercelProjectFrameworkSchema=object({framework:string().min(1).nullish()}),EVE_FRAMEWORK_INTEGRATIONS={nextjs:{label:`Next.js`,importSpecifier:`eve/next`},nuxt:{label:`Nuxt`,importSpecifier:`eve/nuxt`},nuxtjs:{label:`Nuxt`,importSpecifier:`eve/nuxt`},sveltekit:{label:`SvelteKit`,importSpecifier:`eve/sveltekit`}},FRAMEWORK_INTEGRATION_SOURCE_EXTENSIONS=new Set([`.cjs`,`.cts`,`.js`,`.json`,`.jsx`,`.mjs`,`.mts`,`.svelte`,`.ts`,`.tsx`,`.vue`]),FRAMEWORK_INTEGRATION_IGNORED_DIRECTORIES=new Set([`.eve`,`.git`,`.next`,`.nuxt`,`.output`,`.svelte-kit`,`.turbo`,`.vercel`,`build`,`coverage`,`dist`,`node_modules`]);function parseProjectFramework(e,t){let n=VercelProjectFrameworkSchema.safeParse(parseVercelJson(e,t));if(!n.success)throw Error(`Could not read Vercel project framework from ${t}.`);return n.data.framework??void 0}async function fetchProjectFramework(e,t,n,o){let c=normalizeVercelApiResult(await captureVercel([`api`,`/v9/projects/${n}`,`--scope`,t,`--raw`],{cwd:e,signal:o.signal,timeoutMs:VERCEL_PROJECT_REQUEST_TIMEOUT_MS}));if(c.ok)return parseProjectFramework(c.stdout,`project ${n}`);throw isForbiddenApiFailure(c.failure)&&requireVercelTeamAccess(c.failure),Error(`Could not inspect Vercel project "${n}". ${c.failure.message}`)}async function setProjectFramework(e,t,n,o,c,l){let u=normalizeVercelApiResult(await captureVercel([`api`,`/v9/projects/${n}`,`--scope`,t,`--method`,`PATCH`,`--raw-field`,`framework=${o}`,`--raw`],{cwd:e,onOutput:c,signal:l.signal,timeoutMs:VERCEL_PROJECT_REQUEST_TIMEOUT_MS}));if(!u.ok)throw isForbiddenApiFailure(u.failure)&&requireVercelTeamAccess(u.failure),Error(`Could not set Vercel project "${n}" framework to ${o}. ${u.failure.message}`)}async function confirmDetectedFramework(e,t,n){return await e.select({message:`Vercel detected ${n.label}. Is this project using ${n.importSpecifier}?`,options:[{value:!0,label:`Yes, keep ${t}`,hint:`Use this for a host app that integrates eve through ${n.importSpecifier}.`},{value:!1,label:`No, switch to eve`,hint:`Use this for a standalone eve agent.`}]})?`keep`:`switch-to-eve`}function sourceMentionsPackageSpecifier(e,t){return e.includes(`"${t}"`)||e.includes(`'${t}'`)||e.includes(`\`${t}\``)}async function directoryContainsPackageSpecifier(e,t){let n;try{n=await fs.readdir(e,{encoding:`utf8`,withFileTypes:!0})}catch{return!1}for(let r of n){let n=join(e,r.name);if(r.isDirectory()){if(FRAMEWORK_INTEGRATION_IGNORED_DIRECTORIES.has(r.name))continue;if(await directoryContainsPackageSpecifier(n,t))return!0;continue}if(!(!r.isFile()||!FRAMEWORK_INTEGRATION_SOURCE_EXTENSIONS.has(extname(r.name))))try{if(sourceMentionsPackageSpecifier(await fs.readFile(n,`utf8`),t))return!0}catch{continue}}return!1}async function detectFrameworkIntegrationImport(e,t){return directoryContainsPackageSpecifier(e,t)}async function resolveDetectedFrameworkAction(e,t,n,r){let i=EVE_FRAMEWORK_INTEGRATIONS[n];return i===void 0?`switch-to-eve`:await(r.detectFrameworkIntegrationImport??detectFrameworkIntegrationImport)(t,i.importSpecifier)?`keep`:r.headless?`switch-to-eve`:confirmDetectedFramework(e,n,i)}function frameworkPresetLabel(e){return EVE_FRAMEWORK_INTEGRATIONS[e]?.label??e}function describeError(e){return e instanceof Error?e.message:String(e)}async function syncHostFrameworkPreset(e,t,r,i){let a=await resolveVercelHostFrameworkPreset(t);if(a===void 0)return;let o=await readProjectLink(t);if(o===void 0)return;let s=frameworkPresetLabel(a),l;try{l=await fetchProjectFramework(t,o.orgId,o.projectId,i)}catch(t){if(i.signal?.aborted)throw t;e.log.warning(`Could not check this Vercel project's Framework Preset (${describeError(t)}). If it is not already ${s}, set it under Project Settings → Build and Deployment → Framework Settings before deploying.`);return}if(l===a)return;let u=l===void 0?void 0:frameworkPresetLabel(l),d=u===void 0?`had no Framework Preset set`:`was set to "${u}"`;try{await setProjectFramework(t,o.orgId,o.projectId,a,r,i)}catch(t){if(i.signal?.aborted)throw t;e.log.warning(`${describeError(t)} Set this Vercel project's Framework Preset to ${s} (Project Settings → Build and Deployment → Framework Settings) before deploying, or the deployment will not build your ${s} app.`);return}e.log.info(`This project uses ${s}, but its Vercel Framework Preset ${d}; switched it to ${s} so the deployment builds your app.`)}async function ensureCreatedProjectFramework(e,t,n,r,i,a){let o=await fetchProjectFramework(t,n,r,a);o!==`eve`&&(o===void 0?`switch-to-eve`:await resolveDetectedFrameworkAction(e,t,o,a))===`switch-to-eve`&&await setProjectFramework(t,n,r,`eve`,i,a)}export{ensureCreatedProjectFramework,syncHostFrameworkPreset};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function toChannelLocalContinuationToken(e){let t=e.indexOf(`:`);return t<0?e:e.slice(t+1)}export{toChannelLocalContinuationToken};
|
package/dist/src/svelte/index.js
CHANGED
package/dist/src/vue/index.js
CHANGED
package/docs/channels/eve.mdx
CHANGED
|
@@ -18,12 +18,13 @@ export default eveChannel({
|
|
|
18
18
|
|
|
19
19
|
## Routes
|
|
20
20
|
|
|
21
|
-
The application exposes a health route plus eve channel routes that inspect the agent, create sessions, send follow-ups, and stream events:
|
|
21
|
+
The application exposes a health route plus eve channel routes that inspect the agent, create sessions, send follow-ups, cancel turns, and stream events:
|
|
22
22
|
|
|
23
23
|
- `GET /eve/v1/health`
|
|
24
24
|
- `GET /eve/v1/info`
|
|
25
25
|
- `POST /eve/v1/session` (start a session)
|
|
26
26
|
- `POST /eve/v1/session/:sessionId` (send a follow-up)
|
|
27
|
+
- `POST /eve/v1/session/:sessionId/cancel` (cancel the in-flight turn)
|
|
27
28
|
- `GET /eve/v1/session/:sessionId/stream` (stream events, NDJSON)
|
|
28
29
|
|
|
29
30
|
Start a session with a minimal body. The response returns `sessionId` and the `continuationToken` you reuse for follow-ups:
|
|
@@ -44,6 +45,15 @@ curl -N https://<deployment>/eve/v1/session/ses_01h.../stream
|
|
|
44
45
|
# {"type":"message.completed",...}
|
|
45
46
|
```
|
|
46
47
|
|
|
48
|
+
Cancel a session's in-flight turn with an empty body, or scope the cancel to the turn you observed by passing the `turnId` stamped on that turn's stream events:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
curl -X POST https://<deployment>/eve/v1/session/ses_01h.../cancel
|
|
52
|
+
# {"ok":true,"sessionId":"ses_01h...","status":"accepted"}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Cancellation is asynchronous: `"accepted"` means a cancellation hook accepted the request. Confirm the effective outcome on the stream as `turn.cancelled` followed by `session.waiting` — never as a failure. Active local and remote subagents are cancelled recursively before the parent settles; their own streams carry their cancellation boundaries, and cancelled work does not emit `subagent.completed` on the parent. Content emitted before the cancel stays on the event stream, while durable model history keeps only content that had already settled. The session accepts the next message normally. When there is no resumable cancellation target (including an unknown session, a settled turn, or a duplicate cancel), the route responds with `"no_active_turn"` — also a success, so a stop button can fire and forget. A `turnId` naming any other turn is accepted and consumed as a no-op, so a guarded cancel racing a turn boundary cannot stop a turn the caller never saw.
|
|
56
|
+
|
|
47
57
|
See [Sessions, runs & streaming](../concepts/sessions-runs-and-streaming) for the full request and stream flow, including the complete event set.
|
|
48
58
|
|
|
49
59
|
## CORS
|
|
@@ -79,6 +79,8 @@ import { disableTool } from "eve/tools";
|
|
|
79
79
|
export default disableTool();
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
+
Use `agent/tools/agent.ts` to remove the root-only `agent` delegation tool. The root session then receives no tool for delegating to a fresh copy of itself, and the model never sees that tool.
|
|
83
|
+
|
|
82
84
|
If the filename matches no known framework tool, resolution fails instead of silently doing nothing, so a typo surfaces at build time rather than removing the wrong tool.
|
|
83
85
|
|
|
84
86
|
## When to override, disable, or author a new tool
|
|
@@ -15,7 +15,7 @@ Work nests in three levels:
|
|
|
15
15
|
|
|
16
16
|
Every turn runs as a durable workflow, built on the open-source [Workflow SDK](https://workflow-sdk.dev/) (Vercel Workflow when you deploy on Vercel). eve checkpoints progress and serializes durable state at each step boundary. Your code runs inside a managed step, so tools, the sandbox, and subagents feel synchronous even though the session underneath them is durable.
|
|
17
17
|
|
|
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 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.
|
|
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 under `.eve/.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
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
21
|
|
|
@@ -58,7 +58,8 @@ The stream is newline-delimited JSON (NDJSON), one event per line:
|
|
|
58
58
|
| `step.failed` | A model step failed; carries `{ code, message, details? }`. |
|
|
59
59
|
| `turn.completed` | The turn finished. |
|
|
60
60
|
| `turn.failed` | The turn failed; carries `{ code, message, details? }`. |
|
|
61
|
-
| `
|
|
61
|
+
| `turn.cancelled` | The turn was cancelled before finishing; always followed by `session.waiting`. |
|
|
62
|
+
| `session.waiting` | The session parked for the next input; carries the current channel-owned `continuationToken`. |
|
|
62
63
|
| `session.failed` | The session failed. |
|
|
63
64
|
| `session.completed` | The session reached a terminal end. |
|
|
64
65
|
|
|
@@ -70,11 +71,11 @@ Note: consider the privacy, confidentiality, and user-experience implications fo
|
|
|
70
71
|
|
|
71
72
|
A delegated subagent publishes progress on its own child-session stream. The parent only emits `subagent.called` with a `childSessionId`, which a client uses to attach.
|
|
72
73
|
|
|
73
|
-
`step.failed` and `turn.failed` carry `{ code, message, details? }` for the failed fragment or turn, and `session.failed` is the terminal session-level variant. When a turn requested an output schema, the finalized payload lands on `result.completed` as `data.result` before the turn boundary. `authorization.required` carries the sign-in challenge (`data.authorization` may include `url`, `userCode`, `expiresAt`, `instructions`), and `authorization.completed` carries `data.outcome` (`"authorized" | "declined" | "failed" | "timed-out"`).
|
|
74
|
+
`step.failed` and `turn.failed` carry `{ code, message, details? }` for the failed fragment or turn, and `session.failed` is the terminal session-level variant. `turn.cancelled` is not a failure: the cancelled turn ends without any failure event, `session.waiting` follows, and the session accepts the next message normally — whatever the turn streamed before cancellation stays on the stream, while durable history keeps only what had already settled. When a turn requested an output schema, the finalized payload lands on `result.completed` as `data.result` before the turn boundary. `authorization.required` carries the sign-in challenge (`data.authorization` may include `url`, `userCode`, `expiresAt`, `instructions`), and `authorization.completed` carries `data.outcome` (`"authorized" | "declined" | "failed" | "timed-out"`).
|
|
74
75
|
|
|
75
76
|
## Send a follow-up message
|
|
76
77
|
|
|
77
|
-
Once the session is waiting (you'll see `session.waiting`), POST your follow-up to the session endpoint with
|
|
78
|
+
Once the session is waiting (you'll see `session.waiting`), POST your follow-up to the session endpoint with `event.data.continuationToken`:
|
|
78
79
|
|
|
79
80
|
```bash
|
|
80
81
|
curl -X POST http://127.0.0.1:3000/eve/v1/session/<sessionId> \
|
|
@@ -88,14 +89,33 @@ If the session is waiting on a human-in-the-loop approval, a matching text reply
|
|
|
88
89
|
|
|
89
90
|
For deterministic ordering, send one follow-up at a time and wait for the next `session.waiting` event before sending another message to the same session. See [message delivery and queueing](./execution-model-and-durability#message-delivery-and-queueing) for the current runtime contract.
|
|
90
91
|
|
|
92
|
+
## Cancel the in-flight turn
|
|
93
|
+
|
|
94
|
+
POST to the session's cancel endpoint to stop the turn that is currently running. The body is optional; pass `turnId` (stamped on every turn-scoped stream event) to scope the cancel to the turn you observed:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
curl -X POST http://127.0.0.1:3000/eve/v1/session/<sessionId>/cancel
|
|
98
|
+
# {"ok":true,"sessionId":"<sessionId>","status":"accepted"}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`"accepted"` means a cancellation hook accepted the request. Confirm cancellation on the stream as `turn.cancelled` followed by `session.waiting`; the session then accepts the next message normally. If the turn is waiting on active local or remote subagents, eve also requests cancellation of every adopted child, recursively, before settling the parent. Each child reports its own cancellation boundary on its child-session stream; the parent does not emit `subagent.completed` for cancelled work. `"no_active_turn"` means no resumable cancellation target exists, including an unknown session or an already-settled turn. Both statuses are success, so clients can fire and forget. See the [eve channel](../channels/eve) for the full route contract.
|
|
102
|
+
|
|
91
103
|
## Reconnect and rewind
|
|
92
104
|
|
|
93
|
-
The stream is durable. Every event is recorded before a step completes, so the whole stream is replayable.
|
|
105
|
+
The stream is durable. Every event is recorded before a step completes, so the whole stream is replayable. A nonnegative `startIndex` is an absolute event count: use it to pick up where you dropped off or pass `0` to rewind to the start.
|
|
94
106
|
|
|
95
107
|
```bash
|
|
96
108
|
curl "http://127.0.0.1:3000/eve/v1/session/<sessionId>/stream?startIndex=<count>"
|
|
97
109
|
```
|
|
98
110
|
|
|
111
|
+
A negative `startIndex` reads relative to the stream's current tail. For example, `-1` reads the latest event, which is normally `session.waiting` for a resumable session:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
curl "http://127.0.0.1:3000/eve/v1/session/<sessionId>/stream?startIndex=-1"
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
This gives a consumer that only persisted `sessionId` a lightweight way to recover the current `continuationToken`. Because a tail-relative position does not resolve to an absolute consumed-event count, client tail reads do not automatically reconnect or advance the stored cursor.
|
|
118
|
+
|
|
99
119
|
## Use the client from TypeScript
|
|
100
120
|
|
|
101
121
|
For scripts, server-to-server calls, tests, evals, and custom UIs, `eve/client` wraps these routes in a typed client so you don't hand-roll the POST and NDJSON stream loop.
|
|
@@ -22,7 +22,7 @@ Scoped assertions take no explicit value and gate by default. Assertions on `t`
|
|
|
22
22
|
| `t.usedNoTools()` | No tool calls at all |
|
|
23
23
|
| `t.maxToolCalls(n)` | At most `n` tool calls |
|
|
24
24
|
| `t.noFailedActions()` | No tool, subagent, or skill action reported a failure |
|
|
25
|
-
| `t.calledSubagent(name, opts?)` | A subagent delegation happened (
|
|
25
|
+
| `t.calledSubagent(name, opts?)` | A subagent delegation happened (identity, remote, output, status, count) |
|
|
26
26
|
| `t.event(type, opts?)` / `t.notEvent(type, opts?)` | Typed event presence, data, and count matching |
|
|
27
27
|
| `t.eventOrder([...matchers])` | Matching event groups occur in order |
|
|
28
28
|
| `t.eventsSatisfy(label, predicate)` | Escape hatch: any predicate over the typed event stream |
|
|
@@ -77,7 +77,7 @@ Pick the cheapest builder that captures what "correct" means. When exact match i
|
|
|
77
77
|
|
|
78
78
|
## The matcher mini-language
|
|
79
79
|
|
|
80
|
-
`t.calledTool` and `t.calledSubagent` take matcher objects. Tools accept `{ input, output, status, count }`; subagents accept `{ remoteUrl, output, status, count }`. Calls match `status: "completed"` by default; use `"pending"`, `"failed"`, or `"rejected"` explicitly for lifecycle checks. A numeric `count` requires an exact number of calls matching every supplied constraint. Use a predicate for ranges or other custom count requirements; it receives the observed number of matching calls.
|
|
80
|
+
`t.calledTool` and `t.calledSubagent` take matcher objects. Tools accept `{ input, output, status, count }`; subagents accept `{ callId, childSessionId, remoteUrl, output, status, count }`. Calls match `status: "completed"` by default; use `"pending"`, `"failed"`, or `"rejected"` explicitly for lifecycle checks. A numeric `count` requires an exact number of calls matching every supplied constraint. Use a predicate for ranges or other custom count requirements; it receives the observed number of matching calls.
|
|
81
81
|
|
|
82
82
|
Matcher values accept a literal (objects partial-deep-match), a RegExp, or a predicate function that returns a boolean:
|
|
83
83
|
|