eve 0.12.2 → 0.13.0

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 (135) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/src/cli/commands/agent-instructions.d.ts +15 -3
  3. package/dist/src/cli/commands/agent-instructions.js +3 -1
  4. package/dist/src/cli/commands/agent-prompt/build-and-verify.md +33 -0
  5. package/dist/src/cli/commands/agent-prompt/collect-intent.md +18 -0
  6. package/dist/src/cli/commands/agent-prompt/intro-handoff.md +4 -0
  7. package/dist/src/cli/commands/agent-prompt/intro-setup.md +5 -0
  8. package/dist/src/cli/commands/agent-prompt/scaffold.md +19 -0
  9. package/dist/src/cli/commands/agent-prompt/vercel-connect.md +3 -0
  10. package/dist/src/cli/commands/deploy.js +1 -1
  11. package/dist/src/cli/commands/init-repl.d.ts +79 -0
  12. package/dist/src/cli/commands/init-repl.js +1 -0
  13. package/dist/src/cli/commands/init.d.ts +6 -0
  14. package/dist/src/cli/commands/init.js +1 -1
  15. package/dist/src/cli/commands/link.d.ts +2 -2
  16. package/dist/src/cli/commands/link.js +1 -1
  17. package/dist/src/cli/dev/tui/line-editor.d.ts +2 -0
  18. package/dist/src/cli/dev/tui/line-editor.js +2 -2
  19. package/dist/src/cli/dev/tui/prompt-command-handler.js +1 -1
  20. package/dist/src/cli/dev/tui/setup-commands.d.ts +26 -7
  21. package/dist/src/cli/dev/tui/setup-commands.js +2 -2
  22. package/dist/src/cli/dev/tui/setup-flow.d.ts +10 -3
  23. package/dist/src/cli/dev/tui/setup-panel.d.ts +16 -8
  24. package/dist/src/cli/dev/tui/setup-panel.js +3 -3
  25. package/dist/src/cli/dev/tui/setup-selection-input.d.ts +2 -1
  26. package/dist/src/cli/dev/tui/setup-selection-input.js +2 -2
  27. package/dist/src/cli/dev/tui/terminal-renderer.js +10 -10
  28. package/dist/src/cli/dev/tui/terminal-text.d.ts +11 -0
  29. package/dist/src/cli/dev/tui/terminal-text.js +1 -1
  30. package/dist/src/cli/dev/tui/tui-prompter.js +1 -1
  31. package/dist/src/cli/run.d.ts +1 -0
  32. package/dist/src/cli/run.js +2 -2
  33. package/dist/src/cli/ui/live-row.js +1 -1
  34. package/dist/src/cli/ui/progress-pulse.d.ts +10 -0
  35. package/dist/src/cli/ui/progress-pulse.js +1 -0
  36. package/dist/src/discover/discover-agent.js +1 -1
  37. package/dist/src/evals/target.js +1 -1
  38. package/dist/src/execution/node-step.js +1 -1
  39. package/dist/src/execution/sandbox/bindings/just-bash-runtime.js +1 -1
  40. package/dist/src/execution/sandbox/bindings/vercel-sdk-types.d.ts +0 -1
  41. package/dist/src/execution/sandbox/bindings/vercel.js +1 -1
  42. package/dist/src/execution/sandbox/multiplexed-command.d.ts +22 -0
  43. package/dist/src/execution/sandbox/multiplexed-command.js +1 -0
  44. package/dist/src/execution/tool-auth.d.ts +17 -30
  45. package/dist/src/execution/tool-auth.js +1 -1
  46. package/dist/src/execution/workflow-steps.js +1 -1
  47. package/dist/src/harness/tool-loop.js +1 -1
  48. package/dist/src/internal/application/package.js +1 -1
  49. package/dist/src/internal/authored-module-loader.js +2 -2
  50. package/dist/src/internal/nitro/dev-runtime-artifacts.js +1 -1
  51. package/dist/src/internal/nitro/routes/agent-info/build-agent-info-response.js +1 -1
  52. package/dist/src/public/channels/github/api.d.ts +5 -0
  53. package/dist/src/public/channels/github/api.js +1 -1
  54. package/dist/src/public/channels/github/dispatch.js +1 -1
  55. package/dist/src/public/channels/github/pr-context.d.ts +10 -0
  56. package/dist/src/public/channels/github/pr-context.js +2 -2
  57. package/dist/src/public/channels/slack/connections.d.ts +16 -18
  58. package/dist/src/public/channels/slack/defaults.d.ts +1 -1
  59. package/dist/src/public/channels/slack/defaults.js +1 -1
  60. package/dist/src/public/channels/slack/slackChannel.d.ts +6 -7
  61. package/dist/src/public/definitions/tool.d.ts +40 -41
  62. package/dist/src/public/definitions/tool.js +1 -1
  63. package/dist/src/public/tools/index.d.ts +1 -1
  64. package/dist/src/runtime/connections/scoped-authorization.js +1 -1
  65. package/dist/src/runtime/connections/validate-authorization.js +1 -1
  66. package/dist/src/runtime/framework-tools/connection-search-dynamic.js +1 -1
  67. package/dist/src/runtime/resolve-tool.js +1 -1
  68. package/dist/src/runtime/types.d.ts +0 -10
  69. package/dist/src/setup/ai-gateway-api-key.d.ts +15 -0
  70. package/dist/src/setup/ai-gateway-api-key.js +1 -0
  71. package/dist/src/setup/boxes/apply-ai-gateway-credential.js +1 -1
  72. package/dist/src/setup/boxes/detect-ai-gateway.js +2 -2
  73. package/dist/src/setup/boxes/link-project.d.ts +8 -14
  74. package/dist/src/setup/boxes/link-project.js +1 -1
  75. package/dist/src/setup/boxes/resolve-provisioning.d.ts +2 -1
  76. package/dist/src/setup/boxes/resolve-provisioning.js +1 -1
  77. package/dist/src/setup/cli/select-component.d.ts +7 -1
  78. package/dist/src/setup/cli/select-component.js +1 -1
  79. package/dist/src/setup/cli/select-option-codec.d.ts +1 -0
  80. package/dist/src/setup/cli/select-option-codec.js +1 -1
  81. package/dist/src/setup/cli/select-state.d.ts +14 -1
  82. package/dist/src/setup/cli/select-state.js +1 -1
  83. package/dist/src/setup/flows/channels.js +1 -1
  84. package/dist/src/setup/flows/deploy.js +1 -1
  85. package/dist/src/setup/flows/install-vercel-cli.js +1 -1
  86. package/dist/src/setup/flows/link.d.ts +2 -1
  87. package/dist/src/setup/flows/link.js +1 -1
  88. package/dist/src/setup/flows/login.js +1 -1
  89. package/dist/src/setup/flows/model.d.ts +5 -4
  90. package/dist/src/setup/flows/model.js +1 -1
  91. package/dist/src/setup/flows/vercel.js +2 -2
  92. package/dist/src/setup/index.d.ts +1 -1
  93. package/dist/src/setup/package-manager.d.ts +2 -1
  94. package/dist/src/setup/package-manager.js +1 -1
  95. package/dist/src/setup/primitives/pm/index.d.ts +1 -1
  96. package/dist/src/setup/primitives/pm/pnpm.d.ts +11 -1
  97. package/dist/src/setup/primitives/pm/pnpm.js +5 -2
  98. package/dist/src/setup/primitives/pm/types.d.ts +10 -1
  99. package/dist/src/setup/project-resolution.d.ts +9 -6
  100. package/dist/src/setup/project-resolution.js +1 -1
  101. package/dist/src/setup/prompter.d.ts +13 -0
  102. package/dist/src/setup/prompter.js +1 -1
  103. package/dist/src/setup/scaffold/create/add-to-project.js +1 -1
  104. package/dist/src/setup/scaffold/create/project.d.ts +8 -0
  105. package/dist/src/setup/scaffold/create/project.js +8 -7
  106. package/dist/src/setup/scaffold/update/channels.d.ts +8 -0
  107. package/dist/src/setup/scaffold/update/channels.js +2 -2
  108. package/dist/src/setup/scaffold/update/package-json.d.ts +3 -0
  109. package/dist/src/setup/scaffold/update/package-json.js +1 -1
  110. package/dist/src/setup/scaffold/workspace-glob.d.ts +5 -0
  111. package/dist/src/setup/scaffold/workspace-glob.js +1 -0
  112. package/dist/src/setup/scaffold/workspace-root.d.ts +29 -0
  113. package/dist/src/setup/scaffold/workspace-root.js +1 -0
  114. package/dist/src/setup/state.d.ts +7 -2
  115. package/dist/src/setup/vercel-api-failure.d.ts +9 -0
  116. package/dist/src/setup/vercel-api-failure.js +1 -0
  117. package/dist/src/setup/vercel-deployment.js +1 -1
  118. package/dist/src/setup/vercel-project-api.d.ts +25 -0
  119. package/dist/src/setup/vercel-project-api.js +1 -0
  120. package/dist/src/setup/vercel-project.d.ts +11 -57
  121. package/dist/src/setup/vercel-project.js +1 -1
  122. package/dist/src/setup/with-spinner.d.ts +3 -0
  123. package/dist/src/setup/with-spinner.js +1 -0
  124. package/dist/src/shared/package-name.d.ts +4 -0
  125. package/dist/src/shared/package-name.js +1 -0
  126. package/docs/channels/slack.mdx +1 -1
  127. package/docs/connections.mdx +9 -6
  128. package/docs/getting-started.mdx +8 -3
  129. package/docs/guides/auth-and-route-protection.md +57 -10
  130. package/docs/guides/dev-tui.md +3 -3
  131. package/docs/reference/cli.md +3 -3
  132. package/docs/reference/typescript-api.md +7 -7
  133. package/package.json +1 -1
  134. package/dist/src/cli/commands/init-agent-handoff.md +0 -12
  135. package/dist/src/cli/commands/init-agent-instructions.md +0 -16
@@ -1,5 +1,5 @@
1
- import{getGitHubPullRequest,listGitHubPullRequestFiles}from"#public/channels/github/api.js";const MAX_PATCH_BYTES=2e4,GITHUB_DEFAULT_EXCLUDED_DIFF_FILES=[`**/pnpm-lock.yaml`,`**/package-lock.json`,`**/npm-shrinkwrap.json`,`**/yarn.lock`,`**/bun.lockb`,`**/Cargo.lock`,`**/go.sum`,`**/poetry.lock`,`**/Pipfile.lock`,`**/uv.lock`,`**/composer.lock`,`**/Gemfile.lock`,`**/*.min.js`,`**/*.min.css`,`**/*.map`,`**/*.snap`];async function buildGitHubPullRequestContext(n){if(n.pullRequestNumber===null)return;let i=renderPullRequestMetadata(await getGitHubPullRequest({api:n.api,credentials:n.credentials,installationId:n.installationId,owner:n.owner,pullRequestNumber:n.pullRequestNumber,repo:n.repo})),a=await listGitHubPullRequestFiles({api:n.api,credentials:n.credentials,installationId:n.installationId,owner:n.owner,perPage:50,pullRequestNumber:n.pullRequestNumber,repo:n.repo}),o=[...GITHUB_DEFAULT_EXCLUDED_DIFF_FILES,...n.config?.excludedFiles??[]];return i.push(``,...renderPullRequestFiles(a,o)),[[`GitHub pull request context for the current turn. `,`Use this as background for the user's GitHub comment.`,``,i.join(`
1
+ import{getGitHubPullRequest,listGitHubCompareFiles,listGitHubPullRequestFiles}from"#public/channels/github/api.js";const MAX_PATCH_BYTES=2e4,GITHUB_DEFAULT_EXCLUDED_DIFF_FILES=[`**/pnpm-lock.yaml`,`**/package-lock.json`,`**/npm-shrinkwrap.json`,`**/yarn.lock`,`**/bun.lockb`,`**/Cargo.lock`,`**/go.sum`,`**/poetry.lock`,`**/Pipfile.lock`,`**/uv.lock`,`**/composer.lock`,`**/Gemfile.lock`,`**/*.min.js`,`**/*.min.css`,`**/*.map`,`**/*.snap`];async function buildGitHubPullRequestContext(r){if(r.pullRequestNumber===null)return;let a=withPinnedPullRequestShas(await getGitHubPullRequest({api:r.api,credentials:r.credentials,installationId:r.installationId,owner:r.owner,pullRequestNumber:r.pullRequestNumber,repo:r.repo}),r),o=renderPullRequestMetadata(a),s=readNonEmptySha(r.baseSha)??readNonEmptySha(a.base.sha),c=readNonEmptySha(r.headSha)??readNonEmptySha(a.head.sha),l=readNonEmptySha(r.headSha)!==void 0&&c!==void 0&&s!==void 0?(await listGitHubCompareFiles({api:r.api,baseSha:s,credentials:r.credentials,headSha:c,installationId:r.installationId,owner:r.owner,repo:r.repo})).slice(0,50):await listGitHubPullRequestFiles({api:r.api,credentials:r.credentials,installationId:r.installationId,owner:r.owner,perPage:50,pullRequestNumber:r.pullRequestNumber,repo:r.repo}),u=[...GITHUB_DEFAULT_EXCLUDED_DIFF_FILES,...r.config?.excludedFiles??[]];return o.push(``,...renderPullRequestFiles(l,u)),[[`GitHub pull request context for the current turn. `,`Use this as background for the user's GitHub comment.`,``,o.join(`
2
2
  `)].join(`
3
- `)]}function mergeGitHubContext(e){let t=e.github??[],n=e.hook??[];if(!(t.length===0&&n.length===0))return[...t,...n]}function renderPullRequestMetadata(e){return[`<github_pull_request>`,`number: ${e.number}`,`title: ${e.title}`,`state: ${e.state??`unknown`}`,`draft: ${e.draft?`true`:`false`}`,...e.author?.login?[`author: ${e.author.login}`]:[],...e.htmlUrl?[`url: ${e.htmlUrl}`]:[],...e.base.ref?[`base_ref: ${e.base.ref}`]:[],...e.base.sha?[`base_sha: ${e.base.sha}`]:[],...e.head.ref?[`head_ref: ${e.head.ref}`]:[],...e.head.sha?[`head_sha: ${e.head.sha}`]:[],...e.mergeable===null||e.mergeable===void 0?[]:[`mergeable: ${e.mergeable?`true`:`false`}`],...e.changedFiles===void 0?[]:[`changed_files: ${e.changedFiles}`],...e.additions===void 0?[]:[`additions: ${e.additions}`],...e.deletions===void 0?[]:[`deletions: ${e.deletions}`],...e.body?[``,`body:`,indent(truncateText(e.body,4e3))]:[],`</github_pull_request>`]}function renderPullRequestFiles(e,t){if(e.length===0)return[`<github_pull_request_files>`,`none`,`</github_pull_request_files>`];let r=[`<github_pull_request_files>`],i=MAX_PATCH_BYTES,a=!1;for(let n of e){if(r.push(renderFileSummary(n)),fileMatchesAnyGlob(n.filename,t)){r.push(` patch omitted (excluded)`);continue}if(n.patch===void 0)continue;if(i<=0){a=!0;continue}let e=truncateByBytes(n.patch,i);r.push(`patch:`,indent(e.text)),i-=e.bytes,e.truncated&&(a=!0,i=0)}return a&&r.push(``,`patches_truncated: true`,`max_patch_bytes: ${MAX_PATCH_BYTES}`),r.push(`</github_pull_request_files>`),r}function renderFileSummary(e){let t=[e.status??`modified`,e.additions===void 0?void 0:`+${e.additions}`,e.deletions===void 0?void 0:`-${e.deletions}`].filter(e=>e!==void 0);return`- ${e.filename}${t.length>0?` (${t.join(`, `)})`:``}`}function fileMatchesAnyGlob(e,t){return t.some(t=>globToRegExp(t).test(e))}function globToRegExp(e){let t=``;for(let n=0;n<e.length;n+=1){let r=e.charAt(n);r===`*`?e[n+1]===`*`?(t+=`.*`,n+=1,e[n+1]===`/`&&(n+=1)):t+=`[^/]*`:`\\^$.|?+()[]{}`.includes(r)?t+=`\\${r}`:t+=r}return RegExp(`^${t}$`,`u`)}function truncateByBytes(e,t){let n=new TextEncoder().encode(e);return n.byteLength<=t?{bytes:n.byteLength,text:e,truncated:!1}:{bytes:t,text:`${new TextDecoder().decode(n.slice(0,t))}\n[truncated]`,truncated:!0}}function truncateText(e,t){return e.length<=t?e:`${e.slice(0,t)}\n[truncated]`}function indent(e){return e.split(`
3
+ `)]}function mergeGitHubContext(e){let t=e.github??[],n=e.hook??[];if(!(t.length===0&&n.length===0))return[...t,...n]}function withPinnedPullRequestShas(e,t){let n=readNonEmptySha(t.headSha),r=readNonEmptySha(t.baseSha);return n===void 0&&r===void 0?e:{...e,base:{...e.base,sha:r??e.base.sha},head:{...e.head,sha:n??e.head.sha}}}function readNonEmptySha(e){return typeof e==`string`&&e.trim().length>0?e.trim():void 0}function renderPullRequestMetadata(e){return[`<github_pull_request>`,`number: ${e.number}`,`title: ${e.title}`,`state: ${e.state??`unknown`}`,`draft: ${e.draft?`true`:`false`}`,...e.author?.login?[`author: ${e.author.login}`]:[],...e.htmlUrl?[`url: ${e.htmlUrl}`]:[],...e.base.ref?[`base_ref: ${e.base.ref}`]:[],...e.base.sha?[`base_sha: ${e.base.sha}`]:[],...e.head.ref?[`head_ref: ${e.head.ref}`]:[],...e.head.sha?[`head_sha: ${e.head.sha}`]:[],...e.mergeable===null||e.mergeable===void 0?[]:[`mergeable: ${e.mergeable?`true`:`false`}`],...e.changedFiles===void 0?[]:[`changed_files: ${e.changedFiles}`],...e.additions===void 0?[]:[`additions: ${e.additions}`],...e.deletions===void 0?[]:[`deletions: ${e.deletions}`],...e.body?[``,`body:`,indent(truncateText(e.body,4e3))]:[],`</github_pull_request>`]}function renderPullRequestFiles(e,t){if(e.length===0)return[`<github_pull_request_files>`,`none`,`</github_pull_request_files>`];let n=[`<github_pull_request_files>`],i=MAX_PATCH_BYTES,a=!1;for(let r of e){if(n.push(renderFileSummary(r)),fileMatchesAnyGlob(r.filename,t)){n.push(` patch omitted (excluded)`);continue}if(r.patch===void 0)continue;if(i<=0){a=!0;continue}let e=truncateByBytes(r.patch,i);n.push(`patch:`,indent(e.text)),i-=e.bytes,e.truncated&&(a=!0,i=0)}return a&&n.push(``,`patches_truncated: true`,`max_patch_bytes: ${MAX_PATCH_BYTES}`),n.push(`</github_pull_request_files>`),n}function renderFileSummary(e){let t=[e.status??`modified`,e.additions===void 0?void 0:`+${e.additions}`,e.deletions===void 0?void 0:`-${e.deletions}`].filter(e=>e!==void 0);return`- ${e.filename}${t.length>0?` (${t.join(`, `)})`:``}`}function fileMatchesAnyGlob(e,t){return t.some(t=>globToRegExp(t).test(e))}function globToRegExp(e){let t=``;for(let n=0;n<e.length;n+=1){let r=e.charAt(n);r===`*`?e[n+1]===`*`?(t+=`.*`,n+=1,e[n+1]===`/`&&(n+=1)):t+=`[^/]*`:`\\^$.|?+()[]{}`.includes(r)?t+=`\\${r}`:t+=r}return RegExp(`^${t}$`,`u`)}function truncateByBytes(e,t){let n=new TextEncoder().encode(e);return n.byteLength<=t?{bytes:n.byteLength,text:e,truncated:!1}:{bytes:t,text:`${new TextDecoder().decode(n.slice(0,t))}\n[truncated]`,truncated:!0}}function truncateText(e,t){return e.length<=t?e:`${e.slice(0,t)}\n[truncated]`}function indent(e){return e.split(`
4
4
  `).map(e=>` ${e}`).join(`
5
5
  `)}export{GITHUB_DEFAULT_EXCLUDED_DIFF_FILES,buildGitHubPullRequestContext,fileMatchesAnyGlob,mergeGitHubContext};
@@ -5,16 +5,16 @@
5
5
  * an OAuth-style authorization flow (e.g. signing in to Linear). The
6
6
  * challenge is a credential: anyone in a shared thread could complete a
7
7
  * posted sign-in link and bind their own identity to the session. The
8
- * default handler therefore delivers the challenge as an ephemeral
9
- * "Sign in with X" message visible only to the triggering user.
8
+ * default handler therefore posts a link-free public status while
9
+ * delivering the actual challenge as an ephemeral "Sign in with X"
10
+ * message visible only to the triggering user.
10
11
  *
11
- * Only when no user can be targeted (no triggering user id, no challenge
12
- * URL, or the ephemeral delivery fails) does the handler fall back to a
13
- * public status post, link-free by construction. The matching
14
- * `authorization.completed` handler edits that fallback post in place to
12
+ * When no user can be targeted (no triggering user id, no challenge
13
+ * URL, or the ephemeral delivery fails), the public status still leaves
14
+ * the shared thread with safe progress feedback. The matching
15
+ * `authorization.completed` handler edits that status post in place to
15
16
  * surface the outcome (`authorized` / `declined` / `failed` /
16
- * `timed-out`); on the normal ephemeral path there is nothing to edit
17
- * and the outcome surfaces through the resumed turn itself.
17
+ * `timed-out`).
18
18
  */
19
19
  import type { ConnectionAuthorizationOutcome } from "#protocol/message.js";
20
20
  export type { ConnectionAuthorizationOutcome };
@@ -25,22 +25,20 @@ export type { ConnectionAuthorizationOutcome };
25
25
  */
26
26
  export declare function formatConnectionDisplayName(connectionName: string): string;
27
27
  /**
28
- * Public fallback status text for an authorization challenge that could
29
- * not be delivered ephemerally. Deliberately link-free: it must stay safe
30
- * to post in a shared thread. When the channel cannot identify a
31
- * triggering user (rare schedule-initiated sessions or events that lack
32
- * actor metadata) the text drops the "Connect with" call-to-action since
33
- * there's no one to act on it.
28
+ * Public status text for an authorization challenge. Deliberately
29
+ * link-free: it must stay safe to post in a shared thread. When the
30
+ * channel cannot identify a triggering user (rare schedule-initiated
31
+ * sessions or events that lack actor metadata) the text drops the
32
+ * "Connect with" call-to-action since there's no one to act on it.
34
33
  */
35
34
  export declare function buildAuthRequiredPublicText(input: {
36
35
  readonly displayName: string;
37
36
  readonly hasUser: boolean;
38
37
  }): string;
39
38
  /**
40
- * Final-state markdown for the public fallback status message. Edited in
41
- * place by `authorization.completed` so the thread sees resolution
42
- * without scrolling. Unused on the normal ephemeral path, which posts no
43
- * status message.
39
+ * Final-state markdown for the public status message. Edited in place by
40
+ * `authorization.completed` so the thread sees resolution without
41
+ * scrolling.
44
42
  */
45
43
  export declare function buildAuthCompletedText(input: {
46
44
  readonly displayName: string;
@@ -33,7 +33,7 @@ export declare function defaultInputRequestedHandler(): NonNullable<SlackChannel
33
33
  * and the connection-authorization status flow. Each is overridable
34
34
  * per-event by passing the same key under `slackChannel({ events })`.
35
35
  * Typed as the internal full-context map because the default
36
- * `authorization.required` handler owns the public link-free fallback,
36
+ * `authorization.required` handler owns the public link-free status,
37
37
  * which user overrides cannot express.
38
38
  */
39
39
  export declare const defaultEvents: SlackChannelInternalEvents;
@@ -1,4 +1,4 @@
1
1
  import{createLogger,extractErrorId,formatErrorHint}from"#internal/logging.js";import{truncateMessageText,truncateTypingStatus}from"#public/channels/slack/limits.js";import{buildSlackAuthContext}from"#public/channels/slack/auth.js";import{buildAuthCompletedText,buildAuthEphemeralBlocks,buildAuthRequiredPublicText,formatConnectionDisplayName}from"#public/channels/slack/connections.js";import{renderInputRequestBlocks}from"#public/channels/slack/hitl.js";const log=createLogger(`slack.defaults`);function defaultSlackAuth(e,t){let n=e.author;return n?buildSlackAuthContext({channelId:t.slack.channelId,fullName:n.fullName,isBot:n.isBot,teamId:e.teamId,threadTs:t.slack.threadTs,userId:n.userId,userName:n.userName}):null}async function defaultOnAppMention(e,t){return await e.thread.startTyping(`Thinking...`),{auth:defaultSlackAuth(t,e)}}async function defaultOnDirectMessage(e,t){return await e.thread.startTyping(`Thinking...`),{auth:defaultSlackAuth(t,e)}}function firstNonEmptyLine(e){for(let t of e.split(/\r?\n/u)){let e=t.trim();if(e.length>0)return e}}function defaultInputRequestedHandler(){return async(e,t,n)=>{if(e.requests.length===0)return;let i=truncateMessageText(e.requests.map(e=>e.prompt).join(`
2
2
  `));await t.thread.post({blocks:e.requests.flatMap(renderInputRequestBlocks),text:i})}}const defaultEvents={async"turn.started"(e,t,n){t.state.pendingToolCallMessage=null,t.state.lastReasoningTypingAtMs=null,t.state.lastReasoningTypingStatus=null,await t.thread.startTyping(`Working...`)},async"reasoning.appended"(e,t,n){let r=firstNonEmptyLine(e.reasoningSoFar);if(r===void 0)return;let a=truncateTypingStatus(r),o=t.state.lastReasoningTypingStatus,s=o!=null&&a.startsWith(o)&&a.length>=o.length+4,c=Date.now(),l=t.state.lastReasoningTypingAtMs;if(!s&&l!=null){let e=c-l;if(e>=0&&e<5e3)return}await t.thread.startTyping(a),t.state.lastReasoningTypingAtMs=c,t.state.lastReasoningTypingStatus=a},async"actions.requested"(e,t,n){let r=t.state.pendingToolCallMessage;if(t.state.pendingToolCallMessage=null,r){await t.thread.startTyping(truncateTypingStatus(r));return}let a=e.actions.map(e=>e.kind===`tool-call`?e.toolName:e.kind);await t.thread.startTyping(truncateTypingStatus(`Running ${a.join(`, `)}...`))},async"message.completed"(e,t,n){if(e.finishReason===`tool-calls`){t.state.pendingToolCallMessage=e.message?firstNonEmptyLine(e.message)??null:null;return}t.state.pendingToolCallMessage=null,e.message&&await t.thread.post(e.message)},async"turn.failed"(e,r,i){let a=formatErrorHint(e),o=extractErrorId(e.details);await r.thread.post([`I hit an error while handling your request${a}.`,``,`Please try again, rephrase, or reach out if it keeps failing.`,...o?[``,`_Error id: \`${o}\`_`]:[]].join(`
3
3
  `))},async"session.failed"(e,r){let i=formatErrorHint(e),a=extractErrorId(e.details);await r.thread.post([`This session couldn't recover from an error${i}.`,``,`Start a new thread to continue — I can't pick this one back up.`,...a?[``,`_Error id: \`${a}\`_`]:[]].join(`
4
- `))},async"authorization.required"(e,t,n){let r=e.authorization?.displayName??formatConnectionDisplayName(e.name),i=t.state.triggeringUserId??null,a=e.authorization?.url;if(i&&a){let n=e.authorization?.userCode;try{await t.thread.postEphemeral(i,{blocks:buildAuthEphemeralBlocks({displayName:r,url:a,userCode:n}),text:n?`Sign in with ${r}: ${a} (code: ${n})`:`Sign in with ${r}: ${a}`});return}catch(t){log.error(`Slack auth ephemeral delivery failed`,{name:e.name,error:t})}}let o=buildAuthRequiredPublicText({displayName:r,hasUser:i!==null});try{let n=await t.thread.post(o);n.id&&(t.state.pendingAuthMessageTs={...t.state.pendingAuthMessageTs,[e.name]:n.id})}catch(t){log.error(`Slack auth public message delivery failed`,{name:e.name,error:t})}},async"authorization.completed"(e,t,n){let r=t.state.pendingAuthMessageTs??{},i=r[e.name];if(i===void 0)return;let a=buildAuthCompletedText({displayName:e.authorization?.displayName??formatConnectionDisplayName(e.name),outcome:e.outcome,reason:e.reason});try{await t.slack.request(`chat.update`,{channel:t.slack.channelId,ts:i,text:a})}catch(t){log.error(`Slack auth status edit failed`,{name:e.name,error:t})}let s={...r};delete s[e.name],t.state.pendingAuthMessageTs=s}};export{defaultEvents,defaultInputRequestedHandler,defaultOnAppMention,defaultOnDirectMessage,defaultSlackAuth};
4
+ `))},async"authorization.required"(e,t,n){let r=e.authorization?.displayName??formatConnectionDisplayName(e.name),i=t.state.triggeringUserId??null,a=e.authorization?.url,o=t.state.pendingAuthMessageTs??{};if(o[e.name]===void 0){let n=buildAuthRequiredPublicText({displayName:r,hasUser:i!==null});try{let r=await t.thread.post(n);r.id&&(t.state.pendingAuthMessageTs={...o,[e.name]:r.id})}catch(t){log.error(`Slack auth public message delivery failed`,{name:e.name,error:t})}}if(i&&a){let n=e.authorization?.userCode;try{await t.thread.postEphemeral(i,{blocks:buildAuthEphemeralBlocks({displayName:r,url:a,userCode:n}),text:n?`Sign in with ${r}: ${a} (code: ${n})`:`Sign in with ${r}: ${a}`})}catch(t){log.error(`Slack auth ephemeral delivery failed`,{name:e.name,error:t})}}},async"authorization.completed"(e,t,n){let r=t.state.pendingAuthMessageTs??{},i=r[e.name];if(i===void 0)return;let a=buildAuthCompletedText({displayName:e.authorization?.displayName??formatConnectionDisplayName(e.name),outcome:e.outcome,reason:e.reason});try{await t.slack.request(`chat.update`,{channel:t.slack.channelId,ts:i,text:a})}catch(t){log.error(`Slack auth status edit failed`,{name:e.name,error:t})}let s={...r};delete s[e.name],t.state.pendingAuthMessageTs=s}};export{defaultEvents,defaultInputRequestedHandler,defaultOnAppMention,defaultOnDirectMessage,defaultSlackAuth};
@@ -116,11 +116,10 @@ export interface SlackChannelState {
116
116
  lastReasoningTypingStatus?: string | null;
117
117
  /**
118
118
  * Connection name to Slack message ts. Each entry is the public
119
- * link-free fallback status post created by the default
120
- * `authorization.required` handler when the challenge could not be
121
- * delivered ephemerally; the matching `authorization.completed`
122
- * handler edits it in place to surface the resolution outcome. The
123
- * normal ephemeral path stores nothing here.
119
+ * link-free status post created by the default
120
+ * `authorization.required` handler; the matching
121
+ * `authorization.completed` handler edits it in place to surface the
122
+ * resolution outcome.
124
123
  */
125
124
  pendingAuthMessageTs?: Record<string, string>;
126
125
  }
@@ -272,8 +271,8 @@ export interface SlackChannelEvents {
272
271
  * Full-context variant of {@link SlackChannelEvents} consumed by the
273
272
  * channel internals. The framework's default `authorization.required`
274
273
  * handler keeps the full {@link SlackEventContext} because it owns the
275
- * public link-free fallback for sessions with no user to target
276
- * privately. The factory adapts user overrides into this shape with
274
+ * public link-free status while user overrides remain private-only. The
275
+ * factory adapts user overrides into this shape with
277
276
  * {@link constrainAuthorizationRequired}.
278
277
  */
279
278
  export interface SlackChannelInternalEvents extends Omit<SlackChannelEvents, "authorization.required"> {
@@ -2,7 +2,7 @@ import type { StandardJSONSchemaV1 } from "#compiled/@standard-schema/spec/index
2
2
  import type { PublicToolDefinition, ToolModelOutput } from "#shared/tool-definition.js";
3
3
  import type { SessionContext } from "#public/definitions/callback-context.js";
4
4
  import type { JsonObject } from "#shared/json.js";
5
- import type { AuthorizationDefinition, NonInteractiveAuthorizationDefinition, TokenResult } from "#runtime/connections/types.js";
5
+ import type { AuthorizationDefinition, ConnectionAuthorizationContext, NonInteractiveAuthorizationDefinition, TokenResult } from "#runtime/connections/types.js";
6
6
  import { type DynamicEvents, type DynamicSentinel } from "#shared/dynamic-tool-definition.js";
7
7
  type ApprovalToolInput<TInput> = TInput extends object ? Readonly<TInput> : TInput;
8
8
  type ApprovalContextInput<TInput> = unknown extends TInput ? Record<string, unknown> : TInput;
@@ -21,45 +21,62 @@ export interface NeedsApprovalContext<TInput = Record<string, unknown>> {
21
21
  }
22
22
  export type { ToolModelOutput } from "#shared/tool-definition.js";
23
23
  /**
24
- * Authorization strategy declared on a {@link ToolDefinition} via the
25
- * `auth` field. Accepts the same shapes as a connection's `auth`:
24
+ * Authorization provider passed to {@link ToolContext.getToken} or
25
+ * {@link ToolContext.requireAuth}. Accepts the same shapes as a connection's
26
+ * `auth`:
26
27
  * - a `getToken`-only object (static API keys, pre-provisioned JWTs);
27
28
  * `principalType` may be omitted and defaults to `"app"`.
28
- * - a full interactive OAuth definition (e.g. `connect("okta")` from
29
+ * - a full interactive OAuth definition (e.g. `connect("okta/myagent")` from
29
30
  * `@vercel/connect/eve`, or {@link defineInteractiveAuthorization}).
30
31
  */
31
32
  export type ToolAuthDefinition = (Omit<NonInteractiveAuthorizationDefinition, "principalType"> & {
32
33
  readonly principalType?: NonInteractiveAuthorizationDefinition["principalType"];
33
34
  }) | AuthorizationDefinition;
35
+ export type ToolAuthProvider = ToolAuthDefinition;
36
+ /**
37
+ * Controls Eve runtime behavior for an inline tool auth provider.
38
+ */
39
+ export interface ToolAuthOptions {
40
+ /**
41
+ * Connection metadata passed through to provider callbacks. Tool-only
42
+ * providers usually leave this unset; connection-backed helpers can use it
43
+ * to receive the upstream server URL.
44
+ */
45
+ readonly connection?: ConnectionAuthorizationContext;
46
+ /**
47
+ * Optional human-readable provider name shown in sign-in UI. Presentation
48
+ * only; it does not affect OAuth scopes, token cache keys, or callback URLs.
49
+ */
50
+ readonly displayName?: string;
51
+ /**
52
+ * Optional Eve auth-flow key for token caches, callback URLs, pending
53
+ * authorization state, and authorization completion. This is not an OAuth
54
+ * scope. For Vercel Connect OAuth targeting such as `scopes`, `resources`,
55
+ * or `authorizationDetails`, configure the provider with
56
+ * `connect({ connector, tokenParams })`.
57
+ */
58
+ readonly authKey?: string;
59
+ }
34
60
  /**
35
61
  * Authored tool context. Passed as the last argument to
36
62
  * {@link ToolDefinition.execute}.
37
63
  *
38
- * Extends {@link SessionContext} with token accessors. {@link getToken} and
39
- * {@link requireAuth} only do useful work when the tool declares `auth`;
40
- * calling them on a tool without `auth` throws.
64
+ * Extends {@link SessionContext} with token accessors. Passing a provider
65
+ * resolves that provider inline, which lets one tool use multiple credentials.
41
66
  */
42
67
  export type ToolContext = SessionContext & {
43
68
  /**
44
- * Resolves the bearer token for this tool's declared `auth`,
45
- * consulting the per-step token cache before invoking the authored
46
- * `getToken`. For interactive strategies a cache miss throws
47
- * `ConnectionAuthorizationRequiredError`; the runtime catches it,
48
- * suspends the turn on a framework-owned callback URL, shows a
49
- * "Sign in" affordance, and re-runs the tool after the OAuth
50
- * callback completes.
51
- *
52
- * Throws when the tool does not declare an `auth` strategy.
69
+ * Resolves the bearer token for an inline provider. This accepts the same
70
+ * auth shapes as a connection's `auth` field, including `connect("...")`
71
+ * from `@vercel/connect/eve`.
53
72
  */
54
- getToken(): Promise<TokenResult>;
73
+ getToken(provider: ToolAuthProvider, options?: ToolAuthOptions): Promise<TokenResult>;
55
74
  /**
56
- * Signals that the caller must complete this tool's authorization flow
57
- * before proceeding. Throws `ConnectionAuthorizationRequiredError`, which
58
- * the runtime converts into a consent prompt (for interactive strategies)
59
- * and re-runs the tool after sign-in. Use it to gate a tool on
60
- * authorization without resolving a token first.
75
+ * Signals that the caller must complete authorization for an inline
76
+ * provider before proceeding. Use this after a downstream `401` rejects a
77
+ * token returned by {@link getToken}.
61
78
  */
62
- requireAuth(): never;
79
+ requireAuth(provider: ToolAuthProvider, options?: ToolAuthOptions): never;
63
80
  };
64
81
  /**
65
82
  * Public tool definition authored in `agent/tools/*.ts`.
@@ -70,20 +87,6 @@ export type ToolContext = SessionContext & {
70
87
  */
71
88
  export type ToolDefinition<TInput = unknown, TOutput = unknown> = PublicToolDefinition<TInput, TOutput> & {
72
89
  execute(input: TInput, ctx: ToolContext): Promise<TOutput> | TOutput;
73
- /**
74
- * Optional authorization strategy. When set, the execute context gains a
75
- * working {@link ToolContext.getToken} / {@link ToolContext.requireAuth},
76
- * and a thrown `ConnectionAuthorizationRequiredError` (implicit from
77
- * `getToken()` or explicit via `requireAuth()`) drives the framework's
78
- * interactive consent flow, the same machinery MCP connections use, scoped
79
- * to this tool's name.
80
- *
81
- * Use `connect("...")` from `@vercel/connect/eve` for Vercel
82
- * Connect-backed OAuth, {@link defineInteractiveAuthorization} for a
83
- * custom interactive flow, or a plain `{ getToken }` object for
84
- * static/pre-provisioned credentials.
85
- */
86
- auth?: ToolAuthDefinition;
87
90
  /**
88
91
  * Optional per-tool approval gate. The return value determines whether
89
92
  * user approval is required before executing this tool.
@@ -120,7 +123,6 @@ export declare function defineTool<TInputSchema extends StandardJSONSchemaV1<unk
120
123
  execute(input: StandardJSONSchemaV1.InferOutput<TInputSchema>, ctx: ToolContext): Promise<StandardJSONSchemaV1.InferOutput<TOutputSchema>> | StandardJSONSchemaV1.InferOutput<TOutputSchema>;
121
124
  needsApproval?: ToolDefinition<StandardJSONSchemaV1.InferOutput<TInputSchema>, unknown>["needsApproval"];
122
125
  toModelOutput?: ToolDefinition<unknown, StandardJSONSchemaV1.InferOutput<TOutputSchema>>["toModelOutput"];
123
- auth?: ToolAuthDefinition;
124
126
  }): ToolDefinition<StandardJSONSchemaV1.InferOutput<TInputSchema>, StandardJSONSchemaV1.InferOutput<TOutputSchema>>;
125
127
  export declare function defineTool<TSchema extends StandardJSONSchemaV1<unknown, unknown>, TOutput>(definition: {
126
128
  description: ToolDefinition<unknown, unknown>["description"];
@@ -129,7 +131,6 @@ export declare function defineTool<TSchema extends StandardJSONSchemaV1<unknown,
129
131
  execute(input: StandardJSONSchemaV1.InferOutput<TSchema>, ctx: ToolContext): Promise<TOutput> | TOutput;
130
132
  needsApproval?: ToolDefinition<StandardJSONSchemaV1.InferOutput<TSchema>, unknown>["needsApproval"];
131
133
  toModelOutput?: ToolDefinition<unknown, TOutput>["toModelOutput"];
132
- auth?: ToolAuthDefinition;
133
134
  }): ToolDefinition<StandardJSONSchemaV1.InferOutput<TSchema>, TOutput>;
134
135
  export declare function defineTool<TOutputSchema extends StandardJSONSchemaV1<unknown, unknown>>(definition: {
135
136
  description: ToolDefinition<unknown, unknown>["description"];
@@ -138,7 +139,6 @@ export declare function defineTool<TOutputSchema extends StandardJSONSchemaV1<un
138
139
  execute(input: Record<string, unknown>, ctx: ToolContext): Promise<StandardJSONSchemaV1.InferOutput<TOutputSchema>> | StandardJSONSchemaV1.InferOutput<TOutputSchema>;
139
140
  needsApproval?: ToolDefinition<Record<string, unknown>, unknown>["needsApproval"];
140
141
  toModelOutput?: ToolDefinition<unknown, StandardJSONSchemaV1.InferOutput<TOutputSchema>>["toModelOutput"];
141
- auth?: ToolAuthDefinition;
142
142
  }): ToolDefinition<Record<string, unknown>, StandardJSONSchemaV1.InferOutput<TOutputSchema>>;
143
143
  export declare function defineTool<TOutput>(definition: {
144
144
  description: ToolDefinition<unknown, unknown>["description"];
@@ -147,7 +147,6 @@ export declare function defineTool<TOutput>(definition: {
147
147
  execute(input: Record<string, unknown>, ctx: ToolContext): Promise<TOutput> | TOutput;
148
148
  needsApproval?: ToolDefinition<Record<string, unknown>, unknown>["needsApproval"];
149
149
  toModelOutput?: ToolDefinition<unknown, TOutput>["toModelOutput"];
150
- auth?: ToolAuthDefinition;
151
150
  }): ToolDefinition<Record<string, unknown>, TOutput>;
152
151
  export declare function defineTool<TInput = unknown, TOutput = unknown>(definition: ToolDefinition<TInput, TOutput>): ToolDefinition<TInput, TOutput>;
153
152
  /**
@@ -1 +1 @@
1
- import{DYNAMIC_SENTINEL_KIND,TOOL_BRAND}from"#shared/dynamic-tool-definition.js";import{normalizeAuthorizationSpec}from"#runtime/connections/validate-authorization.js";import{stampDefinitionKey}from"#public/tool-result-narrowing.js";function defineTool(e){return e.auth!==void 0&&(e.auth=normalizeAuthorizationSpec(e.auth,`defineTool:`)),Object.assign(e,{[TOOL_BRAND]:!0}),stampDefinitionKey(e,`tool:${e.description}`),e}function defineDynamic(t){let n={kind:DYNAMIC_SENTINEL_KIND,events:t.events};return stampDefinitionKey(n,`dynamic:${Object.keys(t.events).join(`,`)}`),n}const DISABLED_TOOL_SENTINEL_KIND=`eve:disabled-tool`;function disableTool(){return{kind:DISABLED_TOOL_SENTINEL_KIND}}function isDisabledToolSentinel(e){return typeof e==`object`&&!!e&&e.kind===DISABLED_TOOL_SENTINEL_KIND}const ENABLE_WORKFLOW_TOOL_SENTINEL_KIND=`eve:enable-workflow-tool`,ExperimentalWorkflow=Object.freeze({kind:ENABLE_WORKFLOW_TOOL_SENTINEL_KIND});function isEnableWorkflowToolSentinel(e){return typeof e==`object`&&!!e&&e.kind===ENABLE_WORKFLOW_TOOL_SENTINEL_KIND}export{ExperimentalWorkflow,defineDynamic,defineTool,disableTool,isDisabledToolSentinel,isEnableWorkflowToolSentinel};
1
+ import{DYNAMIC_SENTINEL_KIND,TOOL_BRAND}from"#shared/dynamic-tool-definition.js";import{stampDefinitionKey}from"#public/tool-result-narrowing.js";function defineTool(e){if(e.auth!==void 0)throw Error(`defineTool: The "auth" field is no longer supported. Pass auth providers inline to ctx.getToken(provider) or ctx.requireAuth(provider).`);return Object.assign(e,{[TOOL_BRAND]:!0}),stampDefinitionKey(e,`tool:${e.description}`),e}function defineDynamic(t){let n={kind:DYNAMIC_SENTINEL_KIND,events:t.events};return stampDefinitionKey(n,`dynamic:${Object.keys(t.events).join(`,`)}`),n}const DISABLED_TOOL_SENTINEL_KIND=`eve:disabled-tool`;function disableTool(){return{kind:DISABLED_TOOL_SENTINEL_KIND}}function isDisabledToolSentinel(e){return typeof e==`object`&&!!e&&e.kind===DISABLED_TOOL_SENTINEL_KIND}const ENABLE_WORKFLOW_TOOL_SENTINEL_KIND=`eve:enable-workflow-tool`,ExperimentalWorkflow=Object.freeze({kind:ENABLE_WORKFLOW_TOOL_SENTINEL_KIND});function isEnableWorkflowToolSentinel(e){return typeof e==`object`&&!!e&&e.kind===ENABLE_WORKFLOW_TOOL_SENTINEL_KIND}export{ExperimentalWorkflow,defineDynamic,defineTool,disableTool,isDisabledToolSentinel,isEnableWorkflowToolSentinel};
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Tool authoring helpers for `agent/tools/*.ts` files.
3
3
  */
4
- export { type DisabledToolSentinel, type EnableWorkflowToolSentinel, defineDynamic, defineTool, disableTool, isDisabledToolSentinel, isEnableWorkflowToolSentinel, type NeedsApprovalContext, type ToolDefinition, type ToolContext, type ToolModelOutput, ExperimentalWorkflow, } from "#public/definitions/tool.js";
4
+ export { type DisabledToolSentinel, type EnableWorkflowToolSentinel, defineDynamic, defineTool, disableTool, isDisabledToolSentinel, isEnableWorkflowToolSentinel, type NeedsApprovalContext, type ToolAuthOptions, type ToolAuthProvider, type ToolDefinition, type ToolContext, type ToolModelOutput, ExperimentalWorkflow, } from "#public/definitions/tool.js";
5
5
  export type { DynamicToolEntry, DynamicEvents, DynamicToolEvents, DynamicResolveContext, DynamicSentinel, DynamicToolSet, DynamicToolResult, } from "#shared/dynamic-tool-definition.js";
6
6
  export { type SessionContext } from "#public/definitions/callback-context.js";
7
7
  export { toolResultFrom, type MatchedConnectionResult, type MatchedToolResult, type ToolResultFromFn, } from "#public/tool-result-narrowing.js";
@@ -1 +1 @@
1
- import{contextStorage,loadContext}from"#context/container.js";import{supportsInteractiveAuthorization}from"#runtime/connections/types.js";import{getAuthorizationResult,getHookUrl,requestAuthorization}from"#harness/authorization.js";import{evictCachedToken,readCachedToken,writeCachedToken}from"#runtime/connections/authorization-tokens.js";import{principalKey,resolveConnectionPrincipal}from"#runtime/connections/principal.js";async function resolveScopedToken(t){let{scope:n,authorization:r,connection:i}=t,a=contextStorage.getStore(),o=resolveConnectionPrincipal(n,r,a);if(a===void 0)return await r.getToken({connection:i,principal:o});let u=principalKey(o),d=readCachedToken(a,n,u);if(d!==void 0)return d;let f=await r.getToken({connection:i,principal:o});return writeCachedToken(a,n,u,f),f}async function evictScopedToken(t){let{scope:n,authorization:r,connection:i}=t,a=contextStorage.getStore();if(a===void 0)return;let s;try{s=resolveConnectionPrincipal(n,r,a),evictCachedToken(a,n,principalKey(s))}catch{return}try{await r.evict?.({connection:i,principal:s})}catch{}}async function completeScopedAuthorization(e){let{scope:i,authorization:a,connection:o}=e;if(!supportsInteractiveAuthorization(a))return!1;let s=getAuthorizationResult(i);if(s===void 0)return!1;let u=a,d=loadContext(),f=resolveConnectionPrincipal(i,u,d),p=await u.completeAuthorization({callbackUrl:s.hookUrl,connection:o,principal:f,resume:s.resume,callback:s.callback});return writeCachedToken(d,i,principalKey(f),p),!0}async function startScopedAuthorization(e){let{scope:t,authorization:r,connection:o}=e;if(!supportsInteractiveAuthorization(r))return;let s=getHookUrl(t);if(s===void 0)return;let c=r,l=resolveConnectionPrincipal(t,c),{challenge:u,resume:d}=await c.startAuthorization({callbackUrl:s,connection:o,principal:l});return requestAuthorization([{challenge:stampChallengeDisplayName(u,r),hookUrl:s,name:t,resume:d}])}function stampChallengeDisplayName(e,t){let n=t.displayName??e.displayName;return n===e.displayName?e:{...e,displayName:n}}export{completeScopedAuthorization,evictScopedToken,resolveScopedToken,stampChallengeDisplayName,startScopedAuthorization};
1
+ import{contextStorage,loadContext}from"#context/container.js";import{getAuthorizationResult,getHookUrl,requestAuthorization}from"#harness/authorization.js";import{supportsInteractiveAuthorization}from"#runtime/connections/types.js";import{evictCachedToken,readCachedToken,writeCachedToken}from"#runtime/connections/authorization-tokens.js";import{principalKey,resolveConnectionPrincipal}from"#runtime/connections/principal.js";async function resolveScopedToken(t){let{scope:n,authorization:r,connection:i}=t,a=contextStorage.getStore(),o=resolveConnectionPrincipal(n,r,a);if(a===void 0)return await r.getToken({connection:i,principal:o});let u=principalKey(o),d=readCachedToken(a,n,u);if(d!==void 0)return d;let f=await r.getToken({connection:i,principal:o});return writeCachedToken(a,n,u,f),f}async function evictScopedToken(t){let{scope:n,authorization:r,connection:i}=t,a=contextStorage.getStore();if(a===void 0)return;let s;try{s=resolveConnectionPrincipal(n,r,a),evictCachedToken(a,n,principalKey(s))}catch{return}try{await r.evict?.({connection:i,principal:s})}catch{}}async function completeScopedAuthorization(e){let{scope:r,authorization:i,connection:o}=e;if(!supportsInteractiveAuthorization(i))return!1;let s=getAuthorizationResult(r);if(s===void 0)return!1;let u=i,d=loadContext(),f=resolveConnectionPrincipal(r,u,d),p=await u.completeAuthorization({callbackUrl:s.hookUrl,connection:o,principal:f,resume:s.resume,callback:s.callback});return writeCachedToken(d,r,principalKey(f),p),!0}async function startScopedAuthorization(e){let{scope:t,authorization:n,connection:o}=e;if(!supportsInteractiveAuthorization(n))return;let s=getHookUrl(t);if(s===void 0)return;let c=n,l=resolveConnectionPrincipal(t,c),{challenge:u,resume:d}=await c.startAuthorization({callbackUrl:s,connection:o,principal:l});return requestAuthorization([{challenge:stampChallengeDisplayName(u,n),hookUrl:s,name:t,resume:d}])}function stampChallengeDisplayName(e,t){let n=t.displayName??e.displayName;return n===e.displayName?e:{...e,displayName:n}}export{completeScopedAuthorization,evictScopedToken,resolveScopedToken,stampChallengeDisplayName,startScopedAuthorization};
@@ -1 +1 @@
1
- function validateAuthorizationSpec(e,t=`auth`){if(typeof e!=`object`||!e)return`The "${t}" field must be an object with a "getToken" method.`;let n=e;if(typeof n.getToken!=`function`)return`The "${t}.getToken" field must be a function returning Promise<{ token }>.`;let r=n.startAuthorization!==void 0,i=n.completeAuthorization!==void 0;if(!r&&!i&&n.principalType!==void 0&&n.principalType!==`app`&&n.principalType!==`user`)return`The "${t}.principalType" field must be "app" or "user".`;if(r!==i)return`The "${t}" field must provide either both "startAuthorization" and "completeAuthorization" (interactive OAuth) or neither (getToken-only). Got only "${r?`startAuthorization`:`completeAuthorization`}".`;if(r&&typeof n.startAuthorization!=`function`)return`The "${t}.startAuthorization" field must be a function when provided.`;if(i&&typeof n.completeAuthorization!=`function`)return`The "${t}.completeAuthorization" field must be a function when provided.`;if(r&&n.principalType!==`user`)return`Interactive authorization (startAuthorization + completeAuthorization) is restricted to "principalType": "user" in v1. App-level credentials must use a getToken-only definition.`;if(n.displayName!==void 0&&(typeof n.displayName!=`string`||n.displayName.length===0))return`The "${t}.displayName" field must be a non-empty string when provided.`}function normalizeAuthorizationSpec(e,t,n=`auth`){let r=validateAuthorizationSpec(e,n);if(r!==void 0)throw Error(`${t} ${r}`);let i=e,a=extractVercelConnectMarker(i.vercelConnect),o=i.displayName;if(i.startAuthorization!==void 0&&i.completeAuthorization!==void 0){let e={completeAuthorization:i.completeAuthorization,getToken:i.getToken,principalType:`user`,startAuthorization:i.startAuthorization};return a!==void 0&&(e={...e,vercelConnect:a}),o!==void 0&&(e={...e,displayName:o}),e}let s={getToken:i.getToken,principalType:i.principalType??`app`};return a!==void 0&&(s={...s,vercelConnect:a}),o!==void 0&&(s={...s,displayName:o}),s}function extractVercelConnectMarker(e){if(typeof e!=`object`||!e)return;let t=e.connector;if(!(typeof t!=`string`||t.length===0))return{connector:t}}export{normalizeAuthorizationSpec,validateAuthorizationSpec};
1
+ function validateAuthorizationSpec(e,t=`auth`){if(typeof e!=`object`||!e)return`The "${t}" field must be an object with a "getToken" method.`;let n=e;if(typeof n.getToken!=`function`)return`The "${t}.getToken" field must be a function returning Promise<{ token }>.`;let r=n.startAuthorization!==void 0,i=n.completeAuthorization!==void 0;if(!r&&!i&&n.principalType!==void 0&&n.principalType!==`app`&&n.principalType!==`user`)return`The "${t}.principalType" field must be "app" or "user".`;if(r!==i)return`The "${t}" field must provide either both "startAuthorization" and "completeAuthorization" (interactive OAuth) or neither (getToken-only). Got only "${r?`startAuthorization`:`completeAuthorization`}".`;if(r&&typeof n.startAuthorization!=`function`)return`The "${t}.startAuthorization" field must be a function when provided.`;if(i&&typeof n.completeAuthorization!=`function`)return`The "${t}.completeAuthorization" field must be a function when provided.`;if(r&&n.principalType!==`user`)return`Interactive authorization (startAuthorization + completeAuthorization) is restricted to "principalType": "user" in v1. App-level credentials must use a getToken-only definition.`;if(n.displayName!==void 0&&(typeof n.displayName!=`string`||n.displayName.length===0))return`The "${t}.displayName" field must be a non-empty string when provided.`}function normalizeAuthorizationSpec(e,t,n=`auth`){let r=validateAuthorizationSpec(e,n);if(r!==void 0)throw Error(`${t} ${r}`);let i=e,a=extractVercelConnectMarker(i.vercelConnect),o=i.displayName,s=typeof i.evict==`function`?i.evict:void 0;if(i.startAuthorization!==void 0&&i.completeAuthorization!==void 0){let e={completeAuthorization:i.completeAuthorization,getToken:i.getToken,principalType:`user`,startAuthorization:i.startAuthorization};return a!==void 0&&(e={...e,vercelConnect:a}),o!==void 0&&(e={...e,displayName:o}),s!==void 0&&(e={...e,evict:s}),e}let c={getToken:i.getToken,principalType:i.principalType??`app`};return a!==void 0&&(c={...c,vercelConnect:a}),o!==void 0&&(c={...c,displayName:o}),s!==void 0&&(c={...c,evict:s}),c}function extractVercelConnectMarker(e){if(typeof e!=`object`||!e)return;let t=e.connector;if(!(typeof t!=`string`||t.length===0))return{connector:t}}export{normalizeAuthorizationSpec,validateAuthorizationSpec};
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{loadContext}from"#context/container.js";import{ContextKey}from"#context/key.js";import{ConnectionRegistryKey}from"#context/providers/connection.js";import{ConnectionAuthorizationFailedError,isConnectionAuthorizationFailedError,isConnectionAuthorizationRequiredError}from"#public/connections/errors.js";import{supportsInteractiveAuthorization}from"#runtime/connections/types.js";import{stampChallengeDisplayName}from"#runtime/connections/scoped-authorization.js";import{getAuthorizationResult,getHookUrl,requestAuthorization}from"#harness/authorization.js";import{writeCachedToken}from"#runtime/connections/authorization-tokens.js";import{principalKey,resolveConnectionPrincipal}from"#runtime/connections/principal.js";const logger=createLogger(`framework.connection-search-dynamic`),CONNECTION_SEARCH_OUTPUT_SCHEMA={items:{additionalProperties:!1,properties:{connection:{type:`string`},description:{type:`string`},error:{type:`string`},inputSchema:{type:`object`},needsAuthorization:{type:`boolean`},outputSchema:{type:`object`},qualifiedName:{type:`string`},tool:{type:`string`}},required:[`connection`,`description`],type:`object`},type:`array`},ConnectionSearchResultsKey=new ContextKey(`eve.connectionSearchResults`);function qualifiedConnectionToolName(e,t){return`${e}__${t}`}function tokenize(e){return e.toLowerCase().split(/[\s_\-./]+/).filter(e=>e.length>1)}function scoreMatch(e,t){let n=tokenize(t.name),r=tokenize(t.description),i=0;for(let t of e){for(let e of n)(e.includes(t)||t.includes(e))&&(i+=3);for(let e of r)(e.includes(t)||t.includes(e))&&(i+=1)}return i}function resolveInteractiveAuth(e,t){let n=e.getConnections().find(e=>e.connectionName===t);if(n?.authorization&&supportsInteractiveAuthorization(n.authorization))return n.authorization}async function completePendingAuthorizations(e){let n=loadContext(),r=new Set;for(let t of e.getConnections()){let i=getAuthorizationResult(t.connectionName);if(!i)continue;let a=resolveInteractiveAuth(e,t.connectionName);if(!a)continue;let o=resolveConnectionPrincipal(t.connectionName,a),s=await a.completeAuthorization({callbackUrl:i.hookUrl,connection:{url:t.url??``},principal:o,resume:i.resume,callback:i.callback});writeCachedToken(n,t.connectionName,principalKey(o),s),r.add(t.connectionName)}return r}async function executeConnectionSearch(e){let n=loadContext(),i=n.get(ConnectionRegistryKey);if(i===void 0)return[];let s=await completePendingAuthorizations(i),c=e.limit??10,l=tokenize(e.keywords),u=[],f=[],m=e.connection!==void 0&&e.connection!==``?i.getConnections().filter(t=>t.connectionName===e.connection):i.getConnections(),h=[];for(let e of m){let t;try{t=await i.getClient(e.connectionName).getToolMetadata()}catch(t){if(isConnectionAuthorizationRequiredError(t)){if(s.has(e.connectionName)){logger.warn(`connection still unauthorized after authorization`,{connection:e.connectionName}),f.push({connection:e.connectionName,description:e.description,error:`Authorization for "${e.connectionName}" did not take effect; the token was rejected after sign-in.`});continue}let t=resolveInteractiveAuth(i,e.connectionName);if(t){let n=getHookUrl(e.connectionName);if(n){let r=resolveConnectionPrincipal(e.connectionName,t);try{let{challenge:i,resume:a}=await t.startAuthorization({callbackUrl:n,connection:{url:e.url??``},principal:r});h.push({name:e.connectionName,challenge:stampChallengeDisplayName(i,t),hookUrl:n,resume:a})}catch(t){logger.warn(`startAuthorization failed`,{connection:e.connectionName,error:t instanceof Error?t:Error(String(t))})}}}f.push({connection:e.connectionName,description:e.description,needsAuthorization:!0});continue}if(isConnectionAuthorizationFailedError(t)){logger.warn(`connection authorization failed`,{connection:e.connectionName,reason:t.reason,retryable:t.retryable,error:t}),f.push({connection:e.connectionName,description:e.description,error:`Authorization failed for ${e.connectionName}: ${t.message}`});continue}let n=t instanceof Error?t.message:`unknown error`;logger.warn(`failed to load connection tools`,{connection:e.connectionName,error:t instanceof Error?t:Error(n)}),f.push({connection:e.connectionName,description:e.description,error:`Failed to load tools for "${e.connectionName}": ${n}`});continue}for(let n of t){let t=scoreMatch(l,n);t>0&&u.push({item:{connection:e.connectionName,description:n.description,inputSchema:n.inputSchema,outputSchema:n.outputSchema,qualifiedName:qualifiedConnectionToolName(e.connectionName,n.name),tool:n.name},score:t})}}if(h.length>0)return requestAuthorization(h);u.sort((e,t)=>t.score-e.score);let g=u.slice(0,c).map(e=>e.item);if(g.length>0){let e=[...g,...f],t=n.get(ConnectionSearchResultsKey)??[],r=new Map(t.map(e=>[e.qualifiedName,e]));for(let e of g)e.qualifiedName&&r.set(e.qualifiedName,e);return n.set(ConnectionSearchResultsKey,[...r.values()]),e}return m.map(e=>f.find(t=>t.connection===e.connectionName)||{connection:e.connectionName,description:e.description})}function extractDiscoveredTools(e){let t=new Map;for(let n of e){if(n.role!==`tool`)continue;let e=n.content;for(let n of e){if(n.type!==`tool-result`||n.toolName!==`connection_search`)continue;let e=n.output;if(e==null)continue;let r=typeof e==`object`&&`type`in e&&`value`in e?e.value:e;if(Array.isArray(r))for(let e of r)e.tool&&e.qualifiedName&&t.set(e.qualifiedName,e)}}return[...t.values()]}function createConnectionSearchEvents(){return{"step.started":async(e,n)=>{let a=loadContext().get(ConnectionRegistryKey);if(!a||a.getConnections().length===0)return null;let d=a.getConnections().map(e=>e.connectionName),m=extractDiscoveredTools(n.messages),h=loadContext().get(ConnectionSearchResultsKey)??[],g=new Map;for(let e of h)e.qualifiedName&&g.set(e.qualifiedName,e);for(let e of m)e.qualifiedName&&g.set(e.qualifiedName,e);let _=[...g.values()],v={};v.connection_search={description:`Search for tools across your connections. Discovered tools become directly callable by their qualified name (e.g. \`linear__list_issues\`) in your next response. Available connections: ${d.join(`, `)}.`,inputSchema:{type:`object`,additionalProperties:!1,properties:{keywords:{description:`Search keywords and expanded aliases. Distill intent into keywords; avoid stop words like 'a', 'the', 'in'.`,type:`string`},connection:{description:`Optional: limit search to a specific connection name.`,type:`string`},limit:{description:`Max results to return. Default 10.`,type:`number`}},required:[`keywords`]},async execute(e){return executeConnectionSearch(e)},outputSchema:CONNECTION_SEARCH_OUTPUT_SCHEMA};for(let e of _){let n=e.connection,d=e.tool,f=a.getConnectionApproval(n);v[qualifiedConnectionToolName(n,d)]={description:e.description,inputSchema:e.inputSchema??{type:`object`},needsApproval:f,outputSchema:e.outputSchema,async execute(e){let a=loadContext().get(ConnectionRegistryKey),f=a.getConnections().find(e=>e.connectionName===n),p=f?.authorization&&supportsInteractiveAuthorization(f.authorization)?f.authorization:void 0,m=!1;if(p){let e=getAuthorizationResult(n);if(e){m=!0;let r=loadContext(),i=resolveConnectionPrincipal(n,p),a=await p.completeAuthorization({callbackUrl:e.hookUrl,connection:{url:f?.url??``},principal:i,resume:e.resume,callback:e.callback});writeCachedToken(r,n,principalKey(i),a)}}try{return await a.getClient(n).executeTool(d,e)}catch(e){if(!isConnectionAuthorizationRequiredError(e)||!p)throw e;if(m)throw new ConnectionAuthorizationFailedError(n,{retryable:!1,reason:`token_rejected_after_authorization`,message:`Connection "${n}" rejected the token immediately after authorization.`});let t=getHookUrl(n);if(!t)throw e;let r=resolveConnectionPrincipal(n,p),{challenge:a,resume:s}=await p.startAuthorization({callbackUrl:t,connection:{url:f?.url??``},principal:r});return requestAuthorization([{name:n,challenge:stampChallengeDisplayName(a,p),hookUrl:t,resume:s}])}}}}return v}}}function createConnectionSearchResolver(){let e=createConnectionSearchEvents();return{slug:`connection`,eventNames:Object.keys(e),events:e,sourceId:`eve:connection-search-dynamic`,sourceKind:`module`,logicalPath:`eve:framework/connection-search-dynamic`}}export{createConnectionSearchEvents,createConnectionSearchResolver,extractDiscoveredTools};
1
+ import{createLogger}from"#internal/logging.js";import{loadContext}from"#context/container.js";import{ContextKey}from"#context/key.js";import{ConnectionRegistryKey}from"#context/providers/connection.js";import{ConnectionAuthorizationFailedError,isConnectionAuthorizationFailedError,isConnectionAuthorizationRequiredError}from"#public/connections/errors.js";import{getAuthorizationResult,getHookUrl,requestAuthorization}from"#harness/authorization.js";import{supportsInteractiveAuthorization}from"#runtime/connections/types.js";import{stampChallengeDisplayName}from"#runtime/connections/scoped-authorization.js";import{writeCachedToken}from"#runtime/connections/authorization-tokens.js";import{principalKey,resolveConnectionPrincipal}from"#runtime/connections/principal.js";const logger=createLogger(`framework.connection-search-dynamic`),CONNECTION_SEARCH_OUTPUT_SCHEMA={items:{additionalProperties:!1,properties:{connection:{type:`string`},description:{type:`string`},error:{type:`string`},inputSchema:{type:`object`},needsAuthorization:{type:`boolean`},outputSchema:{type:`object`},qualifiedName:{type:`string`},tool:{type:`string`}},required:[`connection`,`description`],type:`object`},type:`array`},ConnectionSearchResultsKey=new ContextKey(`eve.connectionSearchResults`);function qualifiedConnectionToolName(e,t){return`${e}__${t}`}function tokenize(e){return e.toLowerCase().split(/[\s_\-./]+/).filter(e=>e.length>1)}function scoreMatch(e,t){let n=tokenize(t.name),r=tokenize(t.description),i=0;for(let t of e){for(let e of n)(e.includes(t)||t.includes(e))&&(i+=3);for(let e of r)(e.includes(t)||t.includes(e))&&(i+=1)}return i}function resolveInteractiveAuth(e,t){let n=e.getConnections().find(e=>e.connectionName===t);if(n?.authorization&&supportsInteractiveAuthorization(n.authorization))return n.authorization}async function completePendingAuthorizations(e){let n=loadContext(),r=new Set;for(let t of e.getConnections()){let i=getAuthorizationResult(t.connectionName);if(!i)continue;let a=resolveInteractiveAuth(e,t.connectionName);if(!a)continue;let o=resolveConnectionPrincipal(t.connectionName,a),c=await a.completeAuthorization({callbackUrl:i.hookUrl,connection:{url:t.url??``},principal:o,resume:i.resume,callback:i.callback});writeCachedToken(n,t.connectionName,principalKey(o),c),r.add(t.connectionName)}return r}async function executeConnectionSearch(e){let n=loadContext(),i=n.get(ConnectionRegistryKey);if(i===void 0)return[];let s=await completePendingAuthorizations(i),l=e.limit??10,u=tokenize(e.keywords),d=[],p=[],h=e.connection!==void 0&&e.connection!==``?i.getConnections().filter(t=>t.connectionName===e.connection):i.getConnections(),g=[];for(let e of h){let t;try{t=await i.getClient(e.connectionName).getToolMetadata()}catch(t){if(isConnectionAuthorizationRequiredError(t)){if(s.has(e.connectionName)){logger.warn(`connection still unauthorized after authorization`,{connection:e.connectionName}),p.push({connection:e.connectionName,description:e.description,error:`Authorization for "${e.connectionName}" did not take effect; the token was rejected after sign-in.`});continue}let t=resolveInteractiveAuth(i,e.connectionName);if(t){let n=getHookUrl(e.connectionName);if(n){let r=resolveConnectionPrincipal(e.connectionName,t);try{let{challenge:i,resume:a}=await t.startAuthorization({callbackUrl:n,connection:{url:e.url??``},principal:r});g.push({name:e.connectionName,challenge:stampChallengeDisplayName(i,t),hookUrl:n,resume:a})}catch(t){logger.warn(`startAuthorization failed`,{connection:e.connectionName,error:t instanceof Error?t:Error(String(t))})}}}p.push({connection:e.connectionName,description:e.description,needsAuthorization:!0});continue}if(isConnectionAuthorizationFailedError(t)){logger.warn(`connection authorization failed`,{connection:e.connectionName,reason:t.reason,retryable:t.retryable,error:t}),p.push({connection:e.connectionName,description:e.description,error:`Authorization failed for ${e.connectionName}: ${t.message}`});continue}let n=t instanceof Error?t.message:`unknown error`;logger.warn(`failed to load connection tools`,{connection:e.connectionName,error:t instanceof Error?t:Error(n)}),p.push({connection:e.connectionName,description:e.description,error:`Failed to load tools for "${e.connectionName}": ${n}`});continue}for(let n of t){let t=scoreMatch(u,n);t>0&&d.push({item:{connection:e.connectionName,description:n.description,inputSchema:n.inputSchema,outputSchema:n.outputSchema,qualifiedName:qualifiedConnectionToolName(e.connectionName,n.name),tool:n.name},score:t})}}if(g.length>0)return requestAuthorization(g);d.sort((e,t)=>t.score-e.score);let _=d.slice(0,l).map(e=>e.item);if(_.length>0){let e=[..._,...p],t=n.get(ConnectionSearchResultsKey)??[],r=new Map(t.map(e=>[e.qualifiedName,e]));for(let e of _)e.qualifiedName&&r.set(e.qualifiedName,e);return n.set(ConnectionSearchResultsKey,[...r.values()]),e}return h.map(e=>p.find(t=>t.connection===e.connectionName)||{connection:e.connectionName,description:e.description})}function extractDiscoveredTools(e){let t=new Map;for(let n of e){if(n.role!==`tool`)continue;let e=n.content;for(let n of e){if(n.type!==`tool-result`||n.toolName!==`connection_search`)continue;let e=n.output;if(e==null)continue;let r=typeof e==`object`&&`type`in e&&`value`in e?e.value:e;if(Array.isArray(r))for(let e of r)e.tool&&e.qualifiedName&&t.set(e.qualifiedName,e)}}return[...t.values()]}function createConnectionSearchEvents(){return{"step.started":async(e,n)=>{let a=loadContext().get(ConnectionRegistryKey);if(!a||a.getConnections().length===0)return null;let f=a.getConnections().map(e=>e.connectionName),h=extractDiscoveredTools(n.messages),g=loadContext().get(ConnectionSearchResultsKey)??[],_=new Map;for(let e of g)e.qualifiedName&&_.set(e.qualifiedName,e);for(let e of h)e.qualifiedName&&_.set(e.qualifiedName,e);let v=[..._.values()],y={};y.connection_search={description:`Search for tools across your connections. Discovered tools become directly callable by their qualified name (e.g. \`linear__list_issues\`) in your next response. Available connections: ${f.join(`, `)}.`,inputSchema:{type:`object`,additionalProperties:!1,properties:{keywords:{description:`Search keywords and expanded aliases. Distill intent into keywords; avoid stop words like 'a', 'the', 'in'.`,type:`string`},connection:{description:`Optional: limit search to a specific connection name.`,type:`string`},limit:{description:`Max results to return. Default 10.`,type:`number`}},required:[`keywords`]},async execute(e){return executeConnectionSearch(e)},outputSchema:CONNECTION_SEARCH_OUTPUT_SCHEMA};for(let e of v){let n=e.connection,f=e.tool,p=a.getConnectionApproval(n);y[qualifiedConnectionToolName(n,f)]={description:e.description,inputSchema:e.inputSchema??{type:`object`},needsApproval:p,outputSchema:e.outputSchema,async execute(e){let a=loadContext().get(ConnectionRegistryKey),p=a.getConnections().find(e=>e.connectionName===n),m=p?.authorization&&supportsInteractiveAuthorization(p.authorization)?p.authorization:void 0,h=!1;if(m){let e=getAuthorizationResult(n);if(e){h=!0;let r=loadContext(),i=resolveConnectionPrincipal(n,m),a=await m.completeAuthorization({callbackUrl:e.hookUrl,connection:{url:p?.url??``},principal:i,resume:e.resume,callback:e.callback});writeCachedToken(r,n,principalKey(i),a)}}try{return await a.getClient(n).executeTool(f,e)}catch(e){if(!isConnectionAuthorizationRequiredError(e)||!m)throw e;if(h)throw new ConnectionAuthorizationFailedError(n,{retryable:!1,reason:`token_rejected_after_authorization`,message:`Connection "${n}" rejected the token immediately after authorization.`});let t=getHookUrl(n);if(!t)throw e;let r=resolveConnectionPrincipal(n,m),{challenge:a,resume:s}=await m.startAuthorization({callbackUrl:t,connection:{url:p?.url??``},principal:r});return requestAuthorization([{name:n,challenge:stampChallengeDisplayName(a,m),hookUrl:t,resume:s}])}}}}return y}}}function createConnectionSearchResolver(){let e=createConnectionSearchEvents();return{slug:`connection`,eventNames:Object.keys(e),events:e,sourceId:`eve:connection-search-dynamic`,sourceKind:`module`,logicalPath:`eve:framework/connection-search-dynamic`}}export{createConnectionSearchEvents,createConnectionSearchResolver,extractDiscoveredTools};
@@ -1 +1 @@
1
- import{expectFunction,expectObjectRecord}from"#internal/authored-module.js";import{toErrorMessage}from"#shared/errors.js";import{normalizeAuthorizationSpec}from"#runtime/connections/validate-authorization.js";import{ResolveAgentError,loadResolvedModuleExport}from"#runtime/resolve-helpers.js";import{registerDefinitionSource,stampDefinitionKey}from"#public/tool-result-narrowing.js";async function resolveToolDefinition(r,a,o){try{let n=expectObjectRecord(await loadResolvedModuleExport({definition:r,kindLabel:`tool`,moduleMap:a,nodeId:o}),describe(r,`to return an object`)),i={kind:`tool`,logicalPath:r.logicalPath,name:r.name},s=`tool-source:${r.sourceId}`;stampDefinitionKey(n,s),registerDefinitionSource(s,i),registerDefinitionSource(`tool:${n.description}`,i);let c=expectFunction(n.execute,describe(r,`to provide an execute function`));return{description:r.description,execute:c,exportName:r.exportName,inputSchema:r.inputSchema,logicalPath:r.logicalPath,name:r.name,outputSchema:r.outputSchema,sourceId:r.sourceId,sourceKind:`module`,...extractOptionalHooks(n,r)}}catch(e){throw e instanceof ResolveAgentError?e:new ResolveAgentError(`Failed to attach the tool execute function from "${r.logicalPath}": ${toErrorMessage(e)}`,{logicalPath:r.logicalPath,sourceId:r.sourceId})}}function extractOptionalHooks(t,n){let i={};return t.needsApproval!==void 0&&(i.needsApproval=expectFunction(t.needsApproval,describe(n,`to provide a needsApproval function`))),t.toModelOutput!==void 0&&(i.toModelOutput=expectFunction(t.toModelOutput,describe(n,`to provide a toModelOutput function`))),t.inputSchema!==void 0&&isFlexibleSchema(t.inputSchema)&&(i.inputStandardSchema=t.inputSchema),t.outputSchema!==void 0&&isFlexibleSchema(t.outputSchema)&&(i.outputStandardSchema=t.outputSchema),t.auth!==void 0&&(i.auth=normalizeAuthorizationSpec(t.auth,`${describe(n,`to provide a valid auth object`)}:`)),i}function describe(e,t){return`Expected the tool export "${e.exportName??`default`}" from "${e.logicalPath}" ${t}.`}function isFlexibleSchema(e){return typeof e==`object`&&!!e&&`~standard`in e&&typeof e[`~standard`]==`object`}export{resolveToolDefinition};
1
+ import{expectFunction,expectObjectRecord}from"#internal/authored-module.js";import{toErrorMessage}from"#shared/errors.js";import{ResolveAgentError,loadResolvedModuleExport}from"#runtime/resolve-helpers.js";import{registerDefinitionSource,stampDefinitionKey}from"#public/tool-result-narrowing.js";async function resolveToolDefinition(i,a,o){try{let n=expectObjectRecord(await loadResolvedModuleExport({definition:i,kindLabel:`tool`,moduleMap:a,nodeId:o}),describe(i,`to return an object`)),r={kind:`tool`,logicalPath:i.logicalPath,name:i.name},s=`tool-source:${i.sourceId}`;stampDefinitionKey(n,s),registerDefinitionSource(s,r),registerDefinitionSource(`tool:${n.description}`,r);let c=expectFunction(n.execute,describe(i,`to provide an execute function`));return{description:i.description,execute:c,exportName:i.exportName,inputSchema:i.inputSchema,logicalPath:i.logicalPath,name:i.name,outputSchema:i.outputSchema,sourceId:i.sourceId,sourceKind:`module`,...extractOptionalHooks(n,i)}}catch(e){throw e instanceof ResolveAgentError?e:new ResolveAgentError(`Failed to attach the tool execute function from "${i.logicalPath}": ${toErrorMessage(e)}`,{logicalPath:i.logicalPath,sourceId:i.sourceId})}}function extractOptionalHooks(t,n){let r={};return t.needsApproval!==void 0&&(r.needsApproval=expectFunction(t.needsApproval,describe(n,`to provide a needsApproval function`))),t.toModelOutput!==void 0&&(r.toModelOutput=expectFunction(t.toModelOutput,describe(n,`to provide a toModelOutput function`))),t.inputSchema!==void 0&&isFlexibleSchema(t.inputSchema)&&(r.inputStandardSchema=t.inputSchema),t.outputSchema!==void 0&&isFlexibleSchema(t.outputSchema)&&(r.outputStandardSchema=t.outputSchema),r}function describe(e,t){return`Expected the tool export "${e.exportName??`default`}" from "${e.logicalPath}" ${t}.`}function isFlexibleSchema(e){return typeof e==`object`&&!!e&&`~standard`in e&&typeof e[`~standard`]==`object`}export{resolveToolDefinition};
@@ -154,16 +154,6 @@ export type ResolvedToolDefinition = Readonly<Optional<InternalToolDefinitionWit
154
154
  * handlers and the stream. See {@link ToolModelOutput}.
155
155
  */
156
156
  readonly toModelOutput?: (output: unknown) => ToolModelOutput | Promise<ToolModelOutput>;
157
- /**
158
- * Optional authorization strategy reattached from the authored
159
- * module at resolve time. Carries live `getToken` /
160
- * `startAuthorization` / `completeAuthorization` callbacks, so it
161
- * cannot survive compilation and must be read off the resolved
162
- * module like {@link execute}. When present, the execution layer
163
- * builds token accessors onto the tool context and drives the
164
- * interactive consent flow scoped to this tool's {@link name}.
165
- */
166
- readonly auth?: AuthorizationDefinition;
167
157
  };
168
158
  /**
169
159
  * Runtime-owned authored hook definition resolved from a compiled module
@@ -0,0 +1,15 @@
1
+ import { appendEnv } from "./append-env.js";
2
+ export declare const AI_GATEWAY_API_KEY_ENV_VAR = "AI_GATEWAY_API_KEY";
3
+ export declare const AI_GATEWAY_API_KEY_ENV_FILE = ".env.local";
4
+ /** The location written by eve when a user supplies an AI Gateway API key. */
5
+ export interface AiGatewayApiKeyLocation {
6
+ envKey: typeof AI_GATEWAY_API_KEY_ENV_VAR;
7
+ envFile: typeof AI_GATEWAY_API_KEY_ENV_FILE;
8
+ envPath: string;
9
+ }
10
+ /** Trims and saves an explicit AI Gateway API key, replacing any prior value. */
11
+ export declare function writeAiGatewayApiKey(input: {
12
+ projectRoot: string;
13
+ apiKey: string;
14
+ appendEnv?: typeof appendEnv;
15
+ }): Promise<AiGatewayApiKeyLocation>;
@@ -0,0 +1 @@
1
+ import{appendEnv}from"./append-env.js";import{join}from"node:path";const AI_GATEWAY_API_KEY_ENV_VAR=`AI_GATEWAY_API_KEY`,AI_GATEWAY_API_KEY_ENV_FILE=`.env.local`;async function writeAiGatewayApiKey(e){let t=join(e.projectRoot,AI_GATEWAY_API_KEY_ENV_FILE);return await(e.appendEnv??appendEnv)(t,{[AI_GATEWAY_API_KEY_ENV_VAR]:e.apiKey.trim()},{force:!0}),{envKey:AI_GATEWAY_API_KEY_ENV_VAR,envFile:AI_GATEWAY_API_KEY_ENV_FILE,envPath:t}}export{AI_GATEWAY_API_KEY_ENV_FILE,AI_GATEWAY_API_KEY_ENV_VAR,writeAiGatewayApiKey};
@@ -1 +1 @@
1
- import{appendEnv}from"../append-env.js";import{isProjectResolved}from"../project-resolution.js";import{requireProjectPath}from"../state.js";import{withNetworkSpinner}from"../vercel-project.js";import{runVercelEnvPull}from"../run-vercel-link.js";import{detectAiGatewayResolution}from"./detect-ai-gateway.js";import{join}from"node:path";import{createPromptCommandOutput}from"#setup/cli/index.js";const AI_GATEWAY_ENV_KEY=`AI_GATEWAY_API_KEY`,ENV_FILE_NAME=`.env.local`;function applyAiGatewayCredential(s){let c=s.deps??{appendEnv,runVercelEnvPull,detectAiGatewayResolution};async function writeAiGatewayApiKey(e,t){let n=join(e,ENV_FILE_NAME);await c.appendEnv(n,{[AI_GATEWAY_ENV_KEY]:t.trim()},{force:!0}),s.prompter.log.success(`Wrote ${AI_GATEWAY_ENV_KEY} to ${n}`)}return{id:`apply-ai-gateway-credential`,shouldRun(e){let{aiGateway:n,project:r}=e;return n.kind===`byok`||n.kind===`inherit`&&isProjectResolved(r)},async gather(){return null},async perform({state:e,signal:i}){let{prompter:a}=s,o=requireProjectPath(e),l=e.aiGateway,u=isProjectResolved(e.project);if(l.kind===`byop`)return{kind:`unresolved`};if(l.kind===`byok`)return await writeAiGatewayApiKey(o,l.apiGatewayKey),{kind:`api-key`,envFile:ENV_FILE_NAME};if(!u)return a.log.warning(`No Vercel project linked and no API key provided. The agent will not reach a model until you set ${AI_GATEWAY_ENV_KEY} in ${ENV_FILE_NAME} or link a project.`),{kind:`unresolved`};let d=createPromptCommandOutput(a.log),f=await withNetworkSpinner(a,`Pulling Vercel environment variables into .env.local...`,()=>c.runVercelEnvPull(o,d,i));return i?.throwIfAborted(),f||a.log.warning(`Linked the project, but pulling environment variables did not complete.`),c.detectAiGatewayResolution(o)},apply(e,t){return{...e,aiGatewayCredentials:t}}}}export{applyAiGatewayCredential};
1
+ import{appendEnv}from"../append-env.js";import{AI_GATEWAY_API_KEY_ENV_FILE,AI_GATEWAY_API_KEY_ENV_VAR,writeAiGatewayApiKey}from"../ai-gateway-api-key.js";import{isProjectResolved}from"../project-resolution.js";import{requireProjectPath}from"../state.js";import{withSpinner}from"../with-spinner.js";import{runVercelEnvPull}from"../run-vercel-link.js";import{detectAiGatewayResolution}from"./detect-ai-gateway.js";import{createPromptCommandOutput}from"#setup/cli/index.js";function applyAiGatewayCredential(a){let o=a.deps??{appendEnv,runVercelEnvPull,detectAiGatewayResolution};return{id:`apply-ai-gateway-credential`,shouldRun(e){let{aiGateway:t,project:n}=e;return t.kind===`byok`||t.kind===`inherit`&&isProjectResolved(n)},async gather(){return null},async perform({state:e,signal:r}){let{prompter:i}=a,s=requireProjectPath(e),c=e.aiGateway,l=isProjectResolved(e.project);if(c.kind===`byop`)return{kind:`unresolved`};if(c.kind===`byok`){let e=await writeAiGatewayApiKey({projectRoot:s,apiKey:c.apiGatewayKey,appendEnv:o.appendEnv});return a.prompter.log.success(`Wrote ${e.envKey} to ${e.envPath}`),{kind:`api-key`,envFile:e.envFile}}if(!l)return i.log.warning(`No Vercel project linked and no API key provided. The agent will not reach a model until you set ${AI_GATEWAY_API_KEY_ENV_VAR} in ${AI_GATEWAY_API_KEY_ENV_FILE} or link a project.`),{kind:`unresolved`};let u=createPromptCommandOutput(i.log),d=await withSpinner(i,`Pulling Vercel environment variables into .env.local...`,()=>o.runVercelEnvPull(s,u,r));return r?.throwIfAborted(),d||i.log.warning(`Linked the project, but pulling environment variables did not complete.`),o.detectAiGatewayResolution(s)},apply(e,t){return{...e,aiGatewayCredentials:t}}}}export{applyAiGatewayCredential};
@@ -1,2 +1,2 @@
1
- import{requireProjectPath}from"../state.js";import{join}from"node:path";import{readFile}from"node:fs/promises";const ENV_FILE_CANDIDATES=[`.env.local`,`.env`];function readEnvValue(e,t){let n=e.trim();if(n.length===0||n.startsWith(`#`)||!n.startsWith(`${t}=`))return;let r=n.slice(t.length+1);if(r.length===0)return;let i=r.length>=2&&r.startsWith(`"`)&&r.endsWith(`"`)?r.slice(1,-1):r;return i.length===0?void 0:i}async function hasApiKeyInFile(e,t){let r;try{r=await readFile(e,`utf8`)}catch{return!1}for(let e of r.split(`
2
- `))if(readEnvValue(e,t)!==void 0)return!0;return!1}async function findEnvFileWithKey(e,n){for(let i of ENV_FILE_CANDIDATES)if(await hasApiKeyInFile(join(e,i),n))return i}async function detectAiGatewayResolution(e){let t=await findEnvFileWithKey(e,`AI_GATEWAY_API_KEY`);return t===void 0?{kind:`unresolved`}:{kind:`api-key`,envFile:t}}function detectAiGateway(){return{id:`detect-ai-gateway`,shouldRun(e){return e.projectPath.kind===`resolved`},async gather(){return null},async perform({state:t}){return detectAiGatewayResolution(requireProjectPath(t))},apply(e,t){return{...e,aiGatewayCredentials:t}}}}export{detectAiGateway,detectAiGatewayResolution,findEnvFileWithKey};
1
+ import{AI_GATEWAY_API_KEY_ENV_FILE,AI_GATEWAY_API_KEY_ENV_VAR}from"../ai-gateway-api-key.js";import{requireProjectPath}from"../state.js";import{join}from"node:path";import{readFile}from"node:fs/promises";const ENV_FILE_CANDIDATES=[AI_GATEWAY_API_KEY_ENV_FILE,`.env`];function readEnvValue(e,t){let n=e.trim();if(n.length===0||n.startsWith(`#`)||!n.startsWith(`${t}=`))return;let r=n.slice(t.length+1);if(r.length===0)return;let i=r.length>=2&&r.startsWith(`"`)&&r.endsWith(`"`)?r.slice(1,-1):r;return i.length===0?void 0:i}async function hasApiKeyInFile(e,t){let n;try{n=await readFile(e,`utf8`)}catch{return!1}for(let e of n.split(`
2
+ `))if(readEnvValue(e,t)!==void 0)return!0;return!1}async function findEnvFileWithKey(e,t){for(let n of ENV_FILE_CANDIDATES)if(await hasApiKeyInFile(join(e,n),t))return n}async function detectAiGatewayResolution(e){let n=await findEnvFileWithKey(e,AI_GATEWAY_API_KEY_ENV_VAR);return n===void 0?{kind:`unresolved`}:{kind:`api-key`,envFile:n}}function detectAiGateway(){return{id:`detect-ai-gateway`,shouldRun(e){return e.projectPath.kind===`resolved`},async gather(){return null},async perform({state:e}){return detectAiGatewayResolution(requireProjectPath(e))},apply(e,t){return{...e,aiGatewayCredentials:t}}}}export{detectAiGateway,detectAiGatewayResolution,findEnvFileWithKey};
@@ -2,12 +2,11 @@ import { detectProjectResolution, type ProjectResolution } from "../project-reso
2
2
  import type { Prompter } from "../prompter.js";
3
3
  import { type SetupState } from "../state.js";
4
4
  import type { SetupBox } from "../step.js";
5
- import { linkProject, resolveProjectByNameOrId, unresolvedProject } from "../vercel-project.js";
5
+ import { linkProject, unresolvedProject } from "../vercel-project.js";
6
6
  /** Injected for tests; defaults to the real Vercel project helpers. */
7
7
  export interface LinkProjectDeps {
8
8
  linkProject: typeof linkProject;
9
9
  detectProjectResolution: typeof detectProjectResolution;
10
- resolveProjectByNameOrId: typeof resolveProjectByNameOrId;
11
10
  unresolvedProject: typeof unresolvedProject;
12
11
  }
13
12
  export interface LinkProjectOptions {
@@ -16,18 +15,13 @@ export interface LinkProjectOptions {
16
15
  deps?: LinkProjectDeps;
17
16
  }
18
17
  /**
19
- * THE PROJECT BOX. Executes the resolved Vercel project plan after scaffolding,
20
- * once the project directory exists (so `vercel link` can write `.vercel/`).
21
- * The gather prompts for nothing: every decision was made up front by the
22
- * resolve-provisioning box, so `perform` owns all the work.
18
+ * Executes the resolved Vercel project plan after scaffolding, once the project
19
+ * directory exists. Gather prompts for nothing every decision was made in the
20
+ * resolve-provisioning box.
23
21
  *
24
- * The plan is authoritative. The box always re-links to the planned project so
25
- * a stale or mismatched `.vercel` link can never silently win over the choice
26
- * made up front. `vercel link --project X --yes` is an idempotent rewrite, so
27
- * re-runs stay safe. The resolution read back from `.vercel/project.json` lands
28
- * in `state.project`, which every later box reads.
29
- *
30
- * Named `linkVercelProject` because the setup island also exports the
31
- * `linkProject` executor helper this box drives.
22
+ * The plan is authoritative: the box always re-links to the planned project so
23
+ * a stale or mismatched `.vercel` link can't silently win. Re-linking the same
24
+ * identity is idempotent. The resolution read back from the link metadata lands
25
+ * in `state.project`.
32
26
  */
33
27
  export declare function linkVercelProject(options: LinkProjectOptions): SetupBox<SetupState, null, ProjectResolution>;
@@ -1 +1 @@
1
- import{detectProjectResolution,mergeProjectResolution}from"../project-resolution.js";import{requireProjectPath}from"../state.js";import{linkProject,resolveProjectByNameOrId,unresolvedProject}from"../vercel-project.js";import{createPromptCommandOutput}from"#setup/cli/index.js";function linkVercelProject(o){let s=o.deps??{linkProject,detectProjectResolution,resolveProjectByNameOrId,unresolvedProject};return{id:`link-project`,shouldRun(e){return e.vercelProject.kind!==`none`},async gather(){return null},async perform({state:e,signal:t}){let r=e.vercelProject;if(r.kind===`none`)return s.unresolvedProject();let i=requireProjectPath(e),a=createPromptCommandOutput(o.prompter.log),c=await s.linkProject(o.prompter,i,r,a,{signal:t});if(t?.throwIfAborted(),!c)throw Error("Vercel project provisioning did not complete. Run `vercel link` manually, or re-run and choose not to deploy to Vercel.");let l=await s.detectProjectResolution(i,{signal:t});if(l.kind===`unresolved`)throw Error(`Linked the directory, but could not resolve the Vercel project from .vercel/project.json.`);let u=await s.resolveProjectByNameOrId(i,r.team,r.project,{signal:t});if(u===null||l.projectId!==u.id)throw Error(`Linked project identity did not match the planned Vercel project "${r.project}".`);return l},apply(e,n){return{...e,project:mergeProjectResolution(e.project,n)}}}}export{linkVercelProject};
1
+ import{detectProjectResolution,mergeProjectResolution}from"../project-resolution.js";import{requireProjectPath}from"../state.js";import{linkProject,unresolvedProject}from"../vercel-project.js";import{createPromptCommandOutput}from"#setup/cli/index.js";function linkVercelProject(a){let o=a.deps??{linkProject,detectProjectResolution,unresolvedProject};return{id:`link-project`,shouldRun(e){return e.vercelProject.kind!==`none`},async gather(){return null},async perform({state:e,signal:t}){let r=e.vercelProject;if(r.kind===`none`)return o.unresolvedProject();let i=requireProjectPath(e),s=createPromptCommandOutput(a.prompter.log),c=await o.linkProject(a.prompter,i,r,s,{signal:t});if(t?.throwIfAborted(),!c)throw Error("Vercel project provisioning did not complete. Run `vercel link` manually, or re-run and choose not to deploy to Vercel.");let l=await o.detectProjectResolution(i,{signal:t});if(l.kind===`unresolved`)throw Error(`Linked the directory, but could not resolve the Vercel project from its link metadata.`);if(l.projectId!==c.projectId)throw Error(`The linked project does not match the selected project: expected ${c.projectId}, found ${l.projectId}.`);return l},apply(e,n){return{...e,project:mergeProjectResolution(e.project,n)}}}}export{linkVercelProject};
@@ -4,7 +4,7 @@ import { detectProjectResolution, type ProjectResolution } from "../project-reso
4
4
  import type { Prompter } from "../prompter.js";
5
5
  import type { ProvisioningMode, ResolvedAiGateway, ResolvedVercelProject, SetupState, WiringMode } from "../state.js";
6
6
  import type { SetupBox } from "../step.js";
7
- import { assertNewProjectNameAvailable, isVercelAuthenticated, pickNewProjectName, pickProject, pickTeam, requireAuth, resolveTeam, validateTeam } from "../vercel-project.js";
7
+ import { assertNewProjectNameAvailable, isVercelAuthenticated, pickNewProjectName, pickProject, pickTeam, requireAuth, resolveProjectByNameOrId, resolveTeam, validateTeam } from "../vercel-project.js";
8
8
  /** Injected for tests; defaults to the real Vercel project and fs helpers. */
9
9
  export interface ResolveProvisioningDeps {
10
10
  requireAuth: typeof requireAuth;
@@ -17,6 +17,7 @@ export interface ResolveProvisioningDeps {
17
17
  pickProject: typeof pickProject;
18
18
  pickNewProjectName: typeof pickNewProjectName;
19
19
  assertNewProjectNameAvailable: typeof assertNewProjectNameAvailable;
20
+ resolveProjectByNameOrId: typeof resolveProjectByNameOrId;
20
21
  }
21
22
  export interface ResolveProvisioningOptions {
22
23
  /** Resolves the provisioning-tree questions; the composed stack decides how. */
@@ -1 +1 @@
1
- import{select,text}from"../ask.js";import{detectProjectResolution,isProjectResolved,mergeProjectResolution}from"../project-resolution.js";import{assertNewProjectNameAvailable,isVercelAuthenticated,pickNewProjectName,pickProject,pickTeam,requireAuth,resolveTeam,validateTeam,withNetworkSpinner}from"../vercel-project.js";import{pathExists}from"../path-exists.js";import{join,resolve}from"node:path";import{byokProviderEnvVar}from"#setup/scaffold/index.js";import{whimsyFor}from"#setup/cli/index.js";function vercelDemands(e){return{slack:e.channelSelection.includes(`slack`),connectSlugs:e.connectionSelection.filter(e=>e.entry.auth?.kind===`connect`).map(e=>e.slug)}}function connectClause(e){let t=e.length===1?`authenticates`:`authenticate`;return`${e.join(`, `)} ${t} through Vercel Connect`}function vercelRequirements(e){let t=[];return e.slack&&t.push(`Slack needs a public URL`),e.connectSlugs.length>0&&t.push(connectClause(e.connectSlugs)),t}function resolveProvisioning(l){let u=l.deps??{requireAuth,isVercelAuthenticated,detectProjectResolution,pathExists,validateTeam,resolveTeam,pickTeam,pickProject,pickNewProjectName,assertNewProjectNameAvailable},parent=()=>resolve(l.targetDirectory??process.cwd());async function detectAdoptableLink(e,t){if(e.projectPath.kind!==`resolved`)return;let n=e.projectPath.path;if(await u.pathExists(join(n,`.vercel`,`project.json`)))return withNetworkSpinner(l.prompter,whimsyFor(`project-detect`),async()=>{let e=await u.detectProjectResolution(n,{signal:t});if(!(!isProjectResolved(e)||!await u.isVercelAuthenticated(n,{signal:t})))return e})}async function plansFromFlags(e,t,n,r){if(t.skipVercel)return n.apiKey===void 0?{vercelProject:{kind:`none`},aiGateway:{kind:`byop`},modelWiring:`self`}:{vercelProject:{kind:`none`},aiGateway:{kind:`byok`,apiGatewayKey:n.apiKey},modelWiring:`gateway`};if(t.team===void 0||t.team.length===0)throw Error(`Headless Vercel provisioning requires --team <slug> or --scope <slug> so the current CLI scope is not applied silently.`);await u.requireAuth(parent(),void 0,{signal:r}),await u.validateTeam(l.prompter,parent(),t.team,{signal:r});let i=await u.resolveTeam(parent(),t.team,{signal:r}),a=n.apiKey===void 0?{kind:`inherit`}:{kind:`byok`,apiGatewayKey:n.apiKey},o=t.project===void 0?{kind:`new`,project:e,team:i}:{kind:`existing`,project:t.project,team:i};return o.kind===`new`&&await u.assertNewProjectNameAvailable(parent(),i,o.project,{signal:r}),{vercelProject:o,aiGateway:a,modelWiring:`gateway`}}async function promptPlans(n,r){let i=l.prompter,a=n.agentName,o=l.adoptExistingLink===!1?void 0:await detectAdoptableLink(n,r);if(o!==void 0)return i.log.info(`This directory is already linked to a Vercel project, so your agent will run there — the AI Gateway authenticates through your Vercel login.`),{vercelProject:{kind:`none`},aiGateway:{kind:`inherit`},modelWiring:`gateway`,project:o};let s=vercelRequirements(vercelDemands(n)),c=!0;if(s.length>0?i.log.info(`${s.join(` and `)}, so your agent will run on Vercel.`):c=await l.asker.ask(select({key:`deploy`,message:`Where should your agent run?`,options:[{id:`vercel`,value:!0,label:`On Vercel`,hint:`AI Gateway, Durable Workflow, Sandbox, and more`},{id:`local`,value:!1,label:`Locally for now`,hint:`run with eve dev, deploy any time later`}],recommended:!0,required:!0})),c){await u.requireAuth(parent(),i,{signal:r});let t=await u.pickTeam(i,parent(),void 0,{signal:r}),n=[{value:`new`,label:`Create a new project`,hint:`Named ${a}`},{value:`link`,label:`Link an existing project`}],o=l.projectSelection!==`existing-only`&&l.prompter.selectEditable?await l.prompter.selectEditable({message:`Vercel project`,options:n,initialValue:`new`,editable:{value:`new`,defaultValue:a,formatHint:e=>`Named ${e}`,validate:e=>e.trim().length===0?`Project name cannot be empty.`:void 0}}):void 0;if((l.projectSelection===`existing-only`?`link`:o?.value??await l.asker.ask(select({key:`vercel-project`,message:`Vercel project`,options:[{id:`new`,value:`new`,label:`Create a new project`,hint:`Named ${a}`},{id:`link`,value:`link`,label:`Link an existing project`}],recommended:`new`,required:!0})))===`new`){let e=o?.kind===`edited`?o.text:a;return{vercelProject:{kind:`new`,project:await u.pickNewProjectName(i,parent(),t,e,{signal:r}),team:t},aiGateway:{kind:`inherit`},modelWiring:`gateway`}}let s=await u.pickProject(i,parent(),t,{allowCreateWhenEmpty:l.projectSelection!==`existing-only`,signal:r});return{vercelProject:{kind:s.exists?`existing`:`new`,project:s.project,team:t},aiGateway:{kind:`inherit`},modelWiring:`gateway`}}return await l.asker.ask(select({key:`credential`,message:`How should your agent reach the model?`,options:[{id:`api-key`,value:`api-key`,label:`Use my own AI Gateway API key`,hint:`AI_GATEWAY_API_KEY`},{id:`local`,value:`local`,label:`Use my own provider API key`,hint:byokProviderEnvVar(n.modelId)}],recommended:`api-key`,required:!0}))===`api-key`?{vercelProject:{kind:`none`},aiGateway:{kind:`byok`,apiGatewayKey:await l.asker.ask(text({key:`gateway-api-key`,message:`Enter your AI_GATEWAY_API_KEY`,sensitive:!0,validate:e=>e.trim().length===0?`API key cannot be empty.`:null,required:!0}))},modelWiring:`gateway`}:{vercelProject:{kind:`none`},aiGateway:{kind:`byop`},modelWiring:`self`}}return{id:`resolve-provisioning`,async gather({state:e,signal:t}){if(l.mode.headless){let n=await plansFromFlags(e.agentName,l.mode.project,l.mode.aiGateway,t);if(n.vercelProject.kind===`none`){let t=vercelDemands(e);if(t.slack)throw Error(`Slack requires a Vercel project. Remove --skip-vercel to add Slack.`);if(t.connectSlugs.length>0)throw Error(`${connectClause(t.connectSlugs)}, which needs a Vercel project. Remove --skip-vercel to add ${t.connectSlugs.length===1?`it`:`them`}.`)}return n}return promptPlans(e,t)},async perform({input:e}){return e},apply(e,t){return{...e,vercelProject:t.vercelProject,aiGateway:t.aiGateway,modelWiring:t.modelWiring,project:t.project===void 0?e.project:mergeProjectResolution(e.project,t.project)}}}}export{resolveProvisioning};
1
+ import{select,text}from"../ask.js";import{detectProjectResolution,isProjectResolved,mergeProjectResolution}from"../project-resolution.js";import{withSpinner}from"../with-spinner.js";import{assertNewProjectNameAvailable,isVercelAuthenticated,pickNewProjectName,pickProject,pickTeam,requireAuth,resolveProjectByNameOrId,resolveTeam,validateTeam}from"../vercel-project.js";import{pathExists}from"../path-exists.js";import{join,resolve}from"node:path";import{byokProviderEnvVar}from"#setup/scaffold/index.js";import{whimsyFor}from"#setup/cli/index.js";function vercelDemands(e){return{slack:e.channelSelection.includes(`slack`),connectSlugs:e.connectionSelection.filter(e=>e.entry.auth?.kind===`connect`).map(e=>e.slug)}}function connectClause(e){let t=e.length===1?`authenticates`:`authenticate`;return`${e.join(`, `)} ${t} through Vercel Connect`}function vercelRequirements(e){let t=[];return e.slack&&t.push(`Slack needs a public URL`),e.connectSlugs.length>0&&t.push(connectClause(e.connectSlugs)),t}function resolveProvisioning(l){let u=l.deps??{requireAuth,isVercelAuthenticated,detectProjectResolution,pathExists,validateTeam,resolveTeam,pickTeam,pickProject,pickNewProjectName,assertNewProjectNameAvailable,resolveProjectByNameOrId},parent=()=>resolve(l.targetDirectory??process.cwd());async function detectAdoptableLink(e,t){if(e.projectPath.kind!==`resolved`)return;let n=e.projectPath.path;if(await u.pathExists(join(n,`.vercel`,`project.json`)))return withSpinner(l.prompter,whimsyFor(`project-detect`),async()=>{let e=await u.detectProjectResolution(n,{signal:t});if(!(!isProjectResolved(e)||!await u.isVercelAuthenticated(n,{signal:t})))return e})}async function plansFromFlags(e,t,n,r){if(t.skipVercel)return n.apiKey===void 0?{vercelProject:{kind:`none`},aiGateway:{kind:`byop`},modelWiring:`self`}:{vercelProject:{kind:`none`},aiGateway:{kind:`byok`,apiGatewayKey:n.apiKey},modelWiring:`gateway`};if(t.team===void 0||t.team.length===0)throw Error(`Headless Vercel provisioning requires --team <slug> or --scope <slug> so the current CLI scope is not applied silently.`);await u.requireAuth(parent(),void 0,{signal:r}),await u.validateTeam(l.prompter,parent(),t.team,{signal:r});let i=await u.resolveTeam(parent(),t.team,{signal:r}),a=n.apiKey===void 0?{kind:`inherit`}:{kind:`byok`,apiGatewayKey:n.apiKey},o;if(t.project===void 0)o={kind:`new`,project:e,team:i};else{let e=await u.resolveProjectByNameOrId(parent(),i,t.project,{signal:r});if(e===null)throw Error(`Vercel project "${t.project}" was not found in ${i}.`);o={kind:`existing`,project:e,team:i}}return o.kind===`new`&&await u.assertNewProjectNameAvailable(parent(),i,o.project,{signal:r}),{vercelProject:o,aiGateway:a,modelWiring:`gateway`}}async function promptPlans(n,r){let i=l.prompter,a=n.agentName,o=l.adoptExistingLink===!1?void 0:await detectAdoptableLink(n,r);if(o!==void 0)return i.log.info(`This directory is already linked to a Vercel project, so your agent will run there — the AI Gateway authenticates through your Vercel login.`),{vercelProject:{kind:`none`},aiGateway:{kind:`inherit`},modelWiring:`gateway`,project:o};let s=vercelRequirements(vercelDemands(n)),c=!0;if(s.length>0?i.log.info(`${s.join(` and `)}, so your agent will run on Vercel.`):c=await l.asker.ask(select({key:`deploy`,message:`Where should your agent run?`,options:[{id:`vercel`,value:!0,label:`On Vercel`,hint:`AI Gateway, Durable Workflow, Sandbox, and more`},{id:`local`,value:!1,label:`Locally for now`,hint:`run with eve dev, deploy any time later`}],recommended:!0,required:!0})),c){await u.requireAuth(parent(),i,{signal:r});let t=await u.pickTeam(i,parent(),void 0,{signal:r}),n=[{value:`new`,label:`Create a new project`,hint:`Named ${a}`},{value:`link`,label:`Link an existing project`}],o=l.projectSelection!==`existing-only`&&l.prompter.selectEditable?await l.prompter.selectEditable({message:`Vercel project`,options:n,initialValue:`new`,editable:{value:`new`,defaultValue:a,formatHint:e=>`Named ${e}`,validate:e=>e.trim().length===0?`Project name cannot be empty.`:void 0}}):void 0;if((l.projectSelection===`existing-only`?`link`:o?.value??await l.asker.ask(select({key:`vercel-project`,message:`Vercel project`,options:[{id:`new`,value:`new`,label:`Create a new project`,hint:`Named ${a}`},{id:`link`,value:`link`,label:`Link an existing project`}],recommended:`new`,required:!0})))===`new`){let e=o?.kind===`edited`?o.text:a;return{vercelProject:{kind:`new`,project:await u.pickNewProjectName(i,parent(),t,e,{signal:r}),team:t},aiGateway:{kind:`inherit`},modelWiring:`gateway`}}return{vercelProject:await u.pickProject(i,parent(),t,{allowCreateWhenEmpty:l.projectSelection!==`existing-only`,signal:r}),aiGateway:{kind:`inherit`},modelWiring:`gateway`}}return await l.asker.ask(select({key:`credential`,message:`How should your agent reach the model?`,options:[{id:`api-key`,value:`api-key`,label:`Use my own AI Gateway API key`,hint:`AI_GATEWAY_API_KEY`},{id:`local`,value:`local`,label:`Use my own provider API key`,hint:byokProviderEnvVar(n.modelId)}],recommended:`api-key`,required:!0}))===`api-key`?{vercelProject:{kind:`none`},aiGateway:{kind:`byok`,apiGatewayKey:await l.asker.ask(text({key:`gateway-api-key`,message:`Enter your AI_GATEWAY_API_KEY`,sensitive:!0,validate:e=>e.trim().length===0?`API key cannot be empty.`:null,required:!0}))},modelWiring:`gateway`}:{vercelProject:{kind:`none`},aiGateway:{kind:`byop`},modelWiring:`self`}}return{id:`resolve-provisioning`,async gather({state:e,signal:t}){if(l.mode.headless){let n=await plansFromFlags(e.agentName,l.mode.project,l.mode.aiGateway,t);if(n.vercelProject.kind===`none`){let t=vercelDemands(e);if(t.slack)throw Error(`Slack requires a Vercel project. Remove --skip-vercel to add Slack.`);if(t.connectSlugs.length>0)throw Error(`${connectClause(t.connectSlugs)}, which needs a Vercel project. Remove --skip-vercel to add ${t.connectSlugs.length===1?`it`:`them`}.`)}return n}return promptPlans(e,t)},async perform({input:e}){return e},apply(e,t){return{...e,vercelProject:t.vercelProject,aiGateway:t.aiGateway,modelWiring:t.modelWiring,project:t.project===void 0?e.project:mergeProjectResolution(e.project,t.project)}}}}export{resolveProvisioning};
@@ -1,6 +1,6 @@
1
1
  import { Prompt } from "@clack/core";
2
2
  import { type PromptOption, type PromptValue } from "./prompt-ui.js";
3
- import { type SelectState } from "./select-state.js";
3
+ import { type SearchActionOption, type SelectState } from "./select-state.js";
4
4
  /**
5
5
  * A prompt's live status note (e.g. a two-stage quit guard), read on each
6
6
  * render. Returns `undefined` when there is nothing to show. Wired in by
@@ -20,6 +20,7 @@ export declare class SelectComponent extends Prompt<string | string[]> {
20
20
  readonly options: PromptOption<string>[];
21
21
  readonly multiple: boolean;
22
22
  readonly search: boolean;
23
+ readonly searchAction: SearchActionOption | undefined;
23
24
  readonly required: boolean;
24
25
  filter: string;
25
26
  optionCursor: number;
@@ -28,6 +29,7 @@ export declare class SelectComponent extends Prompt<string | string[]> {
28
29
  options: PromptOption<string>[];
29
30
  multiple: boolean;
30
31
  search: boolean;
32
+ searchAction?: SearchActionOption;
31
33
  required: boolean;
32
34
  initial: SelectState;
33
35
  render: (this: Omit<SelectComponent, "prompt">) => string | undefined;
@@ -74,6 +76,10 @@ export declare function runSelectComponent<T extends PromptValue>(input: {
74
76
  options: readonly PromptOption<T>[];
75
77
  multiple: boolean;
76
78
  search: boolean;
79
+ searchAction?: {
80
+ label(query: string): string;
81
+ value(query: string): T;
82
+ };
77
83
  required: boolean;
78
84
  placeholder?: string;
79
85
  defaultValue?: T;