eve 0.15.5 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/dist/src/channel/compiled-channel.d.ts +2 -0
- package/dist/src/channel/cors.d.ts +43 -0
- package/dist/src/channel/cors.js +1 -0
- package/dist/src/cli/commands/init.js +1 -1
- package/dist/src/cli/dev/tui/agent-header.js +1 -1
- package/dist/src/cli/dev/tui/agent-info-probe.d.ts +16 -0
- package/dist/src/cli/dev/tui/agent-info-probe.js +1 -0
- package/dist/src/cli/dev/tui/blocks.js +8 -8
- package/dist/src/cli/dev/tui/mcp-connection-status.d.ts +19 -0
- package/dist/src/cli/dev/tui/mcp-connection-status.js +1 -0
- package/dist/src/cli/dev/tui/prompt-command-handler.js +1 -1
- package/dist/src/cli/dev/tui/prompt-commands.d.ts +1 -1
- package/dist/src/cli/dev/tui/prompt-commands.js +1 -1
- package/dist/src/cli/dev/tui/remote-connection-probe.js +1 -1
- package/dist/src/cli/dev/tui/runner.d.ts +14 -3
- package/dist/src/cli/dev/tui/runner.js +1 -1
- package/dist/src/cli/dev/tui/setup-commands.d.ts +10 -1
- package/dist/src/cli/dev/tui/setup-commands.js +2 -2
- package/dist/src/cli/dev/tui/setup-flow.d.ts +8 -1
- package/dist/src/cli/dev/tui/setup-issues.d.ts +2 -14
- package/dist/src/cli/dev/tui/setup-issues.js +1 -1
- package/dist/src/cli/dev/tui/setup-panel.d.ts +14 -8
- package/dist/src/cli/dev/tui/setup-panel.js +3 -3
- package/dist/src/cli/dev/tui/terminal-renderer.js +6 -6
- package/dist/src/cli/dev/tui/tui-prompter.js +1 -1
- package/dist/src/cli/dev/tui/tui.d.ts +2 -3
- package/dist/src/cli/dev/tui/tui.js +1 -1
- package/dist/src/cli/dev/ui-options.d.ts +21 -0
- package/dist/src/cli/dev/ui-options.js +1 -0
- package/dist/src/cli/run.d.ts +6 -42
- package/dist/src/cli/run.js +2 -2
- package/dist/src/compiled/.vendor-stamp.json +1 -1
- package/dist/src/compiled/@ai-sdk/mcp/index.d.ts +71 -1
- package/dist/src/compiled/@ai-sdk/mcp/index.js +1 -1
- package/dist/src/compiler/manifest.d.ts +8 -2
- package/dist/src/compiler/manifest.js +1 -1
- package/dist/src/compiler/normalize-channel.js +1 -1
- package/dist/src/context/providers/connection-key.d.ts +9 -0
- package/dist/src/context/providers/connection-key.js +1 -0
- package/dist/src/context/providers/connection.d.ts +1 -9
- package/dist/src/context/providers/connection.js +1 -1
- package/dist/src/harness/emission.d.ts +3 -3
- package/dist/src/harness/emission.js +1 -1
- package/dist/src/harness/input-requests.d.ts +1 -0
- package/dist/src/harness/input-requests.js +1 -1
- package/dist/src/harness/stream-actions.d.ts +17 -0
- package/dist/src/harness/stream-actions.js +1 -0
- package/dist/src/harness/tool-loop.js +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/nitro/host/channel-routes.d.ts +2 -0
- package/dist/src/internal/nitro/host/channel-routes.js +5 -3
- package/dist/src/internal/nitro/host/configure-nitro-routes.js +2 -2
- package/dist/src/internal/nitro/host/dev-authored-source-watcher.d.ts +1 -0
- package/dist/src/internal/nitro/host/dev-authored-source-watcher.js +1 -1
- package/dist/src/internal/nitro/host/start-development-server.d.ts +8 -0
- package/dist/src/internal/nitro/host/start-development-server.js +2 -2
- package/dist/src/internal/nitro/host.d.ts +1 -1
- package/dist/src/internal/nitro/host.js +1 -1
- package/dist/src/internal/nitro/routes/channel-dispatch.js +1 -1
- package/dist/src/internal/nitro/routes/dev-runtime-artifacts.d.ts +0 -3
- package/dist/src/internal/nitro/routes/dev-runtime-artifacts.js +1 -1
- package/dist/src/internal/nitro/routes/info.js +1 -1
- package/dist/src/internal/vercel/project-link.d.ts +10 -0
- package/dist/src/internal/vercel/project-link.js +1 -0
- package/dist/src/packages/eve-catalog/src/index.js +1 -1
- package/dist/src/public/channels/auth.d.ts +26 -13
- package/dist/src/public/channels/auth.js +1 -1
- package/dist/src/public/channels/eve.d.ts +31 -0
- package/dist/src/public/channels/eve.js +1 -1
- package/dist/src/public/channels/github/githubChannel.js +1 -1
- package/dist/src/public/channels/github/inbound-types.d.ts +189 -0
- package/dist/src/public/channels/github/inbound-types.js +1 -0
- package/dist/src/public/channels/github/inbound.d.ts +2 -190
- package/dist/src/public/channels/github/inbound.js +2 -2
- package/dist/src/public/channels/index.d.ts +1 -1
- package/dist/src/public/definitions/defineChannel.d.ts +10 -0
- package/dist/src/public/definitions/defineChannel.js +1 -1
- package/dist/src/runtime/agent/mock-model-adapter.d.ts +3 -2
- package/dist/src/runtime/agent/mock-model-adapter.js +1 -1
- package/dist/src/runtime/connections/principal.d.ts +2 -0
- package/dist/src/runtime/connections/principal.js +1 -1
- package/dist/src/runtime/connections/scoped-authorization.d.ts +9 -0
- package/dist/src/runtime/connections/scoped-authorization.js +1 -1
- package/dist/src/runtime/connections/types.d.ts +8 -5
- package/dist/src/runtime/framework-channels/index.d.ts +1 -6
- package/dist/src/runtime/framework-channels/index.js +1 -1
- package/dist/src/runtime/framework-tools/connection-search-dynamic.js +1 -1
- package/dist/src/runtime/framework-tools/index.d.ts +1 -1
- package/dist/src/runtime/framework-tools/index.js +1 -1
- package/dist/src/runtime/framework-tools/skill.js +1 -1
- package/dist/src/runtime/governance/auth/oidc.js +1 -1
- package/dist/src/runtime/governance/auth/types.d.ts +14 -10
- package/dist/src/runtime/governance/auth/vercel-oidc-project.d.ts +12 -0
- package/dist/src/runtime/governance/auth/vercel-oidc-project.js +1 -0
- package/dist/src/runtime/resolve-channel.js +1 -1
- package/dist/src/runtime/types.d.ts +2 -0
- package/dist/src/services/dev-client/client-options.d.ts +5 -0
- package/dist/src/services/dev-client/client-options.js +1 -1
- package/dist/src/services/dev-client/request-headers.d.ts +8 -0
- package/dist/src/services/dev-client/request-headers.js +1 -1
- package/dist/src/services/dev-client/runtime-artifacts.d.ts +1 -0
- package/dist/src/services/dev-client/runtime-artifacts.js +1 -1
- package/dist/src/services/dev-client.d.ts +8 -0
- package/dist/src/services/dev-client.js +1 -1
- package/dist/src/setup/boxes/add-connections.d.ts +10 -8
- package/dist/src/setup/boxes/add-connections.js +1 -1
- package/dist/src/setup/boxes/resolve-provisioning.d.ts +1 -0
- package/dist/src/setup/boxes/resolve-provisioning.js +1 -1
- package/dist/src/setup/boxes/select-connections.js +1 -1
- package/dist/src/setup/cli/channel-setup-prompter.d.ts +9 -2
- package/dist/src/setup/cli/channel-setup-prompter.js +1 -1
- package/dist/src/setup/cli/index.d.ts +1 -1
- package/dist/src/setup/cli/option-row.d.ts +2 -0
- package/dist/src/setup/cli/option-row.js +1 -1
- package/dist/src/setup/cli/prompt-ui.d.ts +2 -0
- package/dist/src/setup/cli/select-state.js +1 -1
- package/dist/src/setup/connection-connector.d.ts +26 -52
- package/dist/src/setup/connection-connector.js +2 -1
- package/dist/src/setup/flows/channels.js +1 -1
- package/dist/src/setup/flows/connections.d.ts +37 -0
- package/dist/src/setup/flows/connections.js +3 -0
- package/dist/src/setup/flows/link.d.ts +1 -0
- package/dist/src/setup/flows/link.js +1 -1
- package/dist/src/setup/project-resolution.d.ts +2 -8
- package/dist/src/setup/project-resolution.js +1 -1
- package/dist/src/setup/prompter.d.ts +2 -0
- package/dist/src/setup/scaffold/connections/catalog.d.ts +10 -5
- package/dist/src/setup/scaffold/connections/catalog.js +1 -1
- package/dist/src/setup/scaffold/create/project.js +11 -11
- package/dist/src/setup/scaffold/create/web-template.d.ts +1 -1
- package/dist/src/setup/scaffold/create/web-template.js +2 -2
- package/dist/src/setup/scaffold/index.d.ts +1 -1
- package/dist/src/setup/scaffold/index.js +1 -1
- package/dist/src/setup/scaffold/update/connections.d.ts +6 -0
- package/dist/src/setup/scaffold/update/connections.js +3 -3
- package/docs/channels/custom.mdx +19 -0
- package/docs/channels/eve.mdx +26 -3
- package/docs/concepts/sessions-runs-and-streaming.md +3 -1
- package/docs/connections/mcp.mdx +161 -19
- package/docs/connections/openapi.mdx +133 -36
- package/docs/connections/overview.mdx +4 -4
- package/docs/guides/auth-and-route-protection.md +5 -5
- package/docs/guides/dev-tui.md +11 -4
- package/docs/guides/frontend/nextjs.mdx +2 -2
- package/docs/guides/frontend/nuxt.mdx +2 -2
- package/docs/guides/frontend/sveltekit.mdx +2 -2
- package/docs/patterns/multi-tenant-approvals.md +4 -0
- package/docs/patterns/multi-tenant-auth.md +156 -37
- package/docs/reference/cli.md +3 -1
- package/docs/tools/human-in-the-loop.md +3 -1
- package/docs/tutorial/ship-it.mdx +1 -1
- package/docs/tutorial/team-playbooks.mdx +1 -1
- package/package.json +2 -2
- package/dist/src/internal/nitro/host/dev-rebuild-registry.d.ts +0 -5
- package/dist/src/internal/nitro/host/dev-rebuild-registry.js +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { type ConnectionSelectOption } from "./connection-add-prompter.js";
|
|
2
|
-
export { type ChannelSetupAction, type ChannelSetupAwaitChoice, type ChannelSetupChoice, type ChannelSetupChoiceOptions, type ChannelSetupLog, type DisabledChannelReasons, withPhase, } from "./channel-setup-prompter.js";
|
|
2
|
+
export { type ChannelSetupAction, type ChannelSetupAwaitChoice, type ChannelSetupChoice, type ChannelSetupChoiceOptions, type ChannelSetupLog, type DisabledChannelReasons, type SetupSpinnerIntent, withPhase, } from "./channel-setup-prompter.js";
|
|
3
3
|
export { createPromptCommandOutput, type PromptCommandLog } from "./command-output.js";
|
|
4
4
|
export { runSelectComponent, SelectComponent, type SelectGuard } from "./select-component.js";
|
|
5
5
|
export { createSelectOptionCodec, type SelectOptionCodec } from "./select-option-codec.js";
|
|
@@ -30,6 +30,8 @@ export interface RowGlyphs {
|
|
|
30
30
|
placeholder: string;
|
|
31
31
|
/** Separator before an inline hint. */
|
|
32
32
|
dot: string;
|
|
33
|
+
/** Attention marker for an unavailable option with actionable guidance. */
|
|
34
|
+
warning: string;
|
|
33
35
|
}
|
|
34
36
|
/** Canonical unicode glyphs; the CLI prompts render with these. */
|
|
35
37
|
export declare const UNICODE_ROW_GLYPHS: RowGlyphs;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const UNICODE_ROW_GLYPHS={pointer:`▷`,selectedPointer:`▶`,success:`✓`,placeholder:`◦`,dot
|
|
1
|
+
const UNICODE_ROW_GLYPHS={pointer:`▷`,selectedPointer:`▶`,success:`✓`,placeholder:`◦`,dot:`·`,warning:`⚠`};function resolveOptionRowState(e,t){if(Number(e.disabled===!0)+Number(e.completed===!0)+Number(e.locked===!0)>1)throw Error(`An option row cannot combine disabled, completed, or locked states.`);if(e.disabled===!0){let t={kind:`disabled`};return e.disabledReason!==void 0&&(t.reason=e.disabledReason),e.disabledReasonTone!==void 0&&(t.reasonTone=e.disabledReasonTone),t}if(e.completed===!0)return{kind:`completed`};if(e.locked===!0){let t={kind:`locked`};return e.lockedReason!==void 0&&(t.reason=e.lockedReason),t}return{kind:`available`,checked:t}}function parenthetical(e){return e===void 0?``:` (${e})`}function unfocusedGlyph(e){return e.placeholder?e.colors.dim(e.glyphs.placeholder):` `}function disabledLabel(e,t,n,r){if(t.reasonTone===`warning`){let i=t.reason===void 0?``:` ${r.warning} ${t.reason}`;return`${n.dim(e)}${n.yellow(i)}`}let i=parenthetical(t.reason);return n.dim(`${e}${i}`)}function optionRowPresentation(e){let{colors:t,glyphs:n,state:r}=e;switch(r.kind){case`available`:return e.isCursor?{glyph:n.selectedPointer,label:e.label}:{glyph:r.checked?t.green(n.success):unfocusedGlyph(e),label:e.accent===`warning`?t.yellow(e.label):e.label};case`completed`:return{glyph:e.isCursor?t.dim(n.pointer):t.green(n.success),label:t.dim(e.label)};case`disabled`:return{glyph:e.isCursor?t.dim(n.pointer):unfocusedGlyph(e),label:disabledLabel(e.label,r,t,n)};case`locked`:return{glyph:t.dim(t.green(n.success)),label:t.dim(`${e.label}${parenthetical(r.reason)}`)}}return r}function renderCursorRow(e,t,n,r){if(!t)return` ${e}`;let i=r===`warning`?n.yellow:n.blue;return n.inverse(i(` ${e} `))}function renderOptionRowContinuation(e){return` ${e}`}function renderOptionRow(e){let{colors:t,glyphs:n}=e,{glyph:r,label:i}=optionRowPresentation(e),a=e.isCursor&&e.state.kind===`available`,o=e.hint;e.isCursor&&e.focusHint!==void 0&&(o=e.focusHint);let s=``;if(o!==void 0){let r=Math.max(0,(e.hintPadding??0)+1-Number(a));s=t.dim(`${` `.repeat(r)}${n.dot} ${o}`)}return`${renderCursorRow(`${r} ${i}`,a,t,e.accent)}${s}`}export{UNICODE_ROW_GLYPHS,renderCursorRow,renderOptionRow,renderOptionRowContinuation,resolveOptionRowState};
|
|
@@ -21,6 +21,8 @@ export interface PromptColors {
|
|
|
21
21
|
export interface PromptOption<T extends PromptValue> {
|
|
22
22
|
value: T;
|
|
23
23
|
label: string;
|
|
24
|
+
/** Completion action kept after searchable results instead of being filtered. */
|
|
25
|
+
trailingAction?: boolean;
|
|
24
26
|
/** Supporting copy; stacked prompts render newline-separated text on separate rows. */
|
|
25
27
|
hint?: string;
|
|
26
28
|
/** Short inline annotation shown dimmed only while the cursor is on this row. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{previousGraphemeBoundary}from"#shared/text-boundaries.js";const SEARCH_ACTION_PREFIX=`\0search-action:`;function searchActionValue(e){return`${SEARCH_ACTION_PREFIX}${e}`}function searchActionQuery(e){return e.startsWith(SEARCH_ACTION_PREFIX)?e.slice(15):void 0}function submitRowIndex(e){return e.length}function filterOptions(e,t,n){let r=t.trim();if(r===``)return[...e];let i=r.toLowerCase(),a=e.filter(e=>e.label.toLowerCase().includes(i)||e.value.toLowerCase().includes(i)||(e.hint?.toLowerCase().includes(i)??!1)||(e.focusHint?.toLowerCase().includes(i)??!1));return n
|
|
1
|
+
import{previousGraphemeBoundary}from"#shared/text-boundaries.js";const SEARCH_ACTION_PREFIX=`\0search-action:`;function searchActionValue(e){return`${SEARCH_ACTION_PREFIX}${e}`}function searchActionQuery(e){return e.startsWith(SEARCH_ACTION_PREFIX)?e.slice(15):void 0}function submitRowIndex(e){return e.length}function filterOptions(e,t,n){let r=t.trim();if(r===``)return[...e];let i=r.toLowerCase(),a=e.filter(e=>e.trailingAction!==!0&&(e.label.toLowerCase().includes(i)||e.value.toLowerCase().includes(i)||(e.hint?.toLowerCase().includes(i)??!1)||(e.focusHint?.toLowerCase().includes(i)??!1)));return n!==void 0&&a.push({value:searchActionValue(r),label:n.label(r)}),[...a,...e.filter(e=>e.trailingAction===!0)]}function isFocusable(e){return!e.disabled&&!e.locked}function isActionable(e){return isFocusable(e)&&!e.completed}function firstFocusableIndex(e,t){let n=e.findIndex(isFocusable);return n>=0?n:t?submitRowIndex(e):0}function stepCursor(e,t,n,r){let i=e.length+ +!!r;if(i===0)return t;let a=t;for(let t=0;t<i;t+=1){if(a=(a+n+i)%i,r&&a===submitRowIndex(e))return a;let t=e[a];if(t&&isFocusable(t))return a}return t}function reduceSelect(t,n,r){let i=r.submitRow===!0;switch(n.type){case`char`:{let e=t.filter+n.char;return{...t,filter:e,cursor:firstFocusableIndex(filterOptions(r.options,e,r.searchAction),i)}}case`backspace`:{if(t.filter.length===0)return t;let n=t.filter.slice(0,previousGraphemeBoundary(t.filter,t.filter.length));return{...t,filter:n,cursor:firstFocusableIndex(filterOptions(r.options,n,r.searchAction),i)}}case`clear`:return t.filter.length===0?t:{...t,filter:``,cursor:firstFocusableIndex(filterOptions(r.options,``,r.searchAction),i)};case`up`:case`down`:{let e=filterOptions(r.options,t.filter,r.searchAction),a=n.type===`up`?-1:1,o=stepCursor(e,t.cursor,a,i);return o===t.cursor?t:{...t,cursor:o}}case`toggle`:{let e=filterOptions(r.options,t.filter,r.searchAction)[t.cursor];if(e===void 0||!isActionable(e))return t;let n=new Set(t.selected);return n.has(e.value)?n.delete(e.value):n.add(e.value),{...t,selected:n}}}}function initialSelectState(e){let t=e.filter??``,n=filterOptions(e.options,t,e.searchAction),r=firstFocusableIndex(n,e.submitRow===!0);if(e.defaultValue!==void 0){let t=n.findIndex(t=>isFocusable(t)&&t.value===e.defaultValue);t>=0&&(r=t)}let i=e.options.filter(e=>e.locked).map(e=>e.value);return{filter:t,cursor:r,selected:new Set([...e.initialValues??[],...i])}}function selectValueAtCursor(e,t){let n=e[t];return n&&isActionable(n)?n.value:void 0}function orderedSelection(e,t){return e.filter(e=>t.has(e.value)).map(e=>e.value)}export{filterOptions,initialSelectState,orderedSelection,reduceSelect,searchActionQuery,searchActionValue,selectValueAtCursor,submitRowIndex};
|
|
@@ -1,66 +1,40 @@
|
|
|
1
1
|
import { type ChannelSetupLog } from "#setup/cli/index.js";
|
|
2
|
-
|
|
2
|
+
import type { Prompter } from "#setup/prompter.js";
|
|
3
|
+
import { type VercelProjectReference } from "#setup/project-resolution.js";
|
|
4
|
+
/** Controls connector selection while adding a Connect-backed connection. */
|
|
3
5
|
export interface SetupConnectionConnectorOptions {
|
|
4
|
-
/** Status and command output stream through this log (rail styling preserved). */
|
|
5
6
|
log: ChannelSetupLog;
|
|
7
|
+
prompter: Prompter;
|
|
6
8
|
projectRoot: string;
|
|
7
|
-
/** Connection slug; also the connector `--name`. */
|
|
8
9
|
slug: string;
|
|
9
|
-
/** `vercel connect create <service>` identifier (e.g. `mcp.linear.app`). */
|
|
10
10
|
service: string;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
canonicalConnectorName: string;
|
|
12
|
+
project: VercelProjectReference;
|
|
13
|
+
signal?: AbortSignal;
|
|
14
|
+
}
|
|
15
|
+
/** Connector identity returned by the Vercel CLI. */
|
|
16
|
+
export interface ConnectConnectorRef {
|
|
17
|
+
uid: string;
|
|
18
|
+
id: string;
|
|
19
|
+
name?: string;
|
|
20
20
|
}
|
|
21
|
-
/** Outcome of the Connect create-and-patch sequence for a connection. */
|
|
22
21
|
export type SetupConnectionConnectorResult = {
|
|
23
|
-
kind: "
|
|
24
|
-
created: false;
|
|
25
|
-
} | {
|
|
26
|
-
kind: "connector-unresolved";
|
|
27
|
-
created: true;
|
|
28
|
-
} | {
|
|
29
|
-
kind: "patch-failed";
|
|
30
|
-
created: true;
|
|
22
|
+
kind: "existing";
|
|
31
23
|
connectorUid: string;
|
|
32
24
|
} | {
|
|
33
|
-
kind: "
|
|
34
|
-
created: true;
|
|
25
|
+
kind: "created";
|
|
35
26
|
connectorUid: string;
|
|
27
|
+
connectorId: string;
|
|
36
28
|
};
|
|
37
|
-
/**
|
|
38
|
-
export interface ConnectConnectorRef {
|
|
39
|
-
uid: string;
|
|
40
|
-
id: string;
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* Reads the connector identifiers from `vercel connect create … -F json`
|
|
44
|
-
* stdout. This is the authoritative source for the just-created connector's
|
|
45
|
-
* UID — it avoids a follow-up `connect list`, which can momentarily 404/rate
|
|
46
|
-
* limit right after creation and cannot disambiguate when a service already
|
|
47
|
-
* has multiple connectors. Returns `undefined` when stdout is empty or not the
|
|
48
|
-
* expected JSON (e.g. an older CLI without `-F json` support on `create`).
|
|
49
|
-
*/
|
|
29
|
+
/** Parses a created connector that can issue user credentials. */
|
|
50
30
|
export declare function parseCreatedConnector(stdout: string): ConnectConnectorRef | undefined;
|
|
51
|
-
/**
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Creates a Vercel Connect OAuth connector for a connection and rewrites the
|
|
62
|
-
* generated `connect("…")` call to the connector UID Connect assigns. The
|
|
63
|
-
* `vercel connect create` step is interactive (it opens a browser to complete
|
|
64
|
-
* the OAuth grant); callers should only invoke this from an interactive flow.
|
|
65
|
-
*/
|
|
31
|
+
/** Removes a connector created by this setup attempt. */
|
|
32
|
+
export declare function cleanupCreatedConnectionConnector(input: {
|
|
33
|
+
log: ChannelSetupLog;
|
|
34
|
+
projectRoot: string;
|
|
35
|
+
connectorId: string;
|
|
36
|
+
/** The linked Vercel owner; inferred from the project link when omitted. */
|
|
37
|
+
orgId?: string;
|
|
38
|
+
}): Promise<void>;
|
|
39
|
+
/** Attaches the canonical connector by name first, then offers explicit Find/Create fallbacks. */
|
|
66
40
|
export declare function setupConnectionConnector(options: SetupConnectionConnectorOptions): Promise<SetupConnectionConnectorResult>;
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{readProjectLink}from"#setup/project-resolution.js";import{createPromptCommandOutput,withPhase}from"#setup/cli/index.js";import{captureVercel,runVercel,runVercelCaptureStdout}from"#setup/primitives/run-vercel.js";const CREATED_CONNECTOR=/\bConnector created:\s*(scl_[A-Za-z0-9_-]+)\b/u;function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function parseJson(e){try{return JSON.parse(e)}catch{return}}function parseConnectorRef(e){if(!isRecord(e)||typeof e.uid!=`string`||typeof e.id!=`string`)return;let t={uid:e.uid,id:e.id};return typeof e.name==`string`&&(t.name=e.name),t}function parseCreatedConnector(e){let t=parseJson(e),n=parseConnectorRef(t);if(!isRecord(t)||n===void 0)return;let r=t.supportedSubjectTypes;return Array.isArray(r)&&r.includes(`user`)?n:void 0}function parseConnectorList(e,t){let n=[];for(let r of e){if(!isRecord(r)||typeof r.service==`string`&&r.service!==t)continue;let e=parseConnectorRef(r);e!==void 0&&n.push(e)}return n}function parseConnectorListPage(e,t){if(!isRecord(e)||!Array.isArray(e.connectors))return;let n=typeof e.cursor==`string`?e.cursor:void 0;return n===void 0?{connectors:parseConnectorList(e.connectors,t)}:{connectors:parseConnectorList(e.connectors,t),cursor:n}}async function listConnectors(e,t,n){let i=[],a=new Set,o;do{let s=[`connect`,`list`,`-F`,`json`,`--all-projects`,`--service`,e.service,`--scope`,t.orgId];o!==void 0&&s.push(`--next`,o);let c=await captureVercel(s,{cwd:e.projectRoot,onOutput:n,signal:e.signal});if(!c.ok)throw Error(c.failure.message);let l=parseConnectorListPage(parseJson(c.stdout),e.service);if(l===void 0)throw Error(`Vercel returned an invalid connector list for ${e.service}.`);i.push(...l.connectors);let u=l.cursor;if(u!==void 0&&a.has(u))throw Error(`The connector list repeated cursor ${u}.`);u!==void 0&&a.add(u),o=u}while(o!==void 0);return i}async function supportsUserAuthorization(e,t,n,i){let a=await captureVercel([`api`,`/v1/connect/connectors/${encodeURIComponent(n.id)}`,`--scope`,t.orgId,`--raw`],{cwd:e.projectRoot,onOutput:i,signal:e.signal});if(!a.ok)throw Error(`Could not verify connector ${n.uid}.`);let o=parseJson(a.stdout);if(!isRecord(o)||o.id!==n.id||o.uid!==n.uid||typeof o.service==`string`&&o.service!==e.service)throw Error(`Vercel returned invalid details for connector ${n.uid}.`);let s=o.supportedSubjectTypes;return Array.isArray(s)&&s.includes(`user`)}function connectorNames(e){let t=new Set;for(let n of e){n.name!==void 0&&t.add(n.name.toLowerCase());let e=n.uid.slice(n.uid.lastIndexOf(`/`)+1).trim();e.length>0&&t.add(e.toLowerCase())}return t}function connectorMatchesCanonicalName(e,t){let n=t.toLowerCase();return e.name?.toLowerCase()===n?!0:e.uid.slice(e.uid.lastIndexOf(`/`)+1).trim().toLowerCase()===n}function nextConnectorName(e,t){if(!t.has(e.toLowerCase()))return e;let n=2;for(;t.has(`${e}-${n}`.toLowerCase());)n+=1;return`${e}-${n}`}async function cleanupCreatedConnectionConnector(n){let r=n.orgId??(await readProjectLink(n.projectRoot))?.orgId,a=[`connect`,`remove`,n.connectorId,`--disconnect-all`,`--yes`];if(r!==void 0&&a.push(`--scope`,r),!await runVercel(a,{cwd:n.projectRoot,onOutput:createPromptCommandOutput(n.log)}))throw Error(`Could not remove connector ${n.connectorId}; run \`vercel connect remove ${n.connectorId} --disconnect-all --yes\`.`)}async function attach(e,t,n,r){return runVercel([`connect`,`attach`,n,`--yes`,`--scope`,t.orgId],{cwd:e.projectRoot,onOutput:r,signal:e.signal})}async function resolveFallbackConnector(e,t,r,i,s){let c=s;for(;;){if(await e.prompter.select({message:`Which connector should ${e.slug} use?`,hintLayout:`inline`,notices:[{tone:`warning`,text:c}],options:[{value:`find`,label:`Find a new one`,hint:`Browse existing connectors`},{value:`create`,label:`Create a new one`,hint:`Register another connector`}]})===`find`){let n=[];for(let a of i)await supportsUserAuthorization(e,t,a,r)&&n.push(a);if(n.length===0){c=`No existing ${e.service} connectors support user authorization.`;continue}let a=new Map(n.map(e=>[e.uid,e])),o=await e.prompter.select({message:`Select a connector for ${e.slug}`,hintLayout:`inline`,search:!0,placeholder:`type to search connectors`,options:n.map(e=>({value:e.uid,label:e.uid,hint:e.name??e.id}))}),s=a.get(o);if(s===void 0)throw Error(`Connector ${o} is no longer available.`);return{kind:`existing`,connector:s}}let s=connectorNames(i),l=(await e.prompter.text({message:`New connector name`,defaultValue:nextConnectorName(e.slug,s),validate:e=>{let t=e.trim().toLowerCase();return t.length===0?`A name is required.`:s.has(t)?`A connector with this name already exists.`:void 0}})).trim(),u=[],createOutput=e=>{u.push(e.text),r(e)},d=await withPhase(e.log,`Waiting for you to complete setup in the browser…`,()=>runVercelCaptureStdout([`connect`,`create`,e.service,`--name`,l,`-F`,`json`,`--scope`,t.orgId],{cwd:e.projectRoot,onOutput:createOutput,signal:e.signal}),{kind:`external-action`,emphasis:`browser`}),f=parseConnectorRef(parseJson(d.stdout))?.id??CREATED_CONNECTOR.exec(u.join(`
|
|
2
|
+
`))?.[1],p=d.ok?parseCreatedConnector(d.stdout):void 0;if(p!==void 0)return{kind:`created`,connector:p};let m=d.ok?`The ${e.service} connector does not support user authorization.`:`Could not create the ${e.service} connector.`;if(f!==void 0){try{await cleanupCreatedConnectionConnector({log:e.log,projectRoot:e.projectRoot,connectorId:f,orgId:t.orgId})}catch(e){let t=e instanceof Error?e.message:String(e);throw Error(`${m} ${t}`)}e.signal?.throwIfAborted()}throw Error(m)}}async function setupConnectionConnector(e){let n=createPromptCommandOutput(e.log),r=e.project,i=await listConnectors(e,r,n),a=i.find(t=>connectorMatchesCanonicalName(t,e.canonicalConnectorName)),o=`Could not find a connector named ${e.canonicalConnectorName}.`;if(a!==void 0)if(await supportsUserAuthorization(e,r,a,n)){if(await attach(e,r,a.uid,n))return e.log.success(`Attached ${a.uid} connector`),{kind:`existing`,connectorUid:a.uid};e.signal?.throwIfAborted(),o=`Could not attach ${a.uid}.`}else o=`${a.uid} does not support user authorization.`;let s=await resolveFallbackConnector(e,r,n,i,o);if(!await attach(e,r,s.connector.uid,n)){if(s.kind===`created`){let t=`Could not attach ${s.connector.uid} to the linked project.`;try{await cleanupCreatedConnectionConnector({log:e.log,projectRoot:e.projectRoot,connectorId:s.connector.id,orgId:r.orgId})}catch(e){let n=e instanceof Error?e.message:String(e);throw Error(`${t} ${n}`)}throw e.signal?.throwIfAborted(),Error(t)}throw Error(`Could not attach ${s.connector.uid} to the linked project.`)}return e.log.success(`Attached ${s.connector.uid} connector`),s.kind===`created`?{kind:`created`,connectorUid:s.connector.uid,connectorId:s.connector.id}:{kind:`existing`,connectorUid:s.connector.uid}}export{cleanupCreatedConnectionConnector,parseCreatedConnector,setupConnectionConnector};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{interactiveAsker}from"../ask.js";import{detectDeployment,isProjectResolved,projectResolutionFromDeployment}from"../project-resolution.js";import{createDefaultSetupState,snapshotSetupState}from"../state.js";import{WizardCancelledError}from"../step.js";import{addChannels}from"../boxes/add-channels.js";import{withSpinner}from"../with-spinner.js";import{getVercelAuthStatus,vercelAuthBlockerReason}from"../vercel-project.js";import{CHANNELS_PROMPT_MESSAGE,selectChannels}from"../boxes/select-channels.js";import{assertCanAddSelectedChannels,inspectExistingChannelRegistrations}from"../channel-add-conflicts.js";import{runInteractive}from"../runner.js";import{prompterSink}from"./in-project.js";import{SCAFFOLDABLE_CHANNELS}from"#setup/scaffold/index.js";import{toErrorMessage}from"#shared/errors.js";const SEE_IT_LIVE_MESSAGE=`See it live`;async function promptSeeItLive(e){try{return await e.select({message:SEE_IT_LIVE_MESSAGE,options:[{value:`deploy`,label:`Deploy and chat`},{value:`later`,label:`Later`}]})}catch(e){if(e instanceof WizardCancelledError)return`later`;throw e}}function channelAlreadyAdded(e,t){return t===`web`?e.webAppPresent:e.slackOwners.length>0}function appendChannel(e,t){return e.includes(t)?[...e]:[...e,t]}async function pickChannel(e,t,n,r){let i=channelListRows(t,n,r),a=!i.some(e=>e.value!==`done`&&e.completed!==!0&&e.disabled!==!0),s={message:CHANNELS_PROMPT_MESSAGE,options:i,hintLayout:`inline`};a&&(s.initialValue=`done`);try{return{kind:`picked`,value:await e.select(s)}}catch(e){if(e instanceof WizardCancelledError)return{kind:`cancelled`};throw e}}function channelLandedDuringSubflow(e,t,n){return!channelAlreadyAdded(e,n)&&channelAlreadyAdded(t,n)}function deployAndChatDetails(e){let t={};return e.slackChatUrl!==void 0&&(t.chatUrl=e.slackChatUrl),e.slackWorkspaceName!==void 0&&(t.workspaceName=e.slackWorkspaceName),t}function vercelChannelBlocker(e,t){let n=vercelAuthBlockerReason(e);if(n!==void 0)return n;if(!t)return`Requires Vercel account, see /model`}function channelListRows(e,t,n){let r=[{value:`repl`,label:`Terminal UI`,completed:!0,focusHint:`Already installed`}];for(let i of SCAFFOLDABLE_CHANNELS){if(channelAlreadyAdded(e,i.kind)){r.push({value:i.kind,label:i.label,completed:!0,focusHint:`Already installed`});continue}let a=e.disabledChannelReasons[i.kind];if(a!==void 0){r.push({value:i.kind,label:i.label,disabled:!0,disabledReason:a});continue}if(i.requiresVercelProject===!0){let e=vercelChannelBlocker(n,t);if(e!==void 0){r.push({value:i.kind,label:i.label,disabled:!0,disabledReason:e,disabledReasonTone:`warning`});continue}}let o={value:i.kind,label:i.label};i.hint!==void 0&&(o.hint=i.hint),r.push(o)}return r.push({value:`done`,label:`Done
|
|
1
|
+
import{interactiveAsker}from"../ask.js";import{detectDeployment,isProjectResolved,projectResolutionFromDeployment}from"../project-resolution.js";import{createDefaultSetupState,snapshotSetupState}from"../state.js";import{WizardCancelledError}from"../step.js";import{addChannels}from"../boxes/add-channels.js";import{withSpinner}from"../with-spinner.js";import{getVercelAuthStatus,vercelAuthBlockerReason}from"../vercel-project.js";import{CHANNELS_PROMPT_MESSAGE,selectChannels}from"../boxes/select-channels.js";import{assertCanAddSelectedChannels,inspectExistingChannelRegistrations}from"../channel-add-conflicts.js";import{runInteractive}from"../runner.js";import{prompterSink}from"./in-project.js";import{SCAFFOLDABLE_CHANNELS}from"#setup/scaffold/index.js";import{toErrorMessage}from"#shared/errors.js";const SEE_IT_LIVE_MESSAGE=`See it live`;async function promptSeeItLive(e){try{return await e.select({message:SEE_IT_LIVE_MESSAGE,options:[{value:`deploy`,label:`Deploy and chat`},{value:`later`,label:`Later`}]})}catch(e){if(e instanceof WizardCancelledError)return`later`;throw e}}function channelAlreadyAdded(e,t){return t===`web`?e.webAppPresent:e.slackOwners.length>0}function appendChannel(e,t){return e.includes(t)?[...e]:[...e,t]}async function pickChannel(e,t,n,r){let i=channelListRows(t,n,r),a=!i.some(e=>e.value!==`done`&&e.completed!==!0&&e.disabled!==!0),s={message:CHANNELS_PROMPT_MESSAGE,options:i,hintLayout:`inline`};a&&(s.initialValue=`done`);try{return{kind:`picked`,value:await e.select(s)}}catch(e){if(e instanceof WizardCancelledError)return{kind:`cancelled`};throw e}}function channelLandedDuringSubflow(e,t,n){return!channelAlreadyAdded(e,n)&&channelAlreadyAdded(t,n)}function deployAndChatDetails(e){let t={};return e.slackChatUrl!==void 0&&(t.chatUrl=e.slackChatUrl),e.slackWorkspaceName!==void 0&&(t.workspaceName=e.slackWorkspaceName),t}function vercelChannelBlocker(e,t){let n=vercelAuthBlockerReason(e);if(n!==void 0)return n;if(!t)return`Requires Vercel account, see /model`}function channelListRows(e,t,n){let r=[{value:`repl`,label:`Terminal UI`,completed:!0,focusHint:`Already installed`}];for(let i of SCAFFOLDABLE_CHANNELS){if(channelAlreadyAdded(e,i.kind)){r.push({value:i.kind,label:i.label,completed:!0,focusHint:`Already installed`});continue}let a=e.disabledChannelReasons[i.kind];if(a!==void 0){r.push({value:i.kind,label:i.label,disabled:!0,disabledReason:a});continue}if(i.requiresVercelProject===!0){let e=vercelChannelBlocker(n,t);if(e!==void 0){r.push({value:i.kind,label:i.label,disabled:!0,disabledReason:e,disabledReasonTone:`warning`});continue}}let o={value:i.kind,label:i.label};i.hint!==void 0&&(o.hint=i.hint),r.push(o)}return r.push({value:`done`,label:`Done`,trailingAction:!0}),r}async function runChannelsFlow(o){let{appRoot:c,prompter:l,signal:u}=o,d={detectDeployment,inspectExistingChannelRegistrations,getVercelAuthStatus,...o.deps},[f,p,m]=await withSpinner(l,`Checking the project…`,()=>Promise.all([d.detectDeployment(c,{signal:u}),d.inspectExistingChannelRegistrations(c),d.getVercelAuthStatus(c,{signal:u})]));u?.throwIfAborted();let h=p,g={...createDefaultSetupState(),project:projectResolutionFromDeployment(f),projectPath:{kind:`resolved`,inPlace:!0,path:c}},_;for(;;){let t=await pickChannel(l,h,isProjectResolved(g.project),m);if(t.kind===`cancelled`){if(g.channels.length===0)return{kind:`cancelled`};break}let r=t.value;if(r===`done`)break;if(r===`repl`||channelAlreadyAdded(h,r))continue;let i=[selectChannels({asker:interactiveAsker(l),variant:`channels-add`,presetChannels:[r],validateSelection:e=>assertCanAddSelectedChannels(e,h)}),addChannels({asker:interactiveAsker(l),prompter:l,configureVercelServices:!0,deps:d.addChannels})],o;try{o=await runInteractive(i,g,prompterSink(l),{snapshot:snapshotSetupState,signal:u})}catch(e){let t=await withSpinner(l,`Checking the project…`,()=>d.inspectExistingChannelRegistrations(c));if(channelLandedDuringSubflow(h,t,r)){if(g={...g,channels:appendChannel(g.channels,r)},h=t,_=toErrorMessage(e),u?.aborted===!0)break;continue}throw e}if(o.kind===`done`){if(g=o.state,h=await withSpinner(l,`Checking the project…`,()=>d.inspectExistingChannelRegistrations(c)),u?.throwIfAborted(),r===`slack`&&g.slackbotAttached&&await promptSeeItLive(l)===`deploy`)return{kind:`deploy-and-chat`,addedChannels:g.channels,chat:deployAndChatDetails(g)}}else{let e=await withSpinner(l,`Checking the project…`,()=>d.inspectExistingChannelRegistrations(c));if(channelLandedDuringSubflow(h,e,r))return{kind:`done`,addedChannels:appendChannel(g.channels,r)};h=e}}return _===void 0?{kind:`done`,addedChannels:g.channels}:{kind:`failed`,addedChannels:g.channels,message:_}}export{SEE_IT_LIVE_MESSAGE,runChannelsFlow};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ensureConnectionDependencies, listAuthoredConnections } from "#setup/scaffold/index.js";
|
|
2
|
+
import { detectPackageManager } from "#setup/package-manager.js";
|
|
3
|
+
import { runPackageManagerInstall } from "#setup/primitives/pm/run.js";
|
|
4
|
+
import { type AddConnectionsDeps } from "../boxes/add-connections.js";
|
|
5
|
+
import { detectDeployment } from "../project-resolution.js";
|
|
6
|
+
import type { Prompter } from "../prompter.js";
|
|
7
|
+
import { getVercelAuthStatus } from "../vercel-project.js";
|
|
8
|
+
import { runLinkFlow } from "./link.js";
|
|
9
|
+
export declare const CONNECTIONS_PROMPT_MESSAGE = "Select an MCP server to add to your agent through Vercel Connect";
|
|
10
|
+
export interface ConnectionsFlowDeps {
|
|
11
|
+
detectDeployment: typeof detectDeployment;
|
|
12
|
+
detectPackageManager: typeof detectPackageManager;
|
|
13
|
+
getVercelAuthStatus: typeof getVercelAuthStatus;
|
|
14
|
+
runLinkFlow: typeof runLinkFlow;
|
|
15
|
+
ensureConnectionDependencies: typeof ensureConnectionDependencies;
|
|
16
|
+
listAuthoredConnections: typeof listAuthoredConnections;
|
|
17
|
+
runPackageManagerInstall: typeof runPackageManagerInstall;
|
|
18
|
+
addConnections?: AddConnectionsDeps;
|
|
19
|
+
}
|
|
20
|
+
export type ConnectionsFlowResult = {
|
|
21
|
+
kind: "done";
|
|
22
|
+
addedConnections: readonly string[];
|
|
23
|
+
} | {
|
|
24
|
+
kind: "cancelled";
|
|
25
|
+
} | {
|
|
26
|
+
kind: "failed";
|
|
27
|
+
addedConnections: readonly string[];
|
|
28
|
+
message: string;
|
|
29
|
+
};
|
|
30
|
+
/** Runs `/connect`, linking a project on first selection when needed. */
|
|
31
|
+
export declare function runConnectionsFlow(input: {
|
|
32
|
+
appRoot: string;
|
|
33
|
+
prompter: Prompter;
|
|
34
|
+
signal?: AbortSignal;
|
|
35
|
+
disabledConnectionReasons?: Readonly<Record<string, string>>;
|
|
36
|
+
deps?: Partial<ConnectionsFlowDeps>;
|
|
37
|
+
}): Promise<ConnectionsFlowResult>;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{interactiveAsker}from"../ask.js";import{detectDeployment,isProjectResolved,projectResolutionFromDeployment}from"../project-resolution.js";import{snapshotSetupState}from"../state.js";import{WizardCancelledError}from"../step.js";import{withSpinner}from"../with-spinner.js";import{getVercelAuthStatus,vercelAuthBlockerReason}from"../vercel-project.js";import{selectConnections}from"../boxes/select-connections.js";import{addConnections}from"../boxes/add-connections.js";import{runInteractive}from"../runner.js";import{inProjectSetupState,prompterSink}from"./in-project.js";import{runLinkFlow}from"./link.js";import{CONNECTION_CATALOG,ensureConnectionDependencies,listAuthoredConnections}from"#setup/scaffold/index.js";import{detectPackageManager}from"#setup/package-manager.js";import{toErrorMessage}from"#shared/errors.js";import{createPromptCommandOutput,withPhase}from"#setup/cli/index.js";import{runPackageManagerInstall}from"#setup/primitives/pm/run.js";const CONNECTIONS_PROMPT_MESSAGE=`Select an MCP server to add to your agent through Vercel Connect`,CONNECT_CONNECTIONS=CONNECTION_CATALOG.filter(e=>e.auth.kind===`connect`);function connectionRows(e,t,n){let r=vercelAuthBlockerReason(t),i=CONNECT_CONNECTIONS.map(t=>{let i={value:t.slug,label:t.label};if(e.has(t.slug))return{...i,completed:!0,focusHint:`Already added`};let a=n[t.slug];return a===void 0?r===void 0?{...i,hint:t.hint}:{...i,disabled:!0,disabledReason:r,disabledReasonTone:`warning`}:{...i,disabled:!0,disabledReason:a,disabledReasonTone:`warning`}});return i.push({value:`done`,label:`Done`,trailingAction:!0}),i}async function pickConnection(e,t,n,r){let i=connectionRows(t,n,r),o={message:CONNECTIONS_PROMPT_MESSAGE,options:i,hintLayout:`inline`,search:!0,placeholder:`type to search MCP servers`};i.some(e=>e.value!==`done`&&e.disabled!==!0&&e.completed!==!0)||(o.initialValue=`done`);try{return await e.select(o)}catch(e){if(e instanceof WizardCancelledError)return;throw e}}async function runConnectionsFlow(s){let{appRoot:c,prompter:l,signal:u}=s,d={detectDeployment,detectPackageManager,ensureConnectionDependencies,getVercelAuthStatus,listAuthoredConnections,runLinkFlow,runPackageManagerInstall,...s.deps},[f,p,m]=await withSpinner(l,`Checking the project…`,()=>Promise.all([d.detectDeployment(c,{signal:u}),d.listAuthoredConnections(c),d.getVercelAuthStatus(c,{signal:u})]));u?.throwIfAborted();let h=inProjectSetupState(c,projectResolutionFromDeployment(f)),g=new Set(p),_=await pickConnection(l,g,m,s.disabledConnectionReasons??{});if(_===void 0)return{kind:`cancelled`};if(_===`done`||g.has(_))return{kind:`done`,addedConnections:[]};try{if(!isProjectResolved(h.project)){if((await d.runLinkFlow({appRoot:c,prompter:l,signal:u,projectSelection:`create-or-link`,teamSelectMessage:()=>`You need to link to a project to use Vercel Connect.
|
|
2
|
+
|
|
3
|
+
Select your team`})).kind===`cancelled`)return{kind:`cancelled`};let e=projectResolutionFromDeployment(await withSpinner(l,`Checking the project…`,()=>d.detectDeployment(c,{signal:u})));if(!isProjectResolved(e))throw Error(`Project link was not found after linking.`);h={...h,project:e}}let t=await d.detectPackageManager(c);if(await d.ensureConnectionDependencies({projectRoot:c}),!await withPhase(l.log,`Installing connection dependencies (${t.kind} install)...`,()=>d.runPackageManagerInstall(t.kind,c,{onOutput:createPromptCommandOutput(l.log),signal:u})))throw Error(`Dependency installation failed. Run \`${t.kind} install\`.`);if((await runInteractive([selectConnections({asker:interactiveAsker(l),presetConnections:[_]}),addConnections({prompter:l,signal:u,deps:d.addConnections})],h,prompterSink(l),{snapshot:snapshotSetupState,signal:u})).kind!==`done`)return{kind:`cancelled`};if(!new Set(await d.listAuthoredConnections(c)).has(_))throw Error(`Connection "${_}" was not added.`);return{kind:`done`,addedConnections:[_]}}catch(e){return e instanceof WizardCancelledError?{kind:`cancelled`}:{kind:`failed`,addedConnections:new Set(await d.listAuthoredConnections(c)).has(_)?[_]:[],message:toErrorMessage(e)}}}export{CONNECTIONS_PROMPT_MESSAGE,runConnectionsFlow};
|
|
@@ -47,5 +47,6 @@ export declare function runLinkFlow(input: {
|
|
|
47
47
|
* branch, where a fresh agent has no project yet).
|
|
48
48
|
*/
|
|
49
49
|
projectSelection?: "create-or-link" | "existing-only";
|
|
50
|
+
teamSelectMessage?: (currentTeam: string) => string;
|
|
50
51
|
deps?: Partial<LinkFlowDeps>;
|
|
51
52
|
}): Promise<LinkFlowResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{__toESM}from"../../_virtual/_rolldown/runtime.js";import{require_picocolors}from"../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js";import{AI_GATEWAY_API_KEY_ENV_VAR}from"../ai-gateway-api-key.js";import{interactiveAsker,withAnswers}from"../ask.js";import{detectProjectIdentity}from"../project-resolution.js";import{snapshotSetupState}from"../state.js";import{WizardCancelledError}from"../step.js";import{withSpinner}from"../with-spinner.js";import{detectAiGateway,findEnvFileWithKey}from"../boxes/detect-ai-gateway.js";import{applyAiGatewayCredential}from"../boxes/apply-ai-gateway-credential.js";import{linkVercelProject}from"../boxes/link-project.js";import{resolveProvisioning}from"../boxes/resolve-provisioning.js";import{runInteractive}from"../runner.js";import{inProjectSetupState,prompterSink}from"./in-project.js";var import_picocolors=__toESM(require_picocolors(),1);async function runLinkFlow(e){let{appRoot:t,prompter:
|
|
1
|
+
import{__toESM}from"../../_virtual/_rolldown/runtime.js";import{require_picocolors}from"../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js";import{AI_GATEWAY_API_KEY_ENV_VAR}from"../ai-gateway-api-key.js";import{interactiveAsker,withAnswers}from"../ask.js";import{detectProjectIdentity}from"../project-resolution.js";import{snapshotSetupState}from"../state.js";import{WizardCancelledError}from"../step.js";import{withSpinner}from"../with-spinner.js";import{detectAiGateway,findEnvFileWithKey}from"../boxes/detect-ai-gateway.js";import{applyAiGatewayCredential}from"../boxes/apply-ai-gateway-credential.js";import{linkVercelProject}from"../boxes/link-project.js";import{resolveProvisioning}from"../boxes/resolve-provisioning.js";import{runInteractive}from"../runner.js";import{inProjectSetupState,prompterSink}from"./in-project.js";var import_picocolors=__toESM(require_picocolors(),1);async function runLinkFlow(e){let{appRoot:t,prompter:a,signal:o,projectSelection:s=`existing-only`}=e,c={detectProjectIdentity,findEnvFileWithKey,...e.deps},l=await withSpinner(a,`Checking the current Vercel link...`,async()=>{let e=await c.detectProjectIdentity(t,{signal:o});return o?.throwIfAborted(),e});if(l===void 0){let[n,r]=await Promise.all([c.findEnvFileWithKey(t,AI_GATEWAY_API_KEY_ENV_VAR),c.findEnvFileWithKey(t,`VERCEL_OIDC_TOKEN`)]),i=n??r;i!==void 0&&e.teamSelectMessage===void 0&&a.log.message(`This directory is not linked to a Vercel project yet — the model currently runs on credentials from ${i}.`)}else{let e=l.teamName===void 0?import_picocolors.default.bold(l.projectName):`${import_picocolors.default.bold(l.projectName)} in ${import_picocolors.default.bold(l.teamName)}`;try{if(await a.select({message:`This directory is already linked to\n${e}`,options:[{value:`relink`,label:`Link to another project`},{value:`dismiss`,label:`Dismiss`}]})===`dismiss`)return{kind:`cancelled`}}catch(e){if(e instanceof WizardCancelledError)return{kind:`cancelled`};throw e}}let u=inProjectSetupState(t,{kind:`unresolved`});if((await runInteractive([resolveProvisioning({asker:withAnswers({deploy:`vercel`})(interactiveAsker(a)),prompter:a,targetDirectory:t,mode:{headless:!1},adoptExistingLink:!1,projectSelection:s,teamSelectMessage:e.teamSelectMessage,deps:c.resolveProvisioning}),linkVercelProject({prompter:a,deps:c.linkProject}),detectAiGateway(),applyAiGatewayCredential({prompter:a,deps:c.applyAiGatewayCredential})],u,prompterSink(a),{snapshot:snapshotSetupState,signal:o})).kind===`cancelled`)return{kind:`cancelled`};let[d,f]=await Promise.all([c.findEnvFileWithKey(t,`VERCEL_OIDC_TOKEN`),c.findEnvFileWithKey(t,AI_GATEWAY_API_KEY_ENV_VAR)]);o?.throwIfAborted(),d===void 0&&f===void 0&&a.log.warning("Linked, but no model credential landed in an env file (VERCEL_OIDC_TOKEN or AI_GATEWAY_API_KEY). Run `vercel env pull` once the project has AI Gateway access.");let p={kind:`done`};return d===void 0?f!==void 0&&(p.credential=AI_GATEWAY_API_KEY_ENV_VAR):p.credential=`VERCEL_OIDC_TOKEN`,p}export{runLinkFlow};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type VercelProjectLink } from "#internal/vercel/project-link.js";
|
|
2
2
|
/** Link and production-deployment status for a Vercel project directory. */
|
|
3
3
|
export type DeploymentState = "unlinked" | "linked" | "deployed";
|
|
4
4
|
/** Vercel project data resolved from local link metadata and the API. */
|
|
@@ -8,13 +8,8 @@ export interface DeploymentInfo {
|
|
|
8
8
|
orgId?: string;
|
|
9
9
|
productionUrl?: string;
|
|
10
10
|
}
|
|
11
|
-
declare const VercelProjectReferenceSchema: z.ZodObject<{
|
|
12
|
-
projectId: z.ZodString;
|
|
13
|
-
orgId: z.ZodString;
|
|
14
|
-
projectName: z.ZodOptional<z.ZodString>;
|
|
15
|
-
}, z.core.$strip>;
|
|
16
11
|
/** Validated Vercel owner and project identifiers. */
|
|
17
|
-
export type VercelProjectReference =
|
|
12
|
+
export type VercelProjectReference = VercelProjectLink;
|
|
18
13
|
/** Parses the complete Vercel owner and project environment pair. */
|
|
19
14
|
export declare function projectReferenceFromEnvironment(environment: Readonly<Record<string, string | undefined>>): VercelProjectReference | undefined;
|
|
20
15
|
/** Rejects Vercel's unsupported legacy link directory before link mutation. */
|
|
@@ -70,4 +65,3 @@ export declare function projectResolutionFromDeployResult(project: ProjectResolu
|
|
|
70
65
|
}): ProjectResolution;
|
|
71
66
|
export declare function isProjectResolved(project: ProjectResolution): boolean;
|
|
72
67
|
export declare function projectProductionUrlFromResolution(project: ProjectResolution): string | undefined;
|
|
73
|
-
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{object
|
|
1
|
+
import{object}from"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/schemas.js";import"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.js";import{captureVercel}from"./primitives/run-vercel.js";import{join}from"node:path";import{stat}from"node:fs/promises";import{VercelProjectLinkSchema,readVercelProjectLink}from"#internal/vercel/project-link.js";const VercelProjectEnvironmentSchema=object({VERCEL_ORG_ID:VercelProjectLinkSchema.shape.orgId,VERCEL_PROJECT_ID:VercelProjectLinkSchema.shape.projectId});function projectReferenceFromEnvironment(e){let t=VercelProjectEnvironmentSchema.safeParse(e);if(t.success)return{orgId:t.data.VERCEL_ORG_ID,projectId:t.data.VERCEL_PROJECT_ID}}async function assertNoLegacyProjectLinkDirectory(e){try{if(!(await stat(join(e,`.now`))).isDirectory())return}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return;throw e}throw Error("Legacy Vercel link directory `.now` is not supported. Remove `.now` before linking this project.")}async function readProjectLink(e){return await assertNoLegacyProjectLinkDirectory(e),await readVercelProjectLink(e)}function pickShortestAlias(e){if(!Array.isArray(e))return;let t;for(let n of e)typeof n!=`string`||n.length===0||(t===void 0||n.length<t.length)&&(t=n);return t}async function fetchProductionAlias(e,n,r,i){let a=await captureVercel([`api`,`/v9/projects/${e}?teamId=${n}`,`--scope`,n],{cwd:r,signal:i.signal});if(a.ok)try{let e=pickShortestAlias(JSON.parse(a.stdout).targets?.production?.alias);return e?`https://${e}`:void 0}catch{return}}async function detectDeployment(e,t={}){t.signal?.throwIfAborted();let n=await readProjectLink(e);if(n===void 0)return{state:`unlinked`};let r=await fetchProductionAlias(n.projectId,n.orgId,e,t);return t.signal?.throwIfAborted(),{state:r?`deployed`:`linked`,projectId:n.projectId,orgId:n.orgId,productionUrl:r}}async function fetchVercelName(e,n,r,i){let a=await captureVercel([`api`,e,`--scope`,n],{cwd:r,signal:i.signal});if(a.ok)try{let e=JSON.parse(a.stdout);return typeof e.name==`string`&&e.name.length>0?e.name:typeof e.slug==`string`&&e.slug.length>0?e.slug:void 0}catch{return}}async function detectProjectIdentity(e,t={}){t.signal?.throwIfAborted();let n=await readProjectLink(e);if(n===void 0)return;let[r,i]=await Promise.all([fetchVercelName(`/v9/projects/${n.projectId}?teamId=${n.orgId}`,n.orgId,e,t).then(e=>e??n.projectId),n.orgId.startsWith(`team_`)?fetchVercelName(`/v2/teams/${n.orgId}`,n.orgId,e,t):Promise.resolve(void 0)]);return t.signal?.throwIfAborted(),{projectName:r,teamName:i}}function projectResolutionFromDeployment(e){return e.state===`unlinked`||e.projectId===void 0?{kind:`unresolved`}:e.state===`deployed`&&e.productionUrl!==void 0?{kind:`deployed`,projectId:e.projectId,productionUrl:e.productionUrl}:{kind:`linked`,projectId:e.projectId}}async function detectProjectResolution(e,t={}){return projectResolutionFromDeployment(await detectDeployment(e,t))}function mergeProjectResolution(e,t){return t.kind===`unresolved`||e.kind===`deployed`&&e.projectId===t.projectId?e:t}function projectResolutionFromDeployResult(e,t){return e.kind===`unresolved`||!t.deployed||t.productionUrl===void 0?e:{kind:`deployed`,projectId:e.projectId,productionUrl:t.productionUrl}}function isProjectResolved(e){return e.kind!==`unresolved`}function projectProductionUrlFromResolution(e){return e.kind===`deployed`?e.productionUrl:void 0}export{assertNoLegacyProjectLinkDirectory,detectDeployment,detectProjectIdentity,detectProjectResolution,isProjectResolved,mergeProjectResolution,projectProductionUrlFromResolution,projectReferenceFromEnvironment,projectResolutionFromDeployResult,projectResolutionFromDeployment,readProjectLink};
|
|
@@ -9,6 +9,8 @@ export type PrompterValue = string | number | boolean;
|
|
|
9
9
|
export interface SelectOption<T extends PrompterValue> {
|
|
10
10
|
value: T;
|
|
11
11
|
label: string;
|
|
12
|
+
/** Completion action kept after searchable results instead of being filtered. */
|
|
13
|
+
trailingAction?: boolean;
|
|
12
14
|
hint?: string;
|
|
13
15
|
/** Short inline annotation shown dimmed only while the cursor is on this row. */
|
|
14
16
|
focusHint?: string;
|
|
@@ -32,8 +32,9 @@ export type ConnectionAuthSpec =
|
|
|
32
32
|
* It starts as a placeholder and is rewritten to the real connector UID once
|
|
33
33
|
* the connector is provisioned (see {@link service}). `service` is the
|
|
34
34
|
* managed-connector identifier passed to `vercel connect create <service>`
|
|
35
|
-
* (e.g.
|
|
36
|
-
*
|
|
35
|
+
* (e.g. `mcp.linear.app`); when omitted, eve falls back to the MCP endpoint
|
|
36
|
+
* host. It is distinct from the connector UID, which Vercel assigns when the
|
|
37
|
+
* connector is created or listed.
|
|
37
38
|
*/
|
|
38
39
|
{
|
|
39
40
|
kind: "connect";
|
|
@@ -107,11 +108,15 @@ export declare function effectiveProtocols(declared: readonly ConnectionProtocol
|
|
|
107
108
|
export declare function isValidConnectionSlug(slug: string): boolean;
|
|
108
109
|
/**
|
|
109
110
|
* The `vercel connect create <service>` identifier for a Connect-backed
|
|
110
|
-
* connection: the explicit `auth.service` when set, otherwise the host
|
|
111
|
-
*
|
|
112
|
-
*
|
|
111
|
+
* connection: the explicit `auth.service` when set, otherwise the MCP host.
|
|
112
|
+
* Returns `undefined` when neither is available, in which case the connector
|
|
113
|
+
* must be provisioned out of band.
|
|
113
114
|
*/
|
|
114
115
|
export declare function connectorServiceForEntry(entry: Pick<ConnectionCatalogEntry, "mcp" | "auth">): string | undefined;
|
|
116
|
+
/** Canonical connector name attempted before offering discovery or creation. */
|
|
117
|
+
export declare function canonicalConnectorNameForEntry(entry: {
|
|
118
|
+
auth?: ConnectionAuthSpec;
|
|
119
|
+
}): string | undefined;
|
|
115
120
|
/** Extracts the bare host from an MCP URL, or `undefined` when unparseable. */
|
|
116
121
|
export declare function mcpServiceHost(url: string | undefined): string | undefined;
|
|
117
122
|
/** Returns the endpoint block required for a protocol, or `null` when missing. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{connectionEntries,connectionProtocols}from"../../../packages/eve-catalog/src/index.js";const SUPPORTED_PROTOCOLS=[`mcp`],CUSTOM_CONNECTION_SLUG=`custom`,CONNECTION_AUTH={linear:{kind:`connect`,connector:`linear`,service:`mcp.linear.app`},notion:{kind:`connect`,connector:`notion`,service:`mcp.notion.com`},datadog:{kind:`connect`,connector:`datadog`,service:`mcp.datadoghq.com`},honeycomb:{kind:`connect`,connector:`honeycomb`,service:`mcp.honeycomb.io`}};function buildCatalogEntry(e,n,r){let i=CONNECTION_AUTH[e];if(i===void 0)throw Error(`Connection "${e}" is in the catalog but has no scaffolder auth overlay.`);let a={slug:e,label:n,protocols:connectionProtocols(r),description:r.description,auth:i};return r.mcp&&(a.mcp={url:r.mcp.url}),r.openapi&&(a.openapi={spec:r.openapi.spec,baseUrl:r.openapi.baseUrl}),a}const CONNECTION_CATALOG=connectionEntries().map(e=>{if(e.connection===void 0)throw Error(`Catalog connection "${e.slug}" is missing its connection identity.`);return buildCatalogEntry(e.slug,e.name,e.connection)}),CATALOG_BY_SLUG=new Map(CONNECTION_CATALOG.map(e=>[e.slug,e]));function getCatalogEntry(e){return CATALOG_BY_SLUG.get(e)}function catalogSlugs(){return CONNECTION_CATALOG.map(e=>e.slug)}function effectiveProtocols(e){let t=e===void 0||e.length===0?SUPPORTED_PROTOCOLS:e;return SUPPORTED_PROTOCOLS.filter(e=>t.includes(e))}const CONNECTION_SLUG_PATTERN=/^[a-z][a-z0-9-]{0,63}$/;function isValidConnectionSlug(e){return CONNECTION_SLUG_PATTERN.test(e)}function connectorServiceForEntry(e){if(e.auth.kind===`connect`)return e.auth.service?e.auth.service:mcpServiceHost(e.mcp?.url)}function mcpServiceHost(e){if(e)try{return new URL(e).host||void 0}catch{return}}function endpointForProtocol(e,t){return t===`mcp`?e.mcp??null:e.openapi??null}export{CONNECTION_CATALOG,CUSTOM_CONNECTION_SLUG,SUPPORTED_PROTOCOLS,catalogSlugs,connectorServiceForEntry,effectiveProtocols,endpointForProtocol,getCatalogEntry,isValidConnectionSlug,mcpServiceHost};
|
|
1
|
+
import{connectionEntries,connectionProtocols}from"../../../packages/eve-catalog/src/index.js";const SUPPORTED_PROTOCOLS=[`mcp`],CUSTOM_CONNECTION_SLUG=`custom`,CONNECTION_AUTH={linear:{kind:`connect`,connector:`linear`,service:`mcp.linear.app`},notion:{kind:`connect`,connector:`notion`,service:`mcp.notion.com`},datadog:{kind:`connect`,connector:`datadog`,service:`mcp.datadoghq.com`},honeycomb:{kind:`connect`,connector:`honeycomb`,service:`mcp.honeycomb.io`}};function buildCatalogEntry(e,n,r){let i=CONNECTION_AUTH[e];if(i===void 0)throw Error(`Connection "${e}" is in the catalog but has no scaffolder auth overlay.`);let a={slug:e,label:n,protocols:connectionProtocols(r),description:r.description,auth:i};return r.mcp&&(a.mcp={url:r.mcp.url}),r.openapi&&(a.openapi={spec:r.openapi.spec,baseUrl:r.openapi.baseUrl}),a}const CONNECTION_CATALOG=connectionEntries().map(e=>{if(e.connection===void 0)throw Error(`Catalog connection "${e.slug}" is missing its connection identity.`);return buildCatalogEntry(e.slug,e.name,e.connection)}),CATALOG_BY_SLUG=new Map(CONNECTION_CATALOG.map(e=>[e.slug,e]));function getCatalogEntry(e){return CATALOG_BY_SLUG.get(e)}function catalogSlugs(){return CONNECTION_CATALOG.map(e=>e.slug)}function effectiveProtocols(e){let t=e===void 0||e.length===0?SUPPORTED_PROTOCOLS:e;return SUPPORTED_PROTOCOLS.filter(e=>t.includes(e))}const CONNECTION_SLUG_PATTERN=/^[a-z][a-z0-9-]{0,63}$/;function isValidConnectionSlug(e){return CONNECTION_SLUG_PATTERN.test(e)}function connectorServiceForEntry(e){if(e.auth.kind===`connect`)return e.auth.service?e.auth.service:mcpServiceHost(e.mcp?.url)}function canonicalConnectorNameForEntry(e){if(e.auth?.kind!==`connect`)return;let t=e.auth.connector.trim();return t.length>0?t:void 0}function mcpServiceHost(e){if(e)try{return new URL(e).host||void 0}catch{return}}function endpointForProtocol(e,t){return t===`mcp`?e.mcp??null:e.openapi??null}export{CONNECTION_CATALOG,CUSTOM_CONNECTION_SLUG,SUPPORTED_PROTOCOLS,canonicalConnectorNameForEntry,catalogSlugs,connectorServiceForEntry,effectiveProtocols,endpointForProtocol,getCatalogEntry,isValidConnectionSlug,mcpServiceHost};
|
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
import{pinnedNodeEngineMajor}from"../../node-engine.js";import{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{basename,join,resolve}from"node:path";import{mkdir,readdir,stat}from"node:fs/promises";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,ALLOWED_CREATE_IN_PLACE_ENTRIES=new Set([`.DS_Store`,`.git`,`.gitkeep`,`.hg`]),DEFAULT_AI_PACKAGE_VERSION=`^7.0.0`,DEFAULT_CONNECT_PACKAGE_VERSION=`0.2.2`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.
|
|
1
|
+
import{pinnedNodeEngineMajor}from"../../node-engine.js";import{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{basename,join,resolve}from"node:path";import{mkdir,readdir,stat}from"node:fs/promises";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,ALLOWED_CREATE_IN_PLACE_ENTRIES=new Set([`.DS_Store`,`.git`,`.gitkeep`,`.hg`]),DEFAULT_AI_PACKAGE_VERSION=`^7.0.0`,DEFAULT_CONNECT_PACKAGE_VERSION=`0.2.2`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.16.1`,nodeEngine:`>=24`};function resolveEvePackageContract(e=DEFAULT_EVE_PACKAGE_CONTRACT){return{version:resolveVersionToken(`evePackage.version`,e.version),nodeEngine:resolveVersionToken(`evePackage.nodeEngine`,e.nodeEngine)}}function modelProviderSlug(e){let t=(e.split(`/`)[0]??``).replaceAll(/[^A-Za-z0-9._-]/gu,``);return t.length>0?t:`anthropic`}function byokProviderEnvVar(e){let t=modelProviderSlug(e).toUpperCase().replaceAll(/[^A-Z0-9]/gu,`_`);return`${/^[0-9]/.test(t)?`_`:``}${t}_API_KEY`}function agentTemplateFiles(e){return{"agent/agent.ts":BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e),"agent/channels/eve.ts":WEB_APP_TEMPLATE_FILES[`agent/channels/eve.ts`],"agent/instructions.md":AGENT_INSTRUCTIONS_TEMPLATE}}function renderTemplate(e,t){return e.replaceAll(`__EVE_INIT_APP_NAME__`,t.appName).replaceAll(`__EVE_INIT_MODEL__`,t.model).replaceAll(`__EVE_INIT_BYOK_PROVIDER__`,modelProviderSlug(t.model)).replaceAll(`__EVE_INIT_BYOK_ENV_VAR__`,byokProviderEnvVar(t.model)).replaceAll(`__EVE_INIT_PACKAGE_VERSION__`,formatEveDependencySpecifier(t.eveVersion)).replaceAll(`__EVE_INIT_AI_SDK_VERSION__`,t.aiPackageVersion).replaceAll(`__EVE_INIT_CONNECT_VERSION__`,t.connectPackageVersion).replaceAll(`__EVE_INIT_ZOD_VERSION__`,t.zodPackageVersion).replaceAll(`__EVE_INIT_TYPESCRIPT_VERSION__`,t.typescriptPackageVersion).replaceAll(`__EVE_INIT_TYPES_NODE_VERSION__`,t.nodeTypesVersion).replaceAll(`__EVE_INIT_NODE_ENGINE__`,t.nodeEngine)}function formatEveDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}const BASE_AGENT_TEMPLATE=`import { defineAgent } from "eve";
|
|
2
2
|
|
|
3
3
|
export default defineAgent({
|
|
4
4
|
model: "__EVE_INIT_MODEL__",
|
|
5
5
|
});
|
|
6
|
-
`;function
|
|
6
|
+
`;function packageManagerAiPinTemplateSuffix(e){switch(e){case`bun`:case`npm`:return`,
|
|
7
|
+
"overrides": {
|
|
8
|
+
"ai": "__EVE_INIT_AI_SDK_VERSION__"
|
|
9
|
+
}`;case`yarn`:return`,
|
|
10
|
+
"resolutions": {
|
|
11
|
+
"ai": "__EVE_INIT_AI_SDK_VERSION__"
|
|
12
|
+
}`;case`pnpm`:return``;default:return e}}function packageJsonTemplate(e){return`{
|
|
7
13
|
"name": "__EVE_INIT_APP_NAME__",
|
|
8
14
|
"version": "0.0.0",
|
|
9
15
|
"type": "module",
|
|
@@ -26,15 +32,9 @@ export default defineAgent({
|
|
|
26
32
|
"devDependencies": {
|
|
27
33
|
"@types/node": "__EVE_INIT_TYPES_NODE_VERSION__",
|
|
28
34
|
"typescript": "__EVE_INIT_TYPESCRIPT_VERSION__"
|
|
29
|
-
}${e
|
|
35
|
+
}${e.includeRootOnlyFields?`${packageManagerAiPinTemplateSuffix(e.packageManager)}${ROOT_ONLY_PACKAGE_JSON_TEMPLATE_SUFFIX}`:``}
|
|
30
36
|
}
|
|
31
37
|
`}const ROOT_ONLY_PACKAGE_JSON_TEMPLATE_SUFFIX=`,
|
|
32
|
-
"overrides": {
|
|
33
|
-
"ai": "__EVE_INIT_AI_SDK_VERSION__"
|
|
34
|
-
},
|
|
35
|
-
"resolutions": {
|
|
36
|
-
"ai": "__EVE_INIT_AI_SDK_VERSION__"
|
|
37
|
-
},
|
|
38
38
|
"engines": {
|
|
39
39
|
"node": "__EVE_INIT_NODE_ENGINE__"
|
|
40
40
|
}
|
|
@@ -81,7 +81,7 @@ from the installed eve package docs. In most installs, those docs are at
|
|
|
81
81
|
installed \`eve\` package location first and read its \`docs/\` directory. If
|
|
82
82
|
package docs are unavailable, use https://eve.dev/docs as a fallback.
|
|
83
83
|
`,"CLAUDE.md":`@AGENTS.md
|
|
84
|
-
`};function templateFiles(e
|
|
84
|
+
`};function templateFiles(e){return{"agent/agent.ts":e.byokProvider?`import { defineAgent } from "eve";
|
|
85
85
|
|
|
86
86
|
export default defineAgent({
|
|
87
87
|
model: "__EVE_INIT_MODEL__",
|
|
@@ -95,4 +95,4 @@ export default defineAgent({
|
|
|
95
95
|
},
|
|
96
96
|
},
|
|
97
97
|
});
|
|
98
|
-
`:BASE_AGENT_TEMPLATE,...SHARED_TEMPLATE_FILES,"package.json":packageJsonTemplate(
|
|
98
|
+
`:BASE_AGENT_TEMPLATE,...SHARED_TEMPLATE_FILES,"package.json":packageJsonTemplate({includeRootOnlyFields:e.includeRootOnlyPackageJsonFields,packageManager:e.packageManager})}}async function assertCanCreateInPlace(e,n){if(!await pathExists(e))return;let r=(await readdir(e)).filter(e=>!ALLOWED_CREATE_IN_PLACE_ENTRIES.has(e));if(r.length>0&&!n){let e=r.slice(0,5).join(`, `),t=r.length>5?`, and ${r.length-5} more`:``;throw Error(`Cannot create project in current directory because it is not empty. Found: ${e}${t}. Use an empty directory.`)}}async function scaffoldBaseProject(o){let s=resolve(o.targetDirectory??process.cwd(),o.projectName),c=o.projectName===`.`,l=o.overwriteExisting??!1,u=o.byokProvider??!1,d=o.packageManager??`pnpm`,f=resolveEvePackageContract(o.evePackage),p=pinnedNodeEngineMajor(f.nodeEngine),m=resolve(o.workspaceProbeDirectory??s),h=isPackageManagerWorkspaceMember(d,m);if(c)await assertCanCreateInPlace(s,l);else if(await pathExists(s))throw Error(`Cannot create project because "${s}" already exists.`);let g={appName:basename(s),model:o.model,eveVersion:f.version,aiPackageVersion:resolveVersionToken(`aiPackageVersion`,o.aiPackageVersion??`^7.0.0`),connectPackageVersion:resolveVersionToken(`connectPackageVersion`,o.connectPackageVersion??`0.2.2`),zodPackageVersion:resolveVersionToken(`zodPackageVersion`,o.zodPackageVersion??`4.4.3`),typescriptPackageVersion:resolveVersionToken(`typescriptPackageVersion`,o.typescriptPackageVersion??`7.0.1-rc`),nodeTypesVersion:p,nodeEngine:p};await mkdir(s,{recursive:!0});for(let[e,r]of Object.entries(templateFiles({byokProvider:u,includeRootOnlyPackageJsonFields:!h,packageManager:d}))){let i=`${s}/${e}`,a=await pathExists(i);await writeTextFile(i,renderTemplate(r,g),{force:c&&l}),a&&await o.onOverwriteFile?.(i)}return await applyPackageManagerWorkspaceConfiguration({packageManager:d,projectRoot:s,workspaceProbeRoot:m,onWorkspaceRootMutation:o.onWorkspaceRootMutation}),await patchWorkspaceRootPackageJson(d,m,{aiPackageVersion:g.aiPackageVersion,nodeEngineRequirement:f.nodeEngine,onWorkspaceRootMutation:o.onWorkspaceRootMutation}),s}async function isEveProject(e){for(let t of SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS)try{return await stat(join(e,`agent`,`agent${t}`)),!0}catch{}return!1}export{CURRENT_DIRECTORY_PROJECT_NAME,DEFAULT_AI_PACKAGE_VERSION,DEFAULT_CONNECT_PACKAGE_VERSION,DEFAULT_EVE_PACKAGE_CONTRACT,DEFAULT_ZOD_PACKAGE_VERSION,agentTemplateFiles,byokProviderEnvVar,formatEveDependencySpecifier,isEveProject,modelProviderSlug,resolveEvePackageContract,scaffoldBaseProject};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const WEB_APP_TEMPLATE_FILES: {
|
|
2
|
-
readonly "agent/channels/eve.ts": 'import { eveChannel } from "eve/channels/eve";\nimport { localDev, placeholderAuth, vercelOidc } from "eve/channels/auth";\n\nexport default eveChannel({\n auth: [\n //
|
|
2
|
+
readonly "agent/channels/eve.ts": 'import { eveChannel } from "eve/channels/eve";\nimport { localDev, placeholderAuth, vercelOidc } from "eve/channels/auth";\n\nexport default eveChannel({\n auth: [\n // Lets the eve TUI and your Vercel deployments reach the deployed agent.\n vercelOidc(),\n // Open on localhost for `eve dev` and the REPL; ignored in production.\n localDev(),\n // This placeholder will not allow browser requests in production.\n // Replace it with your app\'s auth provider, like Auth.js or Clerk,\n // or use none() for a public demo.\n placeholderAuth(),\n ],\n});\n';
|
|
3
3
|
readonly "app/_components/agent-chat.tsx": '"use client";\n\nimport { useEveAgent } from "eve/react";\nimport { AlertCircleIcon } from "lucide-react";\nimport {\n Conversation,\n ConversationContent,\n ConversationScrollButton,\n} from "@/components/ai-elements/conversation";\nimport {\n PromptInput,\n type PromptInputMessage,\n PromptInputSubmit,\n PromptInputTextarea,\n} from "@/components/ai-elements/prompt-input";\nimport { cn } from "@/lib/utils";\nimport { AgentMessage } from "./agent-message";\n\nconst AGENT_NAME = "__EVE_INIT_APP_NAME__";\n\ntype AgentStatus = ReturnType<typeof useEveAgent>["status"];\n\nexport function AgentChat() {\n const agent = useEveAgent();\n const isBusy = agent.status === "submitted" || agent.status === "streaming";\n const isEmpty = agent.data.messages.length === 0;\n\n const handleSubmit = async (message: PromptInputMessage) => {\n const text = message.text.trim();\n if (!text || isBusy) return;\n\n await agent.send({ message: text });\n };\n\n const composer = (\n <PromptInput onSubmit={handleSubmit}>\n <PromptInputTextarea placeholder="Send a message…" />\n <PromptInputSubmit onStop={agent.stop} status={agent.status} />\n </PromptInput>\n );\n\n return (\n <main className="flex h-dvh flex-col overflow-hidden bg-background text-foreground">\n {isEmpty ? null : (\n <header className="flex h-14 shrink-0 items-center justify-center gap-3 pl-4 pr-2">\n <span className="flex min-w-0 items-center gap-2">\n <span className="truncate text-muted-foreground text-sm">{AGENT_NAME}</span>\n <StatusDot status={agent.status} />\n </span>\n </header>\n )}\n\n {agent.error ? (\n <div className="mx-auto w-full max-w-3xl shrink-0 px-4 pt-2 sm:px-6">\n <div className="flex items-start gap-3 rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-2.5 text-sm">\n <AlertCircleIcon className="mt-0.5 size-4 shrink-0 text-destructive" />\n <div>\n <p className="font-medium">Request failed</p>\n <p className="mt-0.5 text-muted-foreground">{agent.error.message}</p>\n </div>\n </div>\n </div>\n ) : null}\n\n {isEmpty ? null : (\n <Conversation className="min-h-0 flex-1">\n <ConversationContent className="mx-auto w-full max-w-3xl gap-6 px-4 py-6 sm:px-6">\n {agent.data.messages.map((message, index) => (\n <AgentMessage\n canRespond={!isBusy}\n isStreaming={\n agent.status === "streaming" && index === agent.data.messages.length - 1\n }\n key={message.id}\n message={message}\n onInputResponses={(inputResponses) => agent.send({ inputResponses })}\n />\n ))}\n </ConversationContent>\n <ConversationScrollButton />\n </Conversation>\n )}\n\n <div\n className={cn(\n "mx-auto w-full px-4 sm:px-6",\n isEmpty\n ? "flex max-w-xl flex-1 flex-col items-center justify-center gap-8 pb-[10vh]"\n : "max-w-3xl shrink-0 pb-6",\n )}\n >\n {isEmpty ? (\n <div className="flex flex-col items-center gap-3 text-center">\n <h1 className="font-medium text-5xl tracking-tighter">{AGENT_NAME}</h1>\n </div>\n ) : null}\n <div className="w-full">{composer}</div>\n </div>\n </main>\n );\n}\n\nfunction StatusDot({ status }: { readonly status: AgentStatus }) {\n const isLive = status === "submitted" || status === "streaming";\n const tone =\n status === "error"\n ? "bg-destructive"\n : isLive\n ? "bg-emerald-500"\n : status === "ready"\n ? "bg-muted-foreground"\n : "bg-muted-foreground/50";\n\n return (\n <span className="relative flex size-1">\n {isLive ? (\n <span\n className={cn(\n "absolute inline-flex size-full animate-ping rounded-full opacity-75",\n tone,\n )}\n />\n ) : null}\n <span className={cn("relative inline-flex size-1 rounded-full transition-colors", tone)} />\n </span>\n );\n}\n';
|
|
4
4
|
readonly "app/_components/agent-message.tsx": '"use client";\n\nimport type {\n EveAuthorizationPart,\n EveDynamicToolPart,\n EveMessage,\n EveMessagePart,\n} from "eve/react";\nimport { CheckCircleIcon, ExternalLinkIcon, KeyRoundIcon, XCircleIcon } from "lucide-react";\nimport { Message, MessageContent, MessageResponse } from "@/components/ai-elements/message";\nimport { Reasoning, ReasoningContent, ReasoningTrigger } from "@/components/ai-elements/reasoning";\nimport {\n Tool,\n ToolContent,\n ToolHeader,\n ToolInput,\n ToolOutput,\n} from "@/components/ai-elements/tool";\nimport { Button } from "@/components/ui/button";\nimport { cn } from "@/lib/utils";\n\nexport type AgentInputResponse = {\n readonly optionId?: string;\n readonly requestId: string;\n readonly text?: string;\n};\n\nexport function AgentMessage({\n canRespond,\n isStreaming,\n message,\n onInputResponses,\n}: {\n readonly canRespond: boolean;\n readonly isStreaming: boolean;\n readonly message: EveMessage;\n readonly onInputResponses: (responses: readonly AgentInputResponse[]) => void | Promise<void>;\n}) {\n const lastTextIndex = message.parts.reduce(\n (last, part, index) => (part.type === "text" ? index : last),\n -1,\n );\n\n return (\n <Message\n data-optimistic={message.metadata?.optimistic ? "true" : undefined}\n from={message.role}\n >\n <MessageContent>\n {message.parts.map((part, index) => (\n <AgentMessagePart\n canRespond={canRespond}\n key={partKey(part, index)}\n onInputResponses={onInputResponses}\n part={part}\n showCaret={isStreaming && message.role === "assistant" && index === lastTextIndex}\n />\n ))}\n </MessageContent>\n </Message>\n );\n}\n\nfunction AgentMessagePart({\n canRespond,\n onInputResponses,\n part,\n showCaret,\n}: {\n readonly canRespond: boolean;\n readonly onInputResponses: (responses: readonly AgentInputResponse[]) => void | Promise<void>;\n readonly part: EveMessagePart;\n readonly showCaret: boolean;\n}) {\n switch (part.type) {\n case "step-start":\n return null;\n case "text":\n return (\n <MessageResponse caret="block" isAnimating={showCaret}>\n {part.text}\n </MessageResponse>\n );\n case "reasoning":\n return (\n <Reasoning defaultOpen isStreaming={part.state === "streaming"}>\n <ReasoningTrigger />\n <ReasoningContent>{part.text}</ReasoningContent>\n </Reasoning>\n );\n case "authorization":\n return <AuthorizationPrompt part={part} />;\n case "dynamic-tool":\n return (\n <Tool\n defaultOpen={part.state === "approval-requested" || part.state === "approval-responded"}\n >\n <ToolHeader\n state={part.state}\n title={part.toolName}\n toolName={part.toolName}\n type="dynamic-tool"\n />\n <ToolContent>\n <ToolInput input={part.input} />\n <InputRequestActions\n canRespond={canRespond}\n part={part}\n onInputResponses={onInputResponses}\n />\n <ToolOutput errorText={part.errorText} output={part.output} />\n </ToolContent>\n </Tool>\n );\n }\n}\n\nfunction AuthorizationPrompt({ part }: { readonly part: EveAuthorizationPart }) {\n const isAuthorized = part.state === "completed" && part.outcome === "authorized";\n const isCompleted = part.state === "completed";\n const Icon = isAuthorized ? CheckCircleIcon : isCompleted ? XCircleIcon : KeyRoundIcon;\n const instructions = part.authorization?.instructions;\n const shouldShowInstructions = instructions !== undefined && instructions !== part.description;\n\n return (\n <div\n className={cn(\n "space-y-3 rounded-md border p-3",\n isAuthorized\n ? "border-emerald-500/30 bg-emerald-500/5"\n : isCompleted\n ? "border-destructive/30 bg-destructive/5"\n : "border-blue-500/30 bg-blue-500/5",\n )}\n >\n <div className="flex items-start gap-3">\n <span\n className={cn(\n "mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-full",\n isAuthorized\n ? "bg-emerald-500/10 text-emerald-700 dark:text-emerald-300"\n : isCompleted\n ? "bg-destructive/10 text-destructive"\n : "bg-blue-500/10 text-blue-700 dark:text-blue-300",\n )}\n >\n <Icon className="size-4" />\n </span>\n <div className="min-w-0 flex-1 space-y-2">\n <p className="font-medium text-sm">{authorizationTitle(part)}</p>\n <p className="text-muted-foreground text-sm">{authorizationDescription(part)}</p>\n {shouldShowInstructions ? (\n <p className="text-muted-foreground text-sm">{instructions}</p>\n ) : null}\n {part.state === "required" && part.authorization?.userCode ? (\n <div className="flex flex-wrap items-center gap-2 text-sm">\n <span className="text-muted-foreground">Code</span>\n <code className="rounded-md bg-background px-2 py-1 font-mono">\n {part.authorization.userCode}\n </code>\n </div>\n ) : null}\n {part.state === "required" && part.authorization?.url ? (\n <Button asChild size="sm">\n <a href={part.authorization.url} rel="noreferrer" target="_blank">\n <ExternalLinkIcon className="size-4" />\n Sign in with {part.displayName}\n </a>\n </Button>\n ) : null}\n </div>\n </div>\n </div>\n );\n}\n\nfunction authorizationTitle(part: EveAuthorizationPart): string {\n if (part.state === "required") {\n return `Connect ${part.displayName}`;\n }\n if (part.outcome === "authorized") {\n return `${part.displayName} connected`;\n }\n return `${part.displayName} authorization ${formatAuthorizationOutcome(part.outcome)}`;\n}\n\nfunction authorizationDescription(part: EveAuthorizationPart): string {\n if (part.state === "required") {\n return part.description;\n }\n if (part.outcome === "authorized") {\n return `${part.displayName} connected.`;\n }\n const tail = part.reason !== undefined ? ` (${part.reason})` : "";\n return `${part.displayName} authorization ${formatAuthorizationOutcome(part.outcome)}${tail}.`;\n}\n\nfunction formatAuthorizationOutcome(outcome: NonNullable<EveAuthorizationPart["outcome"]>): string {\n switch (outcome) {\n case "authorized":\n return "authorized";\n case "declined":\n return "declined";\n case "failed":\n return "failed";\n case "timed-out":\n return "timed out";\n }\n}\n\nfunction InputRequestActions({\n canRespond,\n onInputResponses,\n part,\n}: {\n readonly canRespond: boolean;\n readonly onInputResponses: (responses: readonly AgentInputResponse[]) => void | Promise<void>;\n readonly part: EveDynamicToolPart;\n}) {\n const inputRequest = part.toolMetadata?.eve?.inputRequest;\n if (!inputRequest) {\n return null;\n }\n\n const inputResponse = part.toolMetadata?.eve?.inputResponse;\n const selectedOption = inputRequest.options?.find(\n (option) => option.id === inputResponse?.optionId,\n );\n\n return (\n <div className="space-y-3 rounded-md border border-yellow-500/30 bg-yellow-500/5 p-3">\n <p className="text-muted-foreground text-sm">{inputRequest.prompt}</p>\n {inputResponse ? (\n <p className="font-medium text-sm">\n Responded: {selectedOption?.label ?? inputResponse.text ?? inputResponse.optionId}\n </p>\n ) : (\n <div className="flex flex-wrap gap-2">\n {inputRequest.options?.map((option) => (\n <Button\n disabled={!canRespond}\n key={option.id}\n onClick={() => {\n void onInputResponses([\n {\n optionId: option.id,\n requestId: inputRequest.requestId,\n },\n ]);\n }}\n size="sm"\n type="button"\n variant={option.style === "danger" ? "destructive" : "default"}\n >\n {option.label}\n </Button>\n ))}\n </div>\n )}\n </div>\n );\n}\n\nfunction partKey(part: EveMessagePart, index: number): string {\n switch (part.type) {\n case "authorization":\n return `authorization:${part.turnId}:${part.stepIndex}:${part.name}`;\n case "dynamic-tool":\n return part.toolCallId;\n default:\n return `${part.type}:${index}`;\n }\n}\n';
|
|
5
5
|
readonly "app/globals.css": '@import "tailwindcss";\n@source "../node_modules/streamdown/dist/*.js";\n\n@theme inline {\n --color-background: var(--background);\n --color-foreground: var(--foreground);\n --color-card: var(--card);\n --color-card-foreground: var(--card-foreground);\n --color-popover: var(--popover);\n --color-popover-foreground: var(--popover-foreground);\n --color-primary: var(--primary);\n --color-primary-foreground: var(--primary-foreground);\n --color-secondary: var(--secondary);\n --color-secondary-foreground: var(--secondary-foreground);\n --color-muted: var(--muted);\n --color-muted-foreground: var(--muted-foreground);\n --color-accent: var(--accent);\n --color-accent-foreground: var(--accent-foreground);\n --color-destructive: var(--destructive);\n --color-border: var(--border);\n --color-input: var(--input);\n --color-ring: var(--ring);\n --radius-sm: calc(var(--radius) - 4px);\n --radius-md: calc(var(--radius) - 2px);\n --radius-lg: var(--radius);\n --radius-xl: calc(var(--radius) + 4px);\n --font-sans: "Geist", "Geist Fallback", ui-sans-serif, system-ui, sans-serif;\n --font-mono: "Geist Mono", "Geist Mono Fallback", ui-monospace, monospace;\n}\n\n:root {\n color-scheme: light;\n /* Soft neutral page with white elevated surfaces so cards/composer pop. */\n --background: oklch(0.971 0 0);\n --foreground: oklch(0.16 0 0);\n --card: oklch(1 0 0);\n --card-foreground: oklch(0.16 0 0);\n --popover: oklch(1 0 0);\n --popover-foreground: oklch(0.16 0 0);\n --primary: oklch(0.19 0 0);\n --primary-foreground: oklch(0.985 0 0);\n --secondary: oklch(0.94 0 0);\n --secondary-foreground: oklch(0.19 0 0);\n --muted: oklch(0.94 0 0);\n --muted-foreground: oklch(0.6 0 0);\n --accent: oklch(0.94 0 0);\n --accent-foreground: oklch(0.19 0 0);\n --destructive: oklch(0.577 0.245 27.325);\n --border: oklch(0.916 0 0);\n --input: oklch(0.916 0 0);\n --ring: oklch(0.708 0 0);\n --radius: 0.625rem;\n}\n\n@media (prefers-color-scheme: dark) {\n :root {\n color-scheme: dark;\n --background: oklch(0.145 0 0);\n --foreground: oklch(0.985 0 0);\n --card: oklch(0.205 0 0);\n --card-foreground: oklch(0.985 0 0);\n --popover: oklch(0.205 0 0);\n --popover-foreground: oklch(0.985 0 0);\n --primary: oklch(0.922 0 0);\n --primary-foreground: oklch(0.205 0 0);\n --secondary: oklch(0.269 0 0);\n --secondary-foreground: oklch(0.985 0 0);\n --muted: oklch(0.269 0 0);\n --muted-foreground: oklch(0.708 0 0);\n --accent: oklch(0.269 0 0);\n --accent-foreground: oklch(0.985 0 0);\n --destructive: oklch(0.704 0.191 22.216);\n --border: oklch(1 0 0 / 10%);\n --input: oklch(1 0 0 / 15%);\n --ring: oklch(0.556 0 0);\n }\n}\n\n* {\n border-color: var(--border);\n}\n\nhtml {\n height: 100%;\n}\n\nbody {\n min-height: 100%;\n margin: 0;\n background: var(--background);\n font-family: var(--font-sans);\n}\n\nbutton,\ninput,\ntextarea {\n font: inherit;\n}\n';
|
|
@@ -3,10 +3,10 @@ import { localDev, placeholderAuth, vercelOidc } from "eve/channels/auth";
|
|
|
3
3
|
|
|
4
4
|
export default eveChannel({
|
|
5
5
|
auth: [
|
|
6
|
-
// Open on localhost for \`eve dev\` and the REPL; ignored in production.
|
|
7
|
-
localDev(),
|
|
8
6
|
// Lets the eve TUI and your Vercel deployments reach the deployed agent.
|
|
9
7
|
vercelOidc(),
|
|
8
|
+
// Open on localhost for \`eve dev\` and the REPL; ignored in production.
|
|
9
|
+
localDev(),
|
|
10
10
|
// This placeholder will not allow browser requests in production.
|
|
11
11
|
// Replace it with your app's auth provider, like Auth.js or Clerk,
|
|
12
12
|
// or use none() for a public demo.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { byokProviderEnvVar, CURRENT_DIRECTORY_PROJECT_NAME, isEveProject, scaffoldBaseProject, type EvePackageContract, type ScaffoldBaseProjectOptions, } from "./create/project.js";
|
|
2
2
|
export { DEFAULT_SLACK_CONNECTOR_SLUG, SLACK_CHANNEL_DEFAULT_ROUTE, deriveSlackConnectorSlug, ensureChannel, hasVercelHostFramework, isNextJsProject, listAuthoredChannels, normalizeSlackConnectorSlug, type ChannelKind, type ChannelMutationResult, type EnsureChannelOptions, type SlackConnectorSlug, type WebPackageVersions, } from "./update/channels.js";
|
|
3
3
|
export { SCAFFOLDABLE_CHANNELS, type ScaffoldableChannel } from "./channels-catalog.js";
|
|
4
|
-
export { ensureConnection, listAuthoredConnections, type ConnectionInput, type ConnectionMutationAction, type ConnectionMutationResult, type EnsureConnectionOptions, } from "./update/connections.js";
|
|
4
|
+
export { ensureConnection, ensureConnectionDependencies, listAuthoredConnections, type ConnectionInput, type ConnectionMutationAction, type ConnectionMutationResult, type EnsureConnectionOptions, type EnsureConnectionDependenciesOptions, } from "./update/connections.js";
|
|
5
5
|
export { catalogSlugs, CONNECTION_CATALOG, CUSTOM_CONNECTION_SLUG, effectiveProtocols, endpointForProtocol, getCatalogEntry, isValidConnectionSlug, SUPPORTED_PROTOCOLS, type ConnectionAuthSpec, type ConnectionCatalogEntry, type ConnectionProtocol, type CustomConnectionInput, type EnvHeader, type McpEndpoint, type OpenApiEndpoint, } from "./connections/catalog.js";
|
|
6
6
|
export { WriteFileExistsError } from "./files.js";
|
|
7
7
|
export { HumanActionRequiredError, type HumanAction } from "../human-action.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{CONNECTION_CATALOG,CUSTOM_CONNECTION_SLUG,SUPPORTED_PROTOCOLS,catalogSlugs,effectiveProtocols,endpointForProtocol,getCatalogEntry,isValidConnectionSlug}from"./connections/catalog.js";import{HumanActionRequiredError}from"../human-action.js";import{SCAFFOLDABLE_CHANNELS}from"./channels-catalog.js";import{WriteFileExistsError}from"./files.js";import{CURRENT_DIRECTORY_PROJECT_NAME,byokProviderEnvVar,isEveProject,scaffoldBaseProject}from"./create/project.js";import{DEFAULT_SLACK_CONNECTOR_SLUG,SLACK_CHANNEL_DEFAULT_ROUTE,deriveSlackConnectorSlug,ensureChannel,hasVercelHostFramework,isNextJsProject,listAuthoredChannels,normalizeSlackConnectorSlug}from"./update/channels.js";import{ensureConnection,ensureConnectionDependencies,listAuthoredConnections}from"./update/connections.js";export{CONNECTION_CATALOG,CURRENT_DIRECTORY_PROJECT_NAME,CUSTOM_CONNECTION_SLUG,DEFAULT_SLACK_CONNECTOR_SLUG,HumanActionRequiredError,SCAFFOLDABLE_CHANNELS,SLACK_CHANNEL_DEFAULT_ROUTE,SUPPORTED_PROTOCOLS,WriteFileExistsError,byokProviderEnvVar,catalogSlugs,deriveSlackConnectorSlug,effectiveProtocols,endpointForProtocol,ensureChannel,ensureConnection,ensureConnectionDependencies,getCatalogEntry,hasVercelHostFramework,isEveProject,isNextJsProject,isValidConnectionSlug,listAuthoredChannels,listAuthoredConnections,normalizeSlackConnectorSlug,scaffoldBaseProject};
|
|
@@ -28,6 +28,12 @@ export interface EnsureConnectionOptions {
|
|
|
28
28
|
force?: boolean;
|
|
29
29
|
connectPackageVersion?: string;
|
|
30
30
|
}
|
|
31
|
+
export interface EnsureConnectionDependenciesOptions {
|
|
32
|
+
projectRoot: string;
|
|
33
|
+
connectPackageVersion?: string;
|
|
34
|
+
}
|
|
35
|
+
/** Adds the package dependency required by a Connect-auth connection. */
|
|
36
|
+
export declare function ensureConnectionDependencies(options: EnsureConnectionDependenciesOptions): Promise<PackageJsonMutation[]>;
|
|
31
37
|
/**
|
|
32
38
|
* Scaffolds `agent/connections/<slug>.ts` from a catalog entry or custom
|
|
33
39
|
* input, patching `package.json` for Connect-auth connections and seeding
|