eve 0.9.0 → 0.9.2
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 +24 -0
- package/bin/eve.d.ts +5 -0
- package/bin/eve.js +16 -13
- package/dist/src/cli/agent-detection.d.ts +8 -0
- package/dist/src/cli/agent-detection.js +1 -0
- package/dist/src/cli/commands/agent-instructions.d.ts +7 -0
- package/dist/src/cli/commands/agent-instructions.js +1 -0
- package/dist/src/cli/commands/init-agent-handoff.md +12 -0
- package/dist/src/cli/commands/init-agent-instructions.md +16 -0
- package/dist/src/cli/commands/init-git.js +1 -1
- package/dist/src/cli/commands/init.d.ts +8 -1
- package/dist/src/cli/commands/init.js +1 -1
- package/dist/src/cli/dev/environment.js +1 -1
- package/dist/src/cli/dev/tui/blocks.d.ts +8 -0
- package/dist/src/cli/dev/tui/blocks.js +2 -2
- package/dist/src/cli/dev/tui/command-typeahead.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/runner.d.ts +10 -0
- package/dist/src/cli/dev/tui/runner.js +1 -1
- package/dist/src/cli/dev/tui/setup-commands.d.ts +4 -0
- package/dist/src/cli/dev/tui/setup-commands.js +2 -2
- package/dist/src/cli/dev/tui/setup-issues.d.ts +15 -0
- package/dist/src/cli/dev/tui/setup-issues.js +1 -1
- package/dist/src/cli/dev/tui/terminal-renderer.d.ts +8 -2
- package/dist/src/cli/dev/tui/terminal-renderer.js +9 -6
- package/dist/src/cli/run.js +1 -1
- package/dist/src/compiled/.vendor-stamp.json +3 -1
- package/dist/src/compiled/@vercel/detect-agent/LICENSE +202 -0
- package/dist/src/compiled/@vercel/detect-agent/index.d.ts +20 -0
- package/dist/src/compiled/@vercel/detect-agent/index.js +1 -0
- package/dist/src/compiled/semver/LICENSE +15 -0
- package/dist/src/compiled/semver/index.d.ts +23 -0
- package/dist/src/compiled/semver/index.js +1 -0
- package/dist/src/execution/sandbox/bindings/docker-templates.js +1 -1
- package/dist/src/execution/sandbox/bindings/just-bash.js +1 -1
- package/dist/src/execution/sandbox/bindings/microsandbox-templates.js +1 -1
- package/dist/src/execution/sandbox/logging-session.js +2 -1
- package/dist/src/internal/application/compiled-artifacts.js +1 -1
- package/dist/src/internal/application/optional-package-install.js +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/application/paths.js +1 -1
- package/dist/src/internal/application/tsconfig-dependencies.js +1 -1
- package/dist/src/internal/authored-module-loader.js +2 -2
- package/dist/src/internal/bundler/nitro-rolldown.d.ts +3 -0
- package/dist/src/internal/bundler/nitro-rolldown.js +1 -1
- package/dist/src/internal/nitro/dev-runtime-artifacts.js +1 -1
- package/dist/src/internal/nitro/dev-runtime-source-snapshot-copy.js +1 -1
- package/dist/src/internal/nitro/dev-runtime-source-snapshot.js +1 -1
- package/dist/src/internal/nitro/host/dev-authored-source-watcher.js +1 -1
- package/dist/src/internal/nitro/host/dev-watcher-log.d.ts +3 -0
- package/dist/src/internal/nitro/host/dev-watcher-log.js +1 -1
- package/dist/src/internal/nitro/host/start-development-server.d.ts +1 -2
- package/dist/src/internal/nitro/host/start-development-server.js +2 -1
- package/dist/src/internal/nitro/host/start-production-server.js +2 -2
- package/dist/src/internal/process/pnpm.js +1 -1
- package/dist/src/internal/workflow-bundle/builder-support.js +2 -2
- package/dist/src/internal/workflow-bundle/dynamic-tool-transform.js +1 -1
- package/dist/src/internal/workflow-bundle/workflow-builders.js +1 -1
- package/dist/src/internal/workflow-bundle/workflow-transformer.js +3 -3
- package/dist/src/public/next/server.js +1 -1
- package/dist/src/setup/boxes/add-channels.d.ts +4 -6
- package/dist/src/setup/boxes/add-channels.js +1 -1
- package/dist/src/setup/boxes/apply-ai-gateway-credential.js +1 -1
- package/dist/src/setup/boxes/link-project.js +1 -1
- package/dist/src/setup/boxes/resolve-provisioning.js +1 -1
- package/dist/src/setup/boxes/scaffold.d.ts +2 -2
- package/dist/src/setup/boxes/scaffold.js +1 -1
- package/dist/src/setup/flows/channels.d.ts +2 -0
- package/dist/src/setup/flows/channels.js +1 -1
- package/dist/src/setup/flows/deploy.js +1 -1
- package/dist/src/setup/flows/install-vercel-cli.d.ts +42 -0
- package/dist/src/setup/flows/install-vercel-cli.js +1 -0
- package/dist/src/setup/flows/link.js +1 -1
- package/dist/src/setup/flows/login.d.ts +49 -0
- package/dist/src/setup/flows/login.js +1 -0
- package/dist/src/setup/flows/model.js +1 -1
- package/dist/src/setup/flows/vercel.d.ts +2 -0
- package/dist/src/setup/flows/vercel.js +1 -1
- package/dist/src/setup/node-engine.d.ts +31 -0
- package/dist/src/setup/node-engine.js +1 -0
- package/dist/src/setup/onboarding.d.ts +3 -2
- package/dist/src/setup/onboarding.js +1 -1
- package/dist/src/setup/primitives/coding-agent-env.d.ts +17 -0
- package/dist/src/setup/primitives/coding-agent-env.js +1 -0
- package/dist/src/setup/primitives/pm/pnpm.js +2 -2
- package/dist/src/setup/primitives/pm/run.d.ts +6 -0
- package/dist/src/setup/primitives/pm/run.js +1 -1
- package/dist/src/setup/primitives/run-vercel.d.ts +1 -1
- package/dist/src/setup/primitives/run-vercel.js +1 -1
- package/dist/src/setup/scaffold/create/add-to-project.d.ts +10 -5
- package/dist/src/setup/scaffold/create/add-to-project.js +1 -1
- package/dist/src/setup/scaffold/create/project.d.ts +17 -4
- package/dist/src/setup/scaffold/create/project.js +9 -5
- package/dist/src/setup/scaffold/index.d.ts +1 -1
- package/dist/src/setup/scaffold/update/channels.d.ts +4 -2
- package/dist/src/setup/scaffold/update/channels.js +2 -2
- package/dist/src/setup/scaffold/update/package-json.d.ts +12 -1
- package/dist/src/setup/scaffold/update/package-json.js +1 -1
- package/dist/src/setup/scaffold/version-tokens.js +1 -1
- package/dist/src/setup/slack-connect-create.d.ts +41 -0
- package/dist/src/setup/slack-connect-create.js +1 -0
- package/dist/src/setup/slack-connect-lifecycle.d.ts +40 -11
- package/dist/src/setup/slack-connect-lifecycle.js +1 -1
- package/dist/src/setup/slack-connect.d.ts +25 -14
- package/dist/src/setup/slack-connect.js +1 -1
- package/dist/src/setup/slackbot.d.ts +12 -16
- package/dist/src/setup/slackbot.js +1 -1
- package/dist/src/setup/vercel-project.d.ts +25 -0
- package/dist/src/setup/vercel-project.js +1 -1
- package/dist/src/source-change/apply-model-name.d.ts +2 -2
- package/dist/src/source-change/apply-model-name.js +1 -1
- package/dist/src/source-change/static-source-change.js +1 -1
- package/docs/getting-started.mdx +7 -7
- package/docs/guides/dev-tui.md +3 -1
- package/docs/reference/cli.md +2 -0
- package/package.json +9 -7
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const CODING_AGENT_ENV_MARKERS=[`AI_AGENT`,`ANTIGRAVITY_AGENT`,`AUGMENT_AGENT`,`CLAUDECODE`,`CLAUDE_CODE`,`CLAUDE_CODE_IS_COWORK`,`CODEX_CI`,`CODEX_SANDBOX`,`CODEX_THREAD_ID`,`COPILOT_ALLOW_ALL`,`COPILOT_GITHUB_TOKEN`,`COPILOT_MODEL`,`CURSOR_AGENT`,`CURSOR_EXTENSION_HOST_ROLE`,`CURSOR_TRACE_ID`,`GEMINI_CLI`,`OPENCODE_CLIENT`,`REPL_ID`];function withoutCodingAgentMarkers(e){let t={...e};for(let e of CODING_AGENT_ENV_MARKERS)delete t[e];return t}export{CODING_AGENT_ENV_MARKERS,withoutCodingAgentMarkers};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{pathExists}from"../../path-exists.js";import{
|
|
1
|
+
import{pathExists}from"../../path-exists.js";import{existsSync,realpathSync}from"node:fs";import{dirname,extname,join,resolve}from"node:path";import{readFile,writeFile}from"node:fs/promises";const PNPM_WORKSPACE_PATH=`pnpm-workspace.yaml`,PNPM_WORKSPACE_MEMBERSHIP_ARGUMENTS=[`list`,`--depth`,`-1`,`--json`],PNPM_WORKSPACE_CONTENT=[`minimumReleaseAgeExclude:`,` - eve`,`allowBuilds:`,` sharp: false`,`# Compatibility for Eve releases with an incomplete runtime manifest.`,`packageExtensions:`,` "eve@>=0.6.0-beta.13 <=0.7.0":`,` dependencies:`,` oxc-parser: 0.134.0`,``].join(`
|
|
2
2
|
`),EVE_RELEASE_AGE_EXCLUSION=` - eve`,SHARP_BUILD_POLICY=` sharp: false`;function findYamlBlockEnd(e,t){let n=t+1;for(;n<e.length;){let t=e[n]??``;if(t.length>0&&!t.startsWith(` `)&&!t.startsWith(` `))break;n+=1}return n}function withSharpBuildPolicy(e){let t=e.endsWith(`
|
|
3
3
|
`)?e:`${e}\n`,n=t.split(`
|
|
4
4
|
`),r=n.findIndex(e=>e===`allowBuilds:`);if(r<0)return`${t.trim().length===0?``:`${t}\n`}allowBuilds:\n${SHARP_BUILD_POLICY}\n`;let i=findYamlBlockEnd(n,r);if(n.slice(r+1,i).some(e=>/^\s+sharp:/.test(e)))return e;let a=i;for(;a>r+1&&n[a-1]===``;)--a;return n.splice(a,0,SHARP_BUILD_POLICY),n.join(`
|
|
5
5
|
`)}function withExperimentalEveReleaseAgeExclusion(e){let t=e.endsWith(`
|
|
6
6
|
`)?e:`${e}\n`,n=t.split(`
|
|
7
7
|
`),r=n.findIndex(e=>e===`minimumReleaseAgeExclude:`);if(r<0)return`${t.trim().length===0?``:`${t}\n`}minimumReleaseAgeExclude:\n${EVE_RELEASE_AGE_EXCLUSION}\n`;let i=findYamlBlockEnd(n,r);if(n.slice(r+1,i).some(e=>e.trim()===`- eve`))return e;let a=i;for(;a>r+1&&n[a-1]===``;)--a;return n.splice(a,0,EVE_RELEASE_AGE_EXCLUSION),n.join(`
|
|
8
|
-
`)}async function ensurePnpmWorkspacePolicy(t){if(!await pathExists(t))return await writeFile(t,PNPM_WORKSPACE_CONTENT,`utf8`),`written`;let n=await readFile(t,`utf8`),r=withExperimentalEveReleaseAgeExclusion(withSharpBuildPolicy(n));return r===n?`skipped`:(await writeFile(t,r,`utf8`),`written`)}function hasAncestorPnpmWorkspace(e){let n=dirname(resolve(e));for(;;){if(existsSync(join(n,`pnpm-workspace.yaml`)))return!0;let e=dirname(n);if(e===n)return!1;n=e}}function pnpmWorkspaceClaimsProject(e,t){let
|
|
8
|
+
`)}async function ensurePnpmWorkspacePolicy(t){if(!await pathExists(t))return await writeFile(t,PNPM_WORKSPACE_CONTENT,`utf8`),`written`;let n=await readFile(t,`utf8`),r=withExperimentalEveReleaseAgeExclusion(withSharpBuildPolicy(n));return r===n?`skipped`:(await writeFile(t,r,`utf8`),`written`)}function hasAncestorPnpmWorkspace(e){let n=dirname(resolve(e));for(;;){if(existsSync(join(n,`pnpm-workspace.yaml`)))return!0;let e=dirname(n);if(e===n)return!1;n=e}}function pnpmWorkspaceClaimsProject(e,t){let r;try{r=JSON.parse(e)}catch{return}if(!Array.isArray(r)||r.length===0)return;let canonicalPath=e=>{let t=resolve(e);try{return realpathSync.native(t)}catch{return t}},i=canonicalPath(t),a=!1;for(let e of r){if(typeof e!=`object`||!e)continue;let t=e.path;if(typeof t==`string`&&(a=!0,canonicalPath(t)===i))return!0}return a?!1:void 0}const pnpmPackageManager={kind:`pnpm`,scaffoldFiles:{[PNPM_WORKSPACE_PATH]:PNPM_WORKSPACE_CONTENT},async applyProjectConfiguration(e){let t=join(e,PNPM_WORKSPACE_PATH);return await ensurePnpmWorkspacePolicy(t)===`written`?{filesSkipped:[],filesWritten:[t]}:{filesSkipped:[t],filesWritten:[]}},devArguments:()=>[`exec`,`eve`,`dev`],installArguments:e=>[`install`,`--no-frozen-lockfile`,...e.bypassMinimumReleaseAge===!0?[`--config.minimum-release-age=0`]:[],...e.ignoreWorkspace===!0?[`--ignore-workspace`]:[]],prepareArguments:(e,t)=>[`--dir`,e,...t],resolveInvocation(e){let n=process.env.npm_execpath;if(n!==void 0&&n.toLowerCase().includes(`pnpm`)){let t=extname(n).toLowerCase();return t===`.cjs`||t===`.js`?{args:[n,...e],command:process.execPath}:{args:e,command:n,shell:process.platform===`win32`}}if(process.env.npm_config_user_agent?.toLowerCase().startsWith(`pnpm/`))return{args:e,command:`pnpm`,shell:process.platform===`win32`};let r=process.env.PNPM_HOME;if(r!==void 0){let n=join(r,process.platform===`win32`?`pnpm.CMD`:`pnpm`);if(existsSync(n))return{args:e,command:n,shell:process.platform===`win32`}}return{args:e,command:`pnpm`}}};export{PNPM_WORKSPACE_CONTENT,PNPM_WORKSPACE_MEMBERSHIP_ARGUMENTS,PNPM_WORKSPACE_PATH,hasAncestorPnpmWorkspace,pnpmPackageManager,pnpmWorkspaceClaimsProject};
|
|
@@ -7,6 +7,12 @@ export interface RunPackageManagerOptions {
|
|
|
7
7
|
onOutput?: ProcessOutputHandler;
|
|
8
8
|
/** Aborts the package-manager subprocess when setup is interrupted. */
|
|
9
9
|
signal?: AbortSignal;
|
|
10
|
+
/**
|
|
11
|
+
* Closes stdin so the child cannot prompt — required when a repainting TUI
|
|
12
|
+
* owns the terminal in raw mode, where an inherited stdin would let the child
|
|
13
|
+
* contend for keystrokes.
|
|
14
|
+
*/
|
|
15
|
+
nonInteractive?: boolean;
|
|
10
16
|
}
|
|
11
17
|
/** @deprecated Use {@link RunPackageManagerOptions}. */
|
|
12
18
|
export type RunPnpmOptions = RunPackageManagerOptions;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createProcessOutputBuffer}from"../process-output.js";import{armProcessAbort}from"../process-abort.js";import{PNPM_WORKSPACE_MEMBERSHIP_ARGUMENTS,hasAncestorPnpmWorkspace,pnpmWorkspaceClaimsProject}from"./pnpm.js";import{getPackageManagerStrategy}from"./index.js";import{spawn}from"node:child_process";function spawnPackageManager(n,r,i,s={}){return s.signal?.aborted===!0?Promise.resolve(!1):new Promise(c=>{let l=getPackageManagerStrategy(n),u=l.prepareArguments(r,i),d=l.resolveInvocation(u),f=s.onOutput&&createProcessOutputBuffer(s.onOutput),p=spawn(d.command,[...d.args],{cwd:r,stdio:s
|
|
1
|
+
import{createProcessOutputBuffer}from"../process-output.js";import{armProcessAbort}from"../process-abort.js";import{PNPM_WORKSPACE_MEMBERSHIP_ARGUMENTS,hasAncestorPnpmWorkspace,pnpmWorkspaceClaimsProject}from"./pnpm.js";import{getPackageManagerStrategy}from"./index.js";import{spawn}from"node:child_process";function stdioForRun(e){return e.onOutput?[e.nonInteractive?`ignore`:`inherit`,`pipe`,`pipe`]:e.nonInteractive?[`ignore`,`inherit`,`inherit`]:`inherit`}function spawnPackageManager(n,r,i,s={}){return s.signal?.aborted===!0?Promise.resolve(!1):new Promise(c=>{let l=getPackageManagerStrategy(n),u=l.prepareArguments(r,i),d=l.resolveInvocation(u),f=s.onOutput&&createProcessOutputBuffer(s.onOutput),p=spawn(d.command,[...d.args],{cwd:r,stdio:stdioForRun(s),shell:d.shell,signal:s.signal}),m=armProcessAbort(p,s.signal);p.stdout?.on(`data`,e=>f?.write(`stdout`,e)),p.stderr?.on(`data`,e=>f?.write(`stderr`,e));let h=!1;function settle(e){h||(h=!0,f?.flush(),c(e))}function reportFailure(e){s.onOutput?s.onOutput({stream:`stderr`,text:e}):process.stderr.write(`\n${e}\n`)}p.on(`error`,e=>{s.signal?.aborted===!0||e.name===`AbortError`||(e.code===`ENOENT`?(m(),reportFailure(`${n} not found. Install it before running this step.`),settle(!1)):(m(),reportFailure(`${n} ${i.join(` `)} failed: ${e.message}`),settle(!1)))}),p.on(`close`,e=>{m(),settle(s.signal?.aborted===!0?!1:e===0)})})}function capturePackageManager(n,r,i,s){return s.signal?.aborted===!0?Promise.resolve({ok:!1,stdout:``}):new Promise(c=>{let l=getPackageManagerStrategy(n),u=l.prepareArguments(r,i),d=l.resolveInvocation(u),f=spawn(d.command,[...d.args],{cwd:r,stdio:[`ignore`,`pipe`,`pipe`],shell:d.shell,signal:s.signal}),p=armProcessAbort(f,s.signal),m=[],h=s.onOutput&&createProcessOutputBuffer(s.onOutput);f.stdout?.on(`data`,e=>m.push(e)),f.stderr?.on(`data`,e=>h?.write(`stderr`,e));let g=!1;function settle(e){g||(g=!0,h?.flush(),c({ok:e,stdout:Buffer.concat(m).toString(`utf8`)}))}function reportFailure(e){s.onOutput?s.onOutput({stream:`stderr`,text:e}):process.stderr.write(`\n${e}\n`)}f.on(`error`,e=>{s.signal?.aborted===!0||e.name===`AbortError`||(p(),reportFailure(e.code===`ENOENT`?`${n} not found. Install it before running this step.`:`${n} ${i.join(` `)} failed: ${e.message}`),settle(!1))}),f.on(`close`,e=>{p(),!g&&e!==0&&s.signal?.aborted!==!0&&reportFailure(`${n} ${i.join(` `)} exited with code ${e??`unknown`}.`),settle(s.signal?.aborted===!0?!1:e===0)})})}async function runPackageManagerInstall(e,t,o={}){let s=getPackageManagerStrategy(e),c=o;if(e===`pnpm`&&o.ignoreWorkspace!==!0&&hasAncestorPnpmWorkspace(t)){let r=await capturePackageManager(e,t,PNPM_WORKSPACE_MEMBERSHIP_ARGUMENTS,o);if(!r.ok)return!1;let a=pnpmWorkspaceClaimsProject(r.stdout,t);if(a===void 0)return o.onOutput?.({stream:`stderr`,text:`Could not determine whether the ancestor pnpm workspace includes this project.`}),!1;a||(c={...o,ignoreWorkspace:!0})}return spawnPackageManager(e,t,s.installArguments(c),o)}function eveDevArguments(e){return getPackageManagerStrategy(e).devArguments()}function spawnPnpm(e,t,n={}){return spawnPackageManager(`pnpm`,e,t,n)}function runPnpmInstall(e,t={}){return runPackageManagerInstall(`pnpm`,e,t)}export{eveDevArguments,runPackageManagerInstall,runPnpmInstall,spawnPackageManager,spawnPnpm};
|
|
@@ -3,7 +3,7 @@ import { type ProcessOutputHandler } from "./process-output.js";
|
|
|
3
3
|
export interface RunVercelOptions {
|
|
4
4
|
cwd: string;
|
|
5
5
|
extraEnv?: Readonly<Record<string, string>>;
|
|
6
|
-
/**
|
|
6
|
+
/** Pass `--non-interactive` and close stdin so automation cannot stop on a prompt. */
|
|
7
7
|
nonInteractive?: boolean;
|
|
8
8
|
/** Streams command output to a parent-owned renderer instead of writing outside it. */
|
|
9
9
|
onOutput?: ProcessOutputHandler;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createProcessOutputBuffer}from"./process-output.js";import{armProcessAbort}from"./process-abort.js";import{
|
|
1
|
+
import{withoutCodingAgentMarkers}from"./coding-agent-env.js";import{createProcessOutputBuffer}from"./process-output.js";import{armProcessAbort}from"./process-abort.js";import{accessSync,constants,existsSync,statSync}from"node:fs";import{dirname,join,resolve}from"node:path";import{spawn}from"node:child_process";const CONNECT_FEATURE_FLAG_ENV={FF_CONNECT_ENABLED:`1`},VERCEL_NOT_FOUND_MESSAGE=`Vercel CLI not found. Install with: npm i -g vercel@latest`;function buildSpawnEnv(t){return{...withoutCodingAgentMarkers(process.env),...CONNECT_FEATURE_FLAG_ENV,...t}}function commandArgs(e,t){return!t||e.includes(`--non-interactive`)?e:[...e,`--non-interactive`]}function existingDir(e){let t=resolve(e);for(;!existsSync(t);){let e=dirname(t);if(e===t)break;t=e}return t}function armDeadline(e,t,n){if(t===void 0)return()=>{};let r=setTimeout(()=>{n(),e.kill(`SIGTERM`);let t=setTimeout(()=>e.kill(`SIGKILL`),5e3);t.unref(),e.once(`close`,()=>clearTimeout(t))},t);return r.unref(),()=>clearTimeout(r)}function timeoutMessage(e,t){return`vercel ${e.join(` `)} timed out after ${Math.round(t/1e3)}s and was aborted.`}function abortMessage(e){return`vercel ${e.join(` `)} was aborted.`}function isAbortError(e,t){return t?.aborted===!0||e.name===`AbortError`||e.code===`ABORT_ERR`}function ancestorDirectories(e){let t=[],n=resolve(e);for(;;){t.push(n);let e=dirname(n);if(e===n)return t;n=e}}function findExecutable(e){try{if(accessSync(e,constants.F_OK|constants.X_OK),statSync(e).isFile())return e}catch{return}}function findLocalVercel(e){for(let t of ancestorDirectories(e)){let e=findExecutable(join(t,`node_modules`,`.bin`,`vercel`));if(e!==void 0)return e}}function resolveVercelInvocation(e){let t=findLocalVercel(e);return t===void 0?{command:`vercel`,commandArgs:[]}:{command:t,commandArgs:[]}}function stdioForRun(e){return e.onOutput?[e.nonInteractive?`ignore`:`inherit`,`pipe`,`pipe`]:e.nonInteractive?[`ignore`,`pipe`,`pipe`]:`inherit`}async function runVercel(e,r){return r.signal?.aborted===!0?!1:new Promise(i=>{let a=existingDir(r.cwd),o=resolveVercelInvocation(a),s=r.onOutput&&createProcessOutputBuffer(r.onOutput),c=spawn(o.command,[...o.commandArgs,...commandArgs(e,r.nonInteractive)],{cwd:a,stdio:stdioForRun(r),env:buildSpawnEnv(r.extraEnv??{}),signal:r.signal}),l=armProcessAbort(c,r.signal);c.stdout?.on(`data`,e=>s?.write(`stdout`,e)),c.stderr?.on(`data`,e=>s?.write(`stderr`,e));let u=!1;function settle(e){u||(u=!0,s?.flush(),i(e))}function reportFailure(e){r.onOutput?r.onOutput({stream:`stderr`,text:e}):process.stderr.write(`\n${e}\n`)}let d=armDeadline(c,r.timeoutMs,()=>{reportFailure(timeoutMessage(e,r.timeoutMs??0)),settle(!1)});c.on(`error`,t=>{isAbortError(t,r.signal)||(t.code===`ENOENT`?(l(),d(),reportFailure(VERCEL_NOT_FOUND_MESSAGE),settle(!1)):(l(),d(),reportFailure(`vercel ${e.join(` `)} failed: ${t.message}`),settle(!1)))}),c.on(`close`,t=>{if(l(),d(),r.signal?.aborted===!0){settle(!1);return}!u&&t!==0&&t!==null&&(s?.flush(),reportFailure(`vercel ${e.join(` `)} exited with code ${t}.`)),settle(t===0)})})}async function runVercelCaptureStdout(e,r){return r.signal?.aborted===!0?{ok:!1,stdout:``}:new Promise(i=>{let a=existingDir(r.cwd),o=resolveVercelInvocation(a),s=r.onOutput&&createProcessOutputBuffer(r.onOutput),c=spawn(o.command,[...o.commandArgs,...commandArgs(e,r.nonInteractive)],{cwd:a,stdio:[r.nonInteractive?`ignore`:`inherit`,`pipe`,r.onOutput?`pipe`:`inherit`],env:buildSpawnEnv(r.extraEnv??{}),signal:r.signal}),l=armProcessAbort(c,r.signal),u=[];c.stdout?.on(`data`,e=>u.push(e.toString(`utf8`))),c.stderr?.on(`data`,e=>s?.write(`stderr`,e));let d=!1;function settle(e){d||(d=!0,s?.flush(),i({ok:e,stdout:u.join(``)}))}function reportFailure(e){r.onOutput?r.onOutput({stream:`stderr`,text:e}):process.stderr.write(`\n${e}\n`)}let f=armDeadline(c,r.timeoutMs,()=>{reportFailure(timeoutMessage(e,r.timeoutMs??0)),settle(!1)});c.on(`error`,t=>{isAbortError(t,r.signal)||(l(),f(),reportFailure(t.code===`ENOENT`?VERCEL_NOT_FOUND_MESSAGE:`vercel ${e.join(` `)} failed: ${t.message}`),settle(!1))}),c.on(`close`,t=>{if(l(),f(),r.signal?.aborted===!0){settle(!1);return}!d&&t!==0&&t!==null&&reportFailure(`vercel ${e.join(` `)} exited with code ${t}.`),settle(t===0)})})}async function captureVercel(e,r){return r.signal?.aborted===!0?{ok:!1,failure:{errno:`ABORT_ERR`,stdout:``,stderr:``,message:abortMessage(e)}}:new Promise(i=>{let a=existingDir(r.cwd),o=resolveVercelInvocation(a),s=r.onOutput&&createProcessOutputBuffer(r.onOutput),c=spawn(o.command,[...o.commandArgs,...commandArgs(e,r.nonInteractive)],{cwd:a,stdio:[`ignore`,`pipe`,`pipe`],env:buildSpawnEnv(r.extraEnv??{}),signal:r.signal}),l=armProcessAbort(c,r.signal),u=[],d=[];c.stdout?.on(`data`,e=>u.push(e.toString(`utf8`))),c.stderr?.on(`data`,e=>{d.push(e.toString(`utf8`)),s?.write(`stderr`,e)});let f=!1;function fail(e,t=!0){f||(f=!0,s?.flush(),t&&r.onOutput?.({stream:`stderr`,text:e.message}),i({ok:!1,failure:e}))}function succeed(){f||(f=!0,s?.flush(),i({ok:!0,stdout:u.join(``)}))}let p=armDeadline(c,r.timeoutMs,()=>{fail({code:null,stdout:u.join(``),stderr:d.join(``),message:timeoutMessage(e,r.timeoutMs??0)})});c.on(`error`,t=>{isAbortError(t,r.signal)||(l(),p(),fail({errno:t.code,stdout:u.join(``),stderr:d.join(``),message:t.code===`ENOENT`?VERCEL_NOT_FOUND_MESSAGE:`vercel ${e.join(` `)} failed: ${t.message}`}))}),c.on(`close`,t=>{if(l(),p(),r.signal?.aborted===!0){fail({errno:`ABORT_ERR`,stdout:u.join(``),stderr:d.join(``),message:abortMessage(e)},!1);return}if(t!==0&&t!==null){fail({code:t,stdout:u.join(``),stderr:d.join(``),message:`vercel ${e.join(` `)} exited with code ${t}.`});return}succeed()})})}export{captureVercel,runVercel,runVercelCaptureStdout};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { PackageManagerKind } from "../../package-manager.js";
|
|
2
|
+
import type { NodeEngineOverride } from "../../node-engine.js";
|
|
3
|
+
import { type EvePackageContract } from "./project.js";
|
|
2
4
|
export interface AddAgentToProjectOptions {
|
|
3
5
|
projectRoot: string;
|
|
4
6
|
model: string;
|
|
@@ -7,7 +9,7 @@ export interface AddAgentToProjectOptions {
|
|
|
7
9
|
* generated project configuration. Defaults to pnpm.
|
|
8
10
|
*/
|
|
9
11
|
packageManager?: PackageManagerKind;
|
|
10
|
-
|
|
12
|
+
evePackage?: EvePackageContract;
|
|
11
13
|
aiPackageVersion?: string;
|
|
12
14
|
connectPackageVersion?: string;
|
|
13
15
|
zodPackageVersion?: string;
|
|
@@ -16,12 +18,15 @@ export interface AddAgentToProjectResult {
|
|
|
16
18
|
filesWritten: string[];
|
|
17
19
|
/** Dependencies added to package.json; ones the project already declares anywhere are left untouched. */
|
|
18
20
|
dependenciesAdded: string[];
|
|
21
|
+
/** Present when an incompatible package.json engines.node value was replaced. */
|
|
22
|
+
nodeEngineOverride?: NodeEngineOverride;
|
|
19
23
|
}
|
|
20
24
|
/**
|
|
21
25
|
* Adds an Eve agent to an existing package: writes the `agent/` files, adds
|
|
22
|
-
*
|
|
23
|
-
* the selected package manager's project
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
+
* missing runtime dependencies, reconciles `engines.node` with Eve's
|
|
27
|
+
* requirement, and applies the selected package manager's project
|
|
28
|
+
* configuration. Other host configuration (tsconfig, scripts, ignore files)
|
|
29
|
+
* remains untouched. All conflicts are gathered and reported before anything
|
|
30
|
+
* is written.
|
|
26
31
|
*/
|
|
27
32
|
export declare function addAgentToProject(options: AddAgentToProjectOptions): Promise<AddAgentToProjectResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{getPackageManagerStrategy}from"../../primitives/pm/index.js";import{pathExists,writeTextFile}from"../files.js";import{patchPackageJson}from"../update/package-json.js";import{resolveVersionToken}from"../version-tokens.js";import{agentTemplateFiles,formatEveDependencySpecifier}from"./project.js";import{join}from"node:path";import{readFile}from"node:fs/promises";const DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`,`optionalDependencies`,`peerDependencies`];function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function hasDeclaredDependency(e,t){if(!isJsonObject(e))return!1;for(let n of DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function addAgentToProject(i){let a=join(i.projectRoot,`package.json`);if(!await pathExists(a))throw Error(`Cannot add an Eve agent to "${i.projectRoot}" because it has no package.json. Run \`eve init <name>\` to create a new project instead.`);let o=agentTemplateFiles(i.model),s=[];for(let e of Object.keys(o))await pathExists(join(i.projectRoot,e))&&s.push(e);if(s.length===0&&await pathExists(join(i.projectRoot,`agent`))&&s.push(`agent/`),s.length>0)throw Error(`Cannot add an Eve agent to "${i.projectRoot}" because it already has: ${s.join(`, `)}. Move them aside first.`);let c=
|
|
1
|
+
import{getPackageManagerStrategy}from"../../primitives/pm/index.js";import{pathExists,writeTextFile}from"../files.js";import{patchPackageJson}from"../update/package-json.js";import{resolveVersionToken}from"../version-tokens.js";import{agentTemplateFiles,formatEveDependencySpecifier,resolveEvePackageContract}from"./project.js";import{join}from"node:path";import{readFile}from"node:fs/promises";const DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`,`optionalDependencies`,`peerDependencies`];function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function hasDeclaredDependency(e,t){if(!isJsonObject(e))return!1;for(let n of DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function addAgentToProject(i){let a=join(i.projectRoot,`package.json`);if(!await pathExists(a))throw Error(`Cannot add an Eve agent to "${i.projectRoot}" because it has no package.json. Run \`eve init <name>\` to create a new project instead.`);let o=agentTemplateFiles(i.model),s=[];for(let e of Object.keys(o))await pathExists(join(i.projectRoot,e))&&s.push(e);if(s.length===0&&await pathExists(join(i.projectRoot,`agent`))&&s.push(`agent/`),s.length>0)throw Error(`Cannot add an Eve agent to "${i.projectRoot}" because it already has: ${s.join(`, `)}. Move them aside first.`);let c=resolveEvePackageContract(i.evePackage),l=resolveVersionToken(`aiPackageVersion`,i.aiPackageVersion??`>=7.0.0-beta.177`),u=resolveVersionToken(`connectPackageVersion`,i.connectPackageVersion??`0.2.2`),d=resolveVersionToken(`zodPackageVersion`,i.zodPackageVersion??`4.4.3`),f=[];for(let[e,t]of Object.entries(o)){let r=join(i.projectRoot,e);await writeTextFile(r,t),f.push(r)}let p=JSON.parse(await readFile(a,`utf8`)),m={"@vercel/connect":u,ai:l,eve:formatEveDependencySpecifier(c.version),zod:d},h={};for(let[e,t]of Object.entries(m))hasDeclaredDependency(p,e)||(h[e]=t);let g={nodeEngineRequirement:c.nodeEngine};Object.keys(h).length>0&&(g.dependencies=h);let _=await patchPackageJson(a,g);return await getPackageManagerStrategy(i.packageManager??`pnpm`).applyProjectConfiguration(i.projectRoot),{filesWritten:f,dependenciesAdded:Object.keys(h).sort(),nodeEngineOverride:_.nodeEngineOverride}}export{addAgentToProject};
|
|
@@ -1,9 +1,23 @@
|
|
|
1
1
|
import type { PackageManagerKind } from "../../package-manager.js";
|
|
2
2
|
export declare const CURRENT_DIRECTORY_PROJECT_NAME = ".";
|
|
3
|
-
export declare const DEFAULT_EVE_PACKAGE_VERSION = "__EVE_PACKAGE_VERSION__";
|
|
4
3
|
export declare const DEFAULT_AI_PACKAGE_VERSION = "__AI_SDK_VERSION__";
|
|
5
4
|
export declare const DEFAULT_CONNECT_PACKAGE_VERSION = "__VERCEL_CONNECT_VERSION__";
|
|
6
5
|
export declare const DEFAULT_ZOD_PACKAGE_VERSION = "__ZOD_VERSION__";
|
|
6
|
+
/**
|
|
7
|
+
* The Eve package metadata that generated projects consume together. Keeping
|
|
8
|
+
* the dependency version and Node.js requirement in one value prevents a
|
|
9
|
+
* scaffold from installing one Eve release while declaring another release's
|
|
10
|
+
* runtime contract.
|
|
11
|
+
*/
|
|
12
|
+
export interface EvePackageContract {
|
|
13
|
+
/** Eve dependency version or npm specifier written to the generated package. */
|
|
14
|
+
version: string;
|
|
15
|
+
/** The matching Eve release's authored `package.json` `engines.node` value. */
|
|
16
|
+
nodeEngine: string;
|
|
17
|
+
}
|
|
18
|
+
export declare const DEFAULT_EVE_PACKAGE_CONTRACT: EvePackageContract;
|
|
19
|
+
/** Resolves a stamped or explicitly supplied Eve package contract. */
|
|
20
|
+
export declare function resolveEvePackageContract(contract?: EvePackageContract): EvePackageContract;
|
|
7
21
|
/**
|
|
8
22
|
* Provider slug a gateway model id routes through: the segment before the
|
|
9
23
|
* first "/" (e.g. `anthropic/claude-sonnet-4.6` → `anthropic`). The slug is
|
|
@@ -39,16 +53,15 @@ export interface ScaffoldBaseProjectOptions {
|
|
|
39
53
|
targetDirectory?: string;
|
|
40
54
|
overwriteExisting?: boolean;
|
|
41
55
|
onOverwriteFile?: (filePath: string) => void | Promise<void>;
|
|
42
|
-
|
|
56
|
+
evePackage?: EvePackageContract;
|
|
43
57
|
aiPackageVersion?: string;
|
|
44
58
|
connectPackageVersion?: string;
|
|
45
59
|
zodPackageVersion?: string;
|
|
46
60
|
tsgoPackageVersion?: string;
|
|
47
|
-
typesNodePackageVersion?: string;
|
|
48
61
|
/**
|
|
49
62
|
* Scaffold an inline provider `byok` block in `agent.ts` that reads the
|
|
50
63
|
* provider key from `process.env` instead of relying on the managed Vercel
|
|
51
|
-
* AI Gateway.
|
|
64
|
+
* AI Gateway. `process` is typed by the `@types/node` every scaffold ships.
|
|
52
65
|
*/
|
|
53
66
|
byokProvider?: boolean;
|
|
54
67
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import{getPackageManagerStrategy}from"../../primitives/pm/index.js";import{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{basename,join,resolve}from"node:path";import{mkdir,readdir,stat}from"node:fs/promises";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,ALLOWED_CREATE_IN_PLACE_ENTRIES=new Set([`.DS_Store`,`.git`,`.gitkeep`,`.hg`]),
|
|
1
|
+
import{getPackageManagerStrategy}from"../../primitives/pm/index.js";import{pinnedNodeEngineMajor}from"../../node-engine.js";import{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{basename,join,resolve}from"node:path";import{mkdir,readdir,stat}from"node:fs/promises";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,ALLOWED_CREATE_IN_PLACE_ENTRIES=new Set([`.DS_Store`,`.git`,`.gitkeep`,`.hg`]),DEFAULT_AI_PACKAGE_VERSION=`>=7.0.0-beta.177`,DEFAULT_CONNECT_PACKAGE_VERSION=`0.2.2`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.9.2`,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_TSGO_VERSION__`,t.tsgoPackageVersion).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 packageJsonTemplate(
|
|
6
|
+
`;function packageJsonTemplate(){return`{
|
|
7
7
|
"name": "__EVE_INIT_APP_NAME__",
|
|
8
8
|
"version": "0.0.0",
|
|
9
9
|
"type": "module",
|
|
@@ -24,14 +24,17 @@ export default defineAgent({
|
|
|
24
24
|
"zod": "__EVE_INIT_ZOD_VERSION__"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
|
|
28
|
-
"@typescript/native-preview": "__EVE_INIT_TSGO_VERSION__"
|
|
27
|
+
"@types/node": "__EVE_INIT_TYPES_NODE_VERSION__",
|
|
28
|
+
"@typescript/native-preview": "__EVE_INIT_TSGO_VERSION__"
|
|
29
29
|
},
|
|
30
30
|
"overrides": {
|
|
31
31
|
"ai": "__EVE_INIT_AI_SDK_VERSION__"
|
|
32
32
|
},
|
|
33
33
|
"resolutions": {
|
|
34
34
|
"ai": "__EVE_INIT_AI_SDK_VERSION__"
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": "__EVE_INIT_NODE_ENGINE__"
|
|
35
38
|
}
|
|
36
39
|
}
|
|
37
40
|
`}const AGENT_INSTRUCTIONS_TEMPLATE=`# Identity
|
|
@@ -42,6 +45,7 @@ You are a helpful assistant.
|
|
|
42
45
|
"target": "ES2022",
|
|
43
46
|
"module": "NodeNext",
|
|
44
47
|
"moduleResolution": "NodeNext",
|
|
48
|
+
"types": ["node"],
|
|
45
49
|
"strict": true,
|
|
46
50
|
"esModuleInterop": true,
|
|
47
51
|
"skipLibCheck": true,
|
|
@@ -86,4 +90,4 @@ export default defineAgent({
|
|
|
86
90
|
},
|
|
87
91
|
},
|
|
88
92
|
});
|
|
89
|
-
`:BASE_AGENT_TEMPLATE,...SHARED_TEMPLATE_FILES,"package.json":packageJsonTemplate(
|
|
93
|
+
`:BASE_AGENT_TEMPLATE,...SHARED_TEMPLATE_FILES,"package.json":packageJsonTemplate(),...getPackageManagerStrategy(n).scaffoldFiles}}async function assertCanCreateInPlace(e,t){if(!await pathExists(e))return;let r=(await readdir(e)).filter(e=>!ALLOWED_CREATE_IN_PLACE_ENTRIES.has(e));if(r.length>0&&!t){let e=r.slice(0,5).join(`, `),t=r.length>5?`, and ${r.length-5} more`:``;throw Error(`Cannot create project in current directory because it is not empty. Found: ${e}${t}. Use an empty directory.`)}}async function scaffoldBaseProject(e){let a=resolve(e.targetDirectory??process.cwd(),e.projectName),o=e.projectName===`.`,c=e.overwriteExisting??!1,u=e.byokProvider??!1,d=e.packageManager??`pnpm`,f=resolveEvePackageContract(e.evePackage),p=pinnedNodeEngineMajor(f.nodeEngine);if(o)await assertCanCreateInPlace(a,c);else if(await pathExists(a))throw Error(`Cannot create project because "${a}" already exists.`);let m={appName:basename(a),model:e.model,eveVersion:f.version,aiPackageVersion:resolveVersionToken(`aiPackageVersion`,e.aiPackageVersion??`>=7.0.0-beta.177`),connectPackageVersion:resolveVersionToken(`connectPackageVersion`,e.connectPackageVersion??`0.2.2`),zodPackageVersion:resolveVersionToken(`zodPackageVersion`,e.zodPackageVersion??`4.4.3`),tsgoPackageVersion:resolveVersionToken(`tsgoPackageVersion`,e.tsgoPackageVersion??`7.0.0-dev.20260523.1`),nodeTypesVersion:p,nodeEngine:p};await mkdir(a,{recursive:!0});for(let[t,i]of Object.entries(templateFiles(u,d))){let s=`${a}/${t}`,l=await pathExists(s);await writeTextFile(s,renderTemplate(i,m),{force:o&&c}),l&&await e.onOverwriteFile?.(s)}return a}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,4 +1,4 @@
|
|
|
1
|
-
export { byokProviderEnvVar, CURRENT_DIRECTORY_PROJECT_NAME, isEveProject, scaffoldBaseProject, type ScaffoldBaseProjectOptions, } from "./create/project.js";
|
|
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, isNextJsProject, listAuthoredChannels, normalizeSlackConnectorSlug, type ChannelKind, type ChannelMutationResult, type EnsureChannelOptions, type SlackConnectorSlug, type WebPackageVersions, } from "./update/channels.js";
|
|
3
3
|
export { SCAFFOLDABLE_CHANNELS, type ScaffoldableChannel } from "./channels-catalog.js";
|
|
4
4
|
export { ensureConnection, listAuthoredConnections, type ConnectionInput, type ConnectionMutationAction, type ConnectionMutationResult, type EnsureConnectionOptions, } from "./update/connections.js";
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { PackageManagerKind } from "../../package-manager.js";
|
|
2
|
+
import { type NodeEngineOverride } from "../../node-engine.js";
|
|
3
|
+
import { type EvePackageContract } from "../create/project.js";
|
|
2
4
|
export declare const SLACK_CHANNEL_DEFAULT_ROUTE = "/eve/v1/slack";
|
|
3
5
|
export declare const DEFAULT_SLACK_CONNECTOR_SLUG = "my-agent";
|
|
4
6
|
declare const slackConnectorSlugBrand: unique symbol;
|
|
@@ -38,6 +40,7 @@ interface WebChannelWrittenResult {
|
|
|
38
40
|
filesWritten: string[];
|
|
39
41
|
filesOverwritten?: string[];
|
|
40
42
|
competingNextConfigFiles?: string[];
|
|
43
|
+
nodeEngineOverride?: NodeEngineOverride;
|
|
41
44
|
filesSkipped: string[];
|
|
42
45
|
packageJsonUpdated: PackageJsonMutation[];
|
|
43
46
|
}
|
|
@@ -76,7 +79,7 @@ export interface EnsureChannelOptions {
|
|
|
76
79
|
configureVercelServices?: boolean;
|
|
77
80
|
}
|
|
78
81
|
export interface WebPackageVersions {
|
|
79
|
-
|
|
82
|
+
evePackage?: EvePackageContract;
|
|
80
83
|
aiPackageVersion?: string;
|
|
81
84
|
nextPackageVersion?: string;
|
|
82
85
|
reactPackageVersion?: string;
|
|
@@ -84,7 +87,6 @@ export interface WebPackageVersions {
|
|
|
84
87
|
streamdownPackageVersion?: string;
|
|
85
88
|
zodPackageVersion?: string;
|
|
86
89
|
tsgoPackageVersion?: string;
|
|
87
|
-
typesNodePackageVersion?: string;
|
|
88
90
|
typesReactPackageVersion?: string;
|
|
89
91
|
typesReactDomPackageVersion?: string;
|
|
90
92
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{getPackageManagerStrategy}from"../../primitives/pm/index.js";import{pathExists,writeTextFile}from"../files.js";import{patchPackageJson}from"./package-json.js";import{resolveVersionToken}from"../version-tokens.js";import{getSupportedModuleBaseName,matchesSupportedModuleBaseName}from"./module-files.js";import{WEB_APP_TEMPLATE_FILES,WEB_APP_TEMPLATE_PACKAGE_JSON}from"../create/web-template.js";import"../create/project.js";import{basename,join,resolve}from"node:path";import{readFile,readdir,writeFile}from"node:fs/promises";const SLACK_CHANNEL_DEFAULT_ROUTE=`/eve/v1/slack`,DEFAULT_SLACK_CONNECTOR_SLUG=`my-agent`,PACKAGE_DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`,`peerDependencies`,`optionalDependencies`],WEB_NEXT_CONFIG_PATH=`next.config.ts`,WEB_VERCEL_JSON_PATH=`vercel.json`,WEB_VERCEL_JSON_SCHEMA=`https://openapi.vercel.sh/vercel.json`,WEB_COMPETING_NEXT_CONFIG_PATHS=[`next.config.js`,`next.config.mjs`,WEB_NEXT_CONFIG_PATH,`next.config.mts`].filter(e=>e!==WEB_NEXT_CONFIG_PATH),WEB_DEFAULT_VERCEL_SERVICES={web:{entrypoint:`.`,framework:`nextjs`,routePrefix:`/`},eve:{buildCommand:`eve build`,entrypoint:`.`,framework:`eve`,routePrefix:`/_eve_internal/eve`}};function toSlackConnectorSlug(e){return e}function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}async function readDependencyVersion(e,t){let n=JSON.parse(await readFile(e,`utf8`));if(!isJsonObject(n)||!isJsonObject(n.dependencies))return;let r=n.dependencies[t];return typeof r==`string`?r:void 0}function packageJsonHasDependency(e,t){for(let n of PACKAGE_DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function hasPackageDependency(e,
|
|
1
|
+
import{getPackageManagerStrategy}from"../../primitives/pm/index.js";import{pinnedNodeEngineMajor}from"../../node-engine.js";import{pathExists,writeTextFile}from"../files.js";import{patchPackageJson}from"./package-json.js";import{resolveVersionToken}from"../version-tokens.js";import{getSupportedModuleBaseName,matchesSupportedModuleBaseName}from"./module-files.js";import{WEB_APP_TEMPLATE_FILES,WEB_APP_TEMPLATE_PACKAGE_JSON}from"../create/web-template.js";import{DEFAULT_EVE_PACKAGE_CONTRACT,resolveEvePackageContract}from"../create/project.js";import{basename,join,resolve}from"node:path";import{readFile,readdir,writeFile}from"node:fs/promises";const SLACK_CHANNEL_DEFAULT_ROUTE=`/eve/v1/slack`,DEFAULT_SLACK_CONNECTOR_SLUG=`my-agent`,PACKAGE_DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`,`peerDependencies`,`optionalDependencies`],WEB_NEXT_CONFIG_PATH=`next.config.ts`,WEB_VERCEL_JSON_PATH=`vercel.json`,WEB_VERCEL_JSON_SCHEMA=`https://openapi.vercel.sh/vercel.json`,WEB_COMPETING_NEXT_CONFIG_PATHS=[`next.config.js`,`next.config.mjs`,WEB_NEXT_CONFIG_PATH,`next.config.mts`].filter(e=>e!==WEB_NEXT_CONFIG_PATH),WEB_DEFAULT_VERCEL_SERVICES={web:{entrypoint:`.`,framework:`nextjs`,routePrefix:`/`},eve:{buildCommand:`eve build`,entrypoint:`.`,framework:`eve`,routePrefix:`/_eve_internal/eve`}};function toSlackConnectorSlug(e){return e}function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}async function readDependencyVersion(e,t){let n=JSON.parse(await readFile(e,`utf8`));if(!isJsonObject(n)||!isJsonObject(n.dependencies))return;let r=n.dependencies[t];return typeof r==`string`?r:void 0}function packageJsonHasDependency(e,t){for(let n of PACKAGE_DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function hasPackageDependency(e,t){if(!await pathExists(e))return!1;let r=JSON.parse(await readFile(e,`utf8`));return isJsonObject(r)&&packageJsonHasDependency(r,t)}async function isNextJsProject(e){return hasPackageDependency(join(e,`package.json`),`next`)}async function ensurePackageDependency(e,t,r){return!await pathExists(e)||await readDependencyVersion(e,t)===r?[]:(await patchPackageJson(e,{dependencies:{[t]:r}}),[{path:e,dependencies:[t],devDependencies:[],scripts:[]}])}function resolveWebPackageVersions(e){return{evePackage:e?.evePackage??DEFAULT_EVE_PACKAGE_CONTRACT,aiPackageVersion:e?.aiPackageVersion??`>=7.0.0-beta.177`,nextPackageVersion:e?.nextPackageVersion??`16.2.6`,reactPackageVersion:e?.reactPackageVersion??`19.2.6`,reactDomPackageVersion:e?.reactDomPackageVersion??`19.2.6`,streamdownPackageVersion:e?.streamdownPackageVersion??`2.5.0`,zodPackageVersion:e?.zodPackageVersion??`4.4.3`,tsgoPackageVersion:e?.tsgoPackageVersion??`7.0.0-dev.20260523.1`,typesReactPackageVersion:e?.typesReactPackageVersion??`19.2.15`,typesReactDomPackageVersion:e?.typesReactDomPackageVersion??`19.2.3`}}function formatEveDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}async function patchWebPackageJson(e,r){if(!await pathExists(e))return{mutations:[]};let o=resolveEvePackageContract(r.evePackage),s=pinnedNodeEngineMajor(o.nodeEngine),c={...WEB_APP_TEMPLATE_PACKAGE_JSON.dependencies,ai:resolveVersionToken(`aiPackageVersion`,r.aiPackageVersion),eve:formatEveDependencySpecifier(o.version),next:resolveVersionToken(`nextPackageVersion`,r.nextPackageVersion),react:resolveVersionToken(`reactPackageVersion`,r.reactPackageVersion),"react-dom":resolveVersionToken(`reactDomPackageVersion`,r.reactDomPackageVersion),streamdown:resolveVersionToken(`streamdownPackageVersion`,r.streamdownPackageVersion),zod:resolveVersionToken(`zodPackageVersion`,r.zodPackageVersion)},u={...WEB_APP_TEMPLATE_PACKAGE_JSON.devDependencies,"@types/node":s,"@types/react":resolveVersionToken(`typesReactPackageVersion`,r.typesReactPackageVersion),"@types/react-dom":resolveVersionToken(`typesReactDomPackageVersion`,r.typesReactDomPackageVersion),"@typescript/native-preview":resolveVersionToken(`tsgoPackageVersion`,r.tsgoPackageVersion)},f=WEB_APP_TEMPLATE_PACKAGE_JSON.scripts,p=await patchPackageJson(e,{dependencies:c,devDependencies:u,scripts:f,nodeEngineRequirement:o.nodeEngine});return{mutations:[{path:e,dependencies:Object.keys(c),devDependencies:Object.keys(u),scripts:Object.keys(f)}],nodeEngineOverride:p.nodeEngineOverride}}function normalizeSlackConnectorSlug(e){return toSlackConnectorSlug((e.trim().replace(/^@/,``).split(`/`).at(-1)??``).toLowerCase().replace(/[^a-z0-9_-]+/g,`-`).replace(/^[^a-z0-9]+/,``).replace(/[^a-z0-9]+$/,``).slice(0,100).replace(/[^a-z0-9]+$/,``)||`my-agent`)}async function deriveSlackConnectorSlug(e,t){if(t!==void 0&&t.length>0&&t!==`.`)return normalizeSlackConnectorSlug(t);try{let t=await readFile(join(e,`package.json`),`utf8`),n=JSON.parse(t);if(typeof n.name==`string`&&n.name.length>0)return normalizeSlackConnectorSlug(n.name)}catch{}return normalizeSlackConnectorSlug(basename(resolve(e))||`my-agent`)}function buildSlackTemplate(e){if(!e.startsWith(`slack/`)||e.length===6)throw Error(`Invalid Slack connector UID "${e}".`);return`import { connectSlackCredentials } from "@vercel/connect/eve";
|
|
2
2
|
import { slackChannel } from "eve/channels/slack";
|
|
3
3
|
|
|
4
4
|
export default slackChannel({
|
|
5
5
|
credentials: connectSlackCredentials(${JSON.stringify(e)}),
|
|
6
6
|
});
|
|
7
|
-
`}function renderWebAppTemplate(e,t,n){let r=n?``:`, { configureVercelOutput: false }`;return e.replaceAll(`__EVE_INIT_APP_NAME__`,t).replaceAll(`__EVE_INIT_WITH_EVE_OPTIONS__`,r)}function withWebVercelServices(e){let t=JSON.parse(e);if(!isJsonObject(t))throw Error(`${WEB_VERCEL_JSON_PATH} must contain a JSON object.`);let n=t.experimentalServices;if(n!==void 0&&!isJsonObject(n))throw Error(`${WEB_VERCEL_JSON_PATH} experimentalServices must contain a JSON object.`);let r={...t,$schema:typeof t.$schema==`string`?t.$schema:WEB_VERCEL_JSON_SCHEMA,experimentalServices:{...n,web:n?.web??WEB_DEFAULT_VERCEL_SERVICES.web,eve:n?.eve??WEB_DEFAULT_VERCEL_SERVICES.eve}};return JSON.stringify(t)===JSON.stringify(r)?e:`${JSON.stringify(r,null,2)}\n`}async function ensureWebVercelServices(e){if(!await pathExists(e))return await writeTextFile(e,`${JSON.stringify({$schema:WEB_VERCEL_JSON_SCHEMA,experimentalServices:WEB_DEFAULT_VERCEL_SERVICES},null,2)}\n`,{force:!0}),`written`;let
|
|
7
|
+
`}function renderWebAppTemplate(e,t,n){let r=n?``:`, { configureVercelOutput: false }`;return e.replaceAll(`__EVE_INIT_APP_NAME__`,t).replaceAll(`__EVE_INIT_WITH_EVE_OPTIONS__`,r)}function withWebVercelServices(e){let t=JSON.parse(e);if(!isJsonObject(t))throw Error(`${WEB_VERCEL_JSON_PATH} must contain a JSON object.`);let n=t.experimentalServices;if(n!==void 0&&!isJsonObject(n))throw Error(`${WEB_VERCEL_JSON_PATH} experimentalServices must contain a JSON object.`);let r={...t,$schema:typeof t.$schema==`string`?t.$schema:WEB_VERCEL_JSON_SCHEMA,experimentalServices:{...n,web:n?.web??WEB_DEFAULT_VERCEL_SERVICES.web,eve:n?.eve??WEB_DEFAULT_VERCEL_SERVICES.eve}};return JSON.stringify(t)===JSON.stringify(r)?e:`${JSON.stringify(r,null,2)}\n`}async function ensureWebVercelServices(e){if(!await pathExists(e))return await writeTextFile(e,`${JSON.stringify({$schema:WEB_VERCEL_JSON_SCHEMA,experimentalServices:WEB_DEFAULT_VERCEL_SERVICES},null,2)}\n`,{force:!0}),`written`;let t=await readFile(e,`utf8`),i=withWebVercelServices(t);return i===t?`skipped`:(await writeFile(e,i,`utf8`),`written`)}async function findCompetingNextConfigFiles(e){let t=[];for(let r of WEB_COMPETING_NEXT_CONFIG_PATHS){let i=join(e,r);await pathExists(i)&&t.push(i)}return t}async function ensureChannel(e){switch(e.kind){case`slack`:return ensureSlackChannel({...e,kind:`slack`});case`web`:return ensureWebChannel({...e,kind:`web`})}}async function ensureWebChannel(t){let i=join(t.projectRoot,`package.json`),a=await pathExists(join(t.projectRoot,`app/page.tsx`));if(!t.force&&await isNextJsProject(t.projectRoot))return{kind:`web`,action:`skipped`,skipReason:`nextjs-project`,filesWritten:[],filesSkipped:[i],packageJsonUpdated:[]};let o=await patchWebPackageJson(i,resolveWebPackageVersions(t.webPackageVersions)),s=[],l=[],u=[],d=[],m=basename(resolve(t.projectRoot)),h=t.configureVercelServices??!0;if(h){let e=join(t.projectRoot,WEB_VERCEL_JSON_PATH);await ensureWebVercelServices(e)===`written`?s.push(e):d.push(e)}let g=await getPackageManagerStrategy(t.packageManager??`pnpm`).applyProjectConfiguration(t.projectRoot);s.push(...g.filesWritten),d.push(...g.filesSkipped);for(let[e,i]of Object.entries(WEB_APP_TEMPLATE_FILES)){let a=join(t.projectRoot,e);if(e===`agent/channels/eve.ts`&&!t.force&&await pathExists(a)){d.push(a);continue}let o=await pathExists(a);await writeTextFile(a,renderWebAppTemplate(i,m,h),{force:!0}),s.push(a),o&&l.push(a)}u.push(...await findCompetingNextConfigFiles(t.projectRoot));let _={kind:`web`,action:a?`overwritten`:`created`,filesWritten:s,filesSkipped:d,packageJsonUpdated:o.mutations};return l.length>0&&(_.filesOverwritten=l),u.length>0&&(_.competingNextConfigFiles=u),o.nodeEngineOverride!==void 0&&(_.nodeEngineOverride=o.nodeEngineOverride),_}async function ensureSlackChannel(e){let t=join(e.projectRoot,`agent/channels/slack.ts`),i=await pathExists(t);if(!e.force&&i)return{kind:`slack`,action:`skipped`,filesWritten:[],filesSkipped:[t],packageJsonUpdated:[]};let o=resolveVersionToken(`connectPackageVersion`,e.connectPackageVersion??`0.2.2`),s=await ensurePackageDependency(join(e.projectRoot,`package.json`),`@vercel/connect`,o),c=e.slackConnectorSlug??await deriveSlackConnectorSlug(e.projectRoot);await writeTextFile(t,buildSlackTemplate(e.slackConnectorUid??`slack/${c}`),{force:e.force});let l={kind:`slack`,action:i?`overwritten`:`created`,filesWritten:[t],filesSkipped:[],packageJsonUpdated:s,slackConnectorSlug:c};return i&&(l.filesOverwritten=[t]),l}async function listAuthoredChannels(e){let t=join(e,`agent/channels`),n;try{n=await readdir(t,{withFileTypes:!0})}catch(e){if(e.code===`ENOENT`)return[];throw e}let r=[];for(let e of n){if(e.isFile()){let t=getSupportedModuleBaseName(e.name);t!==null&&r.push(t);continue}if(e.isDirectory())try{(await readdir(join(t,e.name))).some(e=>matchesSupportedModuleBaseName(e,`connection`))&&r.push(e.name)}catch{}}return r.sort()}export{DEFAULT_SLACK_CONNECTOR_SLUG,SLACK_CHANNEL_DEFAULT_ROUTE,deriveSlackConnectorSlug,ensureChannel,isNextJsProject,listAuthoredChannels,normalizeSlackConnectorSlug};
|
|
@@ -1,6 +1,17 @@
|
|
|
1
|
+
import { type NodeEngineOverride } from "../../node-engine.js";
|
|
1
2
|
export interface PackageJsonPatch {
|
|
2
3
|
dependencies?: Record<string, string>;
|
|
3
4
|
devDependencies?: Record<string, string>;
|
|
4
5
|
scripts?: Record<string, string>;
|
|
6
|
+
/**
|
|
7
|
+
* Eve's required Node.js range (e.g. `">=24"`). When the target's
|
|
8
|
+
* `engines.node` is absent or is not confined to the scaffolded major, it is
|
|
9
|
+
* set to that pinned major (e.g. `"24.x"`). Existing ranges within the same
|
|
10
|
+
* major are left untouched.
|
|
11
|
+
*/
|
|
12
|
+
nodeEngineRequirement?: string;
|
|
5
13
|
}
|
|
6
|
-
export
|
|
14
|
+
export interface PackageJsonPatchResult {
|
|
15
|
+
nodeEngineOverride?: NodeEngineOverride;
|
|
16
|
+
}
|
|
17
|
+
export declare function patchPackageJson(path: string, patch: PackageJsonPatch): Promise<PackageJsonPatchResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readFile,writeFile}from"node:fs/promises";async function patchPackageJson(
|
|
1
|
+
import{reconcileNodeEngine}from"../../node-engine.js";import{readFile,writeFile}from"node:fs/promises";function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}async function patchPackageJson(r,i){let a=await readFile(r,`utf8`),o=JSON.parse(a),s=!1,c;if(i.dependencies!==void 0&&(o.dependencies={...o.dependencies,...i.dependencies},s=!0),i.devDependencies!==void 0&&(o.devDependencies={...o.devDependencies,...i.devDependencies},s=!0),i.scripts!==void 0&&(o.scripts={...o.scripts,...i.scripts},s=!0),i.nodeEngineRequirement!==void 0){let t=isJsonObject(o.engines)?o.engines:{},n=reconcileNodeEngine(t.node,i.nodeEngineRequirement);(n.kind===`added`||n.kind===`overridden`)&&(o.engines={...t,node:n.next},s=!0),n.kind===`overridden`&&(c=n)}return s&&await writeFile(r,`${JSON.stringify(o,null,2)}\n`,`utf8`),{nodeEngineOverride:c}}export{patchPackageJson};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{existsSync,readFileSync,realpathSync}from"node:fs";import{dirname,join}from"node:path";import{fileURLToPath}from"node:url";function versionToken(e){return`__${e}_VERSION__`}function bareToken(e){return`__${e}__`}const NODE_ENGINE_TOKEN=bareToken(`NODE_ENGINE`),TOKEN_SOURCES={[versionToken(`EVE_PACKAGE`)]:{kind:`eve-version`},[NODE_ENGINE_TOKEN]:{kind:`eve-node-engine`},[versionToken(`AI_SDK`)]:{kind:`catalog`,packageName:`ai`},[versionToken(`VERCEL_CONNECT`)]:{kind:`catalog`,packageName:`@vercel/connect`},[versionToken(`NEXT`)]:{kind:`catalog`,packageName:`next`},[versionToken(`REACT`)]:{kind:`catalog`,packageName:`react`},[versionToken(`REACT_DOM`)]:{kind:`catalog`,packageName:`react-dom`},[versionToken(`STREAMDOWN`)]:{kind:`catalog`,packageName:`streamdown`},[versionToken(`ZOD`)]:{kind:`catalog`,packageName:`zod`},[versionToken(`TSGO`)]:{kind:`catalog`,packageName:`@typescript/native-preview`},[versionToken(`TYPES_REACT`)]:{kind:`catalog`,packageName:`@types/react`},[versionToken(`TYPES_REACT_DOM`)]:{kind:`catalog`,packageName:`@types/react-dom`}},resolvedTokens=new Map;function findEvePackageRoot(){let o=dirname(realpathSync(fileURLToPath(import.meta.url)));for(;;){let n=join(o,`package.json`);if(existsSync(n)&&JSON.parse(readFileSync(n,`utf8`)).name===`eve`)return o;let a=dirname(o);if(a===o)return;o=a}}function findWorkspaceManifest(t){let n=t;for(;;){let t=join(n,`pnpm-workspace.yaml`);if(existsSync(t))return t;let a=dirname(n);if(a===n)return;n=a}}function readCatalogVersion(e,n){let r=readFileSync(e,`utf8`).split(/\r?\n/),i=!1;for(let e of r){if(/^catalog:\s*$/.test(e)){i=!0;continue}if(!i)continue;if(/^\S/.test(e))break;let t=e.match(/^\s+(?:"([^"]+)"|([\w@/.-]+)):\s*"([^"]+)"/);if(t&&(t[1]??t[2])===n)return t[3]}}function resolveTokenFromDevTree(n){let r=TOKEN_SOURCES[n];if(r!==void 0)try{let n=findEvePackageRoot();if(n===void 0||!existsSync(join(n,`scripts/stamp-version-tokens.mjs`)))return;if(r.kind===`eve-version`){let e=JSON.parse(readFileSync(join(n,`package.json`),`utf8`));return typeof e.version==`string`?e.version:void 0}if(r.kind===`eve-node-engine`){let e=JSON.parse(readFileSync(join(n,`package.json`),`utf8`)).engines?.node;return typeof e==`string`?e:void 0}let a=findWorkspaceManifest(n);return a===void 0?void 0:readCatalogVersion(a,r.packageName)}catch{return}}function resolveVersionToken(e,t){if(!t.startsWith(`__`))return t;let n=resolvedTokens.get(t);if(n!==void 0)return n;let r=resolveTokenFromDevTree(t);if(r===void 0)throw Error(`Scaffold received unstamped version token (${e}=${t}). Build eve before using its dist entrypoint.`);return resolvedTokens.set(t,r),r}export{resolveVersionToken};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ProcessOutputHandler } from "#setup/primitives/process-output.js";
|
|
2
|
+
import type { captureVercel, runVercelCaptureStdout } from "#setup/primitives/run-vercel.js";
|
|
3
|
+
import { type SlackConnectorRef, type SlackWorkspaceConnection } from "./slack-connect.js";
|
|
4
|
+
export interface SlackConnectorCreateDeps {
|
|
5
|
+
captureVercel: typeof captureVercel;
|
|
6
|
+
runVercelCaptureStdout: typeof runVercelCaptureStdout;
|
|
7
|
+
delay?: (ms: number, signal?: AbortSignal) => Promise<void>;
|
|
8
|
+
now?: () => number;
|
|
9
|
+
}
|
|
10
|
+
export type SlackConnectorCreateResult = {
|
|
11
|
+
state: "created";
|
|
12
|
+
via: "cli";
|
|
13
|
+
ref: SlackConnectorRef;
|
|
14
|
+
} | {
|
|
15
|
+
state: "created";
|
|
16
|
+
via: "workspace";
|
|
17
|
+
ref: SlackConnectorRef;
|
|
18
|
+
workspace: SlackWorkspaceConnection;
|
|
19
|
+
} | {
|
|
20
|
+
state: "failed";
|
|
21
|
+
} | {
|
|
22
|
+
state: "unresolved";
|
|
23
|
+
};
|
|
24
|
+
type Phase = <T>(message: string, task: () => Promise<T>) => Promise<T>;
|
|
25
|
+
/**
|
|
26
|
+
* Waits for either the CLI's final browser result or connector metadata proving
|
|
27
|
+
* that Slack connected the workspace. A connector progress event establishes
|
|
28
|
+
* ownership only; the exact detail endpoint establishes workspace completion.
|
|
29
|
+
*/
|
|
30
|
+
export declare function createSlackConnector(input: {
|
|
31
|
+
deps: SlackConnectorCreateDeps;
|
|
32
|
+
projectRoot: string;
|
|
33
|
+
orgId: string | undefined;
|
|
34
|
+
slug: string;
|
|
35
|
+
onOutput: ProcessOutputHandler;
|
|
36
|
+
signal: AbortSignal | undefined;
|
|
37
|
+
phase: Phase;
|
|
38
|
+
onCreated: (ref: SlackConnectorRef) => void;
|
|
39
|
+
waitForWorkspace: (ref: SlackConnectorRef, signal: AbortSignal) => Promise<SlackWorkspaceConnection | undefined>;
|
|
40
|
+
}): Promise<SlackConnectorCreateResult>;
|
|
41
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{parseCreatedSlackConnector}from"./slack-connect.js";import{CONNECT_LOOKUP_TIMEOUT_MS,fetchSlackConnectorDetails}from"./slack-connect-lifecycle.js";import{setTimeout}from"node:timers/promises";import{performance}from"node:perf_hooks";const CREATED_CONNECTOR_PROGRESS=/\bConnector created:\s*(scl_[A-Za-z0-9]+)\b/,realDelay=(e,t)=>setTimeout(e,void 0,{signal:t}),monotonicNow=()=>performance.now();async function pollCreatedSlackConnector(e,r,i,a,o,s){let c=e.delay??realDelay,l=e.now??monotonicNow,u=l()+CONNECT_LOOKUP_TIMEOUT_MS;for(;;){s.throwIfAborted();let t=u-l();if(t<=0)return;let d=await fetchSlackConnectorDetails({deps:e,projectRoot:r,connectorId:i,orgId:a,onOutput:o,timeoutMs:Math.min(1e4,t),signal:s});if(s.throwIfAborted(),d.state===`found`)return d.details.ref;let f=u-l();if(f<=0)return;await c(Math.min(3e3,f),s)}}async function createSlackConnector(t){let n=new AbortController,r=new AbortController,i=new AbortController,o=t.signal?AbortSignal.any([t.signal,n.signal]):n.signal,s=t.signal?AbortSignal.any([t.signal,r.signal]):r.signal,c=t.signal?AbortSignal.any([t.signal,i.signal]):i.signal,l=!1,reportCreated=e=>{l||(l=!0,t.onCreated(e))},u,d,f=new Promise((e,t)=>{u=e,d=t}),p,m,startWorkspaceLookup=e=>{m===void 0&&(m=t.waitForWorkspace(e,c).catch(e=>{if(!(i.signal.aborted&&t.signal?.aborted!==!0))throw e}),m.then(t=>{t!==void 0&&u({ref:e,workspace:t})},d))},createOutput=e=>{t.onOutput(e);let n=e.text.match(CREATED_CONNECTOR_PROGRESS)?.[1];n===void 0||p!==void 0||(p=pollCreatedSlackConnector(t.deps,t.projectRoot,n,t.orgId,t.onOutput,s).catch(e=>{if(!(r.signal.aborted&&t.signal?.aborted!==!0))throw e}),p.then(e=>{e!==void 0&&(reportCreated(e),startWorkspaceLookup(e))},d))},h=t.phase(`Waiting for Slack setup to finish...`,()=>t.deps.runVercelCaptureStdout([`connect`,`create`,`slack`,`--triggers`,`--name`,t.slug,`-F`,`json`],{cwd:t.projectRoot,nonInteractive:!0,onOutput:createOutput,timeoutMs:6e5,signal:o})),g;try{g=await Promise.race([h.then(e=>({via:`cli`,result:e})),f.then(e=>({via:`workspace`,...e}))])}catch(e){throw r.abort(),i.abort(),await Promise.allSettled([p,m].filter(e=>e!==void 0)),e}if(g.via===`workspace`)return n.abort(),await h,t.signal?.throwIfAborted(),{state:`created`,via:`workspace`,ref:g.ref,workspace:g.workspace};if(!g.result.ok)return p!==void 0&&await p,i.abort(),m!==void 0&&await m,t.signal?.throwIfAborted(),{state:`failed`};let _=parseCreatedSlackConnector(g.result.stdout);if(_!==void 0)return reportCreated(_),r.abort(),i.abort(),p!==void 0&&await p,m!==void 0&&await m,t.signal?.throwIfAborted(),{state:`created`,via:`cli`,ref:_};let v=p===void 0?void 0:await p;return i.abort(),m!==void 0&&await m,t.signal?.throwIfAborted(),v===void 0?{state:`unresolved`}:{state:`created`,via:`cli`,ref:v}}export{createSlackConnector};
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { createPromptCommandOutput, type ChannelSetupLog } from "#setup/cli/index.js";
|
|
2
2
|
import { captureVercel, runVercel } from "#setup/primitives/run-vercel.js";
|
|
3
|
-
import {
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { type RawSlackConnector, type SlackConnectorDetails, type SlackConnectorRef, type SlackWorkspaceConnection } from "./slack-connect.js";
|
|
4
5
|
export declare const CONNECT_LOOKUP_TIMEOUT_MS = 60000;
|
|
5
6
|
export declare const CONNECT_MUTATION_TIMEOUT_MS: number;
|
|
7
|
+
declare const VercelProjectLinkSchema: z.ZodObject<{
|
|
8
|
+
projectId: z.ZodString;
|
|
9
|
+
orgId: z.ZodString;
|
|
10
|
+
}, z.core.$strip>;
|
|
6
11
|
/** Connect subprocess operations needed to inventory and remove Slack connectors. */
|
|
7
12
|
export interface SlackConnectLifecycleDeps {
|
|
8
13
|
captureVercel: typeof captureVercel;
|
|
@@ -32,8 +37,10 @@ export interface SlackConnectorCleanupContext {
|
|
|
32
37
|
}
|
|
33
38
|
/** Reads and validates the account-level Slack connector inventory. */
|
|
34
39
|
export declare function listSlackConnectors(deps: SlackConnectLifecycleDeps, projectRoot: string, onOutput: CommandOutput, signal?: AbortSignal): Promise<SlackConnectorInventory>;
|
|
35
|
-
/**
|
|
36
|
-
export
|
|
40
|
+
/** Project and team identifiers from a valid on-disk Vercel link. */
|
|
41
|
+
export type VercelProjectLink = z.infer<typeof VercelProjectLinkSchema>;
|
|
42
|
+
/** Reads the linked Vercel project and team ids from `.vercel/project.json`. */
|
|
43
|
+
export declare function readProjectLink(projectRoot: string): Promise<VercelProjectLink | undefined>;
|
|
37
44
|
export type SlackConnectorLookup = {
|
|
38
45
|
state: "found";
|
|
39
46
|
connector: SlackConnectorRef;
|
|
@@ -67,20 +74,42 @@ export type SlackConnectorAttachmentResult = {
|
|
|
67
74
|
* rather than silently left pointing at the wrong place.
|
|
68
75
|
*/
|
|
69
76
|
export declare function attachSlackConnector(deps: SlackConnectLifecycleDeps, projectRoot: string, ref: SlackConnectorRef, onOutput: CommandOutput, signal?: AbortSignal): Promise<SlackConnectorAttachmentResult>;
|
|
70
|
-
export type
|
|
71
|
-
state: "
|
|
72
|
-
|
|
73
|
-
workspaceUrl: string;
|
|
74
|
-
workspaceName?: string;
|
|
75
|
-
};
|
|
77
|
+
export type SlackWorkspaceLookup = {
|
|
78
|
+
state: "connected";
|
|
79
|
+
workspace: SlackWorkspaceConnection;
|
|
76
80
|
} | {
|
|
77
81
|
state: "pending";
|
|
78
82
|
} | {
|
|
79
83
|
state: "failed";
|
|
80
84
|
message: string;
|
|
81
85
|
};
|
|
82
|
-
|
|
83
|
-
|
|
86
|
+
export type SlackConnectorDetailsLookup = {
|
|
87
|
+
state: "found";
|
|
88
|
+
details: SlackConnectorDetails;
|
|
89
|
+
} | {
|
|
90
|
+
state: "failed";
|
|
91
|
+
message: string;
|
|
92
|
+
};
|
|
93
|
+
/** Fetches and validates one team-scoped connector detail payload. */
|
|
94
|
+
export declare function fetchSlackConnectorDetails(input: {
|
|
95
|
+
deps: Pick<SlackConnectLifecycleDeps, "captureVercel">;
|
|
96
|
+
projectRoot: string;
|
|
97
|
+
connectorId: string;
|
|
98
|
+
orgId: string | undefined;
|
|
99
|
+
onOutput: CommandOutput;
|
|
100
|
+
timeoutMs: number;
|
|
101
|
+
signal?: AbortSignal;
|
|
102
|
+
}): Promise<SlackConnectorDetailsLookup>;
|
|
103
|
+
/** Fetches the Slack workspace connected to a connector, if one exists yet. */
|
|
104
|
+
export declare function fetchSlackWorkspace(input: {
|
|
105
|
+
deps: Pick<SlackConnectLifecycleDeps, "captureVercel">;
|
|
106
|
+
projectRoot: string;
|
|
107
|
+
connectorId: string;
|
|
108
|
+
orgId: string | undefined;
|
|
109
|
+
onOutput: CommandOutput;
|
|
110
|
+
timeoutMs: number;
|
|
111
|
+
signal?: AbortSignal;
|
|
112
|
+
}): Promise<SlackWorkspaceLookup>;
|
|
84
113
|
/**
|
|
85
114
|
* Removes the exact connector returned by `connect create`. When no UID was
|
|
86
115
|
* returned, ownership cannot be proven: a concurrent or eventually-consistent
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{object,string}from"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/schemas.js";import"../node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.js";import{parseSlackConnectorDetails,parseSlackConnectors,pickSlackConnector}from"./slack-connect.js";import{join}from"node:path";import{SLACK_CHANNEL_DEFAULT_ROUTE}from"#setup/scaffold/index.js";import{readFile}from"node:fs/promises";import"#setup/cli/index.js";import"#setup/primitives/run-vercel.js";const CONNECT_LOOKUP_TIMEOUT_MS=6e4,CONNECT_MUTATION_TIMEOUT_MS=2*6e4,VercelProjectLinkSchema=object({projectId:string().min(1),orgId:string().min(1)});async function listSlackConnectors(e,t,n,i){let a=await e.captureVercel([`connect`,`list`,`-F`,`json`,`--all-projects`],{cwd:t,onOutput:n,timeoutMs:CONNECT_LOOKUP_TIMEOUT_MS,signal:i});if(!a.ok)return{state:`failed`,message:a.failure.message};try{let e=JSON.parse(a.stdout);if(typeof e!=`object`||!e)return{state:`failed`,message:`Vercel returned a malformed connector list.`};let t=e;return Array.isArray(t.connectors??t.clients)?{state:`ok`,body:e,connectors:parseSlackConnectors(e)}:{state:`failed`,message:`Vercel returned a malformed connector list.`}}catch{return{state:`failed`,message:`Vercel returned invalid JSON for the connector list.`}}}async function readProjectLink(e){try{let t=await readFile(join(e,`.vercel`,`project.json`),`utf8`),n=VercelProjectLinkSchema.safeParse(JSON.parse(t));return n.success?n.data:void 0}catch{return}}async function findSlackConnector(e,t,n,r,a,o){let s=await listSlackConnectors(e,t,a,o);if(s.state===`failed`)return s;let c=new Set(s.connectors.map(e=>e.uid)),l=pickSlackConnector(s.body,n,r);return l===void 0?{state:`not-found`,connectorUids:c}:{state:`found`,connector:l,connectorUids:c}}async function attachSlackConnector(e,t,n,r,i){return await e.runVercel([`connect`,`detach`,n.uid,`--yes`],{cwd:t,onOutput:r,nonInteractive:!0,timeoutMs:CONNECT_MUTATION_TIMEOUT_MS,signal:i})?await e.runVercel([`connect`,`attach`,n.uid,`--triggers`,`--trigger-path`,SLACK_CHANNEL_DEFAULT_ROUTE,`--yes`],{cwd:t,onOutput:r,nonInteractive:!0,timeoutMs:CONNECT_MUTATION_TIMEOUT_MS,signal:i})?{state:`attached`}:{state:`attach-failed`}:{state:`detach-failed`}}async function fetchSlackConnectorDetails(e){let t=e.orgId===void 0?``:`?teamId=${encodeURIComponent(e.orgId)}`,r=[`api`,`/v1/connect/connectors/${encodeURIComponent(e.connectorId)}${t}`];e.orgId!==void 0&&r.push(`--scope`,e.orgId);let i=await e.deps.captureVercel(r,{cwd:e.projectRoot,onOutput:e.onOutput,timeoutMs:e.timeoutMs,signal:e.signal});if(!i.ok)return{state:`failed`,message:i.failure.message};try{let t=parseSlackConnectorDetails(JSON.parse(i.stdout));return t?.ref.id===e.connectorId?{state:`found`,details:t}:{state:`failed`,message:`Vercel returned an invalid Slack connector.`}}catch{return{state:`failed`,message:`Vercel returned invalid JSON for the Slack connector.`}}}async function fetchSlackWorkspace(e){let t=await fetchSlackConnectorDetails(e);return t.state===`failed`?t:t.details.workspace===void 0?{state:`pending`}:{state:`connected`,workspace:t.details.workspace}}async function cleanupConnectorUid(e,t){let{log:n,deps:r,projectRoot:i,onOutput:a}=e;return await r.runVercel([`connect`,`remove`,t,`--disconnect-all`,`--yes`],{cwd:i,onOutput:a,timeoutMs:CONNECT_MUTATION_TIMEOUT_MS})?!0:(n.warning(`Could not remove the abandoned Slack connector. Run \`vercel connect remove ${t} --disconnect-all --yes\` to clean it up.`),!1)}async function cleanupConnectorUids(e,t){let n=[];for(let r of new Set(t))await cleanupConnectorUid(e,r)||n.push(r);return n.length===0?{state:`clean`}:{state:`failed`,connectorUids:n}}async function cleanupCreatedAttempt(e,t){if(t.createdRef)return cleanupConnectorUids(e,[t.createdRef.uid]);e.log.warning(`Vercel returned no connector UID for the abandoned Slack Connect request, so Eve cannot prove that request was cancelled. No connector was removed; do not retry until the browser request is no longer usable.`);let n=await listSlackConnectors(e.deps,e.projectRoot,e.onOutput);return n.state===`failed`?{state:`failed`,connectorUids:[]}:{state:`failed`,connectorUids:n.connectors.map(e=>e.uid).filter(e=>(e===t.expectedUid||e.startsWith(`${t.expectedUid}-`))&&!t.baselineConnectorUids.has(e))}}export{CONNECT_LOOKUP_TIMEOUT_MS,CONNECT_MUTATION_TIMEOUT_MS,attachSlackConnector,cleanupCreatedAttempt,fetchSlackConnectorDetails,fetchSlackWorkspace,findSlackConnector,listSlackConnectors,readProjectLink};
|