eve 0.11.10 → 0.12.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 (99) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/src/chunks/{use-eve-agent-D9ZhQhyV.js → use-eve-agent-DEm_Jg4k.js} +18 -4
  3. package/dist/src/chunks/{use-eve-agent-DFI0POM9.js → use-eve-agent-DsXOQMFZ.js} +18 -4
  4. package/dist/src/cli/commands/init.js +1 -1
  5. package/dist/src/cli/dev/tui/command-typeahead.d.ts +1 -1
  6. package/dist/src/cli/dev/tui/command-typeahead.js +1 -1
  7. package/dist/src/cli/dev/tui/prompt-command-handler.js +1 -1
  8. package/dist/src/cli/dev/tui/runner.d.ts +6 -2
  9. package/dist/src/cli/dev/tui/runner.js +1 -1
  10. package/dist/src/cli/dev/tui/setup-commands.d.ts +6 -2
  11. package/dist/src/cli/dev/tui/setup-commands.js +2 -2
  12. package/dist/src/cli/dev/tui/setup-issues.d.ts +16 -2
  13. package/dist/src/cli/dev/tui/setup-issues.js +1 -1
  14. package/dist/src/cli/dev/tui/setup-panel.js +2 -2
  15. package/dist/src/cli/dev/tui/target.d.ts +21 -0
  16. package/dist/src/cli/dev/tui/target.js +1 -0
  17. package/dist/src/cli/dev/tui/terminal-renderer.js +3 -3
  18. package/dist/src/cli/dev/tui/test/fake-setup-flow-renderer.d.ts +2 -0
  19. package/dist/src/cli/dev/tui/test/fake-setup-flow-renderer.js +1 -0
  20. package/dist/src/cli/dev/tui/theme.d.ts +3 -1
  21. package/dist/src/cli/dev/tui/theme.js +1 -1
  22. package/dist/src/cli/dev/tui/tui.d.ts +4 -14
  23. package/dist/src/cli/dev/tui/tui.js +1 -1
  24. package/dist/src/cli/dev/url.js +1 -1
  25. package/dist/src/cli/run.d.ts +0 -12
  26. package/dist/src/cli/run.js +2 -2
  27. package/dist/src/client/client.js +1 -1
  28. package/dist/src/client/index.d.ts +1 -1
  29. package/dist/src/client/open-stream.d.ts +2 -0
  30. package/dist/src/client/open-stream.js +1 -1
  31. package/dist/src/client/session.d.ts +2 -1
  32. package/dist/src/client/session.js +1 -1
  33. package/dist/src/client/types.d.ts +9 -0
  34. package/dist/src/context/dynamic-skill-lifecycle.js +1 -1
  35. package/dist/src/context/dynamic-tool-lifecycle.js +1 -1
  36. package/dist/src/evals/cli/eval-client.d.ts +12 -16
  37. package/dist/src/evals/cli/eval-client.js +1 -1
  38. package/dist/src/evals/cli/eval.js +1 -1
  39. package/dist/src/execution/node-step.d.ts +2 -1
  40. package/dist/src/execution/node-step.js +1 -1
  41. package/dist/src/execution/workflow-steps.js +1 -1
  42. package/dist/src/harness/compaction.d.ts +2 -3
  43. package/dist/src/harness/compaction.js +1 -1
  44. package/dist/src/harness/tool-loop.js +1 -1
  45. package/dist/src/internal/application/package.js +1 -1
  46. package/dist/src/internal/nitro/host/dev-authored-source-watcher.js +1 -1
  47. package/dist/src/internal/nitro/host/start-development-server.js +2 -2
  48. package/dist/src/public/definitions/connections/openapi.d.ts +1 -1
  49. package/dist/src/public/definitions/tool.d.ts +6 -0
  50. package/dist/src/runtime/agent/resolve-model.d.ts +7 -4
  51. package/dist/src/runtime/agent/resolve-model.js +1 -1
  52. package/dist/src/runtime/framework-tools/connection-search-dynamic.js +1 -1
  53. package/dist/src/runtime/prompt/connections.js +1 -1
  54. package/dist/src/runtime/sessions/compiled-agent-cache.js +1 -1
  55. package/dist/src/services/dev-client/client-options.d.ts +9 -4
  56. package/dist/src/services/dev-client/client-options.js +1 -1
  57. package/dist/src/services/dev-client/credential-gate.d.ts +19 -0
  58. package/dist/src/services/dev-client/credential-gate.js +1 -0
  59. package/dist/src/services/dev-client/local-host.d.ts +4 -0
  60. package/dist/src/services/dev-client/local-host.js +1 -0
  61. package/dist/src/services/dev-client/request-headers.d.ts +38 -56
  62. package/dist/src/services/dev-client/request-headers.js +1 -1
  63. package/dist/src/services/dev-client/runtime-artifacts.js +1 -1
  64. package/dist/src/services/dev-client/vercel-auth-error.d.ts +2 -0
  65. package/dist/src/services/dev-client/vercel-auth-error.js +2 -2
  66. package/dist/src/services/dev-client.js +1 -1
  67. package/dist/src/setup/cli/option-row.d.ts +11 -5
  68. package/dist/src/setup/cli/option-row.js +1 -1
  69. package/dist/src/setup/cli/prompt-ui.d.ts +6 -6
  70. package/dist/src/setup/cli/prompt-ui.js +2 -2
  71. package/dist/src/setup/flows/model.d.ts +2 -0
  72. package/dist/src/setup/flows/model.js +1 -1
  73. package/dist/src/setup/project-resolution.d.ts +13 -0
  74. package/dist/src/setup/project-resolution.js +1 -1
  75. package/dist/src/setup/scaffold/create/project.js +1 -1
  76. package/dist/src/setup/scaffold/index.d.ts +1 -1
  77. package/dist/src/setup/scaffold/index.js +1 -1
  78. package/dist/src/setup/scaffold/update/channels.d.ts +8 -1
  79. package/dist/src/setup/scaffold/update/channels.js +2 -2
  80. package/dist/src/setup/vercel-deployment.d.ts +53 -0
  81. package/dist/src/setup/vercel-deployment.js +1 -0
  82. package/dist/src/setup/vercel-project.js +1 -1
  83. package/dist/src/setup/verified-remote-client.d.ts +23 -0
  84. package/dist/src/setup/verified-remote-client.js +1 -0
  85. package/dist/src/svelte/index.js +1 -1
  86. package/dist/src/svelte/use-eve-agent.js +1 -1
  87. package/dist/src/vue/index.js +1 -1
  88. package/dist/src/vue/use-eve-agent.js +1 -1
  89. package/docs/concepts/default-harness.md +1 -1
  90. package/docs/connections.mdx +4 -4
  91. package/docs/evals/targets.mdx +7 -5
  92. package/docs/guides/client/overview.mdx +3 -0
  93. package/docs/guides/dev-tui.md +5 -5
  94. package/docs/guides/dynamic-capabilities.md +11 -8
  95. package/docs/subagents.mdx +1 -1
  96. package/docs/tutorial/connect-a-warehouse.mdx +1 -1
  97. package/package.json +1 -1
  98. package/dist/src/harness/tool-result-pruning.d.ts +0 -8
  99. package/dist/src/harness/tool-result-pruning.js +0 -1
@@ -1,18 +1,40 @@
1
- /**
2
- * Returns whether `serverUrl` targets one of the recognized local
3
- * development hostnames. Invalid URLs return `false` so callers can
4
- * always proceed as if the target is remote.
5
- */
6
- export declare function isLocalDevelopmentServerUrl(serverUrl: string): boolean;
7
- /**
8
- * Resolves a Vercel OIDC token for the development client.
9
- *
10
- * Tries the `@vercel/oidc` SDK first (refreshes a freshly-issued token
11
- * when the CLI is linked to a Vercel project), then falls back to the
12
- * `VERCEL_OIDC_TOKEN` environment variable. Returns an empty string
13
- * when no token is available so callers can proceed without auth.
14
- */
15
- export declare function resolveDevelopmentOidcToken(): Promise<string>;
1
+ import { z } from "zod";
2
+ declare const VercelOidcClaimsSchema: z.ZodObject<{
3
+ owner_id: z.ZodString;
4
+ project_id: z.ZodString;
5
+ }, z.core.$strip>;
6
+ /** Vercel owner and project expected to have minted an OIDC token. */
7
+ export interface DevelopmentOidcTarget {
8
+ readonly ownerId: string;
9
+ readonly projectId: string;
10
+ }
11
+ type VercelOidcClaimName = keyof z.infer<typeof VercelOidcClaimsSchema>;
12
+ type InvalidVercelOidcClaim = VercelOidcClaimName | "claims";
13
+ /** Why eve could not use a locally resolved Vercel OIDC token. */
14
+ export type DevelopmentOidcTokenFailure = {
15
+ readonly kind: "resolution-failed";
16
+ readonly message: string;
17
+ } | {
18
+ readonly kind: "malformed-token";
19
+ readonly reason: "missing-payload" | "invalid-json-payload";
20
+ } | {
21
+ readonly kind: "invalid-claims";
22
+ readonly invalidClaims: readonly InvalidVercelOidcClaim[];
23
+ } | {
24
+ readonly kind: "target-mismatch";
25
+ readonly mismatchedClaims: readonly VercelOidcClaimName[];
26
+ };
27
+ /** Result of resolving and checking a Vercel OIDC token for one target. */
28
+ export type DevelopmentOidcTokenResolution = {
29
+ readonly kind: "resolved";
30
+ readonly token: string;
31
+ } | DevelopmentOidcTokenFailure;
32
+ /**
33
+ * Resolves and claim-checks the local Vercel OIDC token for a verified target.
34
+ * It does not authorize a destination; callers must verify the exact origin
35
+ * first and install the result in a `DevelopmentCredentialGate`.
36
+ */
37
+ export declare function resolveDevelopmentOidcToken(input: DevelopmentOidcTarget): Promise<DevelopmentOidcTokenResolution>;
16
38
  /**
17
39
  * Vercel header used to bypass preview protection for framework-owned routes
18
40
  * during local CLI development. Paired with a Protection Bypass for
@@ -31,44 +53,4 @@ export declare const VERCEL_PROTECTION_BYPASS_HEADER = "x-vercel-protection-bypa
31
53
  * `@vercel/oidc`.
32
54
  */
33
55
  export declare const VERCEL_TRUSTED_OIDC_IDP_TOKEN_HEADER = "x-vercel-trusted-oidc-idp-token";
34
- /**
35
- * Vercel request header that carries the runtime OIDC token on function
36
- * invocations.
37
- */
38
- export declare const VERCEL_OIDC_TOKEN_HEADER = "x-vercel-oidc-token";
39
- /**
40
- * Header values accepted by eve's development client helpers.
41
- */
42
- export type DevelopmentRequestHeaders = Headers | ReadonlyArray<readonly [string, string]> | Record<string, string>;
43
- /**
44
- * Creates request headers for one service-issued development request and
45
- * opportunistically refreshes a linked local Vercel OIDC token for eve-owned
46
- * routes when no explicit authorization header is present.
47
- */
48
- export declare function createDevelopmentRequestHeadersAsync(input: {
49
- headers?: DevelopmentRequestHeaders;
50
- resourceUrl: URL;
51
- }): Promise<Headers>;
52
- /**
53
- * Resolves the per-request custom headers used by the development client
54
- * when constructing requests against a configured server URL.
55
- *
56
- * - {@link VERCEL_PROTECTION_BYPASS_HEADER} is attached when
57
- * `VERCEL_AUTOMATION_BYPASS_SECRET` is set.
58
- * - {@link VERCEL_TRUSTED_OIDC_IDP_TOKEN_HEADER} is attached when a Vercel
59
- * OIDC token is available locally (either via `vercel link` +
60
- * `@vercel/oidc` or via the `VERCEL_OIDC_TOKEN` environment variable).
61
- * This lets the CLI bypass Vercel Deployment Protection without the user
62
- * creating a project-scoped Bypass for Automation token first.
63
- *
64
- * Both headers are sent when both sources are available; the platform
65
- * accepts whichever it can validate.
66
- *
67
- * Local dev servers skip the OIDC token entirely — the framework's
68
- * default channel auth chain is `[localDev(), vercelOidc()]`, and
69
- * `localDev()` accepts off Vercel infrastructure, so attaching the
70
- * bypass token would be wasted work.
71
- */
72
- export declare function resolveDevelopmentClientHeaders(input: {
73
- readonly serverUrl: string;
74
- }): Promise<Record<string, string>>;
56
+ export {};
@@ -1 +1 @@
1
- import{EVE_ROUTE_PREFIX}from"#protocol/routes.js";import{getVercelOidcToken}from"#compiled/@vercel/oidc/index.js";const EVE_ROUTE_PREFIX_WITH_SEPARATOR=`${EVE_ROUTE_PREFIX}/`,LOCAL_HOSTNAMES=new Set([`localhost`,`127.0.0.1`,`0.0.0.0`,`::1`,`[::1]`]);function isLocalEveServerUrl(e){return LOCAL_HOSTNAMES.has(e.hostname)}function isLocalDevelopmentServerUrl(e){try{return isLocalEveServerUrl(new URL(e))}catch{return!1}}async function resolveDevelopmentOidcToken(){try{let e=(await getVercelOidcToken()).trim();if(e.length>0)return e}catch{}return process.env.VERCEL_OIDC_TOKEN?.trim()??``}const VERCEL_PROTECTION_BYPASS_HEADER=`x-vercel-protection-bypass`,VERCEL_TRUSTED_OIDC_IDP_TOKEN_HEADER=`x-vercel-trusted-oidc-idp-token`,VERCEL_OIDC_TOKEN_HEADER=`x-vercel-oidc-token`;function isEveRouteUrl(t){return t.pathname.endsWith(EVE_ROUTE_PREFIX)||t.pathname.includes(EVE_ROUTE_PREFIX_WITH_SEPARATOR)}async function createDevelopmentRequestHeadersAsync(e){let t=createBaseDevelopmentRequestHeaders(e),n=await resolveEveRouteOidcToken(t,e.resourceUrl);return n!==null&&attachEveRouteOidcHeaders(t,n),t}function createBaseDevelopmentRequestHeaders(e){let t=new Headers(resolveDevelopmentHeadersInit(e.headers)),n=process.env.VERCEL_AUTOMATION_BYPASS_SECRET?.trim();return n&&isEveRouteUrl(e.resourceUrl)&&t.set(VERCEL_PROTECTION_BYPASS_HEADER,n),t}function attachEveRouteOidcHeaders(e,t){e.has(`authorization`)||e.set(`authorization`,`Bearer ${t}`),e.set(VERCEL_TRUSTED_OIDC_IDP_TOKEN_HEADER,t)}async function resolveEveRouteOidcToken(e,t){return shouldResolveEveRouteOidcToken(t)?e.get(VERCEL_OIDC_TOKEN_HEADER)?.trim()||await resolveLocalDevelopmentOidcToken():null}function shouldResolveEveRouteOidcToken(e){return!(!isEveRouteUrl(e)||isLocalEveServerUrl(e))}async function resolveLocalDevelopmentOidcToken(){let e=await resolveDevelopmentOidcToken();return e.length>0?e:null}function resolveDevelopmentHeadersInit(e){if(e!==void 0)return e instanceof Headers?e:Array.isArray(e)?e.map(([e,t])=>[e,t]):e}async function resolveDevelopmentClientHeaders(e){let t={},n=process.env.VERCEL_AUTOMATION_BYPASS_SECRET?.trim();if(n&&(t[VERCEL_PROTECTION_BYPASS_HEADER]=n),!isLocalDevelopmentServerUrl(e.serverUrl)){let e=await resolveDevelopmentOidcToken();e.length>0&&(t[VERCEL_TRUSTED_OIDC_IDP_TOKEN_HEADER]=e)}return t}export{VERCEL_OIDC_TOKEN_HEADER,VERCEL_PROTECTION_BYPASS_HEADER,VERCEL_TRUSTED_OIDC_IDP_TOKEN_HEADER,createDevelopmentRequestHeadersAsync,isLocalDevelopmentServerUrl,resolveDevelopmentClientHeaders,resolveDevelopmentOidcToken};
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{toErrorMessage}from"#shared/errors.js";import{getVercelOidcToken}from"#compiled/@vercel/oidc/index.js";const VercelOidcClaimsSchema=object({owner_id:string().min(1),project_id:string().min(1)});async function resolveDevelopmentOidcToken(e){try{return validateDevelopmentOidcToken((await getVercelOidcToken({team:e.ownerId,project:e.projectId})).trim(),e)}catch(e){return{kind:`resolution-failed`,message:toErrorMessage(e)}}}function validateDevelopmentOidcToken(e,t){let n=e.split(`.`)[1];if(!n)return{kind:`malformed-token`,reason:`missing-payload`};let r;try{r=JSON.parse(Buffer.from(n,`base64url`).toString(`utf8`))}catch{return{kind:`malformed-token`,reason:`invalid-json-payload`}}let i=VercelOidcClaimsSchema.safeParse(r);if(!i.success)return{kind:`invalid-claims`,invalidClaims:i.error.issues.map(e=>{let t=e.path[0];return t===`owner_id`||t===`project_id`?t:`claims`})};let a=[];return i.data.owner_id!==t.ownerId&&a.push(`owner_id`),i.data.project_id!==t.projectId&&a.push(`project_id`),a.length>0?{kind:`target-mismatch`,mismatchedClaims:a}:{kind:`resolved`,token:e}}const VERCEL_PROTECTION_BYPASS_HEADER=`x-vercel-protection-bypass`,VERCEL_TRUSTED_OIDC_IDP_TOKEN_HEADER=`x-vercel-trusted-oidc-idp-token`;export{VERCEL_PROTECTION_BYPASS_HEADER,VERCEL_TRUSTED_OIDC_IDP_TOKEN_HEADER,resolveDevelopmentOidcToken};
@@ -1 +1 @@
1
- import{resolveDevelopmentClientHeaders}from"./request-headers.js";import{EVE_DEV_RUNTIME_ARTIFACTS_REBUILD_ROUTE_PATH,EVE_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH}from"#protocol/routes.js";async function readDevelopmentRuntimeArtifactsRevision(t){try{let r=new URL(EVE_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH,t.serverUrl);return await parseDevelopmentRuntimeArtifactsRevision(await fetch(r,{headers:await resolveDevelopmentClientHeaders({serverUrl:t.serverUrl})}))}catch{return}}async function rebuildDevelopmentRuntimeArtifacts(n){try{let r=new URL(EVE_DEV_RUNTIME_ARTIFACTS_REBUILD_ROUTE_PATH,n.serverUrl);return await parseDevelopmentRuntimeArtifactsRevision(await fetch(r,{headers:await resolveDevelopmentClientHeaders({serverUrl:n.serverUrl}),method:`POST`}))}catch{return}}async function parseDevelopmentRuntimeArtifactsRevision(e){if(!e.ok)return;let t=await e.json();return typeof t.revision==`string`&&t.revision.length>0?t.revision:void 0}export{readDevelopmentRuntimeArtifactsRevision,rebuildDevelopmentRuntimeArtifacts};
1
+ import{EVE_DEV_RUNTIME_ARTIFACTS_REBUILD_ROUTE_PATH,EVE_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH}from"#protocol/routes.js";async function readDevelopmentRuntimeArtifactsRevision(e){try{let n=new URL(EVE_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH,e.serverUrl);return await parseDevelopmentRuntimeArtifactsRevision(await fetch(n))}catch{return}}async function rebuildDevelopmentRuntimeArtifacts(t){try{let n=new URL(EVE_DEV_RUNTIME_ARTIFACTS_REBUILD_ROUTE_PATH,t.serverUrl);return await parseDevelopmentRuntimeArtifactsRevision(await fetch(n,{method:`POST`}))}catch{return}}async function parseDevelopmentRuntimeArtifactsRevision(e){if(!e.ok)return;let t=await e.json();return typeof t.revision==`string`&&t.revision.length>0?t.revision:void 0}export{readDevelopmentRuntimeArtifactsRevision,rebuildDevelopmentRuntimeArtifacts};
@@ -13,6 +13,7 @@
13
13
  * These helpers let the REPL detect the challenge and render a focused,
14
14
  * actionable message instead.
15
15
  */
16
+ import type { DevelopmentOidcTokenFailure } from "#services/dev-client/request-headers.js";
16
17
  /**
17
18
  * Returns `true` when the thrown error is the Vercel Deployment
18
19
  * Protection SSO challenge.
@@ -39,4 +40,5 @@ export declare function isVercelAuthChallenge(error: unknown): boolean;
39
40
  */
40
41
  export declare function formatVercelAuthChallengeMessage(input: {
41
42
  readonly serverUrl: string;
43
+ readonly oidcTokenFailure?: DevelopmentOidcTokenFailure;
42
44
  }): string;
@@ -1,2 +1,2 @@
1
- import{ClientError}from"#client/client-error.js";const VERCEL_AUTH_CHALLENGE_MARKERS=[`vercel.com/sso-api`,`<title>Authentication Required</title>`,`Vercel Authentication`];function bodyLooksLikeVercelAuthChallenge(e){if(e.length===0)return!1;for(let n of VERCEL_AUTH_CHALLENGE_MARKERS)if(e.includes(n))return!0;return!1}function isVercelAuthChallenge(t){return t instanceof ClientError||typeof t==`object`&&t&&`body`in t&&typeof t.body==`string`?bodyLooksLikeVercelAuthChallenge(t.body):!1}function formatVercelAuthChallengeMessage(e){return[`Vercel Deployment Protection blocked the request to ${e.serverUrl}.`,``,"To access the deployment from `eve dev`, do one of:"," • Run `vercel link` in this project so the CLI can mint an OIDC",` token for the deployment automatically.`,` • Set VERCEL_AUTOMATION_BYPASS_SECRET to a Protection Bypass for`,` Automation token (Project Settings → Deployment Protection).`,` • Disable Deployment Protection on the target deployment.`,``,`Docs: https://vercel.com/docs/deployment-protection`].join(`
2
- `)}export{formatVercelAuthChallengeMessage,isVercelAuthChallenge};
1
+ import{ClientError}from"#client/client-error.js";const VERCEL_AUTH_CHALLENGE_MARKERS=[`vercel.com/sso-api`,`<title>Authentication Required</title>`,`Vercel Authentication`];function bodyLooksLikeVercelAuthChallenge(e){if(e.length===0)return!1;for(let n of VERCEL_AUTH_CHALLENGE_MARKERS)if(e.includes(n))return!0;return!1}function isVercelAuthChallenge(t){return t instanceof ClientError||typeof t==`object`&&t&&`body`in t&&typeof t.body==`string`?bodyLooksLikeVercelAuthChallenge(t.body):!1}function formatVercelAuthChallengeMessage(e){let t=[`Vercel Deployment Protection blocked the request to ${e.serverUrl}.`];return e.oidcTokenFailure!==void 0&&t.push(``,formatOidcTokenFailure(e.oidcTokenFailure)),t.push(``,"To access the deployment from `eve dev`, do one of:"," • Run `vercel link` in this project so the CLI can mint an OIDC",` token for the deployment automatically.`,` • Set VERCEL_AUTOMATION_BYPASS_SECRET to a Protection Bypass for`,` Automation token (Project Settings → Deployment Protection).`,` • Disable Deployment Protection on the target deployment.`,``,`Docs: https://vercel.com/docs/deployment-protection`),t.join(`
2
+ `)}function formatOidcTokenFailure(e){switch(e.kind){case`resolution-failed`:return`The local Vercel OIDC token could not be resolved: ${e.message}`;case`malformed-token`:return e.reason===`missing-payload`?`Vercel returned a local OIDC token without a JWT payload.`:`Vercel returned a local OIDC token whose payload is not valid JSON.`;case`invalid-claims`:return`The local Vercel OIDC token has invalid claims: ${e.invalidClaims.join(`, `)}.`;case`target-mismatch`:return`The local Vercel OIDC token does not match the resolved deployment: ${e.mismatchedClaims.join(`, `)}.`;default:return e}}export{formatVercelAuthChallengeMessage,isVercelAuthChallenge};
@@ -1 +1 @@
1
- import{isLocalDevelopmentServerUrl}from"#services/dev-client/request-headers.js";import{readDevelopmentRuntimeArtifactsRevision,rebuildDevelopmentRuntimeArtifacts}from"#services/dev-client/runtime-artifacts.js";var LocalDevelopmentRuntimeArtifactSessionRefresher=class{#e;#t;#n;constructor(t){this.#e=isLocalDevelopmentServerUrl(t.serverUrl),this.#t=t.serverUrl}clear(){this.#n=void 0}async refresh(e){return shouldRefreshRuntimeArtifactsForTurn(e)?await this.#r({...e,rebuild:!0}):e.session}async refreshIdle(e){return await this.#r({...e,rebuild:!1})}async#r(e){if(!this.#e)return e.session;let n=(e.rebuild?await rebuildDevelopmentRuntimeArtifacts({serverUrl:this.#t}):void 0)??await readDevelopmentRuntimeArtifactsRevision({serverUrl:this.#t});if(n===void 0)return e.session;let r=e.session,i=this.#n;return i!==void 0&&i!==n&&(r.state.continuationToken!==void 0&&(r=e.createSession()),await e.onRuntimeArtifactsChanged?.({previousRevision:i,revision:n})),this.#n=n,r}};function shouldRefreshRuntimeArtifactsForTurn(e){return e.message!==void 0&&(e.inputResponses?.length??0)===0}function createDevelopmentRuntimeArtifactSessionRefresher(e){return new LocalDevelopmentRuntimeArtifactSessionRefresher(e)}export{createDevelopmentRuntimeArtifactSessionRefresher};
1
+ import{isLocalDevelopmentServerUrl}from"#services/dev-client/local-host.js";import{readDevelopmentRuntimeArtifactsRevision,rebuildDevelopmentRuntimeArtifacts}from"#services/dev-client/runtime-artifacts.js";var LocalDevelopmentRuntimeArtifactSessionRefresher=class{#e;#t;#n;constructor(t){this.#e=isLocalDevelopmentServerUrl(t.serverUrl),this.#t=t.serverUrl}clear(){this.#n=void 0}async refresh(e){return shouldRefreshRuntimeArtifactsForTurn(e)?await this.#r({...e,rebuild:!0}):e.session}async refreshIdle(e){return await this.#r({...e,rebuild:!1})}async#r(e){if(!this.#e)return e.session;let n=(e.rebuild?await rebuildDevelopmentRuntimeArtifacts({serverUrl:this.#t}):void 0)??await readDevelopmentRuntimeArtifactsRevision({serverUrl:this.#t});if(n===void 0)return e.session;let r=e.session,i=this.#n;return i!==void 0&&i!==n&&(r.state.continuationToken!==void 0&&(r=e.createSession()),await e.onRuntimeArtifactsChanged?.({previousRevision:i,revision:n})),this.#n=n,r}};function shouldRefreshRuntimeArtifactsForTurn(e){return e.message!==void 0&&(e.inputResponses?.length??0)===0}function createDevelopmentRuntimeArtifactSessionRefresher(e){return new LocalDevelopmentRuntimeArtifactSessionRefresher(e)}export{createDevelopmentRuntimeArtifactSessionRefresher};
@@ -12,15 +12,18 @@
12
12
  */
13
13
  /** The color primitives the row painter needs; satisfied by both the TUI theme and the CLI palette. */
14
14
  export interface RowColors {
15
+ blue(text: string): string;
15
16
  dim(text: string): string;
16
17
  green(text: string): string;
17
- cyan(text: string): string;
18
+ inverse(text: string): string;
18
19
  yellow(text: string): string;
19
20
  }
20
21
  /** The glyphs the row painter draws; the TUI passes theme-derived values, the CLI the unicode set. */
21
22
  export interface RowGlyphs {
22
- /** Hover marker the icon a row changes to under the cursor. */
23
+ /** Hollow cursor marker for an inert row. */
23
24
  pointer: string;
25
+ /** Filled cursor marker for an actionable row. */
26
+ selectedPointer: string;
24
27
  /** Completed / checked marker. */
25
28
  success: string;
26
29
  /** Available, un-hovered marker. */
@@ -58,9 +61,8 @@ interface OptionRowInput {
58
61
  /** Spaces inserted before the hint's dot so hints tab-align to a shared column. */
59
62
  hintPadding?: number;
60
63
  /**
61
- * Accent for the cursor pointer and active label. Defaults to cyan; "warning"
62
- * makes them yellow so the pointer matches an attention row (e.g. a required,
63
- * yellow-labelled action).
64
+ * Accent for an available row. "warning" keeps an attention row yellow at
65
+ * rest and under the cursor highlight.
64
66
  */
65
67
  accent?: "warning";
66
68
  }
@@ -78,6 +80,10 @@ export declare function resolveOptionRowState(option: {
78
80
  locked?: boolean;
79
81
  lockedReason?: string;
80
82
  }, checked: boolean): OptionRowState;
83
+ /** Paints a row with the shared leading cell and optional cursor highlight. */
84
+ export declare function renderCursorRow(text: string, selected: boolean, colors: Pick<RowColors, "blue" | "inverse" | "yellow">, accent?: "warning"): string;
85
+ /** Prefixes a continuation line so its text starts in the option label column. */
86
+ export declare function renderOptionRowContinuation(text: string): string;
81
87
  /**
82
88
  * Paints one option row as `glyph label · hint`. The glyph reflects state with
83
89
  * hover taking precedence for focusable rows: available rows use the active
@@ -1 +1 @@
1
- const UNICODE_ROW_GLYPHS={pointer:`▷`,success:`✓`,placeholder:`◦`,dot:`·`};function resolveOptionRowState(e,t){if(Number(e.disabled===!0)+Number(e.completed===!0)+Number(e.locked===!0)>1)throw Error(`An option row cannot combine disabled, completed, or locked states.`);if(e.disabled===!0){let t={kind:`disabled`};return e.disabledReason!==void 0&&(t.reason=e.disabledReason),e.disabledReasonTone!==void 0&&(t.reasonTone=e.disabledReasonTone),t}if(e.completed===!0)return{kind:`completed`};if(e.locked===!0){let t={kind:`locked`};return e.lockedReason!==void 0&&(t.reason=e.lockedReason),t}return{kind:`available`,checked:t}}function parenthetical(e){return e===void 0?``:` (${e})`}function unfocusedGlyph(e){return e.placeholder?e.colors.dim(e.glyphs.placeholder):` `}function disabledLabel(e,t,n){let r=parenthetical(t.reason);return t.reasonTone===`warning`?`${n.dim(e)}${n.yellow(r)}`:n.dim(`${e}${r}`)}function optionRowPresentation(e){let{colors:t,glyphs:n,state:r}=e,i=e.accent===`warning`?t.yellow:t.cyan;switch(r.kind){case`available`:return e.isCursor?{glyph:i(n.pointer),label:i(e.label)}:{glyph:r.checked?t.green(n.success):unfocusedGlyph(e),label:e.label};case`completed`:return{glyph:e.isCursor?t.dim(n.pointer):t.green(n.success),label:t.dim(e.label)};case`disabled`:return{glyph:e.isCursor?t.dim(n.pointer):unfocusedGlyph(e),label:disabledLabel(e.label,r,t)};case`locked`:return{glyph:t.dim(t.green(n.success)),label:t.dim(`${e.label}${parenthetical(r.reason)}`)}}return r}function renderOptionRow(e){let{colors:t,glyphs:n}=e,{glyph:r,label:i}=optionRowPresentation(e),a=e.hint;e.isCursor&&e.focusHint!==void 0&&(a=e.focusHint);let o=``;return a!==void 0&&(o=t.dim(`${` `.repeat((e.hintPadding??0)+1)}${n.dot} ${a}`)),`${r} ${i}${o}`}export{UNICODE_ROW_GLYPHS,renderOptionRow,resolveOptionRowState};
1
+ const UNICODE_ROW_GLYPHS={pointer:`▷`,selectedPointer:`▶`,success:`✓`,placeholder:`◦`,dot:`·`};function resolveOptionRowState(e,t){if(Number(e.disabled===!0)+Number(e.completed===!0)+Number(e.locked===!0)>1)throw Error(`An option row cannot combine disabled, completed, or locked states.`);if(e.disabled===!0){let t={kind:`disabled`};return e.disabledReason!==void 0&&(t.reason=e.disabledReason),e.disabledReasonTone!==void 0&&(t.reasonTone=e.disabledReasonTone),t}if(e.completed===!0)return{kind:`completed`};if(e.locked===!0){let t={kind:`locked`};return e.lockedReason!==void 0&&(t.reason=e.lockedReason),t}return{kind:`available`,checked:t}}function parenthetical(e){return e===void 0?``:` (${e})`}function unfocusedGlyph(e){return e.placeholder?e.colors.dim(e.glyphs.placeholder):` `}function disabledLabel(e,t,n){let r=parenthetical(t.reason);return t.reasonTone===`warning`?`${n.dim(e)}${n.yellow(r)}`:n.dim(`${e}${r}`)}function optionRowPresentation(e){let{colors:t,glyphs:n,state:r}=e;switch(r.kind){case`available`:return e.isCursor?{glyph:n.selectedPointer,label:e.label}:{glyph:r.checked?t.green(n.success):unfocusedGlyph(e),label:e.accent===`warning`?t.yellow(e.label):e.label};case`completed`:return{glyph:e.isCursor?t.dim(n.pointer):t.green(n.success),label:t.dim(e.label)};case`disabled`:return{glyph:e.isCursor?t.dim(n.pointer):unfocusedGlyph(e),label:disabledLabel(e.label,r,t)};case`locked`:return{glyph:t.dim(t.green(n.success)),label:t.dim(`${e.label}${parenthetical(r.reason)}`)}}return r}function renderCursorRow(e,t,n,r){if(!t)return` ${e}`;let i=r===`warning`?n.yellow:n.blue;return n.inverse(i(` ${e} `))}function renderOptionRowContinuation(e){return` ${e}`}function renderOptionRow(e){let{colors:t,glyphs:n}=e,{glyph:r,label:i}=optionRowPresentation(e),a=e.isCursor&&e.state.kind===`available`,o=e.hint;e.isCursor&&e.focusHint!==void 0&&(o=e.focusHint);let s=``;if(o!==void 0){let r=Math.max(0,(e.hintPadding??0)+1-Number(a));s=t.dim(`${` `.repeat(r)}${n.dot} ${o}`)}return`${renderCursorRow(`${r} ${i}`,a,t,e.accent)}${s}`}export{UNICODE_ROW_GLYPHS,renderCursorRow,renderOptionRow,renderOptionRowContinuation,resolveOptionRowState};
@@ -5,6 +5,7 @@ export type PromptState = "initial" | "active" | "submit" | "cancel" | "error";
5
5
  export type PromptValue = string | number | boolean;
6
6
  /** Coloring operations used by prompt rendering without coupling to a color library. */
7
7
  export interface PromptColors {
8
+ blue(text: string): string;
8
9
  bold(text: string): string;
9
10
  cyan(text: string): string;
10
11
  dim(text: string): string;
@@ -20,17 +21,16 @@ export interface PromptColors {
20
21
  export interface PromptOption<T extends PromptValue> {
21
22
  value: T;
22
23
  label: string;
23
- /** Short inline annotation shown in parentheses while the option is highlighted. */
24
+ /** Supporting copy; stacked prompts render newline-separated text on separate rows. */
24
25
  hint?: string;
25
26
  /** Short inline annotation shown dimmed only while the cursor is on this row. */
26
27
  focusHint?: string;
27
28
  /**
28
- * Longer, display-only explanation shown dimmed on the line below the option
29
- * while it is highlighted during navigation. It is navigation-only: once a
30
- * choice is submitted only the label remains.
29
+ * Longer, display-only explanation for the highlighted option. Its prompt
30
+ * chooses the placement; it is hidden once a choice is submitted.
31
31
  */
32
32
  description?: string;
33
- /** Cursor-pointer/active-label accent; "warning" turns them yellow for an attention row. */
33
+ /** Row accent; "warning" stays yellow both at rest and under the cursor. */
34
34
  accent?: "warning";
35
35
  disabled?: boolean;
36
36
  disabledReason?: string;
@@ -125,7 +125,7 @@ export declare function renderSelectPrompt<T extends PromptValue>(input: {
125
125
  /**
126
126
  * Renders the virtual Submit row that closes every multi-select list. It has
127
127
  * no checkbox — its bold label sits in the checkbox column, trails a green
128
- * check, and brightens under the cursor; enter confirms the checklist only
128
+ * check, and uses the shared cursor highlight; enter confirms the checklist only
129
129
  * from here. The label reads "Skip" while an optional checklist has nothing
130
130
  * picked (the caller computes that), so an empty confirm is honest about what
131
131
  * it does. Callers put a blank rail line above it to set it apart from the
@@ -1,5 +1,5 @@
1
- import{W}from"../../node_modules/.pnpm/@clack_core@1.3.1/node_modules/@clack/core/dist/index.js";import{UNICODE_ROW_GLYPHS,renderOptionRow,resolveOptionRowState}from"./option-row.js";const RAIL=`│`,CORNER=`└`;function bulletFor(e,t){switch(e){case`initial`:case`active`:return t.green(`△`);case`submit`:return t.green(`▲`);case`cancel`:return t.gray(`▲`);case`error`:return t.red(`▲`)}}function railFor(e,t){switch(e){case`initial`:case`active`:return t.white(`│`);case`submit`:return t.green(`│`);case`cancel`:return t.gray(`│`);case`error`:return t.red(`│`)}}function cornerFor(e,t){switch(e){case`initial`:case`active`:return t.white(`└`);case`submit`:return t.green(`└`);case`cancel`:return t.gray(`└`);case`error`:return t.red(`└`)}}function formatPromptHeader(e,t,n){return`${n.leadingRail===`green`?n.colors.green(`│`):n.colors.white(`│`)}\n${bulletFor(e,n.colors)} ${t}\n`}function formatPromptSubmission(e,t,n,r){let i=r.leadingRail===`green`?r.colors.green(`│`):r.colors.white(`│`),a=n===``?``:` ${n}`;return`${i}\n${bulletFor(e,r.colors)} ${r.colors.dim(t)}${a}`}function formatPromptOpener(e,t,n){return`\n${n.bold(n.white(`▲`))} ${n.bold(e)}\n ${n.dim(t)}\n${n.white(`│`)}\n`}function formatPromptOutro(e,t){let n=e.replace(/\n/g,`
1
+ import{W}from"../../node_modules/.pnpm/@clack_core@1.3.1/node_modules/@clack/core/dist/index.js";import{UNICODE_ROW_GLYPHS,renderCursorRow,renderOptionRow,resolveOptionRowState}from"./option-row.js";const RAIL=`│`,CORNER=`└`;function bulletFor(e,t){switch(e){case`initial`:case`active`:return t.green(`△`);case`submit`:return t.green(`▲`);case`cancel`:return t.gray(`▲`);case`error`:return t.red(`▲`)}}function railFor(e,t){switch(e){case`initial`:case`active`:return t.white(`│`);case`submit`:return t.green(`│`);case`cancel`:return t.gray(`│`);case`error`:return t.red(`│`)}}function cornerFor(e,t){switch(e){case`initial`:case`active`:return t.white(`└`);case`submit`:return t.green(`└`);case`cancel`:return t.gray(`└`);case`error`:return t.red(`└`)}}function formatPromptHeader(e,t,n){return`${n.leadingRail===`green`?n.colors.green(`│`):n.colors.white(`│`)}\n${bulletFor(e,n.colors)} ${t}\n`}function formatPromptSubmission(e,t,n,r){let i=r.leadingRail===`green`?r.colors.green(`│`):r.colors.white(`│`),a=n===``?``:` ${n}`;return`${i}\n${bulletFor(e,r.colors)} ${r.colors.dim(t)}${a}`}function formatPromptOpener(e,t,n){return`\n${n.bold(n.white(`▲`))} ${n.bold(e)}\n ${n.dim(t)}\n${n.white(`│`)}\n`}function formatPromptOutro(e,t){let n=e.replace(/\n/g,`
2
2
  `);return`${t.green(`│`)}\n${t.green(`●`)} ${n}\n`}function formatPromptCancellation(e,t){let n=e.replace(/\n/g,`
3
3
  `);return`${t.red(`│`)}\n${t.red(`●`)} ${t.red(n)}\n`}function formatRailLine(t,n,r){if(t===``)return`${n.green(`│`)}\n`;let i=`${n.green(`│`)} `;return`${t.split(`
4
4
  `).map(t=>t===``?n.green(`│`):W(r,t,i)).join(`
5
- `)}\n`}function renderMultiselectPrompt(e){let t=railFor(e.state,e.colors),n=formatPromptHeader(e.state,e.message,{colors:e.colors,leadingRail:e.leadingRail}),r=new Set(e.selectedValues),i=e.options.some(e=>!e.disabled)?``:`\n${t}\n${t} ${e.colors.dim(`(no channels available to add)`)}`;switch(e.state){case`submit`:{let t=r.size===0?e.colors.dim(`(none selected)`):e.options.filter(e=>r.has(e.value)).map(e=>e.label).join(`, `);return formatPromptSubmission(e.state,e.message,t,{colors:e.colors,leadingRail:e.leadingRail})}case`cancel`:return`${n}${t} ${e.colors.strikethrough(e.colors.dim(`cancelled`))}\n${t}`;case`error`:{let r=renderMultiselectRows({...e,rail:t});return`${n.trim()}\n${t} ${r}${i}\n${cornerFor(e.state,e.colors)} ${e.colors.red(e.error??``)}\n`}case`initial`:case`active`:return`${n}${t} ${renderMultiselectRows({...e,rail:t})}${i}\n${cornerWithNote(cornerFor(e.state,e.colors),e.footerNote)}\n`}}function cornerWithNote(e,t){return t?`${e} ${t}`:e}function renderSelectPrompt(e){let t=railFor(e.state,e.colors),n=formatPromptHeader(e.state,e.message,{colors:e.colors,leadingRail:e.leadingRail}),r=e.options[e.cursor];switch(e.state){case`submit`:{let t=r?r.label:``;return formatPromptSubmission(e.state,e.message,t,{colors:e.colors,leadingRail:e.leadingRail})}case`cancel`:return`${n}${t} ${r?e.colors.strikethrough(e.colors.dim(r.label)):``}\n${t}`;case`initial`:case`active`:case`error`:{let r=labelColumnWidth(e.options);return`${n}${t} ${e.options.map((n,i)=>{let a=i===e.cursor;return`${optionRow(n,{colors:e.colors,isCursor:a,isChecked:!1,placeholder:!1,hintPadding:r-n.label.length})}${descriptionLine(n,a,t,e.colors)}`}).join(`\n${t} `)}\n${cornerWithNote(cornerFor(e.state,e.colors),e.footerNote)}\n`}}}function labelColumnWidth(e){return e.reduce((e,t)=>Math.max(e,t.label.length),0)}function optionRow(e,i){return renderOptionRow({colors:i.colors,glyphs:UNICODE_ROW_GLYPHS,label:e.label,hint:e.hint,focusHint:e.focusHint,accent:e.accent,isCursor:i.isCursor,state:resolveOptionRowState(e,i.isChecked),placeholder:i.placeholder,hintPadding:i.hintPadding})}function descriptionLine(e,t,n,r){return t&&e.description&&!e.disabled?`\n${n} ${r.dim(e.description)}`:``}function renderSubmitRow(e,n,r=`Submit`){let i=e?n.cyan(UNICODE_ROW_GLYPHS.pointer):` `,a=n.bold(r);return`${i} ${e?a:n.dim(a)} ${n.green(UNICODE_ROW_GLYPHS.success)}`}function renderMultiselectRows(e){let t=new Set(e.selectedValues),n=labelColumnWidth(e.options),r=e.options.map((r,i)=>{let a=i===e.cursor;return`${optionRow(r,{colors:e.colors,isCursor:a,isChecked:t.has(r.value),placeholder:!0,hintPadding:n-r.label.length})}${descriptionLine(r,a,e.rail,e.colors)}`}).join(`\n${e.rail} `),i=renderSubmitRow(e.cursor===e.options.length,e.colors,e.submitLabel);return`${r}\n${e.rail}\n${e.rail} ${i}`}function searchableHelpLine(e,t,n){let r=(n?[[t.cyan(`type`),`to filter`]]:[[t.cyan(`type`),`to filter`],[t.cyan(`enter`),`to select`]]).map(([e,n])=>`${e}${t.dim(` ${n}`)}`).join(t.dim(` · `));return`\n${e} ${t.dim(`(`)}${r}${t.dim(`)`)}`}function renderSearchableSelect(e){let{colors:t}=e,n=railFor(e.state,t),r=formatPromptHeader(e.state,e.message,{colors:t,leadingRail:e.leadingRail});if(e.state===`submit`)return formatPromptSubmission(e.state,e.message,e.submitDisplay,{colors:t,leadingRail:e.leadingRail});if(e.state===`cancel`)return`${r}${n} ${t.strikethrough(t.dim(e.filter))}${e.filter.trim()?`\n${n}`:``}`;let i=new Set(e.selectedValues),a=0;for(;e.options[a]?.featured;)a+=1;let o=e.viewSize??8,s=e.filter===``&&a>0?Math.min(a,o):o,c=e.multiple&&e.cursor>=e.options.length,l=!c&&e.cursor>=e.options.length?0:e.cursor,u=t.inverse(` `);e.filter.length>0?u=e.filter+t.inverse(` `):e.placeholder&&(u=t.dim(e.placeholder));let d=Math.max(0,Math.min(l-Math.floor(s/2),Math.max(0,e.options.length-s))),f=Math.min(d+s,e.options.length),p=e.options.slice(d,f),m=labelColumnWidth(p),h=p.length===0?t.dim(`(no matches)`):p.map((r,a)=>{let o=!c&&a+d===l;return`${optionRow(r,{colors:t,isCursor:o,isChecked:e.multiple&&i.has(r.value),placeholder:!1,hintPadding:m-r.label.length})}${descriptionLine(r,o,n,t)}`}).join(`\n${n} `),g=e.multiple?`\n${n}\n${n} ${renderSubmitRow(c,t,e.submitLabel)}`:``,_=e.options.length>p.length?`\n${n} ${t.dim(`↑↓ ${e.options.length} options, showing ${d+1}–${f}`)}`:``,v=searchableHelpLine(n,t,e.multiple),y=`${n} ${t.dim(` `)} ${u}\n${n} ${h}${g}${_}${v}`;return e.state===`error`?`${r.trim()}\n${y}\n${cornerFor(e.state,t)} ${t.red(e.error??``)}\n`:`${r}${y}\n${cornerWithNote(cornerFor(e.state,t),e.footerNote)}\n`}export{CORNER,RAIL,bulletFor,cornerFor,formatPromptCancellation,formatPromptHeader,formatPromptOpener,formatPromptOutro,formatPromptSubmission,formatRailLine,railFor,renderMultiselectPrompt,renderSearchableSelect,renderSelectPrompt,renderSubmitRow};
5
+ `)}\n`}function renderMultiselectPrompt(e){let t=railFor(e.state,e.colors),n=formatPromptHeader(e.state,e.message,{colors:e.colors,leadingRail:e.leadingRail}),r=new Set(e.selectedValues),i=e.options.some(e=>!e.disabled)?``:`\n${t}\n${t} ${e.colors.dim(`(no channels available to add)`)}`;switch(e.state){case`submit`:{let t=r.size===0?e.colors.dim(`(none selected)`):e.options.filter(e=>r.has(e.value)).map(e=>e.label).join(`, `);return formatPromptSubmission(e.state,e.message,t,{colors:e.colors,leadingRail:e.leadingRail})}case`cancel`:return`${n}${t} ${e.colors.strikethrough(e.colors.dim(`cancelled`))}\n${t}`;case`error`:{let r=renderMultiselectRows({...e,rail:t});return`${n.trim()}\n${t} ${r}${i}\n${cornerFor(e.state,e.colors)} ${e.colors.red(e.error??``)}\n`}case`initial`:case`active`:return`${n}${t} ${renderMultiselectRows({...e,rail:t})}${i}\n${cornerWithNote(cornerFor(e.state,e.colors),e.footerNote)}\n`}}function cornerWithNote(e,t){return t?`${e} ${t}`:e}function renderSelectPrompt(e){let t=railFor(e.state,e.colors),n=formatPromptHeader(e.state,e.message,{colors:e.colors,leadingRail:e.leadingRail}),r=e.options[e.cursor];switch(e.state){case`submit`:{let t=r?r.label:``;return formatPromptSubmission(e.state,e.message,t,{colors:e.colors,leadingRail:e.leadingRail})}case`cancel`:return`${n}${t} ${r?e.colors.strikethrough(e.colors.dim(r.label)):``}\n${t}`;case`initial`:case`active`:case`error`:{let r=labelColumnWidth(e.options);return`${n}${t} ${e.options.map((n,i)=>{let a=i===e.cursor;return`${optionRow(n,{colors:e.colors,isCursor:a,isChecked:!1,placeholder:!1,hintPadding:r-n.label.length})}${descriptionLine(n,a,t,e.colors)}`}).join(`\n${t} `)}\n${cornerWithNote(cornerFor(e.state,e.colors),e.footerNote)}\n`}}}function labelColumnWidth(e){return e.reduce((e,t)=>Math.max(e,t.label.length),0)}function optionRow(e,n){return renderOptionRow({colors:n.colors,glyphs:UNICODE_ROW_GLYPHS,label:e.label,hint:e.hint,focusHint:e.focusHint,accent:e.accent,isCursor:n.isCursor,state:resolveOptionRowState(e,n.isChecked),placeholder:n.placeholder,hintPadding:n.hintPadding})}function descriptionLine(e,t,n,r){return t&&e.description&&!e.disabled?`\n${n} ${r.dim(e.description)}`:``}function renderSubmitRow(e,r,i=`Submit`){let a=r.bold(i),o=e?`${UNICODE_ROW_GLYPHS.selectedPointer} ${a}`:` ${r.dim(a)}`,s=e?``:` `;return`${renderCursorRow(o,e,r)}${s}${r.green(UNICODE_ROW_GLYPHS.success)}`}function renderMultiselectRows(e){let t=new Set(e.selectedValues),n=labelColumnWidth(e.options),r=e.options.map((r,i)=>{let a=i===e.cursor;return`${optionRow(r,{colors:e.colors,isCursor:a,isChecked:t.has(r.value),placeholder:!0,hintPadding:n-r.label.length})}${descriptionLine(r,a,e.rail,e.colors)}`}).join(`\n${e.rail} `),i=renderSubmitRow(e.cursor===e.options.length,e.colors,e.submitLabel);return`${r}\n${e.rail}\n${e.rail} ${i}`}function searchableHelpLine(e,t,n){let r=(n?[[t.cyan(`type`),`to filter`]]:[[t.cyan(`type`),`to filter`],[t.cyan(`enter`),`to select`]]).map(([e,n])=>`${e}${t.dim(` ${n}`)}`).join(t.dim(` · `));return`\n${e} ${t.dim(`(`)}${r}${t.dim(`)`)}`}function renderSearchableSelect(e){let{colors:t}=e,n=railFor(e.state,t),r=formatPromptHeader(e.state,e.message,{colors:t,leadingRail:e.leadingRail});if(e.state===`submit`)return formatPromptSubmission(e.state,e.message,e.submitDisplay,{colors:t,leadingRail:e.leadingRail});if(e.state===`cancel`)return`${r}${n} ${t.strikethrough(t.dim(e.filter))}${e.filter.trim()?`\n${n}`:``}`;let i=new Set(e.selectedValues),a=0;for(;e.options[a]?.featured;)a+=1;let o=e.viewSize??8,s=e.filter===``&&a>0?Math.min(a,o):o,c=e.multiple&&e.cursor>=e.options.length,l=!c&&e.cursor>=e.options.length?0:e.cursor,u=t.inverse(` `);e.filter.length>0?u=e.filter+t.inverse(` `):e.placeholder&&(u=t.dim(e.placeholder));let d=Math.max(0,Math.min(l-Math.floor(s/2),Math.max(0,e.options.length-s))),f=Math.min(d+s,e.options.length),p=e.options.slice(d,f),m=labelColumnWidth(p),h=p.length===0?t.dim(`(no matches)`):p.map((r,a)=>{let o=!c&&a+d===l;return`${optionRow(r,{colors:t,isCursor:o,isChecked:e.multiple&&i.has(r.value),placeholder:!1,hintPadding:m-r.label.length})}${descriptionLine(r,o,n,t)}`}).join(`\n${n} `),g=e.multiple?`\n${n}\n${n} ${renderSubmitRow(c,t,e.submitLabel)}`:``,_=e.options.length>p.length?`\n${n} ${t.dim(`↑↓ ${e.options.length} options, showing ${d+1}–${f}`)}`:``,v=searchableHelpLine(n,t,e.multiple),y=`${n} ${t.dim(` `)} ${u}\n${n} ${h}${g}${_}${v}`;return e.state===`error`?`${r.trim()}\n${y}\n${cornerFor(e.state,t)} ${t.red(e.error??``)}\n`:`${r}${y}\n${cornerWithNote(cornerFor(e.state,t),e.footerNote)}\n`}export{CORNER,RAIL,bulletFor,cornerFor,formatPromptCancellation,formatPromptHeader,formatPromptOpener,formatPromptOutro,formatPromptSubmission,formatRailLine,railFor,renderMultiselectPrompt,renderSearchableSelect,renderSelectPrompt,renderSubmitRow};
@@ -94,6 +94,8 @@ export declare function detectModelProviderStatus(appRoot: string, options?: Pro
94
94
  export declare function runModelFlow(input: {
95
95
  appRoot: string;
96
96
  prompter: Prompter;
97
+ /** Opens provider setup before the root menu when runtime evidence requires it. */
98
+ initialStep?: "provider";
97
99
  signal?: AbortSignal;
98
100
  deps?: Partial<ModelFlowDeps>;
99
101
  }): Promise<ModelFlowResult>;
@@ -1 +1 @@
1
- import{__toESM}from"../../_virtual/_rolldown/runtime.js";import{require_picocolors}from"../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js";import{interactiveAsker}from"../ask.js";import{detectProjectIdentity}from"../project-resolution.js";import{snapshotSetupState}from"../state.js";import{WizardCancelledError}from"../step.js";import{findEnvFileWithKey}from"../boxes/detect-ai-gateway.js";import{fetchGatewayCatalog,selectModel}from"../boxes/select-model.js";import{runInteractive}from"../runner.js";import{inProjectSetupState,prompterSink}from"./in-project.js";import{runVercelFlow}from"./vercel.js";import{join}from"node:path";import{discoverAgent}from"#discover/discover-agent.js";import{inspectApplication}from"#services/inspect-application.js";import{formatLanguageModelGatewayId}from"#internal/runtime-model.js";import{createCompiledRuntimeModelCatalogLoader}from"#compiler/model-catalog.js";import{createStaticSourceChange}from"#source-change/static-source-change.js";var import_picocolors=__toESM(require_picocolors(),1);const MODEL_MENU_MESSAGE=``;function providerStatusHint(e,t=e=>e){return e.kind===`gateway-project`?`AI Gateway (Linked to ${e.teamName===void 0?t(e.projectName):`${t(e.projectName)} in ${t(e.teamName)}`})`:`AI Gateway (${e.envKey} in ${e.envFile})`}function modelMenuRows(e,t,n,r){let i;r?(i={value:`model`,label:`Change model`},e!==null&&(i.hint=e)):i={value:`model`,label:`Change model`,disabled:!0,description:`Set via an SDK model call in agent.ts; edit the source to change it`};let a;return a=n?.kind===`external`?{value:`provider`,label:`Change provider`,disabled:!0,description:`Disabled in external endpoint mode`}:t.kind===`unset`?{value:`provider`,label:import_picocolors.default.bold(import_picocolors.default.yellow(`Configure provider`)),hint:`Required to enable the agent`,accent:`warning`}:{value:`provider`,label:`Change provider`,hint:providerStatusHint(t,import_picocolors.default.bold)},[i,a,{value:`done`,label:`Done`}]}async function detectModelProviderStatus(e,t={}){let[n,i,a]=await Promise.all([detectProjectIdentity(e,t),findEnvFileWithKey(e,`AI_GATEWAY_API_KEY`),findEnvFileWithKey(e,`VERCEL_OIDC_TOKEN`)]);if(n!==void 0){let e={kind:`gateway-project`,projectName:n.projectName};return n.teamName!==void 0&&(e.teamName=n.teamName),e}return i===void 0?a===void 0?{kind:`unset`}:{kind:`gateway-key`,envKey:`VERCEL_OIDC_TOKEN`,envFile:a}:{kind:`gateway-key`,envKey:`AI_GATEWAY_API_KEY`,envFile:i}}async function runModelFlow(e){let{appRoot:t,prompter:n,signal:r}=e,i={readCurrentModel:readCurrentAgentModel,applyModel:changeAgentModel,detectProviderStatus:detectModelProviderStatus,runVercelFlow,...e.deps};async function checkProject(e){let t=n.log.spinner?.(`Checking the project…`);try{return await e()}finally{t?.stop()}}let detectProvider=()=>i.detectProviderStatus(t,{signal:r}),[{id:o,routing:s,editable:c},l]=await checkProject(()=>Promise.all([i.readCurrentModel(t),detectProvider()]));r?.throwIfAborted();let u,d,p=s?.kind===`external`?{tone:`warning`,text:"`agent.ts` specifies a model provider directly. In-TUI configuration is restricted to AI Gateway endpoints."}:void 0,m=l.kind===`unset`&&s?.kind!==`external`?`provider`:c?`model`:s?.kind===`external`?`done`:`provider`;for(;;){let e;try{e=await n.select({message:``,options:modelMenuRows(o,l,s,c),hintLayout:`stacked`,initialValue:m,notices:p===void 0?[]:[p]})}catch(e){if(!(e instanceof WizardCancelledError))throw e;break}if(e===`done`)break;if(e===`model`){let e=await pickModelFromCatalog({appRoot:t,prompter:n,current:o,signal:r,deps:i.selectModel});if(e===void 0){m=`model`;continue}r?.throwIfAborted(),u=await i.applyModel({appRoot:t,slug:e}),r?.throwIfAborted();break}let f=await i.runVercelFlow({appRoot:t,prompter:n,signal:r});if(r?.throwIfAborted(),f.kind===`cancelled`){m=`provider`;continue}if(`outcome`in f){m=`done`;continue}l=await checkProject(detectProvider),r?.throwIfAborted(),d={status:l},f.credential!==void 0&&(d.credential=f.credential);break}if(u===void 0&&d===void 0)return{kind:`cancelled`};let h={kind:`done`};return u!==void 0&&(h.modelMessage=formatApplyModelOutcome(u)),d!==void 0&&(h.providerOutcome=d),h}async function pickModelFromCatalog(e){let{appRoot:t,prompter:r,current:a,signal:o}=e,f=e.deps?.fetchModels??fetchGatewayCatalog,p={asker:interactiveAsker(r),deps:{fetchModels:async e=>{let t=r.log.spinner?.(`Loading the model catalog...`);try{return await f(e)}finally{t?.stop()}}}};a!==null&&(p.defaultModel=a);let m=await runInteractive([selectModel(p)],inProjectSetupState(t,{kind:`unresolved`}),prompterSink(r),{snapshot:snapshotSetupState,signal:o});return m.kind===`cancelled`?void 0:m.state.modelId}function formatApplyModelOutcome(e){switch(e.kind){case`changed`:return`Model changed to ${import_picocolors.default.bold(e.to)}. Live on your next prompt.`;case`unchanged`:return`Model is already \`${e.model}\`.`;case`rejected`:return e.message}}async function changeAgentModel(e){let{appRoot:t,slug:n}=e,r=await validateModelSlug(t,n);if(r!==null)return{kind:`rejected`,message:r};let{manifest:i}=await discoverAgent({agentRoot:join(t,`agent`),appRoot:t}),a=await createStaticSourceChange(i).updateModelName(n);return a.kind===`bail`?{kind:`rejected`,message:`Couldn't edit ${a.at.logicalPath}: ${a.reason}. Change \`model\` by hand.`}:a.from===a.to?{kind:`unchanged`,model:a.to}:{kind:`changed`,to:a.to}}async function validateModelSlug(e,t){if(!t.includes(`/`))return`\`${t}\` isn't a provider/model id (e.g. anthropic/claude-sonnet-4.6).`;let n=createCompiledRuntimeModelCatalogLoader(e);try{if(await n.getModelLimits(formatLanguageModelGatewayId(t))===null)return`I couldn't confirm \`${t}\` in the AI Gateway model catalog, so I didn't change agent.ts.`}catch{return null}return null}async function readCurrentAgentModel(e){try{let{compiledState:t}=await inspectApplication(e),n=t?.manifest.config.model;return{id:n?.id??null,routing:n?.routing??null,editable:n!==void 0&&n.source===void 0}}catch{return{id:null,routing:null,editable:!1}}}async function modelChangeRefusalForUneditableModel(e){let{editable:t,routing:n}=await readCurrentAgentModel(e);return t?null:`Model is set via ${n?.kind===`external`?`the external provider \`${n.provider}\``:`an SDK model call`} in agent.ts, not a string literal; /model can't rewrite it. Edit \`model\` in agent.ts.`}export{MODEL_MENU_MESSAGE,changeAgentModel,detectModelProviderStatus,formatApplyModelOutcome,modelChangeRefusalForUneditableModel,runModelFlow};
1
+ import{__toESM}from"../../_virtual/_rolldown/runtime.js";import{require_picocolors}from"../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js";import{interactiveAsker}from"../ask.js";import{detectProjectIdentity}from"../project-resolution.js";import{snapshotSetupState}from"../state.js";import{WizardCancelledError}from"../step.js";import{findEnvFileWithKey}from"../boxes/detect-ai-gateway.js";import{fetchGatewayCatalog,selectModel}from"../boxes/select-model.js";import{runInteractive}from"../runner.js";import{inProjectSetupState,prompterSink}from"./in-project.js";import{runVercelFlow}from"./vercel.js";import{join}from"node:path";import{discoverAgent}from"#discover/discover-agent.js";import{inspectApplication}from"#services/inspect-application.js";import{formatLanguageModelGatewayId}from"#internal/runtime-model.js";import{createCompiledRuntimeModelCatalogLoader}from"#compiler/model-catalog.js";import{createStaticSourceChange}from"#source-change/static-source-change.js";var import_picocolors=__toESM(require_picocolors(),1);const MODEL_MENU_MESSAGE=``;function providerStatusHint(e,t=e=>e){return e.kind===`gateway-project`?`AI Gateway (Linked to ${e.teamName===void 0?t(e.projectName):`${t(e.projectName)} in ${t(e.teamName)}`})`:`AI Gateway (${e.envKey} in ${e.envFile})`}function modelMenuRows(e,t,n,r){let i;r?(i={value:`model`,label:`Change model`},e!==null&&(i.hint=e)):i={value:`model`,label:`Change model`,disabled:!0,description:`Set via an SDK model call in agent.ts; edit the source to change it`};let a;return a=n?.kind===`external`?{value:`provider`,label:`Change provider`,disabled:!0,description:`Disabled in external endpoint mode`}:t.kind===`unset`?{value:`provider`,label:import_picocolors.default.bold(import_picocolors.default.yellow(`Configure provider`)),hint:`Required to enable the agent`,accent:`warning`}:{value:`provider`,label:`Change provider`,hint:providerStatusHint(t,import_picocolors.default.bold)},[i,a,{value:`done`,label:`Done`}]}async function detectModelProviderStatus(e,t={}){let[n,i,a]=await Promise.all([detectProjectIdentity(e,t),findEnvFileWithKey(e,`AI_GATEWAY_API_KEY`),findEnvFileWithKey(e,`VERCEL_OIDC_TOKEN`)]);if(n!==void 0){let e={kind:`gateway-project`,projectName:n.projectName};return n.teamName!==void 0&&(e.teamName=n.teamName),e}return i===void 0?a===void 0?{kind:`unset`}:{kind:`gateway-key`,envKey:`VERCEL_OIDC_TOKEN`,envFile:a}:{kind:`gateway-key`,envKey:`AI_GATEWAY_API_KEY`,envFile:i}}async function runModelFlow(e){let{appRoot:t,prompter:n,signal:r}=e,i={readCurrentModel:readCurrentAgentModel,applyModel:changeAgentModel,detectProviderStatus:detectModelProviderStatus,runVercelFlow,...e.deps};async function checkProject(e){let t=n.log.spinner?.(`Checking the project…`);try{return await e()}finally{t?.stop()}}let detectProvider=()=>i.detectProviderStatus(t,{signal:r}),[{id:o,routing:s,editable:c},l]=await checkProject(()=>Promise.all([i.readCurrentModel(t),detectProvider()]));r?.throwIfAborted();let u,d,p=s?.kind===`external`?{tone:`warning`,text:"`agent.ts` specifies a model provider directly. In-TUI configuration is restricted to AI Gateway endpoints."}:void 0,m=l.kind===`unset`&&s?.kind!==`external`?`provider`:c?`model`:s?.kind===`external`?`done`:`provider`,h=s?.kind!==`external`&&(e.initialStep===`provider`||l.kind===`unset`);for(;;){let e;if(h)h=!1,e=`provider`;else try{e=await n.select({message:``,options:modelMenuRows(o,l,s,c),hintLayout:`stacked`,initialValue:m,notices:p===void 0?[]:[p]})}catch(e){if(!(e instanceof WizardCancelledError))throw e;break}if(e===`done`)break;if(e===`model`){let e=await pickModelFromCatalog({appRoot:t,prompter:n,current:o,signal:r,deps:i.selectModel});if(e===void 0){m=`model`;continue}r?.throwIfAborted(),u=await i.applyModel({appRoot:t,slug:e}),r?.throwIfAborted();break}let f=await i.runVercelFlow({appRoot:t,prompter:n,signal:r});if(r?.throwIfAborted(),f.kind===`cancelled`){m=`provider`;continue}if(`outcome`in f){m=`done`;continue}l=await checkProject(detectProvider),r?.throwIfAborted(),d={status:l},f.credential!==void 0&&(d.credential=f.credential);break}if(u===void 0&&d===void 0)return{kind:`cancelled`};let g={kind:`done`};return u!==void 0&&(g.modelMessage=formatApplyModelOutcome(u)),d!==void 0&&(g.providerOutcome=d),g}async function pickModelFromCatalog(e){let{appRoot:t,prompter:r,current:a,signal:o}=e,f=e.deps?.fetchModels??fetchGatewayCatalog,p={asker:interactiveAsker(r),deps:{fetchModels:async e=>{let t=r.log.spinner?.(`Loading the model catalog...`);try{return await f(e)}finally{t?.stop()}}}};a!==null&&(p.defaultModel=a);let m=await runInteractive([selectModel(p)],inProjectSetupState(t,{kind:`unresolved`}),prompterSink(r),{snapshot:snapshotSetupState,signal:o});return m.kind===`cancelled`?void 0:m.state.modelId}function formatApplyModelOutcome(e){switch(e.kind){case`changed`:return`Model changed to ${import_picocolors.default.bold(e.to)}. Live on your next prompt.`;case`unchanged`:return`Model is already \`${e.model}\`.`;case`rejected`:return e.message}}async function changeAgentModel(e){let{appRoot:t,slug:n}=e,r=await validateModelSlug(t,n);if(r!==null)return{kind:`rejected`,message:r};let{manifest:i}=await discoverAgent({agentRoot:join(t,`agent`),appRoot:t}),a=await createStaticSourceChange(i).updateModelName(n);return a.kind===`bail`?{kind:`rejected`,message:`Couldn't edit ${a.at.logicalPath}: ${a.reason}. Change \`model\` by hand.`}:a.from===a.to?{kind:`unchanged`,model:a.to}:{kind:`changed`,to:a.to}}async function validateModelSlug(e,t){if(!t.includes(`/`))return`\`${t}\` isn't a provider/model id (e.g. anthropic/claude-sonnet-4.6).`;let n=createCompiledRuntimeModelCatalogLoader(e);try{if(await n.getModelLimits(formatLanguageModelGatewayId(t))===null)return`I couldn't confirm \`${t}\` in the AI Gateway model catalog, so I didn't change agent.ts.`}catch{return null}return null}async function readCurrentAgentModel(e){try{let{compiledState:t}=await inspectApplication(e),n=t?.manifest.config.model;return{id:n?.id??null,routing:n?.routing??null,editable:n!==void 0&&n.source===void 0}}catch{return{id:null,routing:null,editable:!1}}}async function modelChangeRefusalForUneditableModel(e){let{editable:t,routing:n}=await readCurrentAgentModel(e);return t?null:`Model is set via ${n?.kind===`external`?`the external provider \`${n.provider}\``:`an SDK model call`} in agent.ts, not a string literal; /model can't rewrite it. Edit \`model\` in agent.ts.`}export{MODEL_MENU_MESSAGE,changeAgentModel,detectModelProviderStatus,formatApplyModelOutcome,modelChangeRefusalForUneditableModel,runModelFlow};
@@ -1,3 +1,4 @@
1
+ import { z } from "zod";
1
2
  /** Link and production-deployment status for a Vercel project directory. */
2
3
  export type DeploymentState = "unlinked" | "linked" | "deployed";
3
4
  /** Vercel project data resolved from local link metadata and the API. */
@@ -7,6 +8,17 @@ export interface DeploymentInfo {
7
8
  orgId?: string;
8
9
  productionUrl?: string;
9
10
  }
11
+ declare const VercelProjectReferenceSchema: z.ZodObject<{
12
+ projectId: z.ZodString;
13
+ orgId: z.ZodString;
14
+ projectName: z.ZodOptional<z.ZodString>;
15
+ }, z.core.$strip>;
16
+ /** Validated Vercel owner and project identifiers. */
17
+ export type VercelProjectReference = z.infer<typeof VercelProjectReferenceSchema>;
18
+ /** Parses the complete Vercel owner and project environment pair. */
19
+ export declare function projectReferenceFromEnvironment(environment: Readonly<Record<string, string | undefined>>): VercelProjectReference | undefined;
20
+ /** Reads a validated Vercel project reference from `.vercel/project.json`. */
21
+ export declare function readProjectLink(projectPath: string): Promise<VercelProjectReference | undefined>;
10
22
  export interface ProjectDetectionOptions {
11
23
  signal?: AbortSignal;
12
24
  }
@@ -55,3 +67,4 @@ export declare function projectResolutionFromDeployResult(project: ProjectResolu
55
67
  }): ProjectResolution;
56
68
  export declare function isProjectResolved(project: ProjectResolution): boolean;
57
69
  export declare function projectProductionUrlFromResolution(project: ProjectResolution): string | undefined;
70
+ export {};
@@ -1 +1 @@
1
- import{captureVercel}from"./primitives/run-vercel.js";import{join}from"node:path";import{readFile}from"node:fs/promises";function pickShortestAlias(e){if(!Array.isArray(e))return;let t;for(let n of e)typeof n!=`string`||n.length===0||(t===void 0||n.length<t.length)&&(t=n);return t}async function fetchProductionAlias(t,n,r,i){let a=await captureVercel([`api`,`/v9/projects/${t}?teamId=${n}`,`--scope`,n],{cwd:r,signal:i.signal});if(a.ok)try{let e=pickShortestAlias(JSON.parse(a.stdout).targets?.production?.alias);return e?`https://${e}`:void 0}catch{return}}async function detectDeployment(e,r={}){r.signal?.throwIfAborted();let i;try{i=await readFile(join(e,`.vercel`,`project.json`),`utf8`)}catch{return{state:`unlinked`}}let a;try{a=JSON.parse(i)}catch{return{state:`unlinked`}}let o=typeof a.projectId==`string`?a.projectId:void 0,s=typeof a.orgId==`string`?a.orgId:void 0;if(!o||!s)return{state:`unlinked`};let c=await fetchProductionAlias(o,s,e,r);return r.signal?.throwIfAborted(),{state:c?`deployed`:`linked`,projectId:o,orgId:s,productionUrl:c}}async function fetchVercelName(t,n,r,i){let a=await captureVercel([`api`,t,`--scope`,n],{cwd:r,signal:i.signal});if(a.ok)try{let e=JSON.parse(a.stdout);return typeof e.name==`string`&&e.name.length>0?e.name:typeof e.slug==`string`&&e.slug.length>0?e.slug:void 0}catch{return}}async function detectProjectIdentity(e,r={}){r.signal?.throwIfAborted();let i;try{i=await readFile(join(e,`.vercel`,`project.json`),`utf8`)}catch{return}let a;try{a=JSON.parse(i)}catch{return}let o=typeof a.projectId==`string`?a.projectId:void 0,s=typeof a.orgId==`string`?a.orgId:void 0;if(!o||!s)return;let[c,l]=await Promise.all([fetchVercelName(`/v9/projects/${o}?teamId=${s}`,s,e,r).then(e=>e??o),s.startsWith(`team_`)?fetchVercelName(`/v2/teams/${s}`,s,e,r):Promise.resolve(void 0)]);return r.signal?.throwIfAborted(),{projectName:c,teamName:l}}function projectResolutionFromDeployment(e){return e.state===`unlinked`||e.projectId===void 0?{kind:`unresolved`}:e.state===`deployed`&&e.productionUrl!==void 0?{kind:`deployed`,projectId:e.projectId,productionUrl:e.productionUrl}:{kind:`linked`,projectId:e.projectId}}async function detectProjectResolution(e,t={}){return projectResolutionFromDeployment(await detectDeployment(e,t))}function mergeProjectResolution(e,t){return t.kind===`unresolved`||e.kind===`deployed`&&e.projectId===t.projectId?e:t}function projectResolutionFromDeployResult(e,t){return e.kind===`unresolved`||!t.deployed||t.productionUrl===void 0?e:{kind:`deployed`,projectId:e.projectId,productionUrl:t.productionUrl}}function isProjectResolved(e){return e.kind!==`unresolved`}function projectProductionUrlFromResolution(e){return e.kind===`deployed`?e.productionUrl:void 0}export{detectDeployment,detectProjectIdentity,detectProjectResolution,isProjectResolved,mergeProjectResolution,projectProductionUrlFromResolution,projectResolutionFromDeployResult,projectResolutionFromDeployment};
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{captureVercel}from"./primitives/run-vercel.js";import{join}from"node:path";import{readFile}from"node:fs/promises";const VercelProjectReferenceSchema=object({projectId:string().min(1),orgId:string().min(1),projectName:string().min(1).optional()}),VercelProjectEnvironmentSchema=object({VERCEL_ORG_ID:VercelProjectReferenceSchema.shape.orgId,VERCEL_PROJECT_ID:VercelProjectReferenceSchema.shape.projectId});function projectReferenceFromEnvironment(e){let t=VercelProjectEnvironmentSchema.safeParse(e);if(t.success)return{orgId:t.data.VERCEL_ORG_ID,projectId:t.data.VERCEL_PROJECT_ID}}async function readProjectLink(e){try{let t=await readFile(join(e,`.vercel`,`project.json`),`utf8`),n=VercelProjectReferenceSchema.safeParse(JSON.parse(t));return n.success?n.data:void 0}catch{return}}function pickShortestAlias(e){if(!Array.isArray(e))return;let t;for(let n of e)typeof n!=`string`||n.length===0||(t===void 0||n.length<t.length)&&(t=n);return t}async function fetchProductionAlias(e,t,r,i){let a=await captureVercel([`api`,`/v9/projects/${e}?teamId=${t}`,`--scope`,t],{cwd:r,signal:i.signal});if(a.ok)try{let e=pickShortestAlias(JSON.parse(a.stdout).targets?.production?.alias);return e?`https://${e}`:void 0}catch{return}}async function detectDeployment(e,t={}){t.signal?.throwIfAborted();let n=await readProjectLink(e);if(n===void 0)return{state:`unlinked`};let r=await fetchProductionAlias(n.projectId,n.orgId,e,t);return t.signal?.throwIfAborted(),{state:r?`deployed`:`linked`,projectId:n.projectId,orgId:n.orgId,productionUrl:r}}async function fetchVercelName(e,t,r,i){let a=await captureVercel([`api`,e,`--scope`,t],{cwd:r,signal:i.signal});if(a.ok)try{let e=JSON.parse(a.stdout);return typeof e.name==`string`&&e.name.length>0?e.name:typeof e.slug==`string`&&e.slug.length>0?e.slug:void 0}catch{return}}async function detectProjectIdentity(e,t={}){t.signal?.throwIfAborted();let n=await readProjectLink(e);if(n===void 0)return;let[r,i]=await Promise.all([fetchVercelName(`/v9/projects/${n.projectId}?teamId=${n.orgId}`,n.orgId,e,t).then(e=>e??n.projectId),n.orgId.startsWith(`team_`)?fetchVercelName(`/v2/teams/${n.orgId}`,n.orgId,e,t):Promise.resolve(void 0)]);return t.signal?.throwIfAborted(),{projectName:r,teamName:i}}function projectResolutionFromDeployment(e){return e.state===`unlinked`||e.projectId===void 0?{kind:`unresolved`}:e.state===`deployed`&&e.productionUrl!==void 0?{kind:`deployed`,projectId:e.projectId,productionUrl:e.productionUrl}:{kind:`linked`,projectId:e.projectId}}async function detectProjectResolution(e,t={}){return projectResolutionFromDeployment(await detectDeployment(e,t))}function mergeProjectResolution(e,t){return t.kind===`unresolved`||e.kind===`deployed`&&e.projectId===t.projectId?e:t}function projectResolutionFromDeployResult(e,t){return e.kind===`unresolved`||!t.deployed||t.productionUrl===void 0?e:{kind:`deployed`,projectId:e.projectId,productionUrl:t.productionUrl}}function isProjectResolved(e){return e.kind!==`unresolved`}function projectProductionUrlFromResolution(e){return e.kind===`deployed`?e.productionUrl:void 0}export{detectDeployment,detectProjectIdentity,detectProjectResolution,isProjectResolved,mergeProjectResolution,projectProductionUrlFromResolution,projectReferenceFromEnvironment,projectResolutionFromDeployResult,projectResolutionFromDeployment,readProjectLink};
@@ -1,4 +1,4 @@
1
- import{getPackageManagerStrategy}from"../../primitives/pm/index.js";import{pinnedNodeEngineMajor}from"../../node-engine.js";import{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{basename,join,resolve}from"node:path";import{mkdir,readdir,stat}from"node:fs/promises";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,ALLOWED_CREATE_IN_PLACE_ENTRIES=new Set([`.DS_Store`,`.git`,`.gitkeep`,`.hg`]),DEFAULT_AI_PACKAGE_VERSION=`7.0.0-beta.178`,DEFAULT_CONNECT_PACKAGE_VERSION=`0.2.2`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.11.10`,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";
1
+ import{getPackageManagerStrategy}from"../../primitives/pm/index.js";import{pinnedNodeEngineMajor}from"../../node-engine.js";import{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{basename,join,resolve}from"node:path";import{mkdir,readdir,stat}from"node:fs/promises";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,ALLOWED_CREATE_IN_PLACE_ENTRIES=new Set([`.DS_Store`,`.git`,`.gitkeep`,`.hg`]),DEFAULT_AI_PACKAGE_VERSION=`7.0.0-beta.178`,DEFAULT_CONNECT_PACKAGE_VERSION=`0.2.2`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.12.1`,nodeEngine:`>=24`};function resolveEvePackageContract(e=DEFAULT_EVE_PACKAGE_CONTRACT){return{version:resolveVersionToken(`evePackage.version`,e.version),nodeEngine:resolveVersionToken(`evePackage.nodeEngine`,e.nodeEngine)}}function modelProviderSlug(e){let t=(e.split(`/`)[0]??``).replaceAll(/[^A-Za-z0-9._-]/gu,``);return t.length>0?t:`anthropic`}function byokProviderEnvVar(e){let t=modelProviderSlug(e).toUpperCase().replaceAll(/[^A-Z0-9]/gu,`_`);return`${/^[0-9]/.test(t)?`_`:``}${t}_API_KEY`}function agentTemplateFiles(e){return{"agent/agent.ts":BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e),"agent/channels/eve.ts":WEB_APP_TEMPLATE_FILES[`agent/channels/eve.ts`],"agent/instructions.md":AGENT_INSTRUCTIONS_TEMPLATE}}function renderTemplate(e,t){return e.replaceAll(`__EVE_INIT_APP_NAME__`,t.appName).replaceAll(`__EVE_INIT_MODEL__`,t.model).replaceAll(`__EVE_INIT_BYOK_PROVIDER__`,modelProviderSlug(t.model)).replaceAll(`__EVE_INIT_BYOK_ENV_VAR__`,byokProviderEnvVar(t.model)).replaceAll(`__EVE_INIT_PACKAGE_VERSION__`,formatEveDependencySpecifier(t.eveVersion)).replaceAll(`__EVE_INIT_AI_SDK_VERSION__`,t.aiPackageVersion).replaceAll(`__EVE_INIT_CONNECT_VERSION__`,t.connectPackageVersion).replaceAll(`__EVE_INIT_ZOD_VERSION__`,t.zodPackageVersion).replaceAll(`__EVE_INIT_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__",
@@ -1,5 +1,5 @@
1
1
  export { byokProviderEnvVar, CURRENT_DIRECTORY_PROJECT_NAME, isEveProject, scaffoldBaseProject, type EvePackageContract, type ScaffoldBaseProjectOptions, } from "./create/project.js";
2
- export { DEFAULT_SLACK_CONNECTOR_SLUG, SLACK_CHANNEL_DEFAULT_ROUTE, deriveSlackConnectorSlug, ensureChannel, isNextJsProject, listAuthoredChannels, normalizeSlackConnectorSlug, type ChannelKind, type ChannelMutationResult, type EnsureChannelOptions, type SlackConnectorSlug, type WebPackageVersions, } from "./update/channels.js";
2
+ 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
3
  export { SCAFFOLDABLE_CHANNELS, type ScaffoldableChannel } from "./channels-catalog.js";
4
4
  export { ensureConnection, listAuthoredConnections, type ConnectionInput, type ConnectionMutationAction, type ConnectionMutationResult, type EnsureConnectionOptions, } from "./update/connections.js";
5
5
  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{HumanActionRequiredError}from"../human-action.js";import{SCAFFOLDABLE_CHANNELS}from"./channels-catalog.js";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{DEFAULT_SLACK_CONNECTOR_SLUG,SLACK_CHANNEL_DEFAULT_ROUTE,deriveSlackConnectorSlug,ensureChannel,isNextJsProject,listAuthoredChannels,normalizeSlackConnectorSlug}from"./update/channels.js";import{ensureConnection,listAuthoredConnections}from"./update/connections.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,getCatalogEntry,isEveProject,isNextJsProject,isValidConnectionSlug,listAuthoredChannels,listAuthoredConnections,normalizeSlackConnectorSlug,scaffoldBaseProject};
1
+ import{HumanActionRequiredError}from"../human-action.js";import{SCAFFOLDABLE_CHANNELS}from"./channels-catalog.js";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{DEFAULT_SLACK_CONNECTOR_SLUG,SLACK_CHANNEL_DEFAULT_ROUTE,deriveSlackConnectorSlug,ensureChannel,hasVercelHostFramework,isNextJsProject,listAuthoredChannels,normalizeSlackConnectorSlug}from"./update/channels.js";import{ensureConnection,listAuthoredConnections}from"./update/connections.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,getCatalogEntry,hasVercelHostFramework,isEveProject,isNextJsProject,isValidConnectionSlug,listAuthoredChannels,listAuthoredConnections,normalizeSlackConnectorSlug,scaffoldBaseProject};
@@ -56,12 +56,19 @@ interface WebChannelSkippedResult {
56
56
  type WebChannelMutationResult = WebChannelWrittenResult | WebChannelSkippedResult;
57
57
  /**
58
58
  * Whether the project already carries a Next.js app: `package.json` declares a
59
- * `next` dependency in any dependency field. This is the exact predicate the
59
+ * `next` dependency in the same dependency fields Vercel framework detection
60
+ * checks. This is the exact predicate the
60
61
  * web scaffold skips on (`skipReason: "nextjs-project"`), so pickers can mark
61
62
  * Web Chat as already present precisely when scaffolding would be a no-op.
62
63
  * A missing `package.json` reads as "no app".
63
64
  */
64
65
  export declare function isNextJsProject(projectRoot: string): Promise<boolean>;
66
+ /**
67
+ * Whether the root app declares a Vercel framework that should own the
68
+ * top-level deployment while eve runs as a sibling service. These match Eve's
69
+ * current framework integrations: Next.js, Nuxt, and SvelteKit.
70
+ */
71
+ export declare function hasVercelHostFramework(projectRoot: string): Promise<boolean>;
65
72
  export declare function normalizeSlackConnectorSlug(input: string): SlackConnectorSlug;
66
73
  export declare function deriveSlackConnectorSlug(projectRoot: string, projectNameHint?: string): Promise<SlackConnectorSlug>;
67
74
  export interface EnsureChannelOptions {
@@ -1,7 +1,7 @@
1
- import{getPackageManagerStrategy}from"../../primitives/pm/index.js";import{pinnedNodeEngineMajor}from"../../node-engine.js";import{pathExists,writeTextFile}from"../files.js";import{patchPackageJson}from"./package-json.js";import{resolveVersionToken}from"../version-tokens.js";import{getSupportedModuleBaseName,matchesSupportedModuleBaseName}from"./module-files.js";import{WEB_APP_TEMPLATE_FILES,WEB_APP_TEMPLATE_PACKAGE_JSON}from"../create/web-template.js";import{DEFAULT_EVE_PACKAGE_CONTRACT,resolveEvePackageContract}from"../create/project.js";import{basename,join,resolve}from"node:path";import{readFile,readdir,writeFile}from"node:fs/promises";const SLACK_CHANNEL_DEFAULT_ROUTE=`/eve/v1/slack`,DEFAULT_SLACK_CONNECTOR_SLUG=`my-agent`,PACKAGE_DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`,`peerDependencies`,`optionalDependencies`],WEB_NEXT_CONFIG_PATH=`next.config.ts`,WEB_VERCEL_JSON_PATH=`vercel.json`,WEB_VERCEL_JSON_SCHEMA=`https://openapi.vercel.sh/vercel.json`,WEB_COMPETING_NEXT_CONFIG_PATHS=[`next.config.js`,`next.config.mjs`,WEB_NEXT_CONFIG_PATH,`next.config.mts`].filter(e=>e!==WEB_NEXT_CONFIG_PATH),WEB_DEFAULT_VERCEL_SERVICES={web:{entrypoint:`.`,framework:`nextjs`,routePrefix:`/`},eve:{buildCommand:`eve build`,entrypoint:`.`,framework:`eve`,routePrefix:`/_eve_internal/eve`}};function toSlackConnectorSlug(e){return e}function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}async function readDependencyVersion(e,t){let n=JSON.parse(await readFile(e,`utf8`));if(!isJsonObject(n)||!isJsonObject(n.dependencies))return;let r=n.dependencies[t];return typeof r==`string`?r:void 0}function packageJsonHasDependency(e,t){for(let n of PACKAGE_DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function hasPackageDependency(e,t){if(!await pathExists(e))return!1;let r=JSON.parse(await readFile(e,`utf8`));return isJsonObject(r)&&packageJsonHasDependency(r,t)}async function isNextJsProject(e){return hasPackageDependency(join(e,`package.json`),`next`)}async function ensurePackageDependency(e,t,r){return!await pathExists(e)||await readDependencyVersion(e,t)===r?[]:(await patchPackageJson(e,{dependencies:{[t]:r}}),[{path:e,dependencies:[t],devDependencies:[],scripts:[]}])}function resolveWebPackageVersions(e){return{evePackage:e?.evePackage??DEFAULT_EVE_PACKAGE_CONTRACT,aiPackageVersion:e?.aiPackageVersion??`7.0.0-beta.178`,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(e,r){if(!await pathExists(e))return{mutations:[]};let o=resolveEvePackageContract(r.evePackage),s=pinnedNodeEngineMajor(o.nodeEngine),c={...WEB_APP_TEMPLATE_PACKAGE_JSON.dependencies,ai:resolveVersionToken(`aiPackageVersion`,r.aiPackageVersion),eve:formatEveDependencySpecifier(o.version),next:resolveVersionToken(`nextPackageVersion`,r.nextPackageVersion),react:resolveVersionToken(`reactPackageVersion`,r.reactPackageVersion),"react-dom":resolveVersionToken(`reactDomPackageVersion`,r.reactDomPackageVersion),streamdown:resolveVersionToken(`streamdownPackageVersion`,r.streamdownPackageVersion),zod:resolveVersionToken(`zodPackageVersion`,r.zodPackageVersion)},u={...WEB_APP_TEMPLATE_PACKAGE_JSON.devDependencies,"@types/node":s,"@types/react":resolveVersionToken(`typesReactPackageVersion`,r.typesReactPackageVersion),"@types/react-dom":resolveVersionToken(`typesReactDomPackageVersion`,r.typesReactDomPackageVersion),typescript:`6.0.3`},f=WEB_APP_TEMPLATE_PACKAGE_JSON.scripts,p=await patchPackageJson(e,{dependencies:c,devDependencies:u,scripts:f,nodeEngineRequirement:o.nodeEngine});return{mutations:[{path:e,dependencies:Object.keys(c),devDependencies:Object.keys(u),scripts:Object.keys(f)}],nodeEngineOverride:p.nodeEngineOverride}}function normalizeSlackConnectorSlug(e){return toSlackConnectorSlug((e.trim().replace(/^@/,``).split(`/`).at(-1)??``).toLowerCase().replace(/[^a-z0-9_-]+/g,`-`).replace(/^[^a-z0-9]+/,``).replace(/[^a-z0-9]+$/,``).slice(0,100).replace(/[^a-z0-9]+$/,``)||`my-agent`)}async function deriveSlackConnectorSlug(e,t){if(t!==void 0&&t.length>0&&t!==`.`)return normalizeSlackConnectorSlug(t);try{let t=await readFile(join(e,`package.json`),`utf8`),n=JSON.parse(t);if(typeof n.name==`string`&&n.name.length>0)return normalizeSlackConnectorSlug(n.name)}catch{}return normalizeSlackConnectorSlug(basename(resolve(e))||`my-agent`)}function buildSlackTemplate(e){if(!e.startsWith(`slack/`)||e.length===6)throw Error(`Invalid Slack connector UID "${e}".`);return`import { connectSlackCredentials } from "@vercel/connect/eve";
1
+ import{getPackageManagerStrategy}from"../../primitives/pm/index.js";import{pinnedNodeEngineMajor}from"../../node-engine.js";import{pathExists,writeTextFile}from"../files.js";import{patchPackageJson}from"./package-json.js";import{resolveVersionToken}from"../version-tokens.js";import{getSupportedModuleBaseName,matchesSupportedModuleBaseName}from"./module-files.js";import{WEB_APP_TEMPLATE_FILES,WEB_APP_TEMPLATE_PACKAGE_JSON}from"../create/web-template.js";import{DEFAULT_EVE_PACKAGE_CONTRACT,resolveEvePackageContract}from"../create/project.js";import{basename,join,resolve}from"node:path";import{readFile,readdir,writeFile}from"node:fs/promises";const SLACK_CHANNEL_DEFAULT_ROUTE=`/eve/v1/slack`,DEFAULT_SLACK_CONNECTOR_SLUG=`my-agent`,NEXT_PACKAGE_NAME=`next`,VERCEL_HOST_FRAMEWORK_PACKAGE_NAMES=[`@sveltejs/kit`,NEXT_PACKAGE_NAME,`nuxt`,`nuxt3`,`nuxt-edge`,`nuxt-nightly`],PACKAGE_DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`],WEB_NEXT_CONFIG_PATH=`next.config.ts`,WEB_VERCEL_JSON_PATH=`vercel.json`,WEB_VERCEL_JSON_SCHEMA=`https://openapi.vercel.sh/vercel.json`,WEB_COMPETING_NEXT_CONFIG_PATHS=[`next.config.js`,`next.config.mjs`,WEB_NEXT_CONFIG_PATH,`next.config.mts`].filter(e=>e!==WEB_NEXT_CONFIG_PATH),WEB_DEFAULT_VERCEL_SERVICES={web:{entrypoint:`.`,framework:`nextjs`,routePrefix:`/`},eve:{buildCommand:`eve build`,entrypoint:`.`,framework:`eve`,routePrefix:`/_eve_internal/eve`}};function toSlackConnectorSlug(e){return e}function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}async function readDependencyVersion(e,t){let n=JSON.parse(await readFile(e,`utf8`));if(!isJsonObject(n)||!isJsonObject(n.dependencies))return;let r=n.dependencies[t];return typeof r==`string`?r:void 0}function packageJsonHasDependency(e,t){for(let n of PACKAGE_DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function hasPackageDependency(e,t){if(!await pathExists(e))return!1;let r=JSON.parse(await readFile(e,`utf8`));return isJsonObject(r)&&packageJsonHasDependency(r,t)}async function hasAnyPackageDependency(e,t){if(!await pathExists(e))return!1;let r=JSON.parse(await readFile(e,`utf8`));return isJsonObject(r)?t.some(e=>packageJsonHasDependency(r,e)):!1}async function isNextJsProject(e){return hasPackageDependency(join(e,`package.json`),NEXT_PACKAGE_NAME)}async function hasVercelHostFramework(e){return hasAnyPackageDependency(join(e,`package.json`),VERCEL_HOST_FRAMEWORK_PACKAGE_NAMES)}async function ensurePackageDependency(e,t,r){return!await pathExists(e)||await readDependencyVersion(e,t)===r?[]:(await patchPackageJson(e,{dependencies:{[t]:r}}),[{path:e,dependencies:[t],devDependencies:[],scripts:[]}])}function resolveWebPackageVersions(e){return{evePackage:e?.evePackage??DEFAULT_EVE_PACKAGE_CONTRACT,aiPackageVersion:e?.aiPackageVersion??`7.0.0-beta.178`,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(e,r){if(!await pathExists(e))return{mutations:[]};let o=resolveEvePackageContract(r.evePackage),s=pinnedNodeEngineMajor(o.nodeEngine),c={...WEB_APP_TEMPLATE_PACKAGE_JSON.dependencies,ai:resolveVersionToken(`aiPackageVersion`,r.aiPackageVersion),eve:formatEveDependencySpecifier(o.version),next:resolveVersionToken(`nextPackageVersion`,r.nextPackageVersion),react:resolveVersionToken(`reactPackageVersion`,r.reactPackageVersion),"react-dom":resolveVersionToken(`reactDomPackageVersion`,r.reactDomPackageVersion),streamdown:resolveVersionToken(`streamdownPackageVersion`,r.streamdownPackageVersion),zod:resolveVersionToken(`zodPackageVersion`,r.zodPackageVersion)},u={...WEB_APP_TEMPLATE_PACKAGE_JSON.devDependencies,"@types/node":s,"@types/react":resolveVersionToken(`typesReactPackageVersion`,r.typesReactPackageVersion),"@types/react-dom":resolveVersionToken(`typesReactDomPackageVersion`,r.typesReactDomPackageVersion),typescript:`6.0.3`},f=WEB_APP_TEMPLATE_PACKAGE_JSON.scripts,p=await patchPackageJson(e,{dependencies:c,devDependencies:u,scripts:f,nodeEngineRequirement:o.nodeEngine});return{mutations:[{path:e,dependencies:Object.keys(c),devDependencies:Object.keys(u),scripts:Object.keys(f)}],nodeEngineOverride:p.nodeEngineOverride}}function normalizeSlackConnectorSlug(e){return toSlackConnectorSlug((e.trim().replace(/^@/,``).split(`/`).at(-1)??``).toLowerCase().replace(/[^a-z0-9_-]+/g,`-`).replace(/^[^a-z0-9]+/,``).replace(/[^a-z0-9]+$/,``).slice(0,100).replace(/[^a-z0-9]+$/,``)||`my-agent`)}async function deriveSlackConnectorSlug(e,t){if(t!==void 0&&t.length>0&&t!==`.`)return normalizeSlackConnectorSlug(t);try{let t=await readFile(join(e,`package.json`),`utf8`),n=JSON.parse(t);if(typeof n.name==`string`&&n.name.length>0)return normalizeSlackConnectorSlug(n.name)}catch{}return normalizeSlackConnectorSlug(basename(resolve(e))||`my-agent`)}function buildSlackTemplate(e){if(!e.startsWith(`slack/`)||e.length===6)throw Error(`Invalid Slack connector UID "${e}".`);return`import { connectSlackCredentials } from "@vercel/connect/eve";
2
2
  import { slackChannel } from "eve/channels/slack";
3
3
 
4
4
  export default slackChannel({
5
5
  credentials: connectSlackCredentials(${JSON.stringify(e)}),
6
6
  });
7
- `}function renderWebAppTemplate(e,t){return e.replaceAll(`__EVE_INIT_APP_NAME__`,t).replaceAll(`__EVE_INIT_WITH_EVE_OPTIONS__`,``)}function withWebVercelServices(e){let t=JSON.parse(e);if(!isJsonObject(t))throw Error(`${WEB_VERCEL_JSON_PATH} must contain a JSON object.`);let n=t.experimentalServices;if(n!==void 0&&!isJsonObject(n))throw Error(`${WEB_VERCEL_JSON_PATH} experimentalServices must contain a JSON object.`);let r={...t,$schema:typeof t.$schema==`string`?t.$schema:WEB_VERCEL_JSON_SCHEMA,experimentalServices:{...n,web:n?.web??WEB_DEFAULT_VERCEL_SERVICES.web,eve:n?.eve??WEB_DEFAULT_VERCEL_SERVICES.eve}};return JSON.stringify(t)===JSON.stringify(r)?e:`${JSON.stringify(r,null,2)}\n`}async function ensureWebVercelServices(e){if(!await pathExists(e))return await writeTextFile(e,`${JSON.stringify({$schema:WEB_VERCEL_JSON_SCHEMA,experimentalServices:WEB_DEFAULT_VERCEL_SERVICES},null,2)}\n`,{force:!0}),`written`;let t=await readFile(e,`utf8`),i=withWebVercelServices(t);return i===t?`skipped`:(await writeFile(e,i,`utf8`),`written`)}async function findCompetingNextConfigFiles(e){let t=[];for(let r of WEB_COMPETING_NEXT_CONFIG_PATHS){let i=join(e,r);await pathExists(i)&&t.push(i)}return t}async function ensureChannel(e){switch(e.kind){case`slack`:return ensureSlackChannel({...e,kind:`slack`});case`web`:return ensureWebChannel({...e,kind:`web`})}}async function ensureWebChannel(t){let i=join(t.projectRoot,`package.json`),a=await pathExists(join(t.projectRoot,`app/page.tsx`));if(!t.force&&await isNextJsProject(t.projectRoot))return{kind:`web`,action:`skipped`,skipReason:`nextjs-project`,filesWritten:[],filesSkipped:[i],packageJsonUpdated:[]};let o=await patchWebPackageJson(i,resolveWebPackageVersions(t.webPackageVersions)),s=[],l=[],u=[],d=[],m=basename(resolve(t.projectRoot));if(t.configureVercelServices??!0){let e=join(t.projectRoot,WEB_VERCEL_JSON_PATH);await ensureWebVercelServices(e)===`written`?s.push(e):d.push(e)}let h=await getPackageManagerStrategy(t.packageManager??`pnpm`).applyProjectConfiguration(t.projectRoot);s.push(...h.filesWritten),d.push(...h.filesSkipped);for(let[e,i]of Object.entries(WEB_APP_TEMPLATE_FILES)){let a=join(t.projectRoot,e);if(e===`agent/channels/eve.ts`&&!t.force&&await pathExists(a)){d.push(a);continue}let o=await pathExists(a);await writeTextFile(a,renderWebAppTemplate(i,m),{force:!0}),s.push(a),o&&l.push(a)}u.push(...await findCompetingNextConfigFiles(t.projectRoot));let g={kind:`web`,action:a?`overwritten`:`created`,filesWritten:s,filesSkipped:d,packageJsonUpdated:o.mutations};return l.length>0&&(g.filesOverwritten=l),u.length>0&&(g.competingNextConfigFiles=u),o.nodeEngineOverride!==void 0&&(g.nodeEngineOverride=o.nodeEngineOverride),g}async function ensureSlackChannel(e){let t=join(e.projectRoot,`agent/channels/slack.ts`),i=await pathExists(t);if(!e.force&&i)return{kind:`slack`,action:`skipped`,filesWritten:[],filesSkipped:[t],packageJsonUpdated:[]};let o=resolveVersionToken(`connectPackageVersion`,e.connectPackageVersion??`0.2.2`),s=await ensurePackageDependency(join(e.projectRoot,`package.json`),`@vercel/connect`,o),c=e.slackConnectorSlug??await deriveSlackConnectorSlug(e.projectRoot);await writeTextFile(t,buildSlackTemplate(e.slackConnectorUid??`slack/${c}`),{force:e.force});let l={kind:`slack`,action:i?`overwritten`:`created`,filesWritten:[t],filesSkipped:[],packageJsonUpdated:s,slackConnectorSlug:c};return i&&(l.filesOverwritten=[t]),l}async function listAuthoredChannels(e){let t=join(e,`agent/channels`),n;try{n=await readdir(t,{withFileTypes:!0})}catch(e){if(e.code===`ENOENT`)return[];throw e}let r=[];for(let e of n){if(e.isFile()){let t=getSupportedModuleBaseName(e.name);t!==null&&r.push(t);continue}if(e.isDirectory())try{(await readdir(join(t,e.name))).some(e=>matchesSupportedModuleBaseName(e,`connection`))&&r.push(e.name)}catch{}}return r.sort()}export{DEFAULT_SLACK_CONNECTOR_SLUG,SLACK_CHANNEL_DEFAULT_ROUTE,deriveSlackConnectorSlug,ensureChannel,isNextJsProject,listAuthoredChannels,normalizeSlackConnectorSlug};
7
+ `}function renderWebAppTemplate(e,t){return e.replaceAll(`__EVE_INIT_APP_NAME__`,t).replaceAll(`__EVE_INIT_WITH_EVE_OPTIONS__`,``)}function withWebVercelServices(e){let t=JSON.parse(e);if(!isJsonObject(t))throw Error(`${WEB_VERCEL_JSON_PATH} must contain a JSON object.`);let n=t.experimentalServices;if(n!==void 0&&!isJsonObject(n))throw Error(`${WEB_VERCEL_JSON_PATH} experimentalServices must contain a JSON object.`);let r={...t,$schema:typeof t.$schema==`string`?t.$schema:WEB_VERCEL_JSON_SCHEMA,experimentalServices:{...n,web:n?.web??WEB_DEFAULT_VERCEL_SERVICES.web,eve:n?.eve??WEB_DEFAULT_VERCEL_SERVICES.eve}};return JSON.stringify(t)===JSON.stringify(r)?e:`${JSON.stringify(r,null,2)}\n`}async function ensureWebVercelServices(e){if(!await pathExists(e))return await writeTextFile(e,`${JSON.stringify({$schema:WEB_VERCEL_JSON_SCHEMA,experimentalServices:WEB_DEFAULT_VERCEL_SERVICES},null,2)}\n`,{force:!0}),`written`;let t=await readFile(e,`utf8`),i=withWebVercelServices(t);return i===t?`skipped`:(await writeFile(e,i,`utf8`),`written`)}async function findCompetingNextConfigFiles(e){let t=[];for(let r of WEB_COMPETING_NEXT_CONFIG_PATHS){let i=join(e,r);await pathExists(i)&&t.push(i)}return t}async function ensureChannel(e){switch(e.kind){case`slack`:return ensureSlackChannel({...e,kind:`slack`});case`web`:return ensureWebChannel({...e,kind:`web`})}}async function ensureWebChannel(t){let i=join(t.projectRoot,`package.json`),a=await pathExists(join(t.projectRoot,`app/page.tsx`));if(!t.force&&await isNextJsProject(t.projectRoot))return{kind:`web`,action:`skipped`,skipReason:`nextjs-project`,filesWritten:[],filesSkipped:[i],packageJsonUpdated:[]};let o=await patchWebPackageJson(i,resolveWebPackageVersions(t.webPackageVersions)),s=[],l=[],u=[],d=[],m=basename(resolve(t.projectRoot));if(t.configureVercelServices??!0){let e=join(t.projectRoot,WEB_VERCEL_JSON_PATH);await ensureWebVercelServices(e)===`written`?s.push(e):d.push(e)}let h=await getPackageManagerStrategy(t.packageManager??`pnpm`).applyProjectConfiguration(t.projectRoot);s.push(...h.filesWritten),d.push(...h.filesSkipped);for(let[e,i]of Object.entries(WEB_APP_TEMPLATE_FILES)){let a=join(t.projectRoot,e);if(e===`agent/channels/eve.ts`&&!t.force&&await pathExists(a)){d.push(a);continue}let o=await pathExists(a);await writeTextFile(a,renderWebAppTemplate(i,m),{force:!0}),s.push(a),o&&l.push(a)}u.push(...await findCompetingNextConfigFiles(t.projectRoot));let g={kind:`web`,action:a?`overwritten`:`created`,filesWritten:s,filesSkipped:d,packageJsonUpdated:o.mutations};return l.length>0&&(g.filesOverwritten=l),u.length>0&&(g.competingNextConfigFiles=u),o.nodeEngineOverride!==void 0&&(g.nodeEngineOverride=o.nodeEngineOverride),g}async function ensureSlackChannel(e){let t=join(e.projectRoot,`agent/channels/slack.ts`),i=await pathExists(t);if(!e.force&&i)return{kind:`slack`,action:`skipped`,filesWritten:[],filesSkipped:[t],packageJsonUpdated:[]};let o=resolveVersionToken(`connectPackageVersion`,e.connectPackageVersion??`0.2.2`),s=await ensurePackageDependency(join(e.projectRoot,`package.json`),`@vercel/connect`,o),c=e.slackConnectorSlug??await deriveSlackConnectorSlug(e.projectRoot);await writeTextFile(t,buildSlackTemplate(e.slackConnectorUid??`slack/${c}`),{force:e.force});let l={kind:`slack`,action:i?`overwritten`:`created`,filesWritten:[t],filesSkipped:[],packageJsonUpdated:s,slackConnectorSlug:c};return i&&(l.filesOverwritten=[t]),l}async function listAuthoredChannels(e){let t=join(e,`agent/channels`),n;try{n=await readdir(t,{withFileTypes:!0})}catch(e){if(e.code===`ENOENT`)return[];throw e}let r=[];for(let e of n){if(e.isFile()){let t=getSupportedModuleBaseName(e.name);t!==null&&r.push(t);continue}if(e.isDirectory())try{(await readdir(join(t,e.name))).some(e=>matchesSupportedModuleBaseName(e,`connection`))&&r.push(e.name)}catch{}}return r.sort()}export{DEFAULT_SLACK_CONNECTOR_SLUG,SLACK_CHANNEL_DEFAULT_ROUTE,deriveSlackConnectorSlug,ensureChannel,hasVercelHostFramework,isNextJsProject,listAuthoredChannels,normalizeSlackConnectorSlug};
@@ -0,0 +1,53 @@
1
+ import { captureVercel, type VercelCaptureFailure } from "#setup/primitives/index.js";
2
+ import { readProjectLink, type VercelProjectReference } from "#setup/project-resolution.js";
3
+ declare const verifiedVercelTargetBrand: unique symbol;
4
+ export interface ResolvedVercelDeployment {
5
+ readonly provider: "vercel";
6
+ readonly ownerId: string;
7
+ readonly projectId: string;
8
+ readonly projectName: string;
9
+ readonly environment: string;
10
+ }
11
+ /** Proof that Vercel resolved one exact HTTPS origin under an authenticated scope. */
12
+ export interface VerifiedVercelTarget {
13
+ readonly [verifiedVercelTargetBrand]: true;
14
+ readonly origin: `https://${string}`;
15
+ readonly deployment: ResolvedVercelDeployment;
16
+ }
17
+ export type VercelDeploymentResolutionFailure = {
18
+ readonly cause: "vercel";
19
+ readonly failure: VercelCaptureFailure;
20
+ } | {
21
+ readonly cause: "invalid-json" | "invalid-shape";
22
+ readonly message: string;
23
+ };
24
+ export type VercelDeploymentResolution = {
25
+ readonly kind: "resolved";
26
+ readonly target: VerifiedVercelTarget;
27
+ } | {
28
+ readonly kind: "not-found";
29
+ } | {
30
+ readonly kind: "unscoped";
31
+ } | {
32
+ readonly kind: "project-mismatch";
33
+ readonly expectedProjectId: string;
34
+ readonly actualProjectId: string;
35
+ } | {
36
+ readonly kind: "cancelled";
37
+ } | {
38
+ readonly kind: "failed";
39
+ readonly failure: VercelDeploymentResolutionFailure;
40
+ };
41
+ export interface VercelDeploymentResolutionDeps {
42
+ readonly captureVercel: typeof captureVercel;
43
+ readonly readProjectLink: typeof readProjectLink;
44
+ }
45
+ /** Resolves a Vercel deployment URL to its project and target environment. */
46
+ export declare function resolveVercelDeployment(input: {
47
+ readonly workspaceRoot: string;
48
+ readonly host: string;
49
+ readonly source?: Pick<VercelProjectReference, "orgId" | "projectId">;
50
+ readonly signal?: AbortSignal;
51
+ readonly deps?: Partial<VercelDeploymentResolutionDeps>;
52
+ }): Promise<VercelDeploymentResolution>;
53
+ export {};
@@ -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";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};