eve 0.31.3 → 0.32.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.
- package/CHANGELOG.md +23 -0
- package/dist/src/chunks/{use-eve-agent-CF5D6jSV.js → use-eve-agent-CX87G1vU.js} +30 -5
- package/dist/src/chunks/{use-eve-agent-DbYZLG0h.js → use-eve-agent-DwyRde1N.js} +30 -5
- package/dist/src/cli/commands/integration-connect.d.ts +1 -0
- package/dist/src/cli/commands/integration-connect.js +1 -1
- package/dist/src/cli/commands/integration-setup.d.ts +4 -0
- package/dist/src/cli/commands/integration-setup.js +1 -1
- package/dist/src/cli/commands/register-integration-commands.js +1 -1
- package/dist/src/cli/commands/register-registry-commands.js +1 -1
- package/dist/src/cli/commands/registry-declared-setups.d.ts +23 -0
- package/dist/src/cli/commands/registry-declared-setups.js +1 -0
- package/dist/src/cli/commands/registry-metadata.d.ts +69 -0
- package/dist/src/cli/commands/registry-metadata.js +1 -1
- package/dist/src/cli/commands/registry-package.d.ts +3 -3
- package/dist/src/cli/commands/registry-package.js +1 -1
- package/dist/src/cli/commands/registry-presentation.d.ts +20 -0
- package/dist/src/cli/commands/registry-presentation.js +7 -0
- package/dist/src/cli/commands/registry-search-presentation.d.ts +16 -0
- package/dist/src/cli/commands/registry-search-presentation.js +6 -0
- package/dist/src/cli/commands/registry-setup-command.d.ts +5 -2
- package/dist/src/cli/commands/registry-setup-command.js +1 -2
- package/dist/src/cli/commands/registry.d.ts +16 -7
- package/dist/src/cli/commands/registry.js +1 -6
- package/dist/src/cli/commands/setup-answers.d.ts +2 -0
- package/dist/src/cli/commands/setup-answers.js +1 -0
- package/dist/src/cli/commands/setup-headless.d.ts +79 -0
- package/dist/src/cli/commands/setup-headless.js +1 -0
- package/dist/src/cli/dev/tui/runner.js +1 -1
- package/dist/src/cli/dev/tui/setup-commands.js +3 -3
- package/dist/src/cli/dev/tui/setup-flow.d.ts +8 -1
- package/dist/src/cli/dev/tui/terminal-renderer.js +12 -12
- package/dist/src/cli/dev/tui/traces/trace-conversation.d.ts +1 -1
- package/dist/src/cli/dev/tui/tui-prompter.js +1 -1
- package/dist/src/client/url.d.ts +5 -0
- package/dist/src/client/url.js +1 -1
- package/dist/src/compiled/.vendor-stamp.json +8 -8
- package/dist/src/compiled/@ai-sdk/anthropic/index.d.ts +33 -13
- package/dist/src/compiled/@ai-sdk/anthropic/index.js +4 -2
- package/dist/src/compiled/@ai-sdk/google/index.d.ts +50 -3
- package/dist/src/compiled/@ai-sdk/google/index.js +7 -7
- package/dist/src/compiled/@ai-sdk/mcp/index.d.ts +33 -3
- package/dist/src/compiled/@ai-sdk/mcp/index.js +1 -1
- package/dist/src/compiled/@ai-sdk/openai/index.d.ts +140 -9
- package/dist/src/compiled/@ai-sdk/openai/index.js +9 -6
- package/dist/src/compiled/@ai-sdk/otel/index.js +1 -1
- package/dist/src/compiled/@ai-sdk/provider/index.d.ts +300 -6
- package/dist/src/compiled/@ai-sdk/provider-utils/index.d.ts +70 -20
- package/dist/src/compiled/@opentelemetry/api/index.d.ts +2 -1
- package/dist/src/compiled/@photon-ai/chat-adapter-imessage/index.js +1 -1
- package/dist/src/compiled/@vercel/otel/index.d.ts +6 -0
- package/dist/src/compiled/@vercel/sandbox/index.js +1 -1
- package/dist/src/compiled/_chunks/node/undici-CUIybhQ2.js +95 -0
- package/dist/src/compiled/_chunks/workflow/dist-eUxFublw.js +77 -0
- package/dist/src/compiled/shadcn-registry/index.js +309 -215
- package/dist/src/compiler/extension-compatibility.d.ts +10 -10
- package/dist/src/compiler/extension-compatibility.js +1 -1
- package/dist/src/context/build-callback-context.js +1 -1
- package/dist/src/execution/authorization-callback-match.d.ts +14 -0
- package/dist/src/execution/authorization-callback-match.js +1 -0
- package/dist/src/execution/next-driver-action.d.ts +1 -0
- package/dist/src/execution/parked-delivery-wait.d.ts +16 -1
- package/dist/src/execution/parked-delivery-wait.js +1 -1
- package/dist/src/execution/sandbox/abort-bound-session.d.ts +1 -1
- package/dist/src/execution/sandbox/bindings/docker.js +1 -1
- package/dist/src/execution/sandbox/bindings/just-bash-runtime.js +1 -1
- package/dist/src/execution/sandbox/bindings/microsandbox-lifecycle.js +1 -1
- package/dist/src/execution/sandbox/bindings/microsandbox-runtime.d.ts +1 -0
- package/dist/src/execution/sandbox/bindings/microsandbox-runtime.js +1 -1
- package/dist/src/execution/sandbox/bindings/vercel.js +1 -1
- package/dist/src/execution/sandbox/ensure.js +1 -1
- package/dist/src/execution/session-command-inbox.d.ts +26 -1
- package/dist/src/execution/session-command-inbox.js +1 -1
- package/dist/src/execution/turn-execution-cursor.d.ts +1 -0
- package/dist/src/execution/turn-workflow.js +1 -1
- package/dist/src/execution/workflow-entry.js +1 -1
- package/dist/src/execution/workflow-steps.d.ts +3 -4
- package/dist/src/execution/workflow-steps.js +1 -1
- package/dist/src/harness/authorization.d.ts +24 -11
- package/dist/src/harness/authorization.js +1 -1
- package/dist/src/harness/input-extraction.js +1 -1
- package/dist/src/harness/input-requests.js +1 -1
- package/dist/src/harness/provider-tools.d.ts +1 -1
- package/dist/src/harness/provider-tools.js +1 -1
- package/dist/src/harness/tool-loop.js +2 -2
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/packages/eve-catalog/src/index.js +1 -1
- package/dist/src/protocol/routes.d.ts +8 -6
- package/dist/src/protocol/routes.js +1 -1
- package/dist/src/public/channels/slack/attachments.js +1 -1
- package/dist/src/public/channels/slack/defaults.js +1 -1
- package/dist/src/public/channels/slack/hitl.d.ts +14 -1
- package/dist/src/public/channels/slack/hitl.js +2 -2
- package/dist/src/public/definitions/callback-context.d.ts +2 -2
- package/dist/src/public/definitions/sandbox.d.ts +1 -1
- package/dist/src/public/definitions/tool.d.ts +9 -9
- package/dist/src/public/sandbox/index.d.ts +1 -1
- package/dist/src/public/tools/web-search.d.ts +2 -2
- package/dist/src/runtime/connections/callback-route.d.ts +4 -5
- package/dist/src/runtime/connections/callback-route.js +1 -1
- package/dist/src/runtime/connections/scoped-authorization.js +1 -1
- package/dist/src/runtime/framework-tools/connection-search-dynamic.js +2 -2
- package/dist/src/runtime/framework-tools/todo.js +1 -1
- package/dist/src/runtime/input/types.d.ts +1 -4
- package/dist/src/sandbox/state.d.ts +1 -0
- package/dist/src/setup/ask-editable.d.ts +22 -0
- package/dist/src/setup/ask-editable.js +1 -0
- package/dist/src/setup/ask-signals.d.ts +23 -0
- package/dist/src/setup/ask-signals.js +1 -0
- package/dist/src/setup/ask.d.ts +24 -25
- package/dist/src/setup/ask.js +1 -1
- package/dist/src/setup/boxes/deploy-project.js +1 -1
- package/dist/src/setup/boxes/resolve-provisioning.js +1 -1
- package/dist/src/setup/connection-connector.js +3 -2
- package/dist/src/setup/flows/registry-session.d.ts +33 -0
- package/dist/src/setup/flows/registry-session.js +1 -0
- package/dist/src/setup/flows/registry.d.ts +16 -0
- package/dist/src/setup/flows/registry.js +1 -1
- package/dist/src/setup/index.js +1 -1
- package/dist/src/setup/integrations/discord/setup.d.ts +19 -7
- package/dist/src/setup/integrations/discord/setup.js +4 -3
- package/dist/src/setup/integrations/github/setup.d.ts +36 -7
- package/dist/src/setup/integrations/github/setup.js +2 -2
- package/dist/src/setup/integrations/linear/setup.d.ts +21 -9
- package/dist/src/setup/integrations/linear/setup.js +2 -2
- package/dist/src/setup/integrations/photon/management.d.ts +8 -1
- package/dist/src/setup/integrations/photon/management.js +1 -1
- package/dist/src/setup/integrations/photon/setup-flow.d.ts +28 -24
- package/dist/src/setup/integrations/photon/setup-flow.js +3 -3
- package/dist/src/setup/integrations/photon/setup.d.ts +1 -3
- package/dist/src/setup/integrations/photon/setup.js +1 -1
- package/dist/src/setup/integrations/registry.d.ts +1 -1
- package/dist/src/setup/integrations/registry.js +1 -1
- package/dist/src/setup/integrations/runner.d.ts +14 -11
- package/dist/src/setup/integrations/runner.js +1 -1
- package/dist/src/setup/integrations/shared/prerequisite.d.ts +17 -0
- package/dist/src/setup/integrations/shared/prerequisite.js +1 -0
- package/dist/src/setup/integrations/shared/ui.d.ts +22 -15
- package/dist/src/setup/integrations/shared/ui.js +2 -2
- package/dist/src/setup/integrations/shared/vercel-project.d.ts +11 -0
- package/dist/src/setup/integrations/shared/vercel-project.js +1 -0
- package/dist/src/setup/integrations/slack/setup.d.ts +25 -10
- package/dist/src/setup/integrations/slack/setup.js +1 -1
- package/dist/src/setup/integrations/types.d.ts +43 -13
- package/dist/src/setup/integrations/types.js +1 -1
- package/dist/src/setup/integrations/web/setup.d.ts +22 -3
- package/dist/src/setup/integrations/web/setup.js +1 -1
- package/dist/src/setup/prompter.d.ts +8 -0
- package/dist/src/setup/question-options.d.ts +15 -0
- package/dist/src/setup/question-options.js +1 -0
- package/dist/src/setup/registry-setup-client.d.ts +3 -4
- package/dist/src/setup/registry-setup-client.js +2 -2
- package/dist/src/setup/registry-setup-completion.d.ts +3 -0
- package/dist/src/setup/registry-setup-completion.js +1 -0
- package/dist/src/setup/registry-setup-protocol.d.ts +22 -3
- package/dist/src/setup/registry-setup-protocol.js +1 -1
- package/dist/src/setup/scaffold/create/add-to-project.js +1 -1
- package/dist/src/setup/scaffold/create/project.js +55 -3
- package/dist/src/setup/scaffold/update/channels.js +1 -1
- package/dist/src/setup/setup-question-wire.d.ts +48 -0
- package/dist/src/setup/setup-question-wire.js +1 -0
- package/dist/src/setup/slackbot.d.ts +5 -1
- package/dist/src/setup/slackbot.js +1 -1
- package/dist/src/setup/state.d.ts +2 -2
- package/dist/src/shared/sandbox-backend.d.ts +6 -0
- package/dist/src/shared/sandbox-session.d.ts +15 -0
- package/dist/src/shared/tool-definition.d.ts +2 -2
- package/dist/src/shared/tool-schema.d.ts +5 -4
- package/dist/src/shared/tool-schema.js +1 -1
- package/dist/src/svelte/index.js +1 -1
- package/dist/src/svelte/use-eve-agent.js +1 -1
- package/dist/src/tracing/agent-otel-provider.d.ts +5 -38
- package/dist/src/tracing/agent-otel-provider.js +2 -2
- package/dist/src/tracing/agent-span-id-generator.d.ts +15 -0
- package/dist/src/tracing/agent-span-id-generator.js +1 -0
- package/dist/src/tracing/agent-trace-context-store.d.ts +1 -1
- package/dist/src/tracing/agent-trace-context-store.js +1 -1
- package/dist/src/tracing/agent-trace-state.d.ts +41 -0
- package/dist/src/tracing/agent-trace-state.js +1 -0
- package/dist/src/tracing/local-instrumentation-runtime.js +1 -1
- package/dist/src/vue/index.js +1 -1
- package/dist/src/vue/use-eve-agent.js +1 -1
- package/docs/channels/chat-sdk.mdx +1 -1
- package/docs/channels/github.mdx +1 -1
- package/docs/channels/linear.mdx +1 -1
- package/docs/channels/overview.mdx +2 -2
- package/docs/channels/slack.mdx +154 -40
- package/docs/concepts/default-harness.md +3 -3
- package/docs/concepts/sessions-runs-and-streaming.md +1 -1
- package/docs/connections/mcp.mdx +6 -0
- package/docs/guides/dev-tui.md +58 -142
- package/docs/guides/dynamic-workflows.md +2 -0
- package/docs/guides/frontend/overview.mdx +4 -2
- package/docs/guides/hooks.md +25 -3
- package/docs/guides/session-context.md +18 -0
- package/docs/install-integrations.mdx +2 -0
- package/docs/reference/cli.md +5 -3
- package/docs/reference/typescript-api.md +1 -1
- package/docs/sandbox.mdx +25 -5
- package/docs/skills.mdx +12 -1
- package/docs/subagents.mdx +1 -1
- package/docs/tools/human-in-the-loop.md +1 -1
- package/docs/tutorial/ship-it.mdx +1 -1
- package/package.json +10 -10
- package/dist/src/compiled/_chunks/node/undici-DWL_MYmT.js +0 -95
- package/dist/src/compiled/_chunks/workflow/dist-CZxNEvEs.js +0 -79
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
import{readProjectLink}from"#setup/project-resolution.js";import{captureVercel,runVercel,runVercelCaptureStdout}from"#setup/primitives/run-vercel.js";import{createPromptCommandOutput,withPhase}from"#setup/cli/index.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
|
|
2
|
-
`))
|
|
1
|
+
import{readProjectLink}from"#setup/project-resolution.js";import{captureVercel,runVercel,runVercelCaptureStdout}from"#setup/primitives/run-vercel.js";import{createPromptCommandOutput,withPhase}from"#setup/cli/index.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 connectorCreationFailure(e,t){let n=t?.split(`
|
|
2
|
+
`).map(e=>e.trim()).filter(e=>e.length>0&&!e.startsWith(`Vercel CLI `)).at(-1);return n===void 0?`Could not create the ${e} connector.`:`Could not create the ${e} connector. Vercel returned: ${n}`}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,n,r){let i=[],a=new Set,o;do{let s=[`connect`,`list`,`-F`,`json`,`--all-projects`,`--service`,e.service,`--scope`,n.orgId];o!==void 0&&s.push(`--next`,o);let c=await captureVercel(s,{cwd:e.projectRoot,onOutput:r,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,n,r,i){let a=await captureVercel([`api`,`/v1/connect/connectors/${encodeURIComponent(r.id)}`,`--scope`,n.orgId,`--raw`],{cwd:e.projectRoot,onOutput:i,signal:e.signal});if(!a.ok)throw Error(`Could not verify connector ${r.uid}.`);let o=parseJson(a.stdout);if(!isRecord(o)||o.id!==r.id||o.uid!==r.uid||typeof o.service==`string`&&o.service!==e.service)throw Error(`Vercel returned invalid details for connector ${r.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||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(t){let r=t.orgId??(await readProjectLink(t.projectRoot))?.orgId,a=[`connect`,`remove`,t.connectorId,`--disconnect-all`,`--yes`];if(r!==void 0&&a.push(`--scope`,r),!await runVercel(a,{cwd:t.projectRoot,onOutput:createPromptCommandOutput(t.log)}))throw Error(`Could not remove connector ${t.connectorId}; run \`vercel connect remove ${t.connectorId} --disconnect-all --yes\`.`)}async function attach(e,t,r,i){return runVercel([`connect`,`attach`,r,`--yes`,`--scope`,t.orgId],{cwd:e.projectRoot,onOutput:i,signal:e.signal})}async function resolveFallbackConnector(e,t,n,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 r=[];for(let a of i)await supportsUserAuthorization(e,t,a,n)&&r.push(a);if(r.length===0){c=`No existing ${e.service} connectors support user authorization.`;continue}let a=new Map(r.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:r.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),n(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(`
|
|
3
|
+
`))?.[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.`:connectorCreationFailure(e.service,d.stderr);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 t=createPromptCommandOutput(e.log),n=e.project,r=await listConnectors(e,n,t),a=r.find(t=>connectorMatchesCanonicalName(t,e.canonicalConnectorName)),o=`Could not find a connector named ${e.canonicalConnectorName}.`;if(a!==void 0)if(await supportsUserAuthorization(e,n,a,t)){if(await attach(e,n,a.uid,t))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,n,t,r,o);if(!await attach(e,n,s.connector.uid,t)){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:n.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};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Prompter } from "#setup/prompter.js";
|
|
2
|
+
import { detectDeployment } from "#setup/project-resolution.js";
|
|
3
|
+
import type { RegistrySetupCompletion, RegistrySetupFact } from "#setup/registry-setup-protocol.js";
|
|
4
|
+
import { runDeployFlow } from "./deploy.js";
|
|
5
|
+
export interface RegistrySessionDeps {
|
|
6
|
+
detectDeployment: typeof detectDeployment;
|
|
7
|
+
runDeployFlow: typeof runDeployFlow;
|
|
8
|
+
}
|
|
9
|
+
export interface RegistrySessionItemResult {
|
|
10
|
+
address: string;
|
|
11
|
+
title: string;
|
|
12
|
+
facts: readonly RegistrySetupFact[];
|
|
13
|
+
output: readonly string[];
|
|
14
|
+
}
|
|
15
|
+
export interface RegistrySessionResult {
|
|
16
|
+
kind: "done";
|
|
17
|
+
addedItems: readonly string[];
|
|
18
|
+
items: readonly RegistrySessionItemResult[];
|
|
19
|
+
facts: readonly RegistrySetupFact[];
|
|
20
|
+
output: readonly string[];
|
|
21
|
+
deployed?: "production";
|
|
22
|
+
}
|
|
23
|
+
export interface RegistrySession {
|
|
24
|
+
add(item: string, title: string, output: readonly string[], setup?: RegistrySetupCompletion): void;
|
|
25
|
+
result(deployed?: "production"): RegistrySessionResult;
|
|
26
|
+
continueAfterInstall(input: {
|
|
27
|
+
appRoot: string;
|
|
28
|
+
prompter: Prompter;
|
|
29
|
+
signal?: AbortSignal;
|
|
30
|
+
}): Promise<"add-more" | RegistrySessionResult>;
|
|
31
|
+
}
|
|
32
|
+
/** Owns the accumulated output and deployment decision for one `/add` session. */
|
|
33
|
+
export declare function createRegistrySession(deps: RegistrySessionDeps): RegistrySession;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import"./deploy.js";import"#setup/project-resolution.js";import{mergeRegistrySetupCompletions}from"#setup/registry-setup-completion.js";function createRegistrySession(t){let n=[],r=[],i=[],a={facts:[]},o=``,s=[];function result(e){let t={kind:`done`,addedItems:n,items:r,facts:a.facts,output:i};return e!==void 0&&(t.deployed=e),t}return{add(t,c,l,u={facts:[]}){n.push(t),r.push({address:t,title:c,facts:u.facts,output:l}),i.push(...l),o=c,s=u.facts,a=mergeRegistrySetupCompletions(a,u)},result,async continueAfterInstall(e){if(a.deploymentRequired!==!0)return result();let n=await t.detectDeployment(e.appRoot,{signal:e.signal}),r=n.state===`linked`||n.state===`deployed`;for(e.prompter.replaceContent?.({headline:`Added ${o}`,facts:s});;){let n=await e.prompter.select({message:`What would you like to do next?`,initialValue:`add-more`,hintLayout:`inline`,options:[{value:`add-more`,label:`Add more`},...r?[{value:`deploy`,label:`Deploy`}]:[],{value:`finish`,label:`Finish`}]});if(n===`add-more`)return e.prompter.replaceContent?.(),`add-more`;if(n===`finish`)return result();if(await e.prompter.select({message:`Deploy to prod?`,initialValue:`yes`,options:[{value:`yes`,label:`Yes`},{value:`back`,label:`Back`}]})!==`back`)return result((await t.runDeployFlow({appRoot:e.appRoot,prompter:e.prompter,signal:e.signal,interactive:!0})).kind===`deployed`?`production`:void 0)}}}}export{createRegistrySession};
|
|
@@ -1,16 +1,32 @@
|
|
|
1
1
|
import type { Prompter } from "#setup/prompter.js";
|
|
2
|
+
import { runDeployFlow } from "#setup/flows/deploy.js";
|
|
3
|
+
import { detectDeployment } from "#setup/project-resolution.js";
|
|
4
|
+
import type { RegistrySetupFact } from "#setup/registry-setup-protocol.js";
|
|
2
5
|
export interface RegistryFlowDeps {
|
|
3
6
|
browseRegistryCatalog: (typeof import("#cli/commands/registry.js"))["browseRegistryCatalog"];
|
|
7
|
+
detectDeployment: typeof detectDeployment;
|
|
4
8
|
getRegistryItemManifest: (typeof import("#cli/commands/registry.js"))["getRegistryItemManifest"];
|
|
5
9
|
installRegistryItem: (typeof import("#cli/commands/registry.js"))["installRegistryItem"];
|
|
10
|
+
runDeployFlow: typeof runDeployFlow;
|
|
6
11
|
}
|
|
7
12
|
export type RegistryFlowResult = {
|
|
8
13
|
kind: "done";
|
|
9
14
|
addedItems: readonly string[];
|
|
15
|
+
items: readonly import("./registry-session.js").RegistrySessionItemResult[];
|
|
16
|
+
facts: readonly RegistrySetupFact[];
|
|
10
17
|
output?: readonly string[];
|
|
18
|
+
deployed?: "production";
|
|
11
19
|
} | {
|
|
12
20
|
kind: "cancelled";
|
|
13
21
|
};
|
|
22
|
+
export declare class RegistryFlowFailedError extends Error {
|
|
23
|
+
readonly completed: Extract<RegistryFlowResult, {
|
|
24
|
+
kind: "done";
|
|
25
|
+
}>;
|
|
26
|
+
constructor(error: unknown, completed: Extract<RegistryFlowResult, {
|
|
27
|
+
kind: "done";
|
|
28
|
+
}>);
|
|
29
|
+
}
|
|
14
30
|
/** Runs the categorized interactive registry catalog used by the dev TUI's `/add`. */
|
|
15
31
|
export declare function runRegistryFlow(input: {
|
|
16
32
|
appRoot: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{WizardCancelledError}from"#setup/step.js";import{withSpinner}from"#setup/with-spinner.js";const ADDRESS_PREFIX=`address:`,BACK=`action:back`,DONE=`action:done`,ALL=`category:all`,REGISTRY_CATEGORIES=[{value:`category:channel`,prefix:`channel/`,label:`Channels`,hint:`Where people talk to your agent — Web, Slack, Discord, Teams`,browseLabel:`Browse channels`},{value:`category:connection`,prefix:`connection/`,label:`MCP connections`,hint:`Connect services like Linear, Notion, GitHub, and Vercel`,browseLabel:`Browse MCP connections`},{value:`category:extension`,prefix:`extension/`,label:`Extensions`,hint:`Add browser automation, memory, and developer tools`,browseLabel:`Browse extensions`},{value:`category:instrumentation`,prefix:`instrumentation/`,label:`Observability`,hint:`Trace, evaluate, and monitor your agent`,browseLabel:`Browse observability integrations`}];function itemLabel(e){return e.title===void 0?(e.name.split(`/`).at(-1)??e.name).split(`-`).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(` `):e.title}function itemRows(e){return e.map((e,t)=>({value:`item:${t}`,label:itemLabel(e),hint:e.description??e.type}))}function categoryRows(){return[...REGISTRY_CATEGORIES.map(e=>({value:e.value,label:e.label,hint:e.hint})),{value:ALL,label:`Browse all`,hint:`Search every integration or enter an item address`},{value:DONE,label:`Return to chat`,trailingAction:!0}]}function categoryFor(e){return REGISTRY_CATEGORIES.find(t=>t.value===e)}function itemsForCategory(e,t){if(t===ALL)return e;let n=categoryFor(t);return n===void 0?e:e.filter(e=>e.address.startsWith(n.prefix)||e.name.startsWith(n.prefix))}function stringArray(e){return Array.isArray(e)?e.filter(e=>typeof e==`string`):[]}function itemSource(e){if(e.startsWith(`@`))return e.split(`/`)[0]??e;if(/^https?:\/\//u.test(e))try{return new URL(e).host}catch{return e}return`Vercel`}function manifestRecord(e){return typeof e==`object`&&e&&!Array.isArray(e)?e:{}}function summarizeDetails(e,t=3){let n=e.slice(0,t),r=e.length-n.length;return r>0?`${n.join(`, `)} … (+${r} more)`:n.join(`, `)}function itemDetails(e,t){let n=[{label:`Source`,value:e.source}],r=[...stringArray(t.dependencies),...stringArray(t.devDependencies),...stringArray(t.registryDependencies)];r.length>0&&n.push({label:`Packages`,value:summarizeDetails(r)});let i=t.envVars;if(typeof i==`object`&&i&&!Array.isArray(i)){let e=Object.keys(i);e.length>0&&n.push({label:`Environment`,value:summarizeDetails(e)})}let a=(Array.isArray(t.files)?t.files:[]).flatMap(e=>{if(typeof e!=`object`||!e||Array.isArray(e))return[];let t=e.target;return typeof t==`string`?[t]:[]});return a.length>0&&n.push({label:`Files`,value:summarizeDetails(a)}),n}async function inspectItem(e,n,r,
|
|
1
|
+
import{createRegistrySession}from"./registry-session.js";import{runDeployFlow}from"#setup/flows/deploy.js";import{WizardCancelledError}from"#setup/step.js";import{detectDeployment}from"#setup/project-resolution.js";import{withSpinner}from"#setup/with-spinner.js";const ADDRESS_PREFIX=`address:`,BACK=`action:back`,DONE=`action:done`,ALL=`category:all`,REGISTRY_CATEGORIES=[{value:`category:channel`,prefix:`channel/`,label:`Channels`,hint:`Where people talk to your agent — Web, Slack, Discord, Teams`,browseLabel:`Browse channels`},{value:`category:connection`,prefix:`connection/`,label:`MCP connections`,hint:`Connect services like Linear, Notion, GitHub, and Vercel`,browseLabel:`Browse MCP connections`},{value:`category:extension`,prefix:`extension/`,label:`Extensions`,hint:`Add browser automation, memory, and developer tools`,browseLabel:`Browse extensions`},{value:`category:instrumentation`,prefix:`instrumentation/`,label:`Observability`,hint:`Trace, evaluate, and monitor your agent`,browseLabel:`Browse observability integrations`}];var RegistryFlowFailedError=class extends Error{completed;constructor(e,t){super(e instanceof Error?e.message:String(e),{cause:e}),this.name=`RegistryFlowFailedError`,this.completed=t}};function itemLabel(e){return e.title===void 0?(e.name.split(`/`).at(-1)??e.name).split(`-`).map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(` `):e.title}function itemRows(e){return e.map((e,t)=>({value:`item:${t}`,label:itemLabel(e),hint:e.description??e.type}))}function categoryRows(){return[...REGISTRY_CATEGORIES.map(e=>({value:e.value,label:e.label,hint:e.hint})),{value:ALL,label:`Browse all`,hint:`Search every integration or enter an item address`},{value:DONE,label:`Return to chat`,trailingAction:!0}]}function categoryFor(e){return REGISTRY_CATEGORIES.find(t=>t.value===e)}function itemsForCategory(e,t){if(t===ALL)return e;let n=categoryFor(t);return n===void 0?e:e.filter(e=>e.address.startsWith(n.prefix)||e.name.startsWith(n.prefix))}function stringArray(e){return Array.isArray(e)?e.filter(e=>typeof e==`string`):[]}function itemSource(e){if(e.startsWith(`@`))return e.split(`/`)[0]??e;if(/^https?:\/\//u.test(e))try{return new URL(e).host}catch{return e}return`Vercel`}function manifestRecord(e){return typeof e==`object`&&e&&!Array.isArray(e)?e:{}}function summarizeDetails(e,t=3){let n=e.slice(0,t),r=e.length-n.length;return r>0?`${n.join(`, `)} … (+${r} more)`:n.join(`, `)}function itemDetails(e,t){let n=[{label:`Source`,value:e.source}],r=[...stringArray(t.dependencies),...stringArray(t.devDependencies),...stringArray(t.registryDependencies)];r.length>0&&n.push({label:`Packages`,value:summarizeDetails(r)});let i=t.envVars;if(typeof i==`object`&&i&&!Array.isArray(i)){let e=Object.keys(i);e.length>0&&n.push({label:`Environment`,value:summarizeDetails(e)})}let a=(Array.isArray(t.files)?t.files:[]).flatMap(e=>{if(typeof e!=`object`||!e||Array.isArray(e))return[];let t=e.target;return typeof t==`string`?[t]:[]});return a.length>0&&n.push({label:`Files`,value:summarizeDetails(a)}),n}async function inspectItem(e,t,n,r,a,o){let s=a??manifestRecord(await withSpinner(e,`Loading registry item…`,()=>t.getRegistryItemManifest(n,r.address)));for(;;){let i={message:typeof s.title==`string`?s.title:r.name,metadata:itemDetails(r,s),options:[{value:`add`,label:`Add to project`},{value:`back`,label:`Back`}]},a=typeof s.description==`string`?s.description:r.description;if(a!==void 0&&(i.description=a),await e.select(i)===`back`)return{kind:`back`};let c=e.log.spinner?.(`Installing ${itemLabel(r)} and dependencies…`);try{c?.stop();let install=()=>t.installRegistryItem(n,r.address,{silent:!0,prompter:e,signal:o});return{kind:`added`,...await(e.withExclusiveTerminal?.(install)??install())}}finally{c?.stop()}}}async function resolveAddressItem(e,t,n,r){let a=manifestRecord(await withSpinner(e,`Loading registry item…`,()=>t.getRegistryItemManifest(n,r))),o={address:r,name:typeof a.name==`string`?a.name:r,source:itemSource(r)};return typeof a.type==`string`&&(o.type=a.type),typeof a.description==`string`&&(o.description=a.description),{item:o,manifest:a}}async function runRegistryFlow(c){let l;(c.deps?.browseRegistryCatalog===void 0||c.deps.getRegistryItemManifest===void 0||c.deps.installRegistryItem===void 0)&&(l=await import(`#cli/commands/registry.js`));let u={browseRegistryCatalog:c.deps?.browseRegistryCatalog??l.browseRegistryCatalog,detectDeployment:c.deps?.detectDeployment??detectDeployment,getRegistryItemManifest:c.deps?.getRegistryItemManifest??l.getRegistryItemManifest,installRegistryItem:c.deps?.installRegistryItem??l.installRegistryItem,runDeployFlow:c.deps?.runDeployFlow??runDeployFlow},d=[],f=createRegistrySession(u);try{for(;;){c.signal?.throwIfAborted();let e=await withSpinner(c.prompter,`Loading registry…`,()=>u.browseRegistryCatalog(c.appRoot));d=[...d,...e.errors.map(e=>({tone:`warning`,text:`${e.registry}: ${e.message}`}))];let t=await c.prompter.select({message:`Add an integration`,options:categoryRows(),hintLayout:`inline`,notices:d});if(d=[],t===DONE)return f.result();let n=itemsForCategory(e.items,t),r=itemRows(n);r.push({value:BACK,label:`Back`,trailingAction:!0});let l=await c.prompter.select({message:categoryFor(t)?.browseLabel??`Browse integrations`,options:r,search:!0,placeholder:`Search integrations or enter an item address`,searchAction:{label:e=>`Add “${e}”`,value:e=>`${ADDRESS_PREFIX}${e.trim()}`},hintLayout:`inline`});if(l===BACK)continue;let p=l.startsWith(ADDRESS_PREFIX)?await resolveAddressItem(c.prompter,u,c.appRoot,l.slice(8)):{item:n[Number(l.slice(5))]};if(p.item===void 0)throw Error(`The selected registry item is no longer available.`);let m=await inspectItem(c.prompter,u,c.appRoot,p.item,`manifest`in p?p.manifest:void 0,c.signal);if(m.kind!==`added`)continue;f.add(p.item.address,itemLabel(p.item),m.output,m.setup);let h=await f.continueAfterInstall({appRoot:c.appRoot,prompter:c.prompter,signal:c.signal});if(h!==`add-more`)return h}}catch(e){if(e instanceof WizardCancelledError)return{kind:`cancelled`};let t=f.result();throw t.addedItems.length>0?new RegistryFlowFailedError(e,t):e}}export{RegistryFlowFailedError,runRegistryFlow};
|
package/dist/src/setup/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{runRemoteAuthFlow}from"../cli/dev/tui/remote-auth.js";import{InteractionRequired}from"./ask.js";import{runVercel}from"./primitives/run-vercel.js";import{detectDeployment,detectProjectResolution,projectProductionUrlFromResolution}from"./project-resolution.js";import{runVercelEnvPull}from"./run-vercel-link.js";import{createDefaultSetupState,requireProjectPath,snapshotSetupState}from"./state.js";import{getPackageManagerStrategy}from"./primitives/pm/index.js";import{linkProject,requireAuth,resolveProjectByNameOrId,resolveTeam}from"./vercel-project.js";import{createPromptCommandOutput}from"./cli/command-output.js";import"./cli/index.js";import{setupConnectionConnector}from"./connection-connector.js";import{WizardCancelledError}from"./step.js";import{runHeadless,runInteractive}from"./runner.js";import{HeadlessPromptError,createHeadlessPrompter,formatHeadlessEvent}from"./headless.js";import{createPrompter}from"./prompter.js";import{runPackageManagerInstall,runPnpmInstall,spawnPackageManager,spawnPnpm}from"./primitives/pm/run.js";import"./primitives/index.js";import{provisionSlackbot,reconcileSlackUid}from"./slackbot.js";export{HeadlessPromptError,InteractionRequired,WizardCancelledError,createDefaultSetupState,createHeadlessPrompter,createPromptCommandOutput,createPrompter,detectDeployment,detectProjectResolution,formatHeadlessEvent,getPackageManagerStrategy,linkProject,projectProductionUrlFromResolution,provisionSlackbot,reconcileSlackUid,requireAuth,requireProjectPath,resolveProjectByNameOrId,resolveTeam,runHeadless,runInteractive,runPackageManagerInstall,runPnpmInstall,runRemoteAuthFlow,runVercel,runVercelEnvPull,setupConnectionConnector,snapshotSetupState,spawnPackageManager,spawnPnpm};
|
|
1
|
+
import{runRemoteAuthFlow}from"../cli/dev/tui/remote-auth.js";import{InteractionRequired}from"./ask-signals.js";import"./ask.js";import{runVercel}from"./primitives/run-vercel.js";import{detectDeployment,detectProjectResolution,projectProductionUrlFromResolution}from"./project-resolution.js";import{runVercelEnvPull}from"./run-vercel-link.js";import{createDefaultSetupState,requireProjectPath,snapshotSetupState}from"./state.js";import{getPackageManagerStrategy}from"./primitives/pm/index.js";import{linkProject,requireAuth,resolveProjectByNameOrId,resolveTeam}from"./vercel-project.js";import{createPromptCommandOutput}from"./cli/command-output.js";import"./cli/index.js";import{setupConnectionConnector}from"./connection-connector.js";import{WizardCancelledError}from"./step.js";import{runHeadless,runInteractive}from"./runner.js";import{HeadlessPromptError,createHeadlessPrompter,formatHeadlessEvent}from"./headless.js";import{createPrompter}from"./prompter.js";import{runPackageManagerInstall,runPnpmInstall,spawnPackageManager,spawnPnpm}from"./primitives/pm/run.js";import"./primitives/index.js";import{provisionSlackbot,reconcileSlackUid}from"./slackbot.js";export{HeadlessPromptError,InteractionRequired,WizardCancelledError,createDefaultSetupState,createHeadlessPrompter,createPromptCommandOutput,createPrompter,detectDeployment,detectProjectResolution,formatHeadlessEvent,getPackageManagerStrategy,linkProject,projectProductionUrlFromResolution,provisionSlackbot,reconcileSlackUid,requireAuth,requireProjectPath,resolveProjectByNameOrId,resolveTeam,runHeadless,runInteractive,runPackageManagerInstall,runPnpmInstall,runRemoteAuthFlow,runVercel,runVercelEnvPull,setupConnectionConnector,snapshotSetupState,spawnPackageManager,spawnPnpm};
|
|
@@ -1,19 +1,31 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { VercelProjectReference } from "#setup/project-resolution.js";
|
|
2
2
|
import { deriveSlackConnectorSlug } from "#setup/scaffold/index.js";
|
|
3
3
|
import { writeTextFile } from "#setup/scaffold/files.js";
|
|
4
|
-
import
|
|
4
|
+
import { type SetupApplyContext, type SetupPrepareContext } from "../types.js";
|
|
5
5
|
import { configureDiscordInteractionsEndpoint, registerDiscordCommand, resolveDiscordApplication } from "./api.js";
|
|
6
6
|
import { provisionDiscordConnector } from "./connect.js";
|
|
7
7
|
export interface DiscordSetupDeps {
|
|
8
8
|
configureEndpoint: typeof configureDiscordInteractionsEndpoint;
|
|
9
9
|
deriveConnectorSlug: typeof deriveSlackConnectorSlug;
|
|
10
|
-
ensureVercelProject: typeof ensureVercelProject;
|
|
11
10
|
provisionConnector: typeof provisionDiscordConnector;
|
|
12
11
|
registerCommand: typeof registerDiscordCommand;
|
|
13
12
|
resolveApplication: typeof resolveDiscordApplication;
|
|
14
13
|
writeTextFile: typeof writeTextFile;
|
|
15
14
|
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
export interface DiscordSetupPlan {
|
|
16
|
+
botToken: string;
|
|
17
|
+
commandName: string;
|
|
18
|
+
commandDescription: string;
|
|
19
|
+
project: VercelProjectReference;
|
|
20
|
+
slug: string;
|
|
21
|
+
}
|
|
22
|
+
export declare function prepareDiscordSetup(context: SetupPrepareContext, deps?: DiscordSetupDeps): Promise<DiscordSetupPlan>;
|
|
23
|
+
export declare function applyDiscordSetup(plan: DiscordSetupPlan, context: SetupApplyContext, deps?: DiscordSetupDeps): Promise<{
|
|
24
|
+
deploymentRequired: true;
|
|
25
|
+
facts: {
|
|
26
|
+
label: string;
|
|
27
|
+
value: string;
|
|
28
|
+
kind: "url";
|
|
29
|
+
}[];
|
|
30
|
+
}>;
|
|
31
|
+
export declare const DISCORD_SETUP: import("../types.js").SetupIntegration;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import{configureDiscordInteractionsEndpoint,registerDiscordCommand,resolveDiscordApplication}from"./api.js";import{provisionDiscordConnector}from"./connect.js";import{join}from"node:path";import{deriveSlackConnectorSlug}from"#setup/scaffold/index.js";import{
|
|
1
|
+
import{configureDiscordInteractionsEndpoint,registerDiscordCommand,resolveDiscordApplication}from"./api.js";import{provisionDiscordConnector}from"./connect.js";import{defineSetupIntegration}from"../types.js";import{join}from"node:path";import{deriveSlackConnectorSlug}from"#setup/scaffold/index.js";import{text}from"#setup/ask.js";import{writeTextFile}from"#setup/scaffold/files.js";const defaultDeps={configureEndpoint:configureDiscordInteractionsEndpoint,deriveConnectorSlug:deriveSlackConnectorSlug,provisionConnector:provisionDiscordConnector,registerCommand:registerDiscordCommand,resolveApplication:resolveDiscordApplication,writeTextFile};function validateCommandName(e){let t=e.trim();return t?t.length>32?`Command name must be 32 characters or fewer.`:/^[a-z0-9_-]+$/.test(t)?null:`Use lowercase letters, numbers, hyphens, or underscores.`:`Command name is required.`}function connectTemplate(e){return`import { connectDiscordCredentials } from "@vercel/connect/eve";
|
|
2
2
|
import { discordChannel } from "eve/channels/discord";
|
|
3
3
|
|
|
4
4
|
export default discordChannel({
|
|
5
5
|
credentials: connectDiscordCredentials(${JSON.stringify(e)}),
|
|
6
6
|
});
|
|
7
|
-
`}async function
|
|
8
|
-
|
|
7
|
+
`}async function prepareDiscordSetup(e,t=defaultDeps){if(e.environment.vercel.kind===`unavailable`)throw Error("Discord setup requires an authenticated Vercel CLI. Run `vercel login`, then retry.");e.presenter.log.info(`Create a Discord application or open an existing one, then go to Bot → Reset Token and copy the new bot token.
|
|
8
|
+
Create: https://discord.com/developers/applications?new_application=true
|
|
9
|
+
Existing applications: https://discord.com/developers/applications`);let n=(await e.asker.ask(text({key:`discord-bot-token`,message:`Discord bot token`,required:!0,sensitive:!0,environment:`DISCORD_BOT_TOKEN`}))).trim(),r=await e.asker.ask(text({key:`discord-command-name`,message:`Discord command name`,detected:`ask`,required:!0,validate:validateCommandName})),i=await e.asker.ask(text({key:`discord-command-description`,message:`Discord command description`,detected:`Ask the eve agent`,required:!0,validate:e=>e.trim().length===0?`Command description is required.`:e.trim().length>100?`Command description must be 100 characters or fewer.`:null})),a=await e.resolveVercelProject(`Discord`);return{botToken:n,commandName:r.trim(),commandDescription:i.trim(),project:a,slug:await t.deriveConnectorSlug(e.appRoot)}}async function applyDiscordSetup(e,t,n=defaultDeps){let r=await n.resolveApplication(e.botToken),i=await n.provisionConnector({botToken:e.botToken,log:t.presenter.log,project:e.project,projectRoot:t.appRoot,slug:e.slug,signal:t.signal});await n.registerCommand(r.id,e.botToken,{name:e.commandName,description:e.commandDescription}),await n.configureEndpoint(e.botToken,i.id),await n.writeTextFile(join(t.appRoot,`agent/channels/discord.ts`),connectTemplate(i.uid),{force:t.force});let o=`https://discord.com/oauth2/authorize?client_id=${encodeURIComponent(r.id)}&scope=bot%20applications.commands&permissions=3072`;return t.presenter.nextSteps([`Install the Discord application, then try /${e.commandName}: ${o}`]),{deploymentRequired:!0,facts:[{label:`Discord application dashboard`,value:`https://discord.com/developers/applications/${r.id}/information`,kind:`url`}]}}const DISCORD_SETUP=defineSetupIntegration({kind:`discord`,label:`Discord`,hint:`Slash commands and interactions`,prepare:prepareDiscordSetup,apply:applyDiscordSetup});export{DISCORD_SETUP,applyDiscordSetup,prepareDiscordSetup};
|
|
@@ -1,15 +1,44 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { VercelProjectReference } from "#setup/project-resolution.js";
|
|
2
2
|
import { deriveSlackConnectorSlug } from "#setup/scaffold/index.js";
|
|
3
3
|
import { writeTextFile } from "#setup/scaffold/files.js";
|
|
4
|
-
import
|
|
4
|
+
import { type SetupApplyContext, type SetupPrepareContext } from "../types.js";
|
|
5
5
|
import { provisionGitHubConnector } from "./connect.js";
|
|
6
6
|
export interface GitHubSetupDeps {
|
|
7
7
|
deriveConnectorSlug: typeof deriveSlackConnectorSlug;
|
|
8
|
-
ensureVercelProject: typeof ensureVercelProject;
|
|
9
8
|
provisionConnector: typeof provisionGitHubConnector;
|
|
10
9
|
writeTextFile: typeof writeTextFile;
|
|
11
10
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
declare const GITHUB_EVENT_OPTIONS: readonly [{
|
|
12
|
+
readonly id: "issue_comment";
|
|
13
|
+
readonly label: "New issue and PR comments";
|
|
14
|
+
readonly value: "issue_comment";
|
|
15
|
+
readonly hint: "Reply when a new timeline comment includes `@<bot-name>`.";
|
|
16
|
+
}, {
|
|
17
|
+
readonly id: "pull_request_review_comment";
|
|
18
|
+
readonly label: "New inline PR review comments";
|
|
19
|
+
readonly value: "pull_request_review_comment";
|
|
20
|
+
readonly hint: "Reply when a new inline review comment includes `@<bot-name>`.";
|
|
21
|
+
}, {
|
|
22
|
+
readonly id: "issues";
|
|
23
|
+
readonly label: "New issues";
|
|
24
|
+
readonly value: "issues";
|
|
25
|
+
readonly hint: "Add comments to new issues.";
|
|
26
|
+
}, {
|
|
27
|
+
readonly id: "pull_request";
|
|
28
|
+
readonly label: "New PRs";
|
|
29
|
+
readonly value: "pull_request";
|
|
30
|
+
readonly hint: "Add comments to new pull requests.";
|
|
31
|
+
}];
|
|
32
|
+
type GitHubWebhookEvent = (typeof GITHUB_EVENT_OPTIONS)[number]["value"];
|
|
33
|
+
export interface GitHubSetupPlan {
|
|
34
|
+
events: readonly GitHubWebhookEvent[];
|
|
35
|
+
project: VercelProjectReference;
|
|
36
|
+
slug: string;
|
|
37
|
+
}
|
|
38
|
+
export declare function prepareGitHubSetup(context: SetupPrepareContext, deps?: GitHubSetupDeps): Promise<GitHubSetupPlan>;
|
|
39
|
+
export declare function applyGitHubSetup(plan: GitHubSetupPlan, context: SetupApplyContext, deps?: GitHubSetupDeps): Promise<{
|
|
40
|
+
facts: never[];
|
|
41
|
+
deploymentRequired: true;
|
|
42
|
+
}>;
|
|
43
|
+
export declare const GITHUB_SETUP: import("../types.js").SetupIntegration;
|
|
44
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{provisionGitHubConnector}from"./connect.js";import{join}from"node:path";import{deriveSlackConnectorSlug}from"#setup/scaffold/index.js";import{
|
|
1
|
+
import{defineSetupIntegration}from"../types.js";import{provisionGitHubConnector}from"./connect.js";import{join}from"node:path";import{deriveSlackConnectorSlug}from"#setup/scaffold/index.js";import{writeTextFile}from"#setup/scaffold/files.js";const defaultDeps={deriveConnectorSlug:deriveSlackConnectorSlug,provisionConnector:provisionGitHubConnector,writeTextFile},githubEventsQuestion={key:`github-events`,message:`What should this GitHub App respond to?`,options:[{id:`issue_comment`,label:`New issue and PR comments`,value:`issue_comment`,hint:"Reply when a new timeline comment includes `@<bot-name>`."},{id:`pull_request_review_comment`,label:`New inline PR review comments`,value:`pull_request_review_comment`,hint:"Reply when a new inline review comment includes `@<bot-name>`."},{id:`issues`,label:`New issues`,value:`issues`,hint:`Add comments to new issues.`},{id:`pull_request`,label:`New PRs`,value:`pull_request`,hint:`Add comments to new pull requests.`}],recommended:[`issue_comment`,`pull_request_review_comment`],required:!0,requireSelection:!0};function connectTemplate(e,t,n){let r=[n.includes(`issues`)?` onIssue(ctx, issue) {
|
|
2
2
|
if (issue.action !== "opened") return null;
|
|
3
3
|
return { auth: defaultGitHubAuth(ctx) };
|
|
4
4
|
},`:void 0,n.includes(`pull_request`)?` onPullRequest(ctx, pullRequest) {
|
|
@@ -12,4 +12,4 @@ export default githubChannel({
|
|
|
12
12
|
botName: ${JSON.stringify(t)},
|
|
13
13
|
credentials: connectGitHubCredentials(${JSON.stringify(e)}),${a}
|
|
14
14
|
});
|
|
15
|
-
`}async function
|
|
15
|
+
`}async function prepareGitHubSetup(e,t=defaultDeps){if(e.environment.vercel.kind===`unavailable`)throw Error("GitHub setup requires an authenticated Vercel CLI. Run `vercel login`, then retry.");return{events:await e.asker.askMany(githubEventsQuestion),project:await e.resolveVercelProject(`GitHub`),slug:await t.deriveConnectorSlug(e.appRoot)}}async function applyGitHubSetup(e,t,r=defaultDeps){t.presenter.log.info(`GitHub App`),t.presenter.log.info(`Vercel Connect creates a GitHub App and routes verified webhooks to your deployed agent.`);let i=await r.provisionConnector({log:t.presenter.log,events:e.events,project:e.project,projectRoot:t.appRoot,slug:e.slug,signal:t.signal});return await r.writeTextFile(join(t.appRoot,`agent/channels/github.ts`),connectTemplate(i.uid,i.appSlug,e.events),{force:t.force}),t.presenter.nextSteps([`Deploy the agent, then open the GitHub App in Vercel Connect and install it in the organization or account where you want to use it.`,`Add @${i.appSlug} to a new issue, pull request, or review comment to invoke the agent. GitHub may not autocomplete or render the token as a linked mention.`]),{facts:[],deploymentRequired:!0}}const GITHUB_SETUP=defineSetupIntegration({kind:`github`,label:`GitHub`,hint:`Respond to issues, pull requests, and comments`,prepare:prepareGitHubSetup,apply:applyGitHubSetup});export{GITHUB_SETUP,applyGitHubSetup,prepareGitHubSetup};
|
|
@@ -1,19 +1,31 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { VercelProjectReference } from "#setup/project-resolution.js";
|
|
2
2
|
import { deriveSlackConnectorSlug } from "#setup/scaffold/index.js";
|
|
3
3
|
import { writeTextFile } from "#setup/scaffold/files.js";
|
|
4
|
-
import
|
|
5
|
-
import { attachLinearConnector, findLinearConnector, provisionLinearConnector } from "./connect.js";
|
|
4
|
+
import { type SetupApplyContext, type SetupPrepareContext } from "../types.js";
|
|
5
|
+
import { attachLinearConnector, findLinearConnector, provisionLinearConnector, type LinearConnectorRef } from "./connect.js";
|
|
6
6
|
export interface LinearSetupDeps {
|
|
7
7
|
attachConnector: typeof attachLinearConnector;
|
|
8
8
|
deriveConnectorSlug: typeof deriveSlackConnectorSlug;
|
|
9
|
-
ensureVercelProject: typeof ensureVercelProject;
|
|
10
9
|
findConnector: typeof findLinearConnector;
|
|
11
10
|
provisionConnector: typeof provisionLinearConnector;
|
|
12
11
|
writeTextFile: typeof writeTextFile;
|
|
13
12
|
}
|
|
14
|
-
/** Linear does not allow its brand name in a managed app's name. */
|
|
15
13
|
export declare function linearSafeConnectorSlug(slug: string): string;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
type ConnectorPlan = {
|
|
15
|
+
kind: "reuse";
|
|
16
|
+
connector: LinearConnectorRef;
|
|
17
|
+
} | {
|
|
18
|
+
kind: "create";
|
|
19
|
+
slug: string;
|
|
20
|
+
};
|
|
21
|
+
export interface LinearSetupPlan {
|
|
22
|
+
connector: ConnectorPlan;
|
|
23
|
+
project: VercelProjectReference;
|
|
24
|
+
}
|
|
25
|
+
export declare function prepareLinearSetup(context: SetupPrepareContext, deps?: LinearSetupDeps): Promise<LinearSetupPlan>;
|
|
26
|
+
export declare function applyLinearSetup(plan: LinearSetupPlan, context: SetupApplyContext, deps?: LinearSetupDeps): Promise<{
|
|
27
|
+
facts: never[];
|
|
28
|
+
deploymentRequired: true;
|
|
29
|
+
}>;
|
|
30
|
+
export declare const LINEAR_SETUP: import("../types.js").SetupIntegration;
|
|
31
|
+
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{attachLinearConnector,findLinearConnector,provisionLinearConnector}from"./connect.js";import{join}from"node:path";import{deriveSlackConnectorSlug,normalizeSlackConnectorSlug}from"#setup/scaffold/index.js";import{WizardCancelledError}from"#setup/step.js";import{select,text}from"#setup/ask.js";import{
|
|
1
|
+
import{defineSetupIntegration}from"../types.js";import{attachLinearConnector,findLinearConnector,provisionLinearConnector}from"./connect.js";import{join}from"node:path";import{deriveSlackConnectorSlug,normalizeSlackConnectorSlug}from"#setup/scaffold/index.js";import{WizardCancelledError}from"#setup/step.js";import{select,text}from"#setup/ask.js";import{writeTextFile}from"#setup/scaffold/files.js";const defaultDeps={attachConnector:attachLinearConnector,deriveConnectorSlug:deriveSlackConnectorSlug,findConnector:findLinearConnector,provisionConnector:provisionLinearConnector,writeTextFile};function linearSafeConnectorSlug(e){return normalizeSlackConnectorSlug(e.replaceAll(/linear/gi,``).replace(/[-_]{2,}/g,`-`)||`agent`)}function connectTemplate(e){return`import { connectLinearCredentials } from "@vercel/connect/eve";
|
|
2
2
|
import { linearChannel } from "eve/channels/linear";
|
|
3
3
|
|
|
4
4
|
export default linearChannel({
|
|
5
5
|
credentials: connectLinearCredentials(${JSON.stringify(e)}),
|
|
6
6
|
});
|
|
7
|
-
`}async function
|
|
7
|
+
`}async function prepareLinearSetup(e,t=defaultDeps){if(e.environment.vercel.kind===`unavailable`)throw Error("Linear setup requires an authenticated Vercel CLI. Run `vercel login`, then retry.");let n=await e.resolveVercelProject(`Linear`),r=linearSafeConnectorSlug(await t.deriveConnectorSlug(e.appRoot)),i=linearSafeConnectorSlug(await e.asker.ask(text({key:`linear.connector-name`,message:`Name your Linear agent`,recommended:r,validate:e=>e.trim().length===0?`A Linear agent name is required.`:null}))),a=await t.findConnector({project:n,projectRoot:e.appRoot,slug:i,signal:e.signal});if(a===void 0)return{project:n,connector:{kind:`create`,slug:i}};let o=await e.asker.ask(select({key:`linear.existing-connector`,message:`A Linear connector named "${i}" already exists. What would you like to do?`,options:[{id:`reuse`,label:`Reuse existing connector`,value:`reuse`},{id:`new`,label:`Create a new connector`,value:`new`},{id:`exit`,label:`Exit setup`,value:`exit`}],recommended:`reuse`}));if(o===`exit`)throw new WizardCancelledError;return o===`reuse`?{project:n,connector:{kind:`reuse`,connector:a}}:{project:n,connector:{kind:`create`,slug:linearSafeConnectorSlug(await e.asker.ask(text({key:`linear.new-connector-name`,message:`Name the new Linear agent`,recommended:`${i}-2`,validate:e=>e.trim().length===0?`A Linear agent name is required.`:null})))}}}async function applyLinearSetup(e,t,n=defaultDeps){let r=e.connector.kind===`reuse`?(await n.attachConnector({connector:e.connector.connector,log:t.presenter.log,project:e.project,projectRoot:t.appRoot,signal:t.signal}),e.connector.connector):await n.provisionConnector({log:t.presenter.log,project:e.project,projectRoot:t.appRoot,slug:e.connector.slug,signal:t.signal});return await n.writeTextFile(join(t.appRoot,`agent/channels/linear.ts`),connectTemplate(r.uid),{force:t.force}),t.presenter.nextSteps([`Deploy the agent, then open the Linear app in Vercel Connect and install it in the workspace where you want to delegate issues and comments.`,`Delegate an issue or mention the agent in an Agent Session to start a conversation.`]),{facts:[],deploymentRequired:!0}}const LINEAR_SETUP=defineSetupIntegration({kind:`linear`,label:`Linear Agent`,hint:`Delegate Linear issues and comments`,prepare:prepareLinearSetup,apply:applyLinearSetup});export{LINEAR_SETUP,applyLinearSetup,linearSafeConnectorSlug,prepareLinearSetup};
|
|
@@ -21,13 +21,20 @@ export interface ProvisionPhotonProjectOptions {
|
|
|
21
21
|
export interface UsePhotonProjectOptions {
|
|
22
22
|
projectId: string;
|
|
23
23
|
projectSecret: string;
|
|
24
|
-
|
|
24
|
+
dedicatedLine?: string;
|
|
25
|
+
phoneNumber?: string;
|
|
25
26
|
deps?: PhotonManagementDeps;
|
|
26
27
|
}
|
|
27
28
|
export interface PhotonManagementDeps {
|
|
28
29
|
fetch: typeof fetch;
|
|
29
30
|
delay(ms: number, signal?: AbortSignal): Promise<void>;
|
|
30
31
|
}
|
|
32
|
+
/** Returns the least-loaded dedicated iMessage line, when the project has one. */
|
|
33
|
+
export declare function findDedicatedPhotonLine(input: {
|
|
34
|
+
projectId: string;
|
|
35
|
+
projectSecret: string;
|
|
36
|
+
deps?: Pick<PhotonManagementDeps, "fetch">;
|
|
37
|
+
}): Promise<string | undefined>;
|
|
31
38
|
/** Authorizes Photon and creates an isolated iMessage project for one eve agent. */
|
|
32
39
|
export declare function provisionPhotonProject(options: ProvisionPhotonProjectOptions): Promise<PhotonManagedProject>;
|
|
33
40
|
/** Validates existing Photon credentials and registers the agent's iMessage user. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{z}from"#compiled/zod/index.js";import{setTimeout}from"node:timers/promises";const PHOTON_DASHBOARD_HOST=`https://app.photon.codes`,PHOTON_DEVICE_CLIENT_ID=`photon-cli`,E164=/^\+[1-9]\d{6,14}$/;function validatePhotonPhoneNumber(e){let t=e.trim();return E164.test(t)?t.startsWith(`+1`)&&t.length!==12?`US and Canadian numbers must be +1 followed by exactly 10 digits`:null:`Use E.164 format: + followed by 7–15 digits, for example +15551234567`}const DeviceAuthorizationSchema=z.object({device_code:z.string().min(1),user_code:z.string().min(1),verification_uri_complete:z.string().url().optional(),verification_uri:z.string().url().optional(),expires_in:z.number().positive().optional(),interval:z.number().positive().optional()}),DeviceTokenSchema=z.object({access_token:z.string().min(1).optional(),accessToken:z.string().min(1).optional()}),ProjectSchema=z.object({id:z.string().min(1)}),ProjectSecretSchema=z.object({projectSecret:z.string().min(1)}),ErrorResponseSchema=z.object({error:z.unknown().optional(),message:z.unknown().optional()}),PhoneRegistrationSchema=z.object({
|
|
1
|
+
import{z}from"#compiled/zod/index.js";import{setTimeout}from"node:timers/promises";const PHOTON_DASHBOARD_HOST=`https://app.photon.codes`,PHOTON_SPECTRUM_HOST=`https://spectrum.photon.codes`,PHOTON_DEVICE_CLIENT_ID=`photon-cli`,E164=/^\+[1-9]\d{6,14}$/;function validatePhotonPhoneNumber(e){let t=e.trim();return E164.test(t)?t.startsWith(`+1`)&&t.length!==12?`US and Canadian numbers must be +1 followed by exactly 10 digits`:null:`Use E.164 format: + followed by 7–15 digits, for example +15551234567`}const DeviceAuthorizationSchema=z.object({device_code:z.string().min(1),user_code:z.string().min(1),verification_uri_complete:z.string().url().optional(),verification_uri:z.string().url().optional(),expires_in:z.number().positive().optional(),interval:z.number().positive().optional()}),DeviceTokenSchema=z.object({access_token:z.string().min(1).optional(),accessToken:z.string().min(1).optional()}),ProjectSchema=z.object({id:z.string().min(1)}),ProjectSecretSchema=z.object({projectSecret:z.string().min(1)}),ErrorResponseSchema=z.object({error:z.unknown().optional(),message:z.unknown().optional()}),PhoneRegistrationSchema=z.object({data:z.object({assignedPhoneNumber:z.string().min(1)})}),DedicatedLineSchema=z.object({data:z.object({line:z.object({phoneNumber:z.string().min(1)})})}),defaultDeps={fetch,delay:(e,n)=>setTimeout(e,void 0,{signal:n})};function errorDetail(e,t){let n=ErrorResponseSchema.safeParse(e);return String(n.success?n.data.error??n.data.message??t:t)}function parsePhotonResponse(e,t,n){let r=e.safeParse(t);if(!r.success)throw Error(n);return r.data}async function json(e,t){let n=await e.json().catch(()=>void 0);if(!e.ok)throw Error(`Photon ${t} failed: ${errorDetail(n,e.statusText)}`);return n}function bearer(e){return{authorization:`Bearer ${e}`,"content-type":`application/json`}}function basic(e,t){return{authorization:`Basic ${Buffer.from(`${e}:${t}`).toString(`base64`)}`,"content-type":`application/json`}}async function requestDeviceCode(e){let t=await e.fetch(`${PHOTON_DASHBOARD_HOST}/api/auth/device/code`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({client_id:PHOTON_DEVICE_CLIENT_ID,scope:`openid profile email`})}),r=parsePhotonResponse(DeviceAuthorizationSchema,await json(t,`device login`),`Photon returned an invalid device authorization response.`),a=r.verification_uri_complete??r.verification_uri;if(a===void 0)throw Error(`Photon returned an invalid device authorization response.`);return{deviceCode:r.device_code,userCode:r.user_code,verificationUrl:a,expiresIn:r.expires_in??1800,interval:r.interval??5}}async function pollForToken(e,t,r){let a=Date.now()+e.expiresIn*1e3,o=e.interval*1e3;for(;Date.now()<a;){await t.delay(o,r);let a=await t.fetch(`${PHOTON_DASHBOARD_HOST}/api/auth/device/token`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({grant_type:`urn:ietf:params:oauth:grant-type:device_code`,device_code:e.deviceCode,client_id:PHOTON_DEVICE_CLIENT_ID}),signal:r}),s=await a.json().catch(()=>void 0);if(a.ok){let e=parsePhotonResponse(DeviceTokenSchema,s,`Photon approved device login without returning an access token.`);if(e.access_token!==void 0)return e.access_token;if(e.accessToken!==void 0)return e.accessToken;throw Error(`Photon approved device login without returning an access token.`)}let c=ErrorResponseSchema.safeParse(s),l=c.success?c.data.error??c.data.message:void 0;if(l!==`authorization_pending`){if(l===`slow_down`||a.status===429){o+=a.status===429?1e4:5e3;continue}throw Error(`Photon device login failed: ${String(l??a.statusText)}`)}}throw Error(`Photon device login timed out.`)}async function createProject(e,t,r){let i=await r.fetch(`${PHOTON_DASHBOARD_HOST}/api/projects`,{method:`POST`,headers:bearer(e),body:JSON.stringify({name:t,location:`United States`,platforms:[`imessage`],template:!1,observability:!1})});return parsePhotonResponse(ProjectSchema,await json(i,`project creation`),`Photon did not return a project ID.`).id}async function regenerateSecret(e,t,r){let i=await r.fetch(`${PHOTON_DASHBOARD_HOST}/api/projects/${encodeURIComponent(t)}/regenerate-secret`,{method:`POST`,headers:bearer(e),body:`{}`});return parsePhotonResponse(ProjectSecretSchema,await json(i,`project credential provisioning`),`Photon did not return the new project secret.`).projectSecret}async function registerUser(e,t,n,i){let a=await i.fetch(`${PHOTON_SPECTRUM_HOST}/projects/${encodeURIComponent(e)}/users/`,{method:`POST`,headers:basic(e,t),body:JSON.stringify({type:`shared`,phoneNumber:n})});return parsePhotonResponse(PhoneRegistrationSchema,await json(a,`phone registration`),`Photon returned an invalid phone registration response.`).data.assignedPhoneNumber}async function findDedicatedPhotonLine(e){let t=await(e.deps?.fetch??fetch)(`${PHOTON_SPECTRUM_HOST}/projects/${encodeURIComponent(e.projectId)}/lines/route`,{headers:basic(e.projectId,e.projectSecret)});if(t.status!==404)return parsePhotonResponse(DedicatedLineSchema,await json(t,`dedicated line lookup`),`Photon returned an invalid dedicated line response.`).data.line.phoneNumber}async function deleteProject(e,t,r){let i=await r.fetch(`${PHOTON_DASHBOARD_HOST}/api/projects/${encodeURIComponent(t)}`,{method:`DELETE`,headers:bearer(e)});!i.ok&&i.status!==404&&await json(i,`project cleanup`)}async function provisionPhotonProject(e){let t=e.phoneNumber.trim(),n=validatePhotonPhoneNumber(t);if(n!==null)throw Error(`Photon phone number is invalid. ${n}.`);let r=e.deps??defaultDeps,i=await requestDeviceCode(r);e.onAuthorization({userCode:i.userCode,verificationUrl:i.verificationUrl});let a=await pollForToken(i,r,e.signal),o=await createProject(a,e.projectName,r),cleanup=()=>deleteProject(a,o,r);try{let e=await regenerateSecret(a,o,r),n=await registerUser(o,e,t,r);return n===void 0?{projectId:o,projectSecret:e,cleanup}:{projectId:o,projectSecret:e,assignedPhoneNumber:n,cleanup}}catch(e){throw await cleanup().catch(()=>{}),e}}async function usePhotonProject(e){let t=e.projectId.trim(),n=e.projectSecret.trim();if(!t||!n)throw Error(`Photon project ID and project secret are required.`);let r=e.dedicatedLine??await findDedicatedPhotonLine({projectId:t,projectSecret:n,deps:e.deps});if(r!==void 0)return{projectId:t,projectSecret:n,assignedPhoneNumber:r,cleanup:async()=>{}};if(e.phoneNumber===void 0)throw Error(`Photon phone number is required for projects without a dedicated line.`);let i=e.phoneNumber.trim(),a=validatePhotonPhoneNumber(i);if(a!==null)throw Error(`Photon phone number is invalid. ${a}.`);return{projectId:t,projectSecret:n,assignedPhoneNumber:await registerUser(t,n,i,e.deps??defaultDeps),cleanup:async()=>{}}}export{findDedicatedPhotonLine,provisionPhotonProject,usePhotonProject,validatePhotonPhoneNumber};
|
|
@@ -1,39 +1,43 @@
|
|
|
1
1
|
import { appendEnv } from "../../append-env.js";
|
|
2
|
-
import {
|
|
3
|
-
import { provisionPhotonProject, usePhotonProject } from "./management.js";
|
|
2
|
+
import type { VercelProjectReference } from "../../project-resolution.js";
|
|
4
3
|
import { openUrl } from "../../primitives/open-url.js";
|
|
5
4
|
import { deriveSlackConnectorSlug } from "../../scaffold/index.js";
|
|
6
5
|
import { writeTextFile } from "../../scaffold/files.js";
|
|
7
|
-
import type {
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
export interface PhotonSetupOptions {
|
|
6
|
+
import type { SetupApplyContext, SetupPrepareContext } from "../types.js";
|
|
7
|
+
import { provisionPhotonConnector } from "./connect.js";
|
|
8
|
+
import { findDedicatedPhotonLine, provisionPhotonProject, usePhotonProject } from "./management.js";
|
|
9
|
+
export interface PhotonSetupPlan {
|
|
12
10
|
agentName: string;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
credentials: "vercel-connect" | "environment";
|
|
12
|
+
photonProject: "create" | {
|
|
13
|
+
projectId: string;
|
|
14
|
+
projectSecret: string;
|
|
15
|
+
};
|
|
16
|
+
photonProjectName?: string;
|
|
17
|
+
dedicatedLine?: string;
|
|
18
|
+
phoneNumber?: string;
|
|
19
|
+
vercelProject?: VercelProjectReference;
|
|
19
20
|
}
|
|
20
|
-
/** Outcome of Photon project provisioning and channel scaffolding. */
|
|
21
|
-
export type PhotonSetupResult = {
|
|
22
|
-
kind: "done";
|
|
23
|
-
assignedPhoneNumber?: string;
|
|
24
|
-
dashboardUrl: string;
|
|
25
|
-
} | {
|
|
26
|
-
kind: "cancelled";
|
|
27
|
-
};
|
|
28
21
|
export interface PhotonSetupDeps {
|
|
29
22
|
appendEnv: typeof appendEnv;
|
|
30
23
|
deriveConnectorSlug: typeof deriveSlackConnectorSlug;
|
|
31
|
-
|
|
24
|
+
findDedicatedLine: typeof findDedicatedPhotonLine;
|
|
32
25
|
openUrl: typeof openUrl;
|
|
33
26
|
provisionConnector: typeof provisionPhotonConnector;
|
|
34
27
|
provisionProject: typeof provisionPhotonProject;
|
|
35
28
|
useProject: typeof usePhotonProject;
|
|
36
29
|
writeTextFile: typeof writeTextFile;
|
|
37
30
|
}
|
|
38
|
-
|
|
39
|
-
export declare function
|
|
31
|
+
export declare function preparePhotonSetup(context: SetupPrepareContext, deps?: PhotonSetupDeps): Promise<PhotonSetupPlan>;
|
|
32
|
+
export declare function applyPhotonSetup(plan: PhotonSetupPlan, context: SetupApplyContext, deps?: PhotonSetupDeps): Promise<{
|
|
33
|
+
facts: ({
|
|
34
|
+
label: string;
|
|
35
|
+
value: string;
|
|
36
|
+
kind: "url";
|
|
37
|
+
} | {
|
|
38
|
+
label: string;
|
|
39
|
+
value: string;
|
|
40
|
+
kind: "phone";
|
|
41
|
+
})[];
|
|
42
|
+
deploymentRequired: true;
|
|
43
|
+
}>;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import{appendEnv}from"../../append-env.js";import{text}from"../../ask.js";import{writeTextFile}from"../../scaffold/files.js";import{deriveSlackConnectorSlug}from"../../scaffold/update/channels.js";import"../../scaffold/index.js";import{
|
|
1
|
+
import{appendEnv}from"../../append-env.js";import{select,text}from"../../ask.js";import{writeTextFile}from"../../scaffold/files.js";import{deriveSlackConnectorSlug}from"../../scaffold/update/channels.js";import"../../scaffold/index.js";import{provisionPhotonConnector}from"./connect.js";import{findDedicatedPhotonLine,provisionPhotonProject,usePhotonProject,validatePhotonPhoneNumber}from"./management.js";import{openUrl}from"../../primitives/open-url.js";import{basename,join}from"node:path";const defaultDeps={appendEnv,deriveConnectorSlug:deriveSlackConnectorSlug,findDedicatedLine:findDedicatedPhotonLine,openUrl,provisionConnector:provisionPhotonConnector,provisionProject:provisionPhotonProject,useProject:usePhotonProject,writeTextFile};function connectTemplate(e){return`import { connectPhotonCredentials } from "@vercel/connect/eve";
|
|
2
2
|
import { photonIMessageChannel } from "eve/channels/photon";
|
|
3
3
|
|
|
4
4
|
export default photonIMessageChannel({
|
|
5
5
|
credentials: connectPhotonCredentials(${JSON.stringify(e)}),
|
|
6
6
|
});
|
|
7
|
-
`}async function
|
|
7
|
+
`}async function preparePhotonSetup(e,r=defaultDeps){let i=basename(e.appRoot),a=await e.asker.ask(select({key:`photon-credentials`,message:`How would you like to configure Photon?`,options:[{id:`vercel`,value:`vercel-connect`,label:`Set up Vercel Connect`,hint:`Use a linked Vercel project`},{id:`portable`,value:`environment`,label:`Use portable credentials`,hint:`Configure the Photon webhook manually after deployment`}],recommended:e.environment.vercel.kind===`available`?`vercel-connect`:`environment`,required:!0}));if(a===`vercel-connect`&&e.environment.vercel.kind===`unavailable`)throw Error("Vercel Connect requires an authenticated Vercel CLI. Run `vercel login`, then retry Photon setup.");let o=`eve · ${i||`agent`}`,s=await e.asker.askEditable({key:`photon-project-source`,message:`Photon project`,options:[{id:`create`,value:`create`,label:`Create a new Photon project`,hint:`Name: ${o}`},{id:`existing`,value:`existing`,label:`Use an existing Photon project`,hint:`Enter its project credentials`}],recommended:`create`,required:!0,editable:{key:`photon-project-name`,value:`create`,label:`Name`,recommended:o,validate:e=>e.trim().length===0?`Project name cannot be empty.`:null}}),c=`create`;if(s.value===`existing`){let t=await e.asker.ask(text({key:`photon-project-id`,message:`Photon project ID`,required:!0})),r=await e.asker.ask(text({key:`photon-project-secret`,message:`Photon project secret`,required:!0,sensitive:!0,environment:`IMESSAGE_PROJECT_SECRET`}));c={projectId:t.trim(),projectSecret:r.trim()}}let l=c===`create`?void 0:await r.findDedicatedLine(c),u=l===void 0?await e.asker.ask(text({key:`photon-phone-number`,message:`Your iMessage phone number`,placeholder:`+15551234567`,required:!0,validate:validatePhotonPhoneNumber})):void 0,d=a===`vercel-connect`?await e.resolveVercelProject(`Photon`):void 0,f={agentName:i,credentials:a,photonProject:c,dedicatedLine:l,phoneNumber:u};return s.value===`create`&&(f.photonProjectName=s.text??o),d!==void 0&&(f.vercelProject=d),f}async function resolvePhotonProject(e,t,n){if(e.photonProject!==`create`)return n.useProject({...e.photonProject,dedicatedLine:e.dedicatedLine,phoneNumber:e.phoneNumber});if(e.phoneNumber===void 0)throw Error(`Photon phone number is required.`);let r=t.presenter.log.spinner?.(`Waiting for Photon approval…`,{kind:`external-action`,emphasis:`browser`}),i;try{let r=await n.provisionProject({projectName:e.photonProjectName??`eve · ${e.agentName||`agent`}`,phoneNumber:e.phoneNumber,signal:t.signal,onAuthorization(e){i=t.presenter.beginExternalAction({message:`Authorize Photon`,url:e.verificationUrl,userCode:e.userCode}),n.openUrl(e.verificationUrl)}});return i?.complete(),r}finally{r?.stop()}}async function applyPhotonSetup(e,t,n=defaultDeps){let r=await resolvePhotonProject(e,t,n);try{let i=join(t.appRoot,`agent/channels/photon.ts`);if(e.credentials===`vercel-connect`){let a=await n.deriveConnectorSlug(t.appRoot,e.agentName),o=await n.provisionConnector({credentials:r,log:t.presenter.log,project:e.vercelProject,projectRoot:t.appRoot,slug:a,signal:t.signal});await n.writeTextFile(i,connectTemplate(o.uid),{force:t.force})}else await n.appendEnv(join(t.appRoot,`.env.local`),{IMESSAGE_PROJECT_ID:r.projectId,IMESSAGE_PROJECT_SECRET:r.projectSecret}),await n.writeTextFile(i,`import { photonIMessageChannel } from "eve/channels/photon";
|
|
8
8
|
|
|
9
9
|
async function photonCredentials() {
|
|
10
10
|
const projectId = process.env.IMESSAGE_PROJECT_ID;
|
|
@@ -17,4 +17,4 @@ export default photonIMessageChannel({
|
|
|
17
17
|
credentials: photonCredentials,
|
|
18
18
|
webhookSecret: process.env.IMESSAGE_WEBHOOK_SECRET,
|
|
19
19
|
});
|
|
20
|
-
`,{force:
|
|
20
|
+
`,{force:t.force}),t.presenter.nextSteps([`Deploy the agent, then create a Photon webhook pointing to https://<your-host>/eve/v1/photon.`,`Copy the webhook signing secret into IMESSAGE_WEBHOOK_SECRET, alongside IMESSAGE_PROJECT_ID and IMESSAGE_PROJECT_SECRET, in your host's encrypted environment variables.`]);t.presenter.log.success(`Scaffolded channel: photon`),r.assignedPhoneNumber!==void 0&&t.presenter.note(r.assignedPhoneNumber,`Text your agent`,{tone:`success`});let a=`https://app.photon.codes/dashboard/${r.projectId}`;return t.presenter.note(a,`Photon project`,{tone:`success`}),{facts:[{label:`Photon project dashboard`,value:a,kind:`url`},...r.assignedPhoneNumber===void 0?[]:[{label:`Agent phone number`,value:r.assignedPhoneNumber,kind:`phone`}]],deploymentRequired:!0}}catch(e){throw await r.cleanup().catch(()=>{}),e}}export{applyPhotonSetup,preparePhotonSetup};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{defineSetupIntegration}from"../types.js";import{applyPhotonSetup,preparePhotonSetup}from"./setup-flow.js";const PHOTON_SETUP=defineSetupIntegration({kind:`photon`,label:`Photon`,hint:`Messages through Photon`,prepare:preparePhotonSetup,apply:applyPhotonSetup});export{PHOTON_SETUP};
|
|
@@ -3,4 +3,4 @@ import type { SetupIntegration } from "./types.js";
|
|
|
3
3
|
export declare const SETUP_INTEGRATIONS: readonly SetupIntegration[];
|
|
4
4
|
/** Resolves one built-in setup integration by its registry setup name. */
|
|
5
5
|
export declare function setupIntegration(kind: string): SetupIntegration;
|
|
6
|
-
export {
|
|
6
|
+
export { createSetupContexts, createSetupPresenter } from "./shared/ui.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DISCORD_SETUP}from"./discord/setup.js";import{GITHUB_SETUP}from"./github/setup.js";import{LINEAR_SETUP}from"./linear/setup.js";import{PHOTON_SETUP}from"./photon/setup.js";import{SLACK_SETUP}from"./slack/setup.js";import{WEB_SETUP}from"./web/setup.js";import{
|
|
1
|
+
import{DISCORD_SETUP}from"./discord/setup.js";import{GITHUB_SETUP}from"./github/setup.js";import{LINEAR_SETUP}from"./linear/setup.js";import{PHOTON_SETUP}from"./photon/setup.js";import{SLACK_SETUP}from"./slack/setup.js";import{WEB_SETUP}from"./web/setup.js";import{createSetupContexts,createSetupPresenter}from"./shared/ui.js";const SETUP_INTEGRATIONS=[WEB_SETUP,SLACK_SETUP,DISCORD_SETUP,GITHUB_SETUP,LINEAR_SETUP,PHOTON_SETUP];function setupIntegration(e){let t=SETUP_INTEGRATIONS.find(t=>t.kind===e);if(t===void 0)throw Error(`Integration setup "${e}" is not available in this version of eve. Upgrade eve and try again.`);return t}export{SETUP_INTEGRATIONS,createSetupContexts,createSetupPresenter,setupIntegration};
|