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
|
@@ -1 +1 @@
|
|
|
1
|
-
import{transformWorkflowDirectives}from"./workflow-transformer.js";import{dirname,isAbsolute,join,relative,resolve,sep}from"node:path";import{
|
|
1
|
+
import{transformWorkflowDirectives}from"./workflow-transformer.js";import{existsSync,readFileSync}from"node:fs";import{dirname,isAbsolute,join,relative,resolve,sep}from"node:path";import{readFile}from"node:fs/promises";import{STABLE_WORKFLOW_NAMES}from"#execution/workflow-runtime.js";import{EVE_WORKFLOW_QUEUE_TOPIC}from"#internal/workflow/queue-namespace.js";const WORKFLOW_QUEUE_TRIGGER={type:`queue/v2beta`,topic:EVE_WORKFLOW_QUEUE_TOPIC,consumer:`default`,retryAfterSeconds:5,initialDelaySeconds:0},packageJsonCache=new Map,projectDepsCache=new Map;async function applyWorkflowTransform(t,n,r,o,s,c=STABLE_WORKFLOW_NAMES){let l=s??process.cwd(),{moduleSpecifier:u,stableModuleSpecifier:d}=resolveModuleSpecifier(o===void 0?isAbsolute(t)?t:join(l,t):o,l);return transformWorkflowDirectives({filename:t,mode:r,moduleSpecifier:u,source:n,stableModuleSpecifier:d,stableWorkflowNames:c})}function detectWorkflowPatterns(e){return{hasSerde:e.includes(`workflow.serde`)||e.includes(`@serde`)||e.includes(`workflowSerde`)||e.includes(`__workflow_serde`),hasUseStep:/["']use step["']/.test(e),hasUseWorkflow:/["']use workflow["']/.test(e)}}function getImportPath(e,t){let n=isInNodeModules(e),r=!n&&isWorkspacePackage(e,t);if(n||r){let n=findPackageJson(e);if(n!==null){let i=getProjectDependencies(t).has(n.name);if(!(r||i))return{importPath:toRelativeImportPath(e,t),isPackage:!1};let a=resolveExportSubpath(e,n);return a?{importPath:`${n.name}${a}`,isPackage:!0}:isRootEntrypointFile(e,n)?{importPath:n.name,isPackage:!0}:{importPath:toRelativeImportPath(e,t),isPackage:!1}}}return{importPath:toRelativeImportPath(e,t),isPackage:!1}}function resolveModuleSpecifier(e,t){let n=isInNodeModules(e),r=!n&&isWorkspacePackage(e,t);if(!n&&!r)return{moduleSpecifier:void 0,stableModuleSpecifier:void 0};let i=findPackageJson(e);if(i===null)return{moduleSpecifier:void 0,stableModuleSpecifier:void 0};let a=resolveExportSubpath(e,i),o=a?`${i.name}${a}`:i.name;return{moduleSpecifier:`${o}@${i.version}`,stableModuleSpecifier:o}}function findPackageJson(e){let i=dirname(e),o=[];for(;i!==dirname(i);){let e=packageJsonCache.get(i);if(e!==void 0){for(let t of o)packageJsonCache.set(t,e);return e}o.push(i);let s=join(i,`package.json`);if(existsSync(s))try{let e=JSON.parse(readFileSync(s,`utf8`));if(typeof e.name==`string`&&typeof e.version==`string`){let t={dir:i,exports:e.exports,main:e.main,module:e.module,name:e.name,version:e.version};packageJsonCache.set(i,t);for(let e of o)packageJsonCache.set(e,t);return t}}catch{}i=dirname(i)}for(let e of o)packageJsonCache.set(e,null);return null}function resolveExportSubpath(e,t){if(t.exports===null||typeof t.exports!=`object`||Array.isArray(t.exports))return``;let n=e.replace(/\\/g,`/`),r=t.dir.replace(/\\/g,`/`),i=n.startsWith(`${r}/`)?`./${n.substring(r.length+1)}`:null;if(i===null)return``;for(let[e,n]of Object.entries(t.exports)){let t=resolveExportTarget(n);if(t!==null&&normalizeExportPath(t)===i)return e===`.`?``:e.substring(1)}return``}function resolveExportTarget(e){if(typeof e==`string`)return e;if(Array.isArray(e)){for(let t of e){let e=resolveExportTarget(t);if(e!==null)return e}return null}if(typeof e==`object`&&e)for(let t of[`workflow`,`default`,`require`,`import`,`node`]){let n=e[t],r=resolveExportTarget(n);if(r!==null)return r}return null}function normalizeExportPath(e){return e.startsWith(`./`)?e:`./${e}`}function isInNodeModules(e){return e.split(sep).join(`/`).includes(`/node_modules/`)}function getProjectDependencies(e){let r=projectDepsCache.get(e);if(r!==void 0)return r;let i=new Set,o=join(e,`package.json`);if(existsSync(o))try{let e=JSON.parse(readFileSync(o,`utf8`));for(let t of[`dependencies`,`devDependencies`,`peerDependencies`,`optionalDependencies`]){let n=e[t];if(typeof n==`object`&&n&&!Array.isArray(n))for(let e of Object.keys(n))i.add(e)}}catch{}return projectDepsCache.set(e,i),i}function isWorkspacePackage(e,t){if(isInNodeModules(e))return!1;let n=findPackageJson(e);return n===null||resolve(n.dir)===resolve(t)?!1:getProjectDependencies(t).has(n.name)}function toRelativeImportPath(e,t){let n=t.replace(/\\/g,`/`),r=e.replace(/\\/g,`/`),i=r.startsWith(`${n}/`)?r.substring(n.length+1):relative(t,e).replace(/\\/g,`/`);return i.startsWith(`.`)||(i=`./${i}`),i}function hasRootExport(e){if(typeof e==`string`||Array.isArray(e))return!0;if(typeof e!=`object`||!e)return!1;let t=Object.keys(e);return t.length>0&&t.every(e=>!e.startsWith(`.`))?!0:`.`in e}function normalizePackageTargetPath(e){let t=e.replace(/\\/g,`/`);return t.startsWith(`./`)?t.substring(2):t.startsWith(`/`)?t.substring(1):t}function isRootEntrypointFile(e,t){let n=e.replace(/\\/g,`/`),r=t.dir.replace(/\\/g,`/`);if(!n.startsWith(`${r}/`))return!1;let i=n.substring(r.length+1);if(t.exports!==void 0){let e;if(t.exports!==null&&typeof t.exports==`object`&&`.`in t.exports)e=t.exports[`.`];else if(hasRootExport(t.exports))e=t.exports;else return!1;let n=resolveExportTarget(e);return n!==null&&normalizePackageTargetPath(n)===i}return[t.module,t.main,`index.js`,`index.mjs`,`index.cjs`,`index.ts`,`index.mts`,`index.cts`].flatMap(e=>typeof e==`string`?[normalizePackageTargetPath(e)]:[]).includes(i)}async function readSourceFile(e){return await readFile(e,`utf8`)}export{WORKFLOW_QUEUE_TRIGGER,applyWorkflowTransform,detectWorkflowPatterns,getImportPath,readSourceFile};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{
|
|
2
|
-
`)}\n`:``}`,workflowManifest:a}}async function parseWorkflowSource(t,n){
|
|
1
|
+
import{parseWithNitroRolldownAst}from"#internal/bundler/nitro-rolldown.js";const BUILTIN_STEP_NAMES=new Set([`__builtin_response_array_buffer`,`__builtin_response_json`,`__builtin_response_text`,`__builtin_set_attributes`]);async function transformWorkflowDirectives(e){if(e.mode===!1)return{code:e.source,workflowManifest:{}};let t=await parseWorkflowSource(e.filename,e.source),n=findDirectiveFunctions(t);if(n.length===0)return{code:e.source,workflowManifest:{}};let r=e.moduleSpecifier??`./${stripJavaScriptExtension(e.filename)}`,i=e.stableModuleSpecifier??r,a={},o=[],s=[],c=!1;for(let t of n){if(t.directive===`use step`){let n=createStepId(r,t.name);a.steps??={};let i=a.steps[e.filename]??={};if(i[t.name]={stepId:n},e.mode===`workflow`){let e=t.exportPrefix.length>0?`export `:``;o.push({end:t.rangeEnd,start:t.rangeStart,text:`${e}var ${t.name} = globalThis[Symbol.for("WORKFLOW_USE_STEP")](${JSON.stringify(n)});`})}else o.push({end:t.directiveEnd,start:t.directiveStart,text:``}),e.mode===`step`?(c=!0,s.push(`registerStepFunction(${JSON.stringify(n)}, ${t.name});`)):s.push(`${t.name}.stepId = ${JSON.stringify(n)};`);continue}let n=`workflow//${e.stableWorkflowNames?.has(t.name)===!0?i:r}//${t.name}`;a.workflows??={};let l=a.workflows[e.filename]??={};l[t.name]={workflowId:n},e.mode===`workflow`?(o.push({end:t.directiveEnd,start:t.directiveStart,text:``}),s.push(`${t.name}.workflowId = ${JSON.stringify(n)};`),s.push(`globalThis.__private_workflows.set(${JSON.stringify(n)}, ${t.name});`)):(o.push({end:t.directiveEnd,start:t.directiveStart,text:`throw new Error(${JSON.stringify(`You attempted to execute workflow ${t.name} function directly. To start a workflow, use start(${t.name}) from workflow/api`)});`}),s.push(`${t.name}.workflowId = ${JSON.stringify(n)};`))}let l=`/**__internal_workflows${JSON.stringify(a)}*/;`,u=n.some(e=>e.directive===`use workflow`);if(e.mode===`workflow`&&!u)return{code:`${l}\n${createWorkflowStepProxySource(e.source,t,n,r)}`,workflowManifest:a};let d=applySourceReplacements(e.source,o),f=e.mode===`workflow`?await stripUnusedValueImports(e.filename,d):d;return{code:`${c?`import { registerStepFunction } from "workflow/internal/private";\n${l}\n`:`${l}\n`}${f}${s.length>0?`\n${s.join(`
|
|
2
|
+
`)}\n`:``}`,workflowManifest:a}}async function parseWorkflowSource(t,n){return await parseWithNitroRolldownAst(t,n)}function createWorkflowStepProxySource(e,t,n,r){let i=findExportedLiteralValueDeclarations(e,t),a=n.filter(e=>e.directive===`use step`).map(e=>{let t=e.exported?`export `:``,n=createStepId(r,e.name);return`${t}var ${e.name} = globalThis[Symbol.for("WORKFLOW_USE_STEP")](${JSON.stringify(n)});`}),o=[...i,...a];return o.length>0?`${o.join(`
|
|
3
3
|
`)}\n`:``}function findDirectiveFunctions(e){let t=[],n=collectLocalNamesReExportedAtModuleLevel(e);for(let r of e.body??[]){let e=readTopLevelFunctionDeclaration(r);if(e===null)continue;let i=e.fn,a=i.id?.name,o=readBlockStatements(i.body);if(i.async!==!0||a===void 0||o===void 0)continue;let s=readFunctionDirective(o[0]);s!==null&&t.push({directive:s.value,directiveEnd:s.end,directiveStart:s.start,exportPrefix:e.exported?`export `:``,exported:e.exported||n.has(a),name:a,rangeEnd:e.end,rangeStart:e.start})}return t}function collectLocalNamesReExportedAtModuleLevel(e){let t=new Set;for(let n of e.body??[])if(n.type===`ExportNamedDeclaration`&&!(n.source!==void 0&&n.source!==null)&&!(n.declaration!==void 0&&n.declaration!==null))for(let e of n.specifiers??[]){let n=e.local?.name;n!==void 0&&t.add(n)}return t}function readTopLevelFunctionDeclaration(e){return e.type===`FunctionDeclaration`?readFunctionDeclarationRange(e,!1,e):e.type!==`ExportNamedDeclaration`||e.declaration?.type!==`FunctionDeclaration`?null:readFunctionDeclarationRange(e.declaration,!0,e)}function readFunctionDeclarationRange(e,t,n){return e.start===void 0||e.end===void 0||n.start===void 0||n.end===void 0?null:{end:n.end,exported:t,fn:e,start:n.start}}function readBlockStatements(e){return e===void 0||Array.isArray(e)?e:e.body}function readFunctionDirective(e){let t=e?.directive??(e?.type===`ExpressionStatement`&&e.expression?.type===`Literal`?e.expression.value:void 0);return t!==`use workflow`&&t!==`use step`||e?.start===void 0||e.end===void 0?null:{end:e.end,start:e.start,value:t}}function applySourceReplacements(e,t){let n=``,r=0;for(let i of[...t].sort((e,t)=>e.start-t.start))n+=e.slice(r,i.start),n+=i.text,r=i.end;return n+e.slice(r)}async function stripUnusedValueImports(e,t){let n=await parseWorkflowSource(e,t),r=collectReferencedIdentifiers(n),i=[];for(let e of n.body??[]){if(e.type!==`ImportDeclaration`||e.start===void 0||e.end===void 0)continue;let n=readValueImportBindings(e);n.length>0&&n.every(e=>!r.has(e))&&i.push({end:extendRemovalEnd(t,e.end),start:e.start,text:``})}return i.length>0?applySourceReplacements(t,i):t}function findExportedLiteralValueDeclarations(e,t){let n=[],r=collectLocalReExportAliases(t);for(let i of t.body??[]){if(i.type===`ExportNamedDeclaration`&&i.declaration?.type===`VariableDeclaration`&&i.declaration.kind===`const`&&i.start!==void 0&&i.end!==void 0&&(i.declaration.declarations??[]).every(isLiteralValueDeclarator)){n.push(e.slice(i.start,i.end).trim());continue}if(i.type===`VariableDeclaration`&&(i.kind===`const`||i.kind===`var`||i.kind===`let`))for(let t of i.declarations??[]){if(!isLiteralValueDeclarator(t)||t.start===void 0||t.end===void 0)continue;let a=t.id?.name;if(a===void 0)continue;let o=r.get(a);if(o===void 0||o.length===0)continue;let s=e.slice(t.start,t.end).trim(),c=o.map(e=>e===a?a:`${a} as ${e}`);n.push(`${i.kind} ${s};\nexport { ${c.join(`, `)} };`)}}return n}function collectLocalReExportAliases(e){let t=new Map;for(let n of e.body??[])if(n.type===`ExportNamedDeclaration`&&!(n.source!==void 0&&n.source!==null)&&!(n.declaration!==void 0&&n.declaration!==null))for(let e of n.specifiers??[]){let n=e.local?.name,r=e.exported?.name??n;if(n!==void 0&&r!==void 0){let e=t.get(n)??[];e.push(r),t.set(n,e)}}return t}function isLiteralValueDeclarator(e){return isLiteralValueExpression(e.init)}function isLiteralValueExpression(e){return e==null?!1:e.type===`Literal`?e.value===null||typeof e.value==`boolean`||typeof e.value==`number`||typeof e.value==`string`:e.type===`TemplateLiteral`&&(e.expressions??[]).length===0?!0:e.type===`TSAsExpression`||e.type===`TSSatisfiesExpression`||e.type===`TSNonNullExpression`||e.type===`TSTypeAssertion`?isLiteralValueExpression(e.expression):e.type===`UnaryExpression`&&e.argument?.type===`Literal`?typeof e.argument.value==`number`:!1}function readValueImportBindings(e){return e.importKind===`type`?[]:(e.specifiers??[]).filter(e=>e.importKind!==`type`).map(e=>e.local?.name).filter(e=>e!==void 0)}function collectReferencedIdentifiers(e){let t=new Set;return visitAstNode(e,e=>{e.type===`Identifier`&&typeof e.name==`string`&&t.add(e.name)}),t}function visitAstNode(e,t){if(!(e.type===`ImportDeclaration`||e.type?.startsWith(`TS`))){t(e);for(let n of Object.values(e))if(Array.isArray(n))for(let e of n)isAstNode(e)&&visitAstNode(e,t);else isAstNode(n)&&visitAstNode(n,t)}}function isAstNode(e){return typeof e==`object`&&!!e&&typeof e.type==`string`}function extendRemovalEnd(e,t){let n=t;for(;n<e.length&&(e[n]===` `||e[n]===` `);)n+=1;return e[n]===`\r`&&e[n+1]===`
|
|
4
4
|
`?n+2:e[n]===`
|
|
5
|
-
`?n+1:n}function
|
|
5
|
+
`?n+1:n}function stripJavaScriptExtension(e){return e.replace(/\.(?:[cm]?[jt]sx?)$/,``)}function createStepId(e,n){return BUILTIN_STEP_NAMES.has(n)?n:`step//${e}//${n}`}export{transformWorkflowDirectives};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{EVE_ROUTE_PREFIX}from"#protocol/routes.js";import{resolvePackageRoot}from"#internal/application/package.js";import{
|
|
1
|
+
import{EVE_ROUTE_PREFIX}from"#protocol/routes.js";import{resolvePackageRoot}from"#internal/application/package.js";import{existsSync}from"node:fs";import{join}from"node:path";import{spawn}from"node:child_process";import{mkdir,open,readFile,rm,stat,writeFile}from"node:fs/promises";const EVE_BASE_URL_ENV=`EVE_BASE_URL`,DEFAULT_SERVER_READY_TIMEOUT_MS=18e4,SERVER_URL_CANDIDATE_PATTERN=/https?:\/\/[^\s"'<>]+/g,globalStateSymbol=Symbol.for(`eve.next.state`);function getGlobalState(){let e=globalThis;return e[globalStateSymbol]??={servers:new Map},e[globalStateSymbol]}function joinRoutePrefix(e,t){return`${e.replace(/\/+$/,``)}/${t.replace(/^\/+/,``)}`}function normalizeOrigin(e){return new URL(e).origin}function readEveBaseUrlEnvironment(){let e=process.env[EVE_BASE_URL_ENV];if(!(e===void 0||e.trim().length===0))return normalizeOrigin(e)}function isNodeErrorWithCode(e,t){return e instanceof Error&&`code`in e&&e.code===t}function delay(e){return new Promise(t=>setTimeout(t,e))}function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function resolveEveCacheDirectory(e){return join(e,`.eve`)}function resolveEveDevServerRegistryPath(e){return join(resolveEveCacheDirectory(e),`next-dev-server.json`)}function resolveEveDevServerLockPath(e){return join(resolveEveCacheDirectory(e),`next-dev-server.lock`)}function normalizeDevServerRegistry(e){if(isRecord(e)&&!(typeof e.appRoot!=`string`||typeof e.origin!=`string`||typeof e.updatedAt!=`string`)&&!(e.pid!==null&&typeof e.pid!=`number`))try{return{appRoot:e.appRoot,origin:normalizeOrigin(e.origin),pid:e.pid,updatedAt:e.updatedAt}}catch{return}}async function isEveServerHealthy(t){let n=new AbortController,r=setTimeout(()=>{n.abort()},1e3);try{return(await fetch(joinRoutePrefix(t,`${EVE_ROUTE_PREFIX}/health`),{signal:n.signal})).ok}catch{return!1}finally{clearTimeout(r)}}async function readUsableEveDevServerRegistry(e){try{let t=normalizeDevServerRegistry(JSON.parse(await readFile(resolveEveDevServerRegistryPath(e),`utf8`)));return t===void 0||t.appRoot!==e||!await isEveServerHealthy(t.origin)?void 0:(process.env[EVE_BASE_URL_ENV]=t.origin,t.origin)}catch(e){if(isNodeErrorWithCode(e,`ENOENT`))return;throw e}}async function writeEveDevServerRegistry(e,t){await mkdir(resolveEveCacheDirectory(e),{recursive:!0}),await writeFile(resolveEveDevServerRegistryPath(e),`${JSON.stringify({appRoot:e,origin:t.origin,pid:t.process?.pid??null,updatedAt:new Date().toISOString()},null,2)}\n`)}async function removeStaleEveDevServerLock(e){try{let t=await stat(e);Date.now()-t.mtimeMs>3e4&&await rm(e,{force:!0})}catch(e){if(!isNodeErrorWithCode(e,`ENOENT`))throw e}}async function acquireEveDevServerLock(e,t){let n=resolveEveCacheDirectory(e),r=resolveEveDevServerLockPath(e),i=Date.now()+t;for(await mkdir(n,{recursive:!0});;)try{let e=await open(r,`wx`);return await e.writeFile(`${String(process.pid)}\n`),await e.close(),async()=>{await rm(r,{force:!0})}}catch(n){if(!isNodeErrorWithCode(n,`EEXIST`))throw n;if(await readUsableEveDevServerRegistry(e)!==void 0)return async()=>{};if(await removeStaleEveDevServerLock(r),Date.now()>i)throw Error(`Timed out after ${t}ms waiting for another Next.js process to start Eve.`);await delay(100)}}function createEveBinaryPath(){return join(resolvePackageRoot(),`bin`,`eve.js`)}function isLoopbackHostname(e){return e===`localhost`||e===`::1`||e===`[::1]`||/^127(?:\.\d{1,3}){3}$/.test(e)}function parseLocalServerOrigin(e){let t=URL.parse(e);if(!(t===null||t.protocol!==`http:`&&t.protocol!==`https:`||!isLoopbackHostname(t.hostname)||t.port.length===0))return t.origin}function findLocalServerOrigin(e){for(let t of e.matchAll(SERVER_URL_CANDIDATE_PATTERN)){let e=t[0],n=parseLocalServerOrigin(e);if(n!==void 0)return n}}function startServerProcess(e){return new Promise((t,n)=>{let r=spawn(e.command,e.args,{cwd:e.cwd,env:{...process.env,...e.env},stdio:[`ignore`,`pipe`,`pipe`]}),a=setTimeout(()=>{r.kill(),n(Error(`Timed out after ${e.timeoutMs??DEFAULT_SERVER_READY_TIMEOUT_MS}ms waiting for Eve to print its server URL.`))},e.timeoutMs??DEFAULT_SERVER_READY_TIMEOUT_MS),cleanup=()=>{clearTimeout(a),r.off(`error`,handleError),r.off(`exit`,handleEarlyExit)},handleError=e=>{cleanup(),n(e)},handleEarlyExit=(e,t)=>{cleanup(),n(Error(`Eve server process exited before printing its server URL (code ${String(e)}, signal ${String(t)}).`))},handleOutput=e=>{let n=findLocalServerOrigin(e.toString(`utf8`));n!==void 0&&(cleanup(),t({origin:n,process:r}))};r.once(`error`,handleError),r.once(`exit`,handleEarlyExit),r.stdout.on(`data`,e=>{process.stdout.write(e),handleOutput(e)}),r.stderr.on(`data`,e=>{process.stderr.write(e),handleOutput(e)})})}function installProcessShutdown(e){let t=e.process;if(t===void 0)return e;let close=()=>{t.killed||t.kill()};return process.once(`beforeExit`,close),process.once(`exit`,close),e}function startEveDevServer(e,t){return startServerProcess({args:[createEveBinaryPath(),`dev`,`--no-ui`,`--port`,`0`],command:process.execPath,cwd:e,timeoutMs:t}).then(e=>(process.env[EVE_BASE_URL_ENV]=e.origin,installProcessShutdown(e)))}function startEveProductionServer(e){let t=new URL(e.origin),i=t.port,a=join(e.appRoot,`.output`,`server`,`index.mjs`);if(existsSync(a))return startServerProcess({args:[a],command:process.execPath,cwd:e.appRoot,env:{HOST:t.hostname,NITRO_HOST:t.hostname,NITRO_PORT:i,PORT:i}}).then(installProcessShutdown)}async function resolveSharedEveDevServer(e,t){let n=await readUsableEveDevServerRegistry(e);if(n!==void 0)return{origin:n};let r=await acquireEveDevServerLock(e,t);try{let n=await readUsableEveDevServerRegistry(e);if(n!==void 0)return{origin:n};let r=await startEveDevServer(e,t);return await writeEveDevServerRegistry(e,r),r}finally{await r()}}async function resolveEveDestinationPrefix(e){let t=getGlobalState();if(process.env.NODE_ENV===`production`){if(e.phase===`phase-production-build`)return e.productionDestinationPrefix;let n=`production:${e.appRoot}`,r=t.servers.get(n);return r===void 0&&(r=process.env.VERCEL||e.productionServerOrigin===void 0?void 0:startEveProductionServer({appRoot:e.appRoot,origin:e.productionServerOrigin}),r!==void 0&&(r=r.catch(e=>{throw t.servers.delete(n),e}),t.servers.set(n,r))),r===void 0?e.productionDestinationPrefix:(await r).origin}let n=readEveBaseUrlEnvironment();if(n!==void 0)return n;if(process.env.NODE_ENV!==`development`)return e.productionDestinationPrefix;let r=`dev:${e.appRoot}`,i=t.servers.get(r);return i===void 0&&(i=resolveSharedEveDevServer(e.appRoot,e.devServerTimeoutMs??18e4).catch(e=>{throw t.servers.delete(r),e}),t.servers.set(r,i)),(await i).origin}export{resolveEveDestinationPrefix};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { deriveSlackConnectorSlug, ensureChannel, type ChannelKind } from "#setup/scaffold/index.js";
|
|
1
|
+
import { deriveSlackConnectorSlug, ensureChannel, type ChannelKind, type EvePackageContract } from "#setup/scaffold/index.js";
|
|
2
2
|
import { detectPackageManager } from "#setup/package-manager.js";
|
|
3
3
|
import { runPackageManagerInstall } from "#setup/primitives/pm/run.js";
|
|
4
4
|
import { runVercel } from "#setup/primitives/run-vercel.js";
|
|
@@ -35,12 +35,10 @@ export interface AddChannelsOptions {
|
|
|
35
35
|
*/
|
|
36
36
|
headless?: boolean;
|
|
37
37
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* `webPackageVersions` at all, so every version comes from its build-stamped
|
|
41
|
-
* defaults.
|
|
38
|
+
* Eve package metadata for the scaffolded web `package.json`. When omitted,
|
|
39
|
+
* every package value comes from the build-stamped defaults.
|
|
42
40
|
*/
|
|
43
|
-
|
|
41
|
+
evePackage?: EvePackageContract;
|
|
44
42
|
/** Skip the "Create slackbot?" prompt and use this answer. */
|
|
45
43
|
presetCreateSlackbot?: boolean;
|
|
46
44
|
/** Overwrite existing channel files (`eve channels add --force`). */
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{SkippedSignal,confirm}from"../ask.js";import{detectDeployment,isProjectResolved,mergeProjectResolution,projectResolutionFromDeployment}from"../project-resolution.js";import{provisionSlackbot,reconcileSlackUid}from"../slackbot.js";import{hasVercelProject,requireProjectPath}from"../state.js";import{WizardCancelledError}from"../step.js";import{deriveSlackConnectorSlug,ensureChannel}from"#setup/scaffold/index.js";import{detectPackageManager}from"#setup/package-manager.js";import{HumanActionRequiredError}from"#setup/human-action.js";import{createPromptCommandOutput,withPhase}from"#setup/cli/index.js";import{runPackageManagerInstall}from"#setup/primitives/pm/run.js";import{runVercel}from"#setup/primitives/run-vercel.js";const SLACKBOT_NOT_ATTACHED_ERROR=`Slackbot provisioning did not attach this project. Slack channel was not added.`;function slackbotFailureCopy(e){switch(e.state){case`not-installed`:return{reason:`Slackbot is not connected to a Slack workspace. Slack channel was not added.`,followUp:"Continuing without Slack — the install timed out and was cleaned up; re-run `eve channels add slack` to try again."};case`cleanup-failed`:return{reason:`The abandoned Slack connector could not be removed. Slack channel was not added.`,followUp:`Continuing without Slack — resolve the cleanup warning above before trying again.`};case`connector-lookup-failed`:return{reason:`Existing Slack connectors could not be inspected. Slack channel was not added.`,followUp:"Continuing without Slack — restore Vercel CLI access, then re-run `eve channels add slack`."};case`installation-check-failed`:return{reason:`Slack workspace installation could not be verified. Slack channel was not added.`,followUp:"Continuing without Slack — verify Vercel Connect is reachable, then re-run `eve channels add slack`."};case`existing-not-installed`:return{reason:`The existing Slack connector is not connected to a Slack workspace. Slack channel was not added.`,followUp:`Continuing without Slack — resolve the existing connector warning above before trying again.`};case`detach-failed`:return{reason:`Slackbot provisioning could not replace the existing trigger destination. Slack channel was not added.`,followUp:"Continuing without Slack — run the `vercel connect detach` and `vercel connect attach` commands above."};case`attach-failed`:return{reason:SLACKBOT_NOT_ATTACHED_ERROR,followUp:"Continuing without Slack — finish event delivery with the `vercel connect attach` command above."};case`create-failed`:return{reason:`Slackbot creation failed.`,followUp:"Continuing without Slack — add it later with `eve channels add slack`."}}}function warnOverwrittenFiles(e,t){for(let n of t??[])e.warning(`Overwrote ${n}`)}function warnCompetingNextConfigFiles(e,t){for(let n of t??[])e.warning(`Found competing Next.js config at ${n}; merge any needed settings into next.config.ts and remove it before starting the preview, or Next.js may ignore the generated Eve rewrite.`)}function addChannels(l){let u=l.deps??{ensureChannel,deriveSlackConnectorSlug,provisionSlackbot,reconcileSlackUid,detectPackageManager,runPackageManagerInstall,runVercel,detectDeployment};async function scaffoldSlackChannel(e,t,n,r,i,a){let o=!1;if(!t.slackScaffolded){let t=await u.ensureChannel({projectRoot:n,kind:`slack`,slackConnectorUid:a,slackConnectorSlug:r,force:l.force});warnOverwrittenFiles(e,t.filesOverwritten),t.action===`created`||t.action===`overwritten`?e.success(`Scaffolded channel: slack`):e.info(`Channel "slack" already exists. Skipping file creation.`),o=t.action!==`skipped`,i.slackScaffolded=!0}return i.channelsAdded.push(`slack`),o}async function linkProjectForSlackbot(e,t,n,o,s){if(o)throw new HumanActionRequiredError({kind:`vercel-link`,command:`vercel link`,reason:`Slackbot creation needs this directory linked to a Vercel project.`});if(e.message(`Linking this directory to a Vercel project...`),!await u.runVercel([`link`],{cwd:t,signal:s}))throw s?.throwIfAborted(),Error(`Vercel project linking failed. Slackbot creation did not start.`);let c=mergeProjectResolution(n,projectResolutionFromDeployment(
|
|
1
|
+
import{SkippedSignal,confirm}from"../ask.js";import{detectDeployment,isProjectResolved,mergeProjectResolution,projectResolutionFromDeployment}from"../project-resolution.js";import{provisionSlackbot,reconcileSlackUid}from"../slackbot.js";import{hasVercelProject,requireProjectPath}from"../state.js";import{WizardCancelledError}from"../step.js";import{deriveSlackConnectorSlug,ensureChannel}from"#setup/scaffold/index.js";import{formatNodeEngineOverrideWarning}from"#setup/node-engine.js";import{detectPackageManager}from"#setup/package-manager.js";import{HumanActionRequiredError}from"#setup/human-action.js";import{createPromptCommandOutput,withPhase}from"#setup/cli/index.js";import{runPackageManagerInstall}from"#setup/primitives/pm/run.js";import{runVercel}from"#setup/primitives/run-vercel.js";const SLACKBOT_NOT_ATTACHED_ERROR=`Slackbot provisioning did not attach this project. Slack channel was not added.`;function slackbotFailureCopy(e){switch(e.state){case`not-installed`:return{reason:`Slackbot is not connected to a Slack workspace. Slack channel was not added.`,followUp:"Continuing without Slack — the install timed out and was cleaned up; re-run `eve channels add slack` to try again."};case`cleanup-failed`:return{reason:`The abandoned Slack connector could not be removed. Slack channel was not added.`,followUp:`Continuing without Slack — resolve the cleanup warning above before trying again.`};case`connector-lookup-failed`:return{reason:`Existing Slack connectors could not be inspected. Slack channel was not added.`,followUp:"Continuing without Slack — restore Vercel CLI access, then re-run `eve channels add slack`."};case`installation-check-failed`:return{reason:`Slack workspace installation could not be verified. Slack channel was not added.`,followUp:"Continuing without Slack — verify Vercel Connect is reachable, then re-run `eve channels add slack`."};case`existing-not-installed`:return{reason:`The existing Slack connector is not connected to a Slack workspace. Slack channel was not added.`,followUp:`Continuing without Slack — resolve the existing connector warning above before trying again.`};case`detach-failed`:return{reason:`Slackbot provisioning could not replace the existing trigger destination. Slack channel was not added.`,followUp:"Continuing without Slack — run the `vercel connect detach` and `vercel connect attach` commands above."};case`attach-failed`:return{reason:SLACKBOT_NOT_ATTACHED_ERROR,followUp:"Continuing without Slack — finish event delivery with the `vercel connect attach` command above."};case`create-failed`:return{reason:`Slackbot creation failed.`,followUp:"Continuing without Slack — add it later with `eve channels add slack`."}}}function warnOverwrittenFiles(e,t){for(let n of t??[])e.warning(`Overwrote ${n}`)}function warnCompetingNextConfigFiles(e,t){for(let n of t??[])e.warning(`Found competing Next.js config at ${n}; merge any needed settings into next.config.ts and remove it before starting the preview, or Next.js may ignore the generated Eve rewrite.`)}function addChannels(l){let u=l.deps??{ensureChannel,deriveSlackConnectorSlug,provisionSlackbot,reconcileSlackUid,detectPackageManager,runPackageManagerInstall,runVercel,detectDeployment};async function scaffoldSlackChannel(e,t,n,r,i,a){let o=!1;if(!t.slackScaffolded){let t=await u.ensureChannel({projectRoot:n,kind:`slack`,slackConnectorUid:a,slackConnectorSlug:r,force:l.force});warnOverwrittenFiles(e,t.filesOverwritten),t.action===`created`||t.action===`overwritten`?e.success(`Scaffolded channel: slack`):e.info(`Channel "slack" already exists. Skipping file creation.`),o=t.action!==`skipped`,i.slackScaffolded=!0}return i.channelsAdded.push(`slack`),o}async function linkProjectForSlackbot(e,t,n,o,s){if(o)throw new HumanActionRequiredError({kind:`vercel-link`,command:`vercel link`,reason:`Slackbot creation needs this directory linked to a Vercel project.`});if(e.message(`Linking this directory to a Vercel project...`),!await u.runVercel([`link`],{cwd:t,signal:s}))throw s?.throwIfAborted(),Error(`Vercel project linking failed. Slackbot creation did not start.`);let c=mergeProjectResolution(n,projectResolutionFromDeployment(await u.detectDeployment(t,{signal:s})));if(!isProjectResolved(c))throw Error(`Vercel project linking failed. Slackbot creation did not start.`);return c}async function addWebChannelToPayload(e,t,n,r,i,a){if(!t.channelSelection.includes(`web`))return;if(t.webScaffolded){i.channelsAdded.push(`web`);return}e.message(`Scaffolding Web Chat channel files...`);let o={projectRoot:n,kind:`web`,packageManager:r,force:l.force,configureVercelServices:l.configureVercelServices??hasVercelProject(t)};l.evePackage!==void 0&&(o.webPackageVersions={evePackage:l.evePackage});let s=await u.ensureChannel(o);if(a?.throwIfAborted(),warnOverwrittenFiles(e,s.filesOverwritten),s.kind===`web`&&s.action!==`skipped`&&s.nodeEngineOverride!==void 0&&e.warning(formatNodeEngineOverrideWarning(s.nodeEngineOverride)),warnCompetingNextConfigFiles(e,`competingNextConfigFiles`in s?s.competingNextConfigFiles:void 0),s.action===`created`||s.action===`overwritten`){e.success(`Scaffolded channel: web`),i.webScaffolded=!0,i.channelsAdded.push(`web`);return}e.info(`Next.js project detected. Skipping Web Chat scaffolding.`)}function assertSlackProjectReady(e){if(l.ensureLinkedProject===void 0){if(!hasVercelProject(e))throw Error(`Slack requires a Vercel project. Re-run and choose to deploy to Vercel to add Slack.`);if(!isProjectResolved(e.project))throw Error(`Expected a linked Vercel project for Slack, but none was resolved.`)}}async function provisionSlackbotWithControls(e,t,n,r){if(r===void 0&&l.prompter.awaitChoice===void 0)return u.provisionSlackbot(e,t,n);let i={};return r!==void 0&&(i.signal=r),l.prompter.awaitChoice!==void 0&&(i.awaitChoice=l.prompter.awaitChoice),u.provisionSlackbot(e,t,n,void 0,i)}async function scaffoldAttachedSlackChannel(e,t,n,r,i,a){if(!await scaffoldSlackChannel(e,t,n,r,i,a.connectorUid)&&!await u.reconcileSlackUid(e,n,a,`slack/${r}`))throw Error(`Slack connector UID update is required before deployment.`)}async function addSlackChannelToPayload(e,t,n,i,a,o){if(!t.channelSelection.includes(`slack`))return;assertSlackProjectReady(t);let s=await u.deriveSlackConnectorSlug(i,t.agentName);if(t.slackbotCreated){if(!t.slackbotAttached)throw Error(SLACKBOT_NOT_ATTACHED_ERROR);if(!t.deploymentPending)return;let n=t.slackConnectorUid;if(n===void 0)throw Error(`Slack connector UID was not resolved. Slack deployment did not start.`);await scaffoldAttachedSlackChannel(e,t,i,s,a,{state:`attached`,connectorUid:n});return}if(n.createSlackbot!==!0){e.info(`Slack channel was not added because Slackbot setup was skipped.`);return}isProjectResolved(a.project)||(a.project=await linkProjectForSlackbot(e,i,a.project,n.headless,o));let c=await provisionSlackbotWithControls(e,i,s,o);if(o?.throwIfAborted(),c.state===`cancelled`)throw new WizardCancelledError;if(c.state!==`attached`){let t=slackbotFailureCopy(c);if(l.slackbotFailure!==`warn-and-continue`)throw Error(t.reason);e.warning(`${t.reason} ${t.followUp}`);return}a.slackbot={connectorUid:c.connectorUid,chatUrl:c.chatUrl,workspaceName:c.workspaceName},await scaffoldAttachedSlackChannel(e,t,i,s,a,c)}async function installChannelDependencies(e,t,n,r,i){if(r.channelsAdded.length!==0){if(await withPhase(e,`Installing channel dependencies (${n} install)...`,()=>u.runPackageManagerInstall(n,t,{onOutput:createPromptCommandOutput(e),signal:i}))){r.dependenciesInstalled=!0;return}e.warning(`Dependency installation failed. The new channels stay unloadable until \`${n} install\` or a deploy succeeds.`)}}async function performAddChannels(e,t,n){n?.throwIfAborted();let r=l.prompter.log,i=requireProjectPath(e),a={channelsAdded:[],webScaffolded:e.webScaffolded,slackScaffolded:e.slackScaffolded,dependenciesInstalled:!1,project:e.project},o=await u.detectPackageManager(i);return await addWebChannelToPayload(r,e,i,o.kind,a,n),await addSlackChannelToPayload(r,e,t,i,a,n),await installChannelDependencies(r,i,o.kind,a,n),a}return{id:`add-channels`,async gather({state:n}){let r=l.headless??!1;if(r&&n.channelSelection.includes(`slack`))throw Error("Slack setup is interactive. Run `eve channels add slack` from an interactive terminal.");if(!n.channelSelection.includes(`slack`)||l.presetCreateSlackbot!==void 0||n.slackbotCreated)return{headless:r,createSlackbot:l.presetCreateSlackbot};try{return{headless:r,createSlackbot:await l.asker.ask(confirm({key:`create-slackbot`,message:`Do you want to create your slackbot?`}))}}catch(t){if(t instanceof SkippedSignal)return{headless:r,createSlackbot:!1};throw t}},async perform({state:e,input:t,signal:n}){try{return await performAddChannels(e,t,n)}catch(e){if(!(e instanceof WizardCancelledError)){let t=e instanceof Error?e.message:String(e),n=t.split(`
|
|
2
2
|
`)[0]?.trim()??t;l.prompter.log.error(n)}throw e}},apply(e,t){let n=[...e.channels];for(let e of t.channelsAdded)n.includes(e)||n.push(e);let r={...e,channels:n,webScaffolded:t.webScaffolded,slackScaffolded:t.slackScaffolded,deploymentPending:e.deploymentPending||t.channelsAdded.length>0,deploymentDependenciesInstalled:t.channelsAdded.length>0?t.dependenciesInstalled:e.deploymentDependenciesInstalled,project:mergeProjectResolution(e.project,t.project)};return t.slackbot===void 0?r:{...r,slackbotCreated:!0,slackbotAttached:!0,slackConnectorUid:t.slackbot.connectorUid,slackChatUrl:t.slackbot.chatUrl,slackWorkspaceName:t.slackbot.workspaceName}}}}export{addChannels};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{appendEnv}from"../append-env.js";import{isProjectResolved}from"../project-resolution.js";import{requireProjectPath}from"../state.js";import{withNetworkSpinner}from"../vercel-project.js";import{runVercelEnvPull}from"../run-vercel-link.js";import{detectAiGatewayResolution}from"./detect-ai-gateway.js";import{join}from"node:path";import{createPromptCommandOutput}from"#setup/cli/index.js";const AI_GATEWAY_ENV_KEY=`AI_GATEWAY_API_KEY`,ENV_FILE_NAME=`.env.local`;function applyAiGatewayCredential(s){let c=s.deps??{appendEnv,runVercelEnvPull,detectAiGatewayResolution};async function writeAiGatewayApiKey(e,t){let n=join(e,ENV_FILE_NAME);await c.appendEnv(n,{[AI_GATEWAY_ENV_KEY]:t.trim()},{force:!0}),s.prompter.log.success(`Wrote ${AI_GATEWAY_ENV_KEY} to ${n}`)}return{id:`apply-ai-gateway-credential`,shouldRun(e){let{aiGateway:n,project:r}=e;return n.kind===`byok`||n.kind===`inherit`&&isProjectResolved(r)},async gather(){return null},async perform({state:e,signal:i}){let{prompter:a}=s,o=requireProjectPath(e),l=e.aiGateway,u=isProjectResolved(e.project);if(l.kind===`byop`)return{kind:`unresolved`};if(l.kind===`byok`)return await writeAiGatewayApiKey(o,l.apiGatewayKey),{kind:`api-key`,envFile:ENV_FILE_NAME};if(!u)return a.log.warning(`No Vercel project linked and no API key provided. The agent will not reach a model until you set ${AI_GATEWAY_ENV_KEY} in ${ENV_FILE_NAME} or link a project.`),{kind:`unresolved`};let d=createPromptCommandOutput(a.log),f=await withNetworkSpinner(a,`Pulling Vercel environment variables into .env.local...`,()=>
|
|
1
|
+
import{appendEnv}from"../append-env.js";import{isProjectResolved}from"../project-resolution.js";import{requireProjectPath}from"../state.js";import{withNetworkSpinner}from"../vercel-project.js";import{runVercelEnvPull}from"../run-vercel-link.js";import{detectAiGatewayResolution}from"./detect-ai-gateway.js";import{join}from"node:path";import{createPromptCommandOutput}from"#setup/cli/index.js";const AI_GATEWAY_ENV_KEY=`AI_GATEWAY_API_KEY`,ENV_FILE_NAME=`.env.local`;function applyAiGatewayCredential(s){let c=s.deps??{appendEnv,runVercelEnvPull,detectAiGatewayResolution};async function writeAiGatewayApiKey(e,t){let n=join(e,ENV_FILE_NAME);await c.appendEnv(n,{[AI_GATEWAY_ENV_KEY]:t.trim()},{force:!0}),s.prompter.log.success(`Wrote ${AI_GATEWAY_ENV_KEY} to ${n}`)}return{id:`apply-ai-gateway-credential`,shouldRun(e){let{aiGateway:n,project:r}=e;return n.kind===`byok`||n.kind===`inherit`&&isProjectResolved(r)},async gather(){return null},async perform({state:e,signal:i}){let{prompter:a}=s,o=requireProjectPath(e),l=e.aiGateway,u=isProjectResolved(e.project);if(l.kind===`byop`)return{kind:`unresolved`};if(l.kind===`byok`)return await writeAiGatewayApiKey(o,l.apiGatewayKey),{kind:`api-key`,envFile:ENV_FILE_NAME};if(!u)return a.log.warning(`No Vercel project linked and no API key provided. The agent will not reach a model until you set ${AI_GATEWAY_ENV_KEY} in ${ENV_FILE_NAME} or link a project.`),{kind:`unresolved`};let d=createPromptCommandOutput(a.log),f=await withNetworkSpinner(a,`Pulling Vercel environment variables into .env.local...`,()=>c.runVercelEnvPull(o,d,i));return i?.throwIfAborted(),f||a.log.warning(`Linked the project, but pulling environment variables did not complete.`),c.detectAiGatewayResolution(o)},apply(e,t){return{...e,aiGatewayCredentials:t}}}}export{applyAiGatewayCredential};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{detectProjectResolution,mergeProjectResolution}from"../project-resolution.js";import{requireProjectPath}from"../state.js";import{linkProject,resolveProjectByNameOrId,unresolvedProject}from"../vercel-project.js";import{createPromptCommandOutput}from"#setup/cli/index.js";function linkVercelProject(o){let s=o.deps??{linkProject,detectProjectResolution,resolveProjectByNameOrId,unresolvedProject};return{id:`link-project`,shouldRun(e){return e.vercelProject.kind!==`none`},async gather(){return null},async perform({state:e,signal:t}){let r=e.vercelProject;if(r.kind===`none`)return s.unresolvedProject();let i=requireProjectPath(e),a=createPromptCommandOutput(o.prompter.log),c=
|
|
1
|
+
import{detectProjectResolution,mergeProjectResolution}from"../project-resolution.js";import{requireProjectPath}from"../state.js";import{linkProject,resolveProjectByNameOrId,unresolvedProject}from"../vercel-project.js";import{createPromptCommandOutput}from"#setup/cli/index.js";function linkVercelProject(o){let s=o.deps??{linkProject,detectProjectResolution,resolveProjectByNameOrId,unresolvedProject};return{id:`link-project`,shouldRun(e){return e.vercelProject.kind!==`none`},async gather(){return null},async perform({state:e,signal:t}){let r=e.vercelProject;if(r.kind===`none`)return s.unresolvedProject();let i=requireProjectPath(e),a=createPromptCommandOutput(o.prompter.log),c=await s.linkProject(o.prompter,i,r,a,{signal:t});if(t?.throwIfAborted(),!c)throw Error("Vercel project provisioning did not complete. Run `vercel link` manually, or re-run and choose not to deploy to Vercel.");let l=await s.detectProjectResolution(i,{signal:t});if(l.kind===`unresolved`)throw Error(`Linked the directory, but could not resolve the Vercel project from .vercel/project.json.`);let u=await s.resolveProjectByNameOrId(i,r.team,r.project,{signal:t});if(u===null||l.projectId!==u.id)throw Error(`Linked project identity did not match the planned Vercel project "${r.project}".`);return l},apply(e,n){return{...e,project:mergeProjectResolution(e.project,n)}}}}export{linkVercelProject};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{select,text}from"../ask.js";import{detectProjectResolution,isProjectResolved,mergeProjectResolution}from"../project-resolution.js";import{assertNewProjectNameAvailable,isVercelAuthenticated,pickNewProjectName,pickProject,pickTeam,requireAuth,resolveTeam,validateTeam,withNetworkSpinner}from"../vercel-project.js";import{pathExists}from"../path-exists.js";import{join,resolve}from"node:path";import{byokProviderEnvVar}from"#setup/scaffold/index.js";import{whimsyFor}from"#setup/cli/index.js";function vercelDemands(e){return{slack:e.channelSelection.includes(`slack`),connectSlugs:e.connectionSelection.filter(e=>e.entry.auth?.kind===`connect`).map(e=>e.slug)}}function connectClause(e){let t=e.length===1?`authenticates`:`authenticate`;return`${e.join(`, `)} ${t} through Vercel Connect`}function vercelRequirements(e){let t=[];return e.slack&&t.push(`Slack needs a public URL`),e.connectSlugs.length>0&&t.push(connectClause(e.connectSlugs)),t}function resolveProvisioning(l){let u=l.deps??{requireAuth,isVercelAuthenticated,detectProjectResolution,pathExists,validateTeam,resolveTeam,pickTeam,pickProject,pickNewProjectName,assertNewProjectNameAvailable},parent=()=>resolve(l.targetDirectory??process.cwd());async function detectAdoptableLink(e,t){if(e.projectPath.kind!==`resolved`)return;let n=e.projectPath.path;if(await u.pathExists(join(n,`.vercel`,`project.json`)))return withNetworkSpinner(l.prompter,whimsyFor(`project-detect`),async()=>{let e=
|
|
1
|
+
import{select,text}from"../ask.js";import{detectProjectResolution,isProjectResolved,mergeProjectResolution}from"../project-resolution.js";import{assertNewProjectNameAvailable,isVercelAuthenticated,pickNewProjectName,pickProject,pickTeam,requireAuth,resolveTeam,validateTeam,withNetworkSpinner}from"../vercel-project.js";import{pathExists}from"../path-exists.js";import{join,resolve}from"node:path";import{byokProviderEnvVar}from"#setup/scaffold/index.js";import{whimsyFor}from"#setup/cli/index.js";function vercelDemands(e){return{slack:e.channelSelection.includes(`slack`),connectSlugs:e.connectionSelection.filter(e=>e.entry.auth?.kind===`connect`).map(e=>e.slug)}}function connectClause(e){let t=e.length===1?`authenticates`:`authenticate`;return`${e.join(`, `)} ${t} through Vercel Connect`}function vercelRequirements(e){let t=[];return e.slack&&t.push(`Slack needs a public URL`),e.connectSlugs.length>0&&t.push(connectClause(e.connectSlugs)),t}function resolveProvisioning(l){let u=l.deps??{requireAuth,isVercelAuthenticated,detectProjectResolution,pathExists,validateTeam,resolveTeam,pickTeam,pickProject,pickNewProjectName,assertNewProjectNameAvailable},parent=()=>resolve(l.targetDirectory??process.cwd());async function detectAdoptableLink(e,t){if(e.projectPath.kind!==`resolved`)return;let n=e.projectPath.path;if(await u.pathExists(join(n,`.vercel`,`project.json`)))return withNetworkSpinner(l.prompter,whimsyFor(`project-detect`),async()=>{let e=await u.detectProjectResolution(n,{signal:t});if(!(!isProjectResolved(e)||!await u.isVercelAuthenticated(n,{signal:t})))return e})}async function plansFromFlags(e,t,n,r){if(t.skipVercel)return n.apiKey===void 0?{vercelProject:{kind:`none`},aiGateway:{kind:`byop`},modelWiring:`self`}:{vercelProject:{kind:`none`},aiGateway:{kind:`byok`,apiGatewayKey:n.apiKey},modelWiring:`gateway`};if(t.team===void 0||t.team.length===0)throw Error(`Headless Vercel provisioning requires --team <slug> or --scope <slug> so the current CLI scope is not applied silently.`);await u.requireAuth(parent(),void 0,{signal:r}),await u.validateTeam(l.prompter,parent(),t.team,{signal:r});let i=await u.resolveTeam(parent(),t.team,{signal:r}),a=n.apiKey===void 0?{kind:`inherit`}:{kind:`byok`,apiGatewayKey:n.apiKey},o=t.project===void 0?{kind:`new`,project:e,team:i}:{kind:`existing`,project:t.project,team:i};return o.kind===`new`&&await u.assertNewProjectNameAvailable(parent(),i,o.project,{signal:r}),{vercelProject:o,aiGateway:a,modelWiring:`gateway`}}async function promptPlans(n,r){let i=l.prompter,a=n.agentName,o=l.adoptExistingLink===!1?void 0:await detectAdoptableLink(n,r);if(o!==void 0)return i.log.info(`This directory is already linked to a Vercel project, so your agent will run there — the AI Gateway authenticates through your Vercel login.`),{vercelProject:{kind:`none`},aiGateway:{kind:`inherit`},modelWiring:`gateway`,project:o};let s=vercelRequirements(vercelDemands(n)),c=!0;if(s.length>0?i.log.info(`${s.join(` and `)}, so your agent will run on Vercel.`):c=await l.asker.ask(select({key:`deploy`,message:`Where should your agent run?`,options:[{id:`vercel`,value:!0,label:`On Vercel`,hint:`AI Gateway, Durable Workflow, Sandbox, and more`},{id:`local`,value:!1,label:`Locally for now`,hint:`run with eve dev, deploy any time later`}],recommended:!0,required:!0})),c){await u.requireAuth(parent(),i,{signal:r});let t=await u.pickTeam(i,parent(),void 0,{signal:r}),n=[{value:`new`,label:`Create a new project`,hint:`Named ${a}`},{value:`link`,label:`Link an existing project`}],o=l.projectSelection!==`existing-only`&&l.prompter.selectEditable?await l.prompter.selectEditable({message:`Vercel project`,options:n,initialValue:`new`,editable:{value:`new`,defaultValue:a,formatHint:e=>`Named ${e}`,validate:e=>e.trim().length===0?`Project name cannot be empty.`:void 0}}):void 0;if((l.projectSelection===`existing-only`?`link`:o?.value??await l.asker.ask(select({key:`vercel-project`,message:`Vercel project`,options:[{id:`new`,value:`new`,label:`Create a new project`,hint:`Named ${a}`},{id:`link`,value:`link`,label:`Link an existing project`}],recommended:`new`,required:!0})))===`new`){let e=o?.kind===`edited`?o.text:a;return{vercelProject:{kind:`new`,project:await u.pickNewProjectName(i,parent(),t,e,{signal:r}),team:t},aiGateway:{kind:`inherit`},modelWiring:`gateway`}}let s=await u.pickProject(i,parent(),t,{allowCreateWhenEmpty:l.projectSelection!==`existing-only`,signal:r});return{vercelProject:{kind:s.exists?`existing`:`new`,project:s.project,team:t},aiGateway:{kind:`inherit`},modelWiring:`gateway`}}return await l.asker.ask(select({key:`credential`,message:`How should your agent reach the model?`,options:[{id:`api-key`,value:`api-key`,label:`Use my own AI Gateway API key`,hint:`AI_GATEWAY_API_KEY`},{id:`local`,value:`local`,label:`Use my own provider API key`,hint:byokProviderEnvVar(n.modelId)}],recommended:`api-key`,required:!0}))===`api-key`?{vercelProject:{kind:`none`},aiGateway:{kind:`byok`,apiGatewayKey:await l.asker.ask(text({key:`gateway-api-key`,message:`Enter your AI_GATEWAY_API_KEY`,sensitive:!0,validate:e=>e.trim().length===0?`API key cannot be empty.`:null,required:!0}))},modelWiring:`gateway`}:{vercelProject:{kind:`none`},aiGateway:{kind:`byop`},modelWiring:`self`}}return{id:`resolve-provisioning`,async gather({state:e,signal:t}){if(l.mode.headless){let n=await plansFromFlags(e.agentName,l.mode.project,l.mode.aiGateway,t);if(n.vercelProject.kind===`none`){let t=vercelDemands(e);if(t.slack)throw Error(`Slack requires a Vercel project. Remove --skip-vercel to add Slack.`);if(t.connectSlugs.length>0)throw Error(`${connectClause(t.connectSlugs)}, which needs a Vercel project. Remove --skip-vercel to add ${t.connectSlugs.length===1?`it`:`them`}.`)}return n}return promptPlans(e,t)},async perform({input:e}){return e},apply(e,t){return{...e,vercelProject:t.vercelProject,aiGateway:t.aiGateway,modelWiring:t.modelWiring,project:t.project===void 0?e.project:mergeProjectResolution(e.project,t.project)}}}}export{resolveProvisioning};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { isEveProject, scaffoldBaseProject } from "#setup/scaffold/index.js";
|
|
1
|
+
import { isEveProject, scaffoldBaseProject, type EvePackageContract } from "#setup/scaffold/index.js";
|
|
2
2
|
import type { Prompter } from "../prompter.js";
|
|
3
3
|
import { type SetupState } from "../state.js";
|
|
4
4
|
import type { SetupBox } from "../step.js";
|
|
@@ -10,7 +10,7 @@ export interface ScaffoldDeps {
|
|
|
10
10
|
export interface ScaffoldOptions {
|
|
11
11
|
/** Reports scaffold progress and overwrite warnings. The box never prompts. */
|
|
12
12
|
prompter: Prompter;
|
|
13
|
-
|
|
13
|
+
evePackage?: EvePackageContract;
|
|
14
14
|
/** Parent directory the project folder is created inside. Defaults to cwd. */
|
|
15
15
|
targetDirectory?: string;
|
|
16
16
|
/** Allow the in-place scaffold to replace Eve scaffold files that already exist. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{CURRENT_DIRECTORY_PROJECT_NAME,requireProjectPath}from"../state.js";import{isEveProject,scaffoldBaseProject}from"#setup/scaffold/index.js";function scaffold(i){let a=i.deps??{scaffoldBaseProject,isEveProject};return{id:`scaffold`,async gather(){return{headless:i.headless??!1}},async perform({state:n,input:r}){let{prompter:o}=i,s=n.projectPath.inPlace?CURRENT_DIRECTORY_PROJECT_NAME:n.agentName,c=requireProjectPath(n);if(r.headless&&!i.overwriteExisting&&await a.isEveProject(c))return o.log.message(`Existing Eve project detected; continuing setup...`),c;o.log.message(`Scaffolding project files...`);let l=await a.scaffoldBaseProject({projectName:s,model:n.modelId,byokProvider:n.modelWiring===`self`,targetDirectory:i.targetDirectory,overwriteExisting:i.overwriteExisting,onOverwriteFile:e=>o.log.warning(`Overwrote ${e}`),
|
|
1
|
+
import{CURRENT_DIRECTORY_PROJECT_NAME,requireProjectPath}from"../state.js";import{isEveProject,scaffoldBaseProject}from"#setup/scaffold/index.js";function scaffold(i){let a=i.deps??{scaffoldBaseProject,isEveProject};return{id:`scaffold`,async gather(){return{headless:i.headless??!1}},async perform({state:n,input:r}){let{prompter:o}=i,s=n.projectPath.inPlace?CURRENT_DIRECTORY_PROJECT_NAME:n.agentName,c=requireProjectPath(n);if(r.headless&&!i.overwriteExisting&&await a.isEveProject(c))return o.log.message(`Existing Eve project detected; continuing setup...`),c;o.log.message(`Scaffolding project files...`);let l=await a.scaffoldBaseProject({projectName:s,model:n.modelId,byokProvider:n.modelWiring===`self`,targetDirectory:i.targetDirectory,overwriteExisting:i.overwriteExisting,onOverwriteFile:e=>o.log.warning(`Overwrote ${e}`),evePackage:i.evePackage});return o.log.success(`Scaffolded project at ${l}`),l},apply(e,t){return{...e,projectPath:{kind:`resolved`,inPlace:e.projectPath.inPlace,path:t}}}}}export{scaffold};
|
|
@@ -2,10 +2,12 @@ import { type AddChannelsDeps } from "../boxes/add-channels.js";
|
|
|
2
2
|
import { inspectExistingChannelRegistrations } from "../channel-add-conflicts.js";
|
|
3
3
|
import { detectDeployment } from "../project-resolution.js";
|
|
4
4
|
import type { Prompter } from "../prompter.js";
|
|
5
|
+
import { getVercelAuthStatus } from "../vercel-project.js";
|
|
5
6
|
/** Injected for tests; defaults to the real detection and box effects. */
|
|
6
7
|
export interface ChannelsFlowDeps {
|
|
7
8
|
detectDeployment: typeof detectDeployment;
|
|
8
9
|
inspectExistingChannelRegistrations: typeof inspectExistingChannelRegistrations;
|
|
10
|
+
getVercelAuthStatus: typeof getVercelAuthStatus;
|
|
9
11
|
addChannels?: AddChannelsDeps;
|
|
10
12
|
}
|
|
11
13
|
export type ChannelsFlowResult = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{interactiveAsker}from"../ask.js";import{detectDeployment,isProjectResolved,projectResolutionFromDeployment}from"../project-resolution.js";import{createDefaultSetupState,snapshotSetupState}from"../state.js";import{WizardCancelledError}from"../step.js";import{addChannels}from"../boxes/add-channels.js";import{CHANNELS_PROMPT_MESSAGE,selectChannels}from"../boxes/select-channels.js";import{assertCanAddSelectedChannels,inspectExistingChannelRegistrations}from"../channel-add-conflicts.js";import{runInteractive}from"../runner.js";import{prompterSink}from"./in-project.js";import{SCAFFOLDABLE_CHANNELS}from"#setup/scaffold/index.js";import{toErrorMessage}from"#shared/errors.js";const SEE_IT_LIVE_MESSAGE=`See it live`;async function promptSeeItLive(e){try{return await e.select({message:SEE_IT_LIVE_MESSAGE,options:[{value:`deploy`,label:`Deploy and chat`},{value:`later`,label:`Later`}]})}catch(e){if(e instanceof WizardCancelledError)return`later`;throw e}}function channelAlreadyAdded(e,t){return t===`web`?e.webAppPresent:e.slackOwners.length>0}function appendChannel(e,t){return e.includes(t)?[...e]:[...e,t]}async function pickChannel(e,t,n){let
|
|
1
|
+
import{interactiveAsker}from"../ask.js";import{detectDeployment,isProjectResolved,projectResolutionFromDeployment}from"../project-resolution.js";import{createDefaultSetupState,snapshotSetupState}from"../state.js";import{WizardCancelledError}from"../step.js";import{addChannels}from"../boxes/add-channels.js";import{getVercelAuthStatus}from"../vercel-project.js";import{CHANNELS_PROMPT_MESSAGE,selectChannels}from"../boxes/select-channels.js";import{assertCanAddSelectedChannels,inspectExistingChannelRegistrations}from"../channel-add-conflicts.js";import{runInteractive}from"../runner.js";import{prompterSink}from"./in-project.js";import{SCAFFOLDABLE_CHANNELS}from"#setup/scaffold/index.js";import{toErrorMessage}from"#shared/errors.js";const SEE_IT_LIVE_MESSAGE=`See it live`;async function promptSeeItLive(e){try{return await e.select({message:SEE_IT_LIVE_MESSAGE,options:[{value:`deploy`,label:`Deploy and chat`},{value:`later`,label:`Later`}]})}catch(e){if(e instanceof WizardCancelledError)return`later`;throw e}}function channelAlreadyAdded(e,t){return t===`web`?e.webAppPresent:e.slackOwners.length>0}function appendChannel(e,t){return e.includes(t)?[...e]:[...e,t]}async function pickChannel(e,t,n,r){let i=channelListRows(t,n,r),a=!i.some(e=>e.value!==`done`&&e.completed!==!0&&e.disabled!==!0),s={message:CHANNELS_PROMPT_MESSAGE,options:i,hintLayout:`inline`};a&&(s.initialValue=`done`);try{return{kind:`picked`,value:await e.select(s)}}catch(e){if(e instanceof WizardCancelledError)return{kind:`cancelled`};throw e}}function channelLandedDuringSubflow(e,t,n){return!channelAlreadyAdded(e,n)&&channelAlreadyAdded(t,n)}function deployAndChatDetails(e){let t={};return e.slackChatUrl!==void 0&&(t.chatUrl=e.slackChatUrl),e.slackWorkspaceName!==void 0&&(t.workspaceName=e.slackWorkspaceName),t}function vercelChannelBlocker(e,t){if(e===`cli-missing`)return`Vercel CLI not found, see /vc`;if(e===`logged-out`)return`Log in to Vercel first, see /login`;if(e===`unavailable`)return`Couldn't reach Vercel, check your connection`;if(!t)return`Requires Vercel account, see /model`}function channelListRows(e,t,n){let r=[{value:`repl`,label:`Terminal UI`,completed:!0,focusHint:`Already installed`}];for(let i of SCAFFOLDABLE_CHANNELS){if(channelAlreadyAdded(e,i.kind)){r.push({value:i.kind,label:i.label,completed:!0,focusHint:`Already installed`});continue}let a=e.disabledChannelReasons[i.kind];if(a!==void 0){r.push({value:i.kind,label:i.label,disabled:!0,disabledReason:a});continue}if(i.requiresVercelProject===!0){let e=vercelChannelBlocker(n,t);if(e!==void 0){r.push({value:i.kind,label:i.label,disabled:!0,disabledReason:e,disabledReasonTone:`warning`});continue}}let o={value:i.kind,label:i.label};i.hint!==void 0&&(o.hint=i.hint),r.push(o)}return r.push({value:`done`,label:`Done`}),r}async function runChannelsFlow(o){let{appRoot:c,prompter:l,signal:u}=o,d={detectDeployment,inspectExistingChannelRegistrations,getVercelAuthStatus,...o.deps};async function checkProject(e){let t=l.log.spinner?.(`Checking the project…`);try{return await e()}finally{t?.stop()}}let[f,p,m]=await checkProject(()=>Promise.all([d.detectDeployment(c,{signal:u}),d.inspectExistingChannelRegistrations(c),d.getVercelAuthStatus(c,{signal:u})]));u?.throwIfAborted();let h=p,g={...createDefaultSetupState(),project:projectResolutionFromDeployment(f),projectPath:{kind:`resolved`,inPlace:!0,path:c}},_;for(;;){let t=await pickChannel(l,h,isProjectResolved(g.project),m);if(t.kind===`cancelled`){if(g.channels.length===0)return{kind:`cancelled`};break}let r=t.value;if(r===`done`)break;if(r===`repl`||channelAlreadyAdded(h,r))continue;let i=[selectChannels({asker:interactiveAsker(l),variant:`channels-add`,presetChannels:[r],validateSelection:e=>assertCanAddSelectedChannels(e,h)}),addChannels({asker:interactiveAsker(l),prompter:l,configureVercelServices:!0,deps:d.addChannels})],o;try{o=await runInteractive(i,g,prompterSink(l),{snapshot:snapshotSetupState,signal:u})}catch(e){let t=await checkProject(()=>d.inspectExistingChannelRegistrations(c));if(channelLandedDuringSubflow(h,t,r)){if(g={...g,channels:appendChannel(g.channels,r)},h=t,_=toErrorMessage(e),u?.aborted===!0)break;continue}throw e}if(o.kind===`done`){if(g=o.state,h=await checkProject(()=>d.inspectExistingChannelRegistrations(c)),u?.throwIfAborted(),r===`slack`&&g.slackbotAttached&&await promptSeeItLive(l)===`deploy`)return{kind:`deploy-and-chat`,addedChannels:g.channels,chat:deployAndChatDetails(g)}}else{let e=await checkProject(()=>d.inspectExistingChannelRegistrations(c));if(channelLandedDuringSubflow(h,e,r))return{kind:`done`,addedChannels:appendChannel(g.channels,r)};h=e}}return _===void 0?{kind:`done`,addedChannels:g.channels}:{kind:`failed`,addedChannels:g.channels,message:_}}export{SEE_IT_LIVE_MESSAGE,runChannelsFlow};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{interactiveAsker,withAnswers}from"../ask.js";import{detectDeployment,isProjectResolved,projectResolutionFromDeployment}from"../project-resolution.js";import{snapshotSetupState}from"../state.js";import{deployProject}from"../boxes/deploy-project.js";import{linkVercelProject}from"../boxes/link-project.js";import{resolveProvisioning}from"../boxes/resolve-provisioning.js";import{runHeadless,runInteractive}from"../runner.js";import{inProjectSetupState,prompterSink}from"./in-project.js";function productionUrlOf(e){return e.kind===`deployed`?e.productionUrl:void 0}async function runDeployFlow(t){let{appRoot:n,prompter:r,interactive:i,signal:a}=t,o={detectDeployment,...t.deps},s=r.log.spinner?.(`Checking the current Vercel link...`),c;try{let e=
|
|
1
|
+
import{interactiveAsker,withAnswers}from"../ask.js";import{detectDeployment,isProjectResolved,projectResolutionFromDeployment}from"../project-resolution.js";import{snapshotSetupState}from"../state.js";import{deployProject}from"../boxes/deploy-project.js";import{linkVercelProject}from"../boxes/link-project.js";import{resolveProvisioning}from"../boxes/resolve-provisioning.js";import{runHeadless,runInteractive}from"../runner.js";import{inProjectSetupState,prompterSink}from"./in-project.js";function productionUrlOf(e){return e.kind===`deployed`?e.productionUrl:void 0}async function runDeployFlow(t){let{appRoot:n,prompter:r,interactive:i,signal:a}=t,o={detectDeployment,...t.deps},s=r.log.spinner?.(`Checking the current Vercel link...`),c;try{let e=await o.detectDeployment(n,{signal:a});a?.throwIfAborted(),c=projectResolutionFromDeployment(e)}finally{s?.stop()}let l=isProjectResolved(c);if(!l&&!i)return{kind:`needs-link`};let u=inProjectSetupState(n,c,{deploymentPending:!0}),d=l?[deployProject({prompter:r,headless:!i,deps:o.deployProject})]:[resolveProvisioning({asker:withAnswers({deploy:`vercel`})(interactiveAsker(r)),prompter:r,targetDirectory:n,mode:{headless:!1},deps:o.resolveProvisioning}),linkVercelProject({prompter:r,deps:o.linkProject}),deployProject({prompter:r,headless:!i,deps:o.deployProject})],f=prompterSink(r);if(!i)return{kind:`deployed`,productionUrl:productionUrlOf((await runHeadless(d,u,f,{snapshot:snapshotSetupState,signal:a})).project)};let p=await runInteractive(d,u,f,{snapshot:snapshotSetupState,signal:a});return p.kind===`cancelled`?{kind:`cancelled`}:{kind:`deployed`,productionUrl:productionUrlOf(p.state.project)}}export{runDeployFlow};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { detectPackageManager } from "#setup/package-manager.js";
|
|
2
|
+
import { spawnPackageManager } from "#setup/primitives/index.js";
|
|
3
|
+
import { getVercelAuthStatus } from "#setup/vercel-project.js";
|
|
4
|
+
import type { Prompter } from "../prompter.js";
|
|
5
|
+
export type InstallVercelCliResult =
|
|
6
|
+
/** The CLI is already resolvable; nothing to do. */
|
|
7
|
+
{
|
|
8
|
+
kind: "already";
|
|
9
|
+
}
|
|
10
|
+
/** The package manager installed it and it now resolves. */
|
|
11
|
+
| {
|
|
12
|
+
kind: "installed";
|
|
13
|
+
}
|
|
14
|
+
/** The install exited non-zero, or the CLI still isn't on PATH afterward. */
|
|
15
|
+
| {
|
|
16
|
+
kind: "failed";
|
|
17
|
+
}
|
|
18
|
+
/** The user interrupted (Ctrl-C / Esc) before the install finished. */
|
|
19
|
+
| {
|
|
20
|
+
kind: "cancelled";
|
|
21
|
+
};
|
|
22
|
+
/** Injected for tests; defaults to the real probe, detection, and install. */
|
|
23
|
+
export interface InstallVercelCliDeps {
|
|
24
|
+
getVercelAuthStatus: typeof getVercelAuthStatus;
|
|
25
|
+
detectPackageManager: typeof detectPackageManager;
|
|
26
|
+
spawnPackageManager: typeof spawnPackageManager;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* THE INSTALL FLOW for the dev TUI's `/vc`: the fix command for the
|
|
30
|
+
* "Vercel CLI not found" diagnostic, so every diagnostic has a matching
|
|
31
|
+
* command. Short-circuits when the CLI already resolves; otherwise runs a
|
|
32
|
+
* global install with the project's package manager, streaming output to the
|
|
33
|
+
* rail, then re-probes. A global install can exit clean yet leave the binary
|
|
34
|
+
* off PATH (pnpm/yarn global bins commonly aren't), so success is confirmed by
|
|
35
|
+
* the re-probe, not the exit code alone.
|
|
36
|
+
*/
|
|
37
|
+
export declare function runInstallVercelCliFlow(input: {
|
|
38
|
+
appRoot: string;
|
|
39
|
+
prompter: Prompter;
|
|
40
|
+
signal?: AbortSignal;
|
|
41
|
+
deps?: Partial<InstallVercelCliDeps>;
|
|
42
|
+
}): Promise<InstallVercelCliResult>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{detectPackageManager}from"#setup/package-manager.js";import{spawnPackageManager}from"#setup/primitives/index.js";import{getVercelAuthStatus}from"#setup/vercel-project.js";import{createPromptCommandOutput}from"#setup/cli/index.js";const defaultDeps={getVercelAuthStatus,detectPackageManager,spawnPackageManager};function globalInstallArguments(e){switch(e){case`npm`:return[`install`,`-g`,`vercel@latest`];case`yarn`:return[`global`,`add`,`vercel@latest`];case`pnpm`:case`bun`:return[`add`,`-g`,`vercel@latest`]}}async function withSpinner(e,t,n){let r=e.log.spinner?.(t);try{return await n()}finally{r?.stop()}}async function runInstallVercelCliFlow(e){let{appRoot:t,prompter:n,signal:i}=e,a={...defaultDeps,...e.deps},o=createPromptCommandOutput(n.log),probe=async()=>await a.getVercelAuthStatus(t,{signal:i})!==`cli-missing`;if(await withSpinner(n,`Checking for the Vercel CLI…`,probe))return i?.throwIfAborted(),{kind:`already`};i?.throwIfAborted();let s=await a.detectPackageManager(t),c=await withSpinner(n,`Installing the Vercel CLI with ${s.kind}…`,()=>a.spawnPackageManager(s.kind,t,globalInstallArguments(s.kind),{onOutput:o,signal:i,nonInteractive:!0}));if(i?.aborted===!0)return{kind:`cancelled`};if(!c)return{kind:`failed`};let l=await withSpinner(n,`Verifying the Vercel CLI…`,probe);return i?.throwIfAborted(),l?{kind:`installed`}:{kind:`failed`}}export{runInstallVercelCliFlow};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{__toESM}from"../../_virtual/_rolldown/runtime.js";import{require_picocolors}from"../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js";import{interactiveAsker,withAnswers}from"../ask.js";import{detectProjectIdentity}from"../project-resolution.js";import{snapshotSetupState}from"../state.js";import{WizardCancelledError}from"../step.js";import{detectAiGateway,findEnvFileWithKey}from"../boxes/detect-ai-gateway.js";import{applyAiGatewayCredential}from"../boxes/apply-ai-gateway-credential.js";import{linkVercelProject}from"../boxes/link-project.js";import{resolveProvisioning}from"../boxes/resolve-provisioning.js";import{runInteractive}from"../runner.js";import{inProjectSetupState,prompterSink}from"./in-project.js";var import_picocolors=__toESM(require_picocolors(),1);async function runLinkFlow(e){let{appRoot:t,prompter:i,signal:a,projectSelection:o=`existing-only`}=e,s={detectProjectIdentity,findEnvFileWithKey,...e.deps},c=i.log.spinner?.(`Checking the current Vercel link...`),l;try{l=
|
|
1
|
+
import{__toESM}from"../../_virtual/_rolldown/runtime.js";import{require_picocolors}from"../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js";import{interactiveAsker,withAnswers}from"../ask.js";import{detectProjectIdentity}from"../project-resolution.js";import{snapshotSetupState}from"../state.js";import{WizardCancelledError}from"../step.js";import{detectAiGateway,findEnvFileWithKey}from"../boxes/detect-ai-gateway.js";import{applyAiGatewayCredential}from"../boxes/apply-ai-gateway-credential.js";import{linkVercelProject}from"../boxes/link-project.js";import{resolveProvisioning}from"../boxes/resolve-provisioning.js";import{runInteractive}from"../runner.js";import{inProjectSetupState,prompterSink}from"./in-project.js";var import_picocolors=__toESM(require_picocolors(),1);async function runLinkFlow(e){let{appRoot:t,prompter:i,signal:a,projectSelection:o=`existing-only`}=e,s={detectProjectIdentity,findEnvFileWithKey,...e.deps},c=i.log.spinner?.(`Checking the current Vercel link...`),l;try{l=await s.detectProjectIdentity(t,{signal:a}),a?.throwIfAborted()}finally{c?.stop()}if(l===void 0){let[e,n]=await Promise.all([s.findEnvFileWithKey(t,`AI_GATEWAY_API_KEY`),s.findEnvFileWithKey(t,`VERCEL_OIDC_TOKEN`)]),r=e??n;r!==void 0&&i.log.message(`This directory is not linked to a Vercel project yet — the model currently runs on credentials from ${r}.`)}else{let e=l.teamName===void 0?import_picocolors.default.bold(l.projectName):`${import_picocolors.default.bold(l.projectName)} in ${import_picocolors.default.bold(l.teamName)}`;try{if(await i.select({message:`This directory is already linked to\n${e}`,options:[{value:`relink`,label:`Link to another project`},{value:`dismiss`,label:`Dismiss`}]})===`dismiss`)return{kind:`cancelled`}}catch(e){if(e instanceof WizardCancelledError)return{kind:`cancelled`};throw e}}let u=inProjectSetupState(t,{kind:`unresolved`});if((await runInteractive([resolveProvisioning({asker:withAnswers({deploy:`vercel`})(interactiveAsker(i)),prompter:i,targetDirectory:t,mode:{headless:!1},adoptExistingLink:!1,projectSelection:o,deps:s.resolveProvisioning}),linkVercelProject({prompter:i,deps:s.linkProject}),detectAiGateway(),applyAiGatewayCredential({prompter:i,deps:s.applyAiGatewayCredential})],u,prompterSink(i),{snapshot:snapshotSetupState,signal:a})).kind===`cancelled`)return{kind:`cancelled`};let[d,f]=await Promise.all([s.findEnvFileWithKey(t,`VERCEL_OIDC_TOKEN`),s.findEnvFileWithKey(t,`AI_GATEWAY_API_KEY`)]);a?.throwIfAborted(),d===void 0&&f===void 0&&i.log.warning("Linked, but no model credential landed in an env file (VERCEL_OIDC_TOKEN or AI_GATEWAY_API_KEY). Run `vercel env pull` once the project has AI Gateway access.");let p={kind:`done`};return d===void 0?f!==void 0&&(p.credential=`AI_GATEWAY_API_KEY`):p.credential=`VERCEL_OIDC_TOKEN`,p}export{runLinkFlow};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { createPromptCommandOutput } from "#setup/cli/index.js";
|
|
2
|
+
import { getVercelAuthStatus } from "#setup/vercel-project.js";
|
|
3
|
+
import type { Prompter } from "../prompter.js";
|
|
4
|
+
export type LoginFlowResult =
|
|
5
|
+
/** A `vercel whoami` already succeeds; nothing to do. */
|
|
6
|
+
{
|
|
7
|
+
kind: "already";
|
|
8
|
+
}
|
|
9
|
+
/** `vercel login` ran and the directory is now authenticated. */
|
|
10
|
+
| {
|
|
11
|
+
kind: "logged-in";
|
|
12
|
+
}
|
|
13
|
+
/** `vercel login` exited without leaving an authenticated session. */
|
|
14
|
+
| {
|
|
15
|
+
kind: "failed";
|
|
16
|
+
}
|
|
17
|
+
/** The Vercel CLI is not installed, so login cannot start. */
|
|
18
|
+
| {
|
|
19
|
+
kind: "cli-missing";
|
|
20
|
+
}
|
|
21
|
+
/** Vercel could not be reached, so login state could not be determined. */
|
|
22
|
+
| {
|
|
23
|
+
kind: "unavailable";
|
|
24
|
+
}
|
|
25
|
+
/** The user stopped waiting (Cancel / Esc) before login completed. */
|
|
26
|
+
| {
|
|
27
|
+
kind: "cancelled";
|
|
28
|
+
};
|
|
29
|
+
/** Injected for tests; defaults to the real auth probe and `vercel login`. */
|
|
30
|
+
export interface LoginFlowDeps {
|
|
31
|
+
getVercelAuthStatus: typeof getVercelAuthStatus;
|
|
32
|
+
runVercelLogin: (input: {
|
|
33
|
+
cwd: string;
|
|
34
|
+
onOutput: ReturnType<typeof createPromptCommandOutput>;
|
|
35
|
+
signal?: AbortSignal;
|
|
36
|
+
}) => Promise<boolean>;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* THE LOGIN FLOW for the dev TUI's `/login`. Short-circuits when already
|
|
40
|
+
* authenticated; otherwise runs `vercel login` as a browser flow the TUI waits
|
|
41
|
+
* on (see {@link runVercelLoginWithControls}) and re-probes after, so a
|
|
42
|
+
* half-finished or abandoned login reports `failed`, never a false success.
|
|
43
|
+
*/
|
|
44
|
+
export declare function runLoginFlow(input: {
|
|
45
|
+
appRoot: string;
|
|
46
|
+
prompter: Prompter;
|
|
47
|
+
signal?: AbortSignal;
|
|
48
|
+
deps?: Partial<LoginFlowDeps>;
|
|
49
|
+
}): Promise<LoginFlowResult>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{getVercelAuthStatus}from"#setup/vercel-project.js";import{createPromptCommandOutput}from"#setup/cli/index.js";import{runVercel}from"#setup/primitives/run-vercel.js";const defaultDeps={getVercelAuthStatus,runVercelLogin:({cwd:e,onOutput:t,signal:r})=>runVercel([`login`],{cwd:e,nonInteractive:!0,onOutput:t,timeoutMs:3e5,signal:r})};async function withSpinner(e,t,n){let r=e.log.spinner?.(t);try{return await n()}finally{r?.stop()}}async function runVercelLoginWithControls(e,t,n,r,i){if(r.awaitChoice===void 0)return withSpinner(r,`Opening Vercel login in your browser…`,()=>e.runVercelLogin({cwd:t,onOutput:n,signal:i}));let a=new AbortController,o=i?AbortSignal.any([i,a.signal]):a.signal,s=r.awaitChoice({status:`Logging in to Vercel…`,context:`Complete the login in your browser`,actions:[{value:`cancel`,label:`Cancel`}]}),c=e.runVercelLogin({cwd:t,onOutput:n,signal:o});try{let e=await Promise.race([c.then(e=>({via:`work`,ok:e})),s.choice.then(()=>({via:`choice`}))]);return e.via===`work`?e.ok:(a.abort(),await c.catch(()=>{}),`cancelled`)}finally{s.close()}}async function runLoginFlow(e){let{appRoot:n,prompter:i,signal:a}=e,o={...defaultDeps,...e.deps},s=createPromptCommandOutput(i.log),probeAuth=()=>o.getVercelAuthStatus(n,{signal:a}),c=await withSpinner(i,`Checking your Vercel login…`,probeAuth);switch(a?.throwIfAborted(),c){case`authenticated`:return{kind:`already`};case`cli-missing`:return{kind:`cli-missing`};case`unavailable`:return{kind:`unavailable`};case`logged-out`:break;default:return c}let l=await runVercelLoginWithControls(o,n,s,i,a);if(l===`cancelled`)return{kind:`cancelled`};if(!l)return{kind:`failed`};let u=await withSpinner(i,`Confirming your Vercel login…`,probeAuth);switch(a?.throwIfAborted(),u){case`authenticated`:return{kind:`logged-in`};case`logged-out`:return{kind:`failed`};case`cli-missing`:return{kind:`cli-missing`};case`unavailable`:return{kind:`unavailable`};default:return u}}export{runLoginFlow};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{__toESM}from"../../_virtual/_rolldown/runtime.js";import{require_picocolors}from"../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js";import{interactiveAsker}from"../ask.js";import{detectProjectIdentity}from"../project-resolution.js";import{snapshotSetupState}from"../state.js";import{WizardCancelledError}from"../step.js";import{findEnvFileWithKey}from"../boxes/detect-ai-gateway.js";import{fetchGatewayCatalog,selectModel}from"../boxes/select-model.js";import{runInteractive}from"../runner.js";import{inProjectSetupState,prompterSink}from"./in-project.js";import{runVercelFlow}from"./vercel.js";import{join}from"node:path";import{discoverAgent}from"#discover/discover-agent.js";import{inspectApplication}from"#services/inspect-application.js";import{formatLanguageModelGatewayId}from"#internal/runtime-model.js";import{createCompiledRuntimeModelCatalogLoader}from"#compiler/model-catalog.js";import{createStaticSourceChange}from"#source-change/static-source-change.js";var import_picocolors=__toESM(require_picocolors(),1);const MODEL_MENU_MESSAGE=``;function providerStatusHint(e,t=e=>e){return e.kind===`gateway-project`?`AI Gateway (Linked to ${e.teamName===void 0?t(e.projectName):`${t(e.projectName)} in ${t(e.teamName)}`})`:`AI Gateway (${e.envKey} in ${e.envFile})`}function modelMenuRows(e,t,n,r){let i;r?(i={value:`model`,label:`Change model`},e!==null&&(i.hint=e)):i={value:`model`,label:`Change model`,disabled:!0,description:`Set via an SDK model call in agent.ts; edit the source to change it`};let a;return a=n?.kind===`external`?{value:`provider`,label:`Change provider`,disabled:!0,description:`Disabled in external endpoint mode`}:t.kind===`unset`?{value:`provider`,label:import_picocolors.default.bold(import_picocolors.default.yellow(`Configure provider`)),hint:`Required to enable the agent`,accent:`warning`}:{value:`provider`,label:`Change provider`,hint:providerStatusHint(t,import_picocolors.default.bold)},[i,a,{value:`done`,label:`Done`}]}function applyModelNotice(e){switch(e.kind){case`changed`:return{tone:`success`,text:`Model changed to ${e.to}`};case`unchanged`:return{tone:`info`,text:`Model is already ${e.model}`};case`rejected`:return{tone:`warning`,text:e.message}}}function providerNotice(e){return e.kind===`unset`?{tone:`warning`,text:`Provider updated — no gateway credential detected yet.`}:{tone:`success`,text:`Connected to AI Gateway`}}async function detectModelProviderStatus(e,t={}){let[n,i,a]=await Promise.all([detectProjectIdentity(e,t),findEnvFileWithKey(e,`AI_GATEWAY_API_KEY`),findEnvFileWithKey(e,`VERCEL_OIDC_TOKEN`)]);if(n!==void 0){let e={kind:`gateway-project`,projectName:n.projectName};return n.teamName!==void 0&&(e.teamName=n.teamName),e}return i===void 0?a===void 0?{kind:`unset`}:{kind:`gateway-key`,envKey:`VERCEL_OIDC_TOKEN`,envFile:a}:{kind:`gateway-key`,envKey:`AI_GATEWAY_API_KEY`,envFile:i}}async function runModelFlow(e){let{appRoot:t,prompter:n,signal:r}=e,i={readCurrentModel:readCurrentAgentModel,applyModel:changeAgentModel,detectProviderStatus:detectModelProviderStatus,runVercelFlow,...e.deps};async function checkProject(e){let t=n.log.spinner?.(`Checking the project…`);try{return await e()}finally{t?.stop()}}let detectProvider=()=>
|
|
1
|
+
import{__toESM}from"../../_virtual/_rolldown/runtime.js";import{require_picocolors}from"../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js";import{interactiveAsker}from"../ask.js";import{detectProjectIdentity}from"../project-resolution.js";import{snapshotSetupState}from"../state.js";import{WizardCancelledError}from"../step.js";import{findEnvFileWithKey}from"../boxes/detect-ai-gateway.js";import{fetchGatewayCatalog,selectModel}from"../boxes/select-model.js";import{runInteractive}from"../runner.js";import{inProjectSetupState,prompterSink}from"./in-project.js";import{runVercelFlow}from"./vercel.js";import{join}from"node:path";import{discoverAgent}from"#discover/discover-agent.js";import{inspectApplication}from"#services/inspect-application.js";import{formatLanguageModelGatewayId}from"#internal/runtime-model.js";import{createCompiledRuntimeModelCatalogLoader}from"#compiler/model-catalog.js";import{createStaticSourceChange}from"#source-change/static-source-change.js";var import_picocolors=__toESM(require_picocolors(),1);const MODEL_MENU_MESSAGE=``;function providerStatusHint(e,t=e=>e){return e.kind===`gateway-project`?`AI Gateway (Linked to ${e.teamName===void 0?t(e.projectName):`${t(e.projectName)} in ${t(e.teamName)}`})`:`AI Gateway (${e.envKey} in ${e.envFile})`}function modelMenuRows(e,t,n,r){let i;r?(i={value:`model`,label:`Change model`},e!==null&&(i.hint=e)):i={value:`model`,label:`Change model`,disabled:!0,description:`Set via an SDK model call in agent.ts; edit the source to change it`};let a;return a=n?.kind===`external`?{value:`provider`,label:`Change provider`,disabled:!0,description:`Disabled in external endpoint mode`}:t.kind===`unset`?{value:`provider`,label:import_picocolors.default.bold(import_picocolors.default.yellow(`Configure provider`)),hint:`Required to enable the agent`,accent:`warning`}:{value:`provider`,label:`Change provider`,hint:providerStatusHint(t,import_picocolors.default.bold)},[i,a,{value:`done`,label:`Done`}]}function applyModelNotice(e){switch(e.kind){case`changed`:return{tone:`success`,text:`Model changed to ${e.to}`};case`unchanged`:return{tone:`info`,text:`Model is already ${e.model}`};case`rejected`:return{tone:`warning`,text:e.message}}}function providerNotice(e){return e.kind===`unset`?{tone:`warning`,text:`Provider updated — no gateway credential detected yet.`}:{tone:`success`,text:`Connected to AI Gateway`}}async function detectModelProviderStatus(e,t={}){let[n,i,a]=await Promise.all([detectProjectIdentity(e,t),findEnvFileWithKey(e,`AI_GATEWAY_API_KEY`),findEnvFileWithKey(e,`VERCEL_OIDC_TOKEN`)]);if(n!==void 0){let e={kind:`gateway-project`,projectName:n.projectName};return n.teamName!==void 0&&(e.teamName=n.teamName),e}return i===void 0?a===void 0?{kind:`unset`}:{kind:`gateway-key`,envKey:`VERCEL_OIDC_TOKEN`,envFile:a}:{kind:`gateway-key`,envKey:`AI_GATEWAY_API_KEY`,envFile:i}}async function runModelFlow(e){let{appRoot:t,prompter:n,signal:r}=e,i={readCurrentModel:readCurrentAgentModel,applyModel:changeAgentModel,detectProviderStatus:detectModelProviderStatus,runVercelFlow,...e.deps};async function checkProject(e){let t=n.log.spinner?.(`Checking the project…`);try{return await e()}finally{t?.stop()}}let detectProvider=()=>i.detectProviderStatus(t,{signal:r}),[{id:o,routing:s,editable:c},l]=await checkProject(()=>Promise.all([i.readCurrentModel(t),detectProvider()]));r?.throwIfAborted();let u,d,p,m,h=s?.kind===`external`?{tone:`warning`,text:"`agent.ts` specifies a model provider directly. In-TUI configuration is restricted to AI Gateway endpoints."}:void 0,g=l.kind===`unset`&&s?.kind!==`external`?`provider`:c?`model`:s?.kind===`external`?`done`:`provider`;for(;;){let e;try{e=await n.select({message:``,options:modelMenuRows(o,l,s,c),hintLayout:`stacked`,initialValue:g,notices:[h,p,m].filter(e=>e!==void 0)})}catch(e){if(!(e instanceof WizardCancelledError))throw e;break}if(e===`done`)break;if(e===`model`){let e=await pickModelFromCatalog({appRoot:t,prompter:n,current:o,signal:r,deps:i.selectModel});e===void 0?g=`model`:(r?.throwIfAborted(),u=await i.applyModel({appRoot:t,slug:e}),r?.throwIfAborted(),p=applyModelNotice(u),u.kind===`changed`&&(o=u.to),g=`done`);continue}let f=await i.runVercelFlow({appRoot:t,prompter:n,signal:r});if(r?.throwIfAborted(),f.kind===`cancelled`){g=`provider`;continue}if(`outcome`in f){g=`done`;continue}l=await checkProject(detectProvider),r?.throwIfAborted(),d={status:l},f.credential!==void 0&&(d.credential=f.credential),m=providerNotice(l),g=`done`}if(u===void 0&&d===void 0)return{kind:`cancelled`};let _={kind:`done`};return u!==void 0&&(_.modelMessage=formatApplyModelOutcome(u)),d!==void 0&&(_.providerOutcome=d),_}async function pickModelFromCatalog(e){let{appRoot:t,prompter:r,current:a,signal:o}=e,f=e.deps?.fetchModels??fetchGatewayCatalog,p={asker:interactiveAsker(r),deps:{fetchModels:async e=>{let t=r.log.spinner?.(`Loading the model catalog...`);try{return await f(e)}finally{t?.stop()}}}};a!==null&&(p.defaultModel=a);let m=await runInteractive([selectModel(p)],inProjectSetupState(t,{kind:`unresolved`}),prompterSink(r),{snapshot:snapshotSetupState,signal:o});return m.kind===`cancelled`?void 0:m.state.modelId}function formatApplyModelOutcome(e){switch(e.kind){case`changed`:return`Model changed to ${import_picocolors.default.bold(e.to)}. Live on your next prompt.`;case`unchanged`:return`Model is already \`${e.model}\`.`;case`rejected`:return e.message}}async function changeAgentModel(e){let{appRoot:t,slug:n}=e,r=await validateModelSlug(t,n);if(r!==null)return{kind:`rejected`,message:r};let{manifest:i}=await discoverAgent({agentRoot:join(t,`agent`),appRoot:t}),a=await createStaticSourceChange(i).updateModelName(n);return a.kind===`bail`?{kind:`rejected`,message:`Couldn't edit ${a.at.logicalPath}: ${a.reason}. Change \`model\` by hand.`}:a.from===a.to?{kind:`unchanged`,model:a.to}:{kind:`changed`,to:a.to}}async function validateModelSlug(e,t){if(!t.includes(`/`))return`\`${t}\` isn't a provider/model id (e.g. anthropic/claude-sonnet-4.6).`;let n=createCompiledRuntimeModelCatalogLoader(e);try{if(await n.getModelLimits(formatLanguageModelGatewayId(t))===null)return`I couldn't confirm \`${t}\` in the AI Gateway model catalog, so I didn't change agent.ts.`}catch{return null}return null}async function readCurrentAgentModel(e){try{let{compiledState:t}=await inspectApplication(e),n=t?.manifest.config.model;return{id:n?.id??null,routing:n?.routing??null,editable:n!==void 0&&n.source===void 0}}catch{return{id:null,routing:null,editable:!1}}}async function modelChangeRefusalForUneditableModel(e){let{editable:t,routing:n}=await readCurrentAgentModel(e);return t?null:`Model is set via ${n?.kind===`external`?`the external provider \`${n.provider}\``:`an SDK model call`} in agent.ts, not a string literal; /model can't rewrite it. Edit \`model\` in agent.ts.`}export{MODEL_MENU_MESSAGE,changeAgentModel,detectModelProviderStatus,formatApplyModelOutcome,modelChangeRefusalForUneditableModel,runModelFlow};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { appendEnv } from "../append-env.js";
|
|
2
2
|
import type { Prompter } from "../prompter.js";
|
|
3
3
|
import { validateGatewayApiKey } from "../validate-gateway-key.js";
|
|
4
|
+
import { getVercelAuthStatus } from "../vercel-project.js";
|
|
4
5
|
import { runLinkFlow, type LinkFlowResult } from "./link.js";
|
|
5
6
|
export declare const PROVIDER_QUESTION = "Which model provider do you want to use?";
|
|
6
7
|
export declare const CONNECTION_QUESTION = "How do you want to connect to AI Gateway?";
|
|
@@ -8,6 +9,7 @@ export declare const EXTERNAL_PROVIDER_INSTRUCTIONS_TITLE = "Using another model
|
|
|
8
9
|
export declare const EXTERNAL_PROVIDER_INSTRUCTIONS: readonly string[];
|
|
9
10
|
/** Injected for tests; defaults to the real link flow, env write, and key check. */
|
|
10
11
|
export interface VercelFlowDeps {
|
|
12
|
+
getVercelAuthStatus: typeof getVercelAuthStatus;
|
|
11
13
|
runLinkFlow: typeof runLinkFlow;
|
|
12
14
|
appendEnv: typeof appendEnv;
|
|
13
15
|
validateGatewayApiKey: typeof validateGatewayApiKey;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{__toESM}from"../../_virtual/_rolldown/runtime.js";import{require_picocolors}from"../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js";import{appendEnv}from"../append-env.js";import{WizardCancelledError}from"../step.js";import{runLinkFlow}from"./link.js";import{validateGatewayApiKey}from"../validate-gateway-key.js";import{join}from"node:path";var import_picocolors=__toESM(require_picocolors(),1);const AI_GATEWAY_ENV_KEY=`AI_GATEWAY_API_KEY`,ENV_FILE_NAME=`.env.local`,PROVIDER_QUESTION=`Which model provider do you want to use?`,CONNECTION_QUESTION=`How do you want to connect to AI Gateway?`,EXTERNAL_PROVIDER_INSTRUCTIONS_TITLE=`Using another model provider`,EXTERNAL_PROVIDER_INSTRUCTIONS=[`Set your provider's API key in ${ENV_FILE_NAME} — e.g. ANTHROPIC_API_KEY or OPENAI_API_KEY.`,'In agent/agent.ts, set `model` to a provider-authored model — e.g. `anthropic("claude-opus-4.8")` from `@ai-sdk/anthropic`.',`See https://beta.eve.dev/docs/agent-config for details.`,"A running `eve dev` reloads env files automatically — no restart needed."];async function runVercelFlow(e){let{appRoot:t,prompter:a,signal:o}=e,s={runLinkFlow,appendEnv,validateGatewayApiKey,...e.deps},c,l;try{c=await a.select({message:PROVIDER_QUESTION,options:[{value:`gateway`,label:`Vercel AI Gateway`,hint:`one key, every model`},{value:`other`,label:`Something else`,hint:`use your own provider credentials`}],hintLayout:`stacked`}),c===`gateway
|
|
1
|
+
import{__toESM}from"../../_virtual/_rolldown/runtime.js";import{require_picocolors}from"../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js";import{appendEnv}from"../append-env.js";import{WizardCancelledError}from"../step.js";import{getVercelAuthStatus}from"../vercel-project.js";import{runLinkFlow}from"./link.js";import{validateGatewayApiKey}from"../validate-gateway-key.js";import{join}from"node:path";var import_picocolors=__toESM(require_picocolors(),1);const AI_GATEWAY_ENV_KEY=`AI_GATEWAY_API_KEY`,ENV_FILE_NAME=`.env.local`,PROVIDER_QUESTION=`Which model provider do you want to use?`,CONNECTION_QUESTION=`How do you want to connect to AI Gateway?`,EXTERNAL_PROVIDER_INSTRUCTIONS_TITLE=`Using another model provider`,EXTERNAL_PROVIDER_INSTRUCTIONS=[`Set your provider's API key in ${ENV_FILE_NAME} — e.g. ANTHROPIC_API_KEY or OPENAI_API_KEY.`,'In agent/agent.ts, set `model` to a provider-authored model — e.g. `anthropic("claude-opus-4.8")` from `@ai-sdk/anthropic`.',`See https://beta.eve.dev/docs/agent-config for details.`,"A running `eve dev` reloads env files automatically — no restart needed."];function projectConnectionOption(e){let t={value:`project`,label:`Connect via a project`,hint:`vercel link + env pull`};switch(e){case`authenticated`:return t;case`cli-missing`:return{...t,disabled:!0,disabledReason:`Vercel CLI not found, see /vc`,disabledReasonTone:`warning`};case`logged-out`:return{...t,disabled:!0,disabledReason:`Log in to Vercel first, see /login`,disabledReasonTone:`warning`};case`unavailable`:return{...t,disabled:!0,disabledReason:`Couldn't reach Vercel, check your connection`,disabledReasonTone:`warning`};default:return e}}async function runVercelFlow(e){let{appRoot:t,prompter:a,signal:o}=e,s={getVercelAuthStatus,runLinkFlow,appendEnv,validateGatewayApiKey,...e.deps},c,l;try{if(c=await a.select({message:PROVIDER_QUESTION,options:[{value:`gateway`,label:`Vercel AI Gateway`,hint:`one key, every model`},{value:`other`,label:`Something else`,hint:`use your own provider credentials`}],hintLayout:`stacked`}),c===`gateway`){let e=a.log.spinner?.(`Checking your Vercel login…`),n;try{n=await s.getVercelAuthStatus(t,{signal:o}),o?.throwIfAborted()}finally{e?.stop()}l=await a.select({message:CONNECTION_QUESTION,options:[projectConnectionOption(n),{value:`own-key`,label:`Use my own key`,hint:`paste an ${AI_GATEWAY_ENV_KEY}`}],hintLayout:`stacked`})}}catch(e){if(e instanceof WizardCancelledError)return{kind:`cancelled`};throw e}if(c===`other`)return a.acknowledge?await a.acknowledge({message:EXTERNAL_PROVIDER_INSTRUCTIONS_TITLE,lines:EXTERNAL_PROVIDER_INSTRUCTIONS}):a.note(EXTERNAL_PROVIDER_INSTRUCTIONS.join(`
|
|
2
2
|
`),EXTERNAL_PROVIDER_INSTRUCTIONS_TITLE),{kind:`done`,outcome:`external-provider`};if(l===`own-key`)for(;;){let e;try{e=await a.password({message:`Enter your ${AI_GATEWAY_ENV_KEY}`,validate:e=>e.trim().length===0?`API key cannot be empty.`:void 0})}catch(e){if(e instanceof WizardCancelledError)return{kind:`cancelled`};throw e}o?.throwIfAborted();let n=e.trim(),r=a.log.spinner?.(`Validating…`),i;try{i=await s.validateGatewayApiKey(n,o)}finally{r?.stop()}if(o?.throwIfAborted(),i.kind===`invalid`){a.log.error(`${i.message} Check the key and try again, or Esc to cancel.`);continue}return i.kind===`inconclusive`?a.log.warning(`Couldn't reach the gateway to validate (${i.message}). Saving the key anyway.`):a.log.success(`${import_picocolors.default.green(`✓`)} ${import_picocolors.default.bold(`Valid key`)}`),await s.appendEnv(join(t,ENV_FILE_NAME),{[AI_GATEWAY_ENV_KEY]:n},{force:!0}),o?.throwIfAborted(),a.log.success(`Saved ${AI_GATEWAY_ENV_KEY} to ${ENV_FILE_NAME}.`),{kind:`done`,credential:AI_GATEWAY_ENV_KEY}}else return await s.runLinkFlow({appRoot:t,prompter:a,signal:o,projectSelection:`create-or-link`})}export{CONNECTION_QUESTION,EXTERNAL_PROVIDER_INSTRUCTIONS,EXTERNAL_PROVIDER_INSTRUCTIONS_TITLE,PROVIDER_QUESTION,runVercelFlow};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** An authored Node.js engine value replaced by Eve's selected scaffold major. */
|
|
2
|
+
export interface NodeEngineOverride {
|
|
3
|
+
previous: unknown;
|
|
4
|
+
next: string;
|
|
5
|
+
}
|
|
6
|
+
export type NodeEngineReconciliation = {
|
|
7
|
+
kind: "added";
|
|
8
|
+
next: string;
|
|
9
|
+
} | ({
|
|
10
|
+
kind: "overridden";
|
|
11
|
+
} & NodeEngineOverride) | {
|
|
12
|
+
kind: "unchanged";
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* The single-major `engines.node` value a generated project should declare,
|
|
16
|
+
* derived from Eve's required range — e.g. `">=24"` → `"24.x"`. A scaffolded
|
|
17
|
+
* app is a deployment artifact, not a library: Vercel reads `engines.node` to
|
|
18
|
+
* pick the build's Node and resolves an open range to the newest *supported*
|
|
19
|
+
* major, so `">=24"` would float onto a future major as Vercel widens its set,
|
|
20
|
+
* whereas `"24.x"` stays on major 24 while still taking minor/patch updates.
|
|
21
|
+
* Eve's own package keeps the open range; only generated apps pin.
|
|
22
|
+
*/
|
|
23
|
+
export declare function pinnedNodeEngineMajor(requiredRange: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* Reconciles an authored `engines.node` value with the single Node.js major
|
|
26
|
+
* selected for scaffolded Eve projects. Existing ranges are preserved only
|
|
27
|
+
* when every version they permit remains inside that selected major.
|
|
28
|
+
*/
|
|
29
|
+
export declare function reconcileNodeEngine(existingValue: unknown, requiredRange: string): NodeEngineReconciliation;
|
|
30
|
+
/** Formats the warning shown when Eve replaces an incompatible Node.js engine value. */
|
|
31
|
+
export declare function formatNodeEngineOverrideWarning(override: NodeEngineOverride): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import semver from"#compiled/semver/index.js";const{Range,intersects,minVersion,subset,validRange}=semver;function isNonEmptySubset(e,t){let r=validRange(e);return r!==null&&intersects(r,t)&&subset(r,t)}function nextAllowedMajor(e,n){let i=`>=${n+1}.0.0`,a;for(let n of new Range(e).set){let e=minVersion([...n.map(e=>e.value).filter(Boolean),i].join(` `));e!==null&&(a===void 0||e.major<a)&&(a=e.major)}return a}function pinnedNodeEngineMajor(e){let t=validRange(e);if(t===null)throw Error(`Eve declares an invalid Node.js engine range: "${e}".`);let n=minVersion(t);if(n===null)throw Error(`Eve declares an empty Node.js engine range: "${e}".`);let i=n.major;for(;i!==void 0;){let e=`${i}.x`;if(isNonEmptySubset(e,t))return e;i=nextAllowedMajor(t,i)}throw Error(`Eve's Node.js engine range "${e}" cannot be represented by a major pin without widening it.`)}function reconcileNodeEngine(e,t){let n=pinnedNodeEngineMajor(t);return e===void 0?{kind:`added`,next:n}:typeof e==`string`&&isNonEmptySubset(e,n)?{kind:`unchanged`}:{kind:`overridden`,previous:e,next:n}}function formatPackageJsonValue(e){return JSON.stringify(e)??String(e)}function formatNodeEngineOverrideWarning(e){return`Overrode package.json engines.node from ${formatPackageJsonValue(e.previous)} to "${e.next}" because the previous value was not confined to the Node.js major selected by Eve.`}export{formatNodeEngineOverrideWarning,pinnedNodeEngineMajor,reconcileNodeEngine};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Prompter } from "./prompter.js";
|
|
2
2
|
import type { AnySetupBox } from "./runner.js";
|
|
3
|
+
import type { EvePackageContract } from "./scaffold/index.js";
|
|
3
4
|
import type { ArgsHeadlessAiGateway, ArgsHeadlessProject, ChannelKind, ChatPreference, SetupMode, SetupState } from "./state.js";
|
|
4
5
|
/**
|
|
5
6
|
* Options for {@link composeOnboardingBoxes}. These carry exactly what the
|
|
@@ -41,8 +42,8 @@ export interface OnboardingBoxesOptions {
|
|
|
41
42
|
* setup remains an interactive/onboarding handoff, not a headless flow.
|
|
42
43
|
*/
|
|
43
44
|
headless?: boolean;
|
|
44
|
-
/**
|
|
45
|
-
|
|
45
|
+
/** Eve package metadata baked into the scaffolded `package.json`. */
|
|
46
|
+
evePackage?: EvePackageContract;
|
|
46
47
|
}
|
|
47
48
|
/**
|
|
48
49
|
* Composes the full programmatic onboarding flow.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{headlessAsker,interactiveAsker}from"./ask.js";import{addChannels}from"./boxes/add-channels.js";import{selectConnections}from"./boxes/select-connections.js";import{addConnections}from"./boxes/add-connections.js";import{detectAiGateway}from"./boxes/detect-ai-gateway.js";import{applyAiGatewayCredential}from"./boxes/apply-ai-gateway-credential.js";import{deployProject}from"./boxes/deploy-project.js";import{linkVercelProject}from"./boxes/link-project.js";import{oneShotNextSteps}from"./boxes/one-shot-next-steps.js";import{preflight}from"./boxes/preflight.js";import{resolveProvisioning}from"./boxes/resolve-provisioning.js";import{resolveTarget}from"./boxes/resolve-target.js";import{scaffold}from"./boxes/scaffold.js";import{selectChannels}from"./boxes/select-channels.js";import{selectChat}from"./boxes/select-chat.js";import{selectModel}from"./boxes/select-model.js";import{selectSetupMode}from"./boxes/select-setup-mode.js";import{resolve}from"node:path";function onlyWhen(e,t){return{...t,shouldRun:n=>e(n)&&(t.shouldRun?.(n)??!0)}}function completeSetupOnly(e){return onlyWhen(e=>e.setupMode===`complete`,e)}function composeOnboardingBoxes(r){let i=r.headless?{headless:!0,project:r.provisioning?.project??{},aiGateway:r.provisioning?.aiGateway??{}}:{headless:!1},a=r.headless?headlessAsker():interactiveAsker(r.prompter);return[resolveTarget({asker:a,notify:e=>r.prompter.note(e),presetName:r.presetName,targetDirectory:r.targetDirectory,inPlace:r.inPlace,resumeExisting:r.headless}),selectSetupMode({asker:a,presetMode:r.presetMode,presetModel:r.presetModel}),...[selectModel({asker:a,presetModel:r.presetModel}),selectChannels({asker:a,presetChannels:r.presetChannels,variant:`onboarding`}),selectConnections({asker:a,presetConnections:r.presetConnections,headless:r.headless}),resolveProvisioning({asker:a,prompter:r.prompter,targetDirectory:r.targetDirectory,mode:i})].map(completeSetupOnly),preflight({cwd:resolve(r.targetDirectory??process.cwd()),headless:r.headless}),scaffold({prompter:r.prompter,
|
|
1
|
+
import{headlessAsker,interactiveAsker}from"./ask.js";import{addChannels}from"./boxes/add-channels.js";import{selectConnections}from"./boxes/select-connections.js";import{addConnections}from"./boxes/add-connections.js";import{detectAiGateway}from"./boxes/detect-ai-gateway.js";import{applyAiGatewayCredential}from"./boxes/apply-ai-gateway-credential.js";import{deployProject}from"./boxes/deploy-project.js";import{linkVercelProject}from"./boxes/link-project.js";import{oneShotNextSteps}from"./boxes/one-shot-next-steps.js";import{preflight}from"./boxes/preflight.js";import{resolveProvisioning}from"./boxes/resolve-provisioning.js";import{resolveTarget}from"./boxes/resolve-target.js";import{scaffold}from"./boxes/scaffold.js";import{selectChannels}from"./boxes/select-channels.js";import{selectChat}from"./boxes/select-chat.js";import{selectModel}from"./boxes/select-model.js";import{selectSetupMode}from"./boxes/select-setup-mode.js";import{resolve}from"node:path";function onlyWhen(e,t){return{...t,shouldRun:n=>e(n)&&(t.shouldRun?.(n)??!0)}}function completeSetupOnly(e){return onlyWhen(e=>e.setupMode===`complete`,e)}function composeOnboardingBoxes(r){let i=r.headless?{headless:!0,project:r.provisioning?.project??{},aiGateway:r.provisioning?.aiGateway??{}}:{headless:!1},a=r.headless?headlessAsker():interactiveAsker(r.prompter);return[resolveTarget({asker:a,notify:e=>r.prompter.note(e),presetName:r.presetName,targetDirectory:r.targetDirectory,inPlace:r.inPlace,resumeExisting:r.headless}),selectSetupMode({asker:a,presetMode:r.presetMode,presetModel:r.presetModel}),...[selectModel({asker:a,presetModel:r.presetModel}),selectChannels({asker:a,presetChannels:r.presetChannels,variant:`onboarding`}),selectConnections({asker:a,presetConnections:r.presetConnections,headless:r.headless}),resolveProvisioning({asker:a,prompter:r.prompter,targetDirectory:r.targetDirectory,mode:i})].map(completeSetupOnly),preflight({cwd:resolve(r.targetDirectory??process.cwd()),headless:r.headless}),scaffold({prompter:r.prompter,evePackage:r.evePackage,targetDirectory:r.targetDirectory,overwriteExisting:r.overwriteExisting,headless:r.headless}),...[detectAiGateway(),linkVercelProject({prompter:r.prompter}),applyAiGatewayCredential({prompter:r.prompter}),addChannels({asker:a,prompter:r.prompter,evePackage:r.evePackage,presetCreateSlackbot:r.presetCreateSlackbot,headless:r.headless,slackbotFailure:`warn-and-continue`}),addConnections({prompter:r.prompter})].map(completeSetupOnly),completeSetupOnly(onlyWhen(e=>e.slackScaffolded,deployProject({prompter:r.prompter,skip:r.presetNoDeploy,headless:r.headless}))),completeSetupOnly(selectChat({asker:a,presetPreference:r.presetChatPreference})),oneShotNextSteps({prompter:r.prompter})]}export{composeOnboardingBoxes};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment variables `@vercel/detect-agent@1.2.3` reads as launch markers.
|
|
3
|
+
*
|
|
4
|
+
* Two consumers share this list. Tests that assert a human path delete these
|
|
5
|
+
* from the child environment, because the test runner itself is often launched
|
|
6
|
+
* by a coding agent and the markers would leak into spawned CLIs. And every
|
|
7
|
+
* `vercel` subprocess eve spawns strips them ({@link withoutCodingAgentMarkers}),
|
|
8
|
+
* so the Vercel CLI never sees an agent it would react to — eve drives it
|
|
9
|
+
* explicitly (stdin, flags), and an inherited marker has been observed to turn a
|
|
10
|
+
* read-only `vercel whoami` into a login attempt. The list lives here as the one
|
|
11
|
+
* place that knows the dependency's internals; revisit it when the pinned
|
|
12
|
+
* version changes. (The package also probes `/opt/.devin`, which cannot be
|
|
13
|
+
* masked through the environment.)
|
|
14
|
+
*/
|
|
15
|
+
export declare const CODING_AGENT_ENV_MARKERS: readonly string[];
|
|
16
|
+
/** A copy of `env` with the coding-agent launch markers removed. */
|
|
17
|
+
export declare function withoutCodingAgentMarkers(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|