eve 0.52.3 → 0.52.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/src/cli/commands/registry-add-command.d.ts +3 -0
  3. package/dist/src/cli/commands/registry-add-command.js +1 -0
  4. package/dist/src/cli/commands/registry-metadata.d.ts +4 -1
  5. package/dist/src/cli/commands/registry-metadata.js +1 -1
  6. package/dist/src/cli/commands/registry.d.ts +1 -2
  7. package/dist/src/cli/commands/registry.js +1 -1
  8. package/dist/src/compiled/.vendor-stamp.json +1 -1
  9. package/dist/src/compiler/extension-compatibility.d.ts +2 -2
  10. package/dist/src/compiler/extension-compatibility.js +1 -1
  11. package/dist/src/context/dynamic-tool-lifecycle.js +1 -1
  12. package/dist/src/evals/reporters/index.d.ts +1 -0
  13. package/dist/src/evals/reporters/index.js +1 -1
  14. package/dist/src/evals/runner/reporters/datadog.d.ts +137 -0
  15. package/dist/src/evals/runner/reporters/datadog.js +3 -0
  16. package/dist/src/execution/parked-delivery-wait.js +1 -1
  17. package/dist/src/execution/sandbox/bindings/vercel-options.d.ts +10 -0
  18. package/dist/src/execution/sandbox/bindings/vercel-options.js +1 -0
  19. package/dist/src/execution/sandbox/bindings/vercel.js +2 -1
  20. package/dist/src/execution/sandbox/shell-quote.d.ts +1 -12
  21. package/dist/src/execution/sandbox/shell-quote.js +1 -1
  22. package/dist/src/execution/session-command-inbox.js +1 -1
  23. package/dist/src/execution/tasks/child/workflow.js +1 -1
  24. package/dist/src/execution/tasks/parent/tool-execution.js +1 -1
  25. package/dist/src/execution/tool-auth.d.ts +4 -32
  26. package/dist/src/execution/tool-auth.js +1 -1
  27. package/dist/src/execution/tools/connection-search.js +2 -2
  28. package/dist/src/execution/tools/sleep-workflow.js +1 -1
  29. package/dist/src/execution/tools/subagent/accept-event-step.d.ts +1 -1
  30. package/dist/src/execution/tools/subagent/accept-event-step.js +1 -1
  31. package/dist/src/execution/tools/subagent/invoke-agent.js +1 -1
  32. package/dist/src/execution/tools/subagent/invoke-step.js +1 -1
  33. package/dist/src/execution/tools/workflow/ask.d.ts +3 -2
  34. package/dist/src/execution/tools/workflow/ask.js +1 -1
  35. package/dist/src/execution/tools/workflow/authorization-completion.d.ts +3 -0
  36. package/dist/src/execution/tools/workflow/authorization-completion.js +1 -0
  37. package/dist/src/execution/tools/workflow/body.d.ts +2 -0
  38. package/dist/src/execution/tools/workflow/body.js +1 -1
  39. package/dist/src/execution/tools/workflow/step-context.d.ts +31 -0
  40. package/dist/src/execution/tools/workflow/step-context.js +1 -0
  41. package/dist/src/execution/tools/workflow/step-execution.d.ts +3 -0
  42. package/dist/src/execution/tools/workflow/step-execution.js +1 -0
  43. package/dist/src/execution/tools/workflow/step.d.ts +3 -0
  44. package/dist/src/execution/tools/workflow/step.js +1 -0
  45. package/dist/src/execution/turn-workflow-tool-run.js +1 -1
  46. package/dist/src/execution/wire/session-inbox-contract.d.ts +7 -0
  47. package/dist/src/execution/wire/session-inbox-contract.js +1 -1
  48. package/dist/src/execution/wire/session-inbox-resume.d.ts +2 -0
  49. package/dist/src/execution/wire/session-inbox-resume.js +1 -1
  50. package/dist/src/harness/authorization.d.ts +5 -2
  51. package/dist/src/harness/authorization.js +1 -1
  52. package/dist/src/internal/application/package.js +1 -1
  53. package/dist/src/internal/authored-definition/connection.js +1 -1
  54. package/dist/src/internal/authored-package-boundary.js +1 -1
  55. package/dist/src/internal/vercel/build-command.d.ts +2 -1
  56. package/dist/src/internal/vercel/build-command.js +1 -1
  57. package/dist/src/internal/workflow-bundle/builder-support.js +1 -1
  58. package/dist/src/internal/workflow-bundle/workflow-builders.js +1 -1
  59. package/dist/src/internal/workflow-bundle/workflow-transformer.d.ts +3 -5
  60. package/dist/src/internal/workflow-bundle/workflow-transformer.js +4 -3
  61. package/dist/src/public/channels/github/checkout.js +1 -1
  62. package/dist/src/public/channels/slack/activity.js +1 -1
  63. package/dist/src/runtime/authorization-context.d.ts +14 -0
  64. package/dist/src/runtime/authorization-context.js +1 -0
  65. package/dist/src/runtime/connections/mcp-client.js +1 -1
  66. package/dist/src/runtime/connections/scoped-authorization.d.ts +18 -2
  67. package/dist/src/runtime/connections/scoped-authorization.js +1 -1
  68. package/dist/src/runtime/resolve-connection.js +1 -1
  69. package/dist/src/runtime/sandbox/keys.js +1 -1
  70. package/dist/src/sandbox/backends/default.d.ts +2 -0
  71. package/dist/src/sandbox/backends/default.js +1 -1
  72. package/dist/src/self-modification/agent.d.ts +5 -2
  73. package/dist/src/self-modification/agent.js +1 -1
  74. package/dist/src/self-modification/config.d.ts +52 -0
  75. package/dist/src/self-modification/config.js +1 -0
  76. package/dist/src/self-modification/credentials.d.ts +18 -0
  77. package/dist/src/self-modification/credentials.js +1 -0
  78. package/dist/src/self-modification/extension/eve-add.d.ts +7 -2
  79. package/dist/src/self-modification/extension/eve-add.js +1 -1
  80. package/dist/src/self-modification/extension/extension.d.ts +46 -1
  81. package/dist/src/self-modification/extension/extension.js +1 -1
  82. package/dist/src/self-modification/extension/instructions.js +23 -9
  83. package/dist/src/self-modification/extension/production-registry-add.d.ts +42 -0
  84. package/dist/src/self-modification/extension/production-registry-add.js +1 -0
  85. package/dist/src/self-modification/extension/tools/edit_file.js +1 -1
  86. package/dist/src/self-modification/extension/tools/publish.d.ts +7 -0
  87. package/dist/src/self-modification/extension/tools/publish.js +1 -0
  88. package/dist/src/self-modification/extension/tools/registry_add.d.ts +39 -7
  89. package/dist/src/self-modification/extension/tools/registry_add.js +1 -1
  90. package/dist/src/self-modification/extension/tools/search_registry.d.ts +1 -0
  91. package/dist/src/self-modification/extension/tools/search_registry.js +1 -1
  92. package/dist/src/self-modification/filesystem.js +1 -1
  93. package/dist/src/self-modification/git-workspace.d.ts +31 -0
  94. package/dist/src/self-modification/git-workspace.js +1 -0
  95. package/dist/src/self-modification/git.d.ts +6 -0
  96. package/dist/src/self-modification/git.js +1 -0
  97. package/dist/src/self-modification/github-publisher.d.ts +27 -0
  98. package/dist/src/self-modification/github-publisher.js +2 -0
  99. package/dist/src/self-modification/identifiers.d.ts +4 -0
  100. package/dist/src/self-modification/identifiers.js +1 -0
  101. package/dist/src/self-modification/mode.d.ts +4 -0
  102. package/dist/src/self-modification/mode.js +1 -0
  103. package/dist/src/self-modification/network-policy.d.ts +1 -0
  104. package/dist/src/self-modification/network-policy.js +1 -0
  105. package/dist/src/self-modification/proposal.d.ts +39 -0
  106. package/dist/src/self-modification/proposal.js +2 -0
  107. package/dist/src/self-modification/sandbox.d.ts +25 -1
  108. package/dist/src/self-modification/sandbox.js +1 -1
  109. package/dist/src/self-modification/setup.d.ts +34 -0
  110. package/dist/src/self-modification/setup.js +22 -0
  111. package/dist/src/self-modification/workspace-lock.d.ts +2 -0
  112. package/dist/src/self-modification/workspace-lock.js +1 -0
  113. package/dist/src/setup/integrations/registry.js +1 -1
  114. package/dist/src/setup/integrations/runner.js +1 -1
  115. package/dist/src/setup/integrations/self-modification/setup.d.ts +29 -0
  116. package/dist/src/setup/integrations/self-modification/setup.js +1 -0
  117. package/dist/src/setup/integrations/types.d.ts +2 -0
  118. package/dist/src/setup/integrations/types.js +1 -1
  119. package/dist/src/setup/scaffold/create/project.js +1 -1
  120. package/dist/src/shared/empty-delivery.js +1 -1
  121. package/dist/src/shared/git.d.ts +16 -0
  122. package/dist/src/shared/git.js +1 -0
  123. package/dist/src/shared/shell-quote.d.ts +2 -0
  124. package/dist/src/shared/shell-quote.js +1 -0
  125. package/dist/src/shared/vercel-services.js +1 -1
  126. package/dist/src/tasks/session-index.d.ts +1 -1
  127. package/dist/src/tasks/session-index.js +1 -1
  128. package/dist/src/tasks/session-task-cohorts.d.ts +10 -0
  129. package/dist/src/tasks/session-task-cohorts.js +1 -0
  130. package/dist/src/tools/workflow-definition.d.ts +5 -2
  131. package/docs/concepts/sessions-runs-and-streaming.md +2 -0
  132. package/docs/evals/reporters.mdx +20 -1
  133. package/docs/sandbox.mdx +2 -0
  134. package/docs/subagents/index.mdx +10 -0
  135. package/docs/tools/workflows.mdx +61 -2
  136. package/package.json +17 -1
  137. package/dist/src/self-modification/extension/source-lock.d.ts +0 -2
  138. package/dist/src/self-modification/extension/source-lock.js +0 -1
@@ -1,2 +1,26 @@
1
- declare const _default: import("#public/sandbox/index.js").SandboxDefinition<Record<string, never>, Record<string, never>>;
1
+ import { type DefaultSandboxProbes } from "#sandbox/backends/default.js";
2
+ import { type SandboxBackend, type SandboxDefinition } from "#public/sandbox/index.js";
3
+ import { type SelfModificationConfig } from "./config.js";
4
+ export interface SelfModificationSandboxOptions {
5
+ /**
6
+ * Production backend. Deployed self-modification owns an allow-all network
7
+ * policy and temporarily adds a credential transform while checking out its
8
+ * source. When omitted, eve selects Vercel Sandbox on Vercel or microsandbox
9
+ * on a supported self-hosted system.
10
+ */
11
+ readonly backend?: SandboxBackend;
12
+ /** Policy shared with the agent and extension mount. */
13
+ readonly config?: SelfModificationConfig;
14
+ }
15
+ type SelfModificationSandboxProbes = Pick<DefaultSandboxProbes, "isDeployedOnVercel" | "isMicrosandboxSupported">;
16
+ /** Defines the local source mount or isolated production proposal workspace. */
17
+ export declare function defineSelfModificationSandbox(options?: SelfModificationSandboxOptions): SandboxDefinition;
18
+ /**
19
+ * Deployed self-modification deliberately selects a backend that can inject
20
+ * GitHub auth at the network boundary, keeping the credential outside the
21
+ * sandbox and agent. Docker and just-bash do not provide that separation.
22
+ * Internal—exported for tests, which inject availability probes.
23
+ */
24
+ export declare function selectDeployedSelfModificationBackend(configured: SandboxBackend | undefined, probes: SelfModificationSandboxProbes): SandboxBackend;
25
+ declare const _default: SandboxDefinition;
2
26
  export default _default;
@@ -1 +1 @@
1
- import{createSelfModificationFilesystem}from"./filesystem.js";import{defineSandbox}from"#public/sandbox/index.js";import{justbash}from"#public/sandbox/just-bash.js";var sandbox_default=defineSandbox({backend:justbash({filesystem:createSelfModificationFilesystem})});export{sandbox_default as default};
1
+ import{resolveSelfModificationConfig}from"./config.js";import{createGitHubCredentialProvider}from"./credentials.js";import{resolveSelfModificationMode}from"./mode.js";import{SELF_MODIFICATION_BASELINE_NETWORK_POLICY}from"./network-policy.js";import{REPOSITORY_PATH,prepareSelfModificationWorkspace}from"./git-workspace.js";import{createSelfModificationFilesystem}from"./filesystem.js";import{shellQuote}from"#shared/shell-quote.js";import{SANDBOX_BACKEND_PROBES}from"#sandbox/backends/default.js";import{defaultBackend,defineSandbox}from"#public/sandbox/index.js";import{justbash}from"#public/sandbox/just-bash.js";import{microsandbox}from"#public/sandbox/microsandbox.js";import{vercel}from"#public/sandbox/vercel.js";function defineSelfModificationSandbox(e={}){let t=resolveSelfModificationConfig(e.config);return defineSandbox({backend:()=>{let n=resolveSelfModificationMode(t);return n===`local`?justbash({filesystem:createSelfModificationFilesystem}):n===`disabled`?e.backend??defaultBackend():selectDeployedSelfModificationBackend(e.backend,SANDBOX_BACKEND_PROBES)},async onSession({ctx:e,use:n}){if(resolveSelfModificationMode(t)!==`deployed`||t.deployed===void 0)return;if(e.session.parent===void 0)throw Error(`Production self-modification workspaces require a delegated child session.`);let r=t.deployed,i=await n();await i.setNetworkPolicy(SELF_MODIFICATION_BASELINE_NETWORK_POLICY);let a=await createGitHubCredentialProvider(r.credentials).resolve({capability:`checkout`,repository:r.repository});await prepareSelfModificationWorkspace({directory:r.directory,repository:r.repository,sandbox:i,targetBranch:r.targetBranch,token:a});let o=r.directory===`.`?REPOSITORY_PATH:`${REPOSITORY_PATH}/${r.directory}`;if((await i.run({command:`rm -rf /source && ln -s ${shellQuote(`${o}/agent`)} /source`})).exitCode!==0)throw Error(`Self-modification could not mount the production agent source.`)}})}function selectDeployedSelfModificationBackend(e,t){if(e!==void 0){if(e.name===`vercel`||e.name===`microsandbox`)return e;throw unsupportedBackend(e.name)}if(t.isDeployedOnVercel())return vercel({networkPolicy:SELF_MODIFICATION_BASELINE_NETWORK_POLICY});if(t.isMicrosandboxSupported())return microsandbox({networkPolicy:SELF_MODIFICATION_BASELINE_NETWORK_POLICY});throw unsupportedBackend()}function unsupportedBackend(e){let t=e===void 0?`No supported backend is available.`:`The configured ${e} backend does not support them.`;return Error(`Deployed self-modification requires runtime credential transforms. ${t} Use vercel() on Vercel or microsandbox() on a supported self-hosted system.`)}var sandbox_default=defineSelfModificationSandbox();export{sandbox_default as default,defineSelfModificationSandbox,selectDeployedSelfModificationBackend};
@@ -0,0 +1,34 @@
1
+ import { relative } from "node:path";
2
+ export interface SelfModificationSetupValues {
3
+ readonly branch: string;
4
+ readonly connector: string;
5
+ readonly directory: string;
6
+ readonly repository: string;
7
+ }
8
+ export interface DetectedGitRepository {
9
+ readonly branch?: string;
10
+ readonly directory?: string;
11
+ readonly owner?: string;
12
+ readonly repo?: string;
13
+ readonly remoteKind: "github" | "missing" | "other";
14
+ }
15
+ export interface SelfModificationSetupOperations {
16
+ attachConnector(connector: string): Promise<void>;
17
+ detectGitRepository(): Promise<DetectedGitRepository>;
18
+ findOrCreateConnector(name: string): Promise<string>;
19
+ readConfig(): Promise<string | undefined>;
20
+ writeConfig(source: string): Promise<void>;
21
+ }
22
+ export declare function connectorName(owner: string, repo: string): string;
23
+ export declare function renderSelfModificationConfig(values?: SelfModificationSetupValues): string;
24
+ /** Distinguishes resumable generated source from authored source without evaluating it. */
25
+ export declare function classifySelfModificationConfig(source: string | undefined): "missing" | "local" | "generated" | "authored";
26
+ export declare function parseGitHubRemote(remote: string): {
27
+ owner: string;
28
+ repo: string;
29
+ } | undefined;
30
+ export declare function defaultSelfModificationSetupOperations(appRoot: string): SelfModificationSetupOperations;
31
+ export declare function repositoryRelativeDirectory(repositoryRoot: string, appRoot: string, relativePath?: typeof relative): string;
32
+ export declare function repositoryPartError(value: string): string | undefined;
33
+ export declare function directoryError(value: string): string | undefined;
34
+ export declare function gitRefError(value: string): string | undefined;
@@ -0,0 +1,22 @@
1
+ import{SELF_MODIFICATION_CONFIG_PATH}from"./git-workspace.js";import{createHash}from"node:crypto";import{readFile,writeFile}from"node:fs/promises";import{join,relative}from"node:path";import{execFile}from"node:child_process";import{promisify}from"node:util";const runFile=promisify(execFile);function connectorName(e,t){return`selfmod-${e}-${t}`.toLowerCase().replaceAll(/[^a-z0-9-]/gu,`-`)}function renderSelfModificationConfig(e){if(e===void 0)return`import { defineSelfModificationConfig } from "eve/self-modification/config";
2
+
3
+ export default defineSelfModificationConfig({});
4
+ `;let t=`import { defineSelfModificationConfig } from "eve/self-modification/config";
5
+
6
+ export default defineSelfModificationConfig({
7
+ deployed: {
8
+ source: {
9
+ git: {
10
+ repository: ${JSON.stringify(e.repository)},
11
+ directory: ${JSON.stringify(e.directory)},
12
+ },
13
+ },
14
+ target: { branch: ${JSON.stringify(e.branch)} },
15
+ credentials: {
16
+ vercelConnect: { connector: ${JSON.stringify(e.connector)} },
17
+ },
18
+ },
19
+ });
20
+ `;return`// eve-self-modification: generated-v1 digest:${createHash(`sha256`).update(t).digest(`hex`)}\n${t}`}function classifySelfModificationConfig(e){if(e===void 0)return`missing`;if(e===renderSelfModificationConfig())return`local`;let[t,...n]=e.split(`
21
+ `);return/^\/\/ eve-self-modification: generated-v1 digest:([a-f0-9]{64})$/u.exec(t??``)?.[1]===createHash(`sha256`).update(n.join(`
22
+ `)).digest(`hex`)?`generated`:`authored`}function parseGitHubRemote(e){let t=e.trim().match(/^(?:https?:\/\/github\.com\/|git@github\.com:|ssh:\/\/git@github\.com\/)([^/]+)\/([^/]+?)(?:\.git)?$/u);return t?.[1]===void 0||t[2]===void 0?void 0:{owner:t[1],repo:t[2]}}function defaultSelfModificationSetupOperations(e){let t=join(e,SELF_MODIFICATION_CONFIG_PATH);return{async detectGitRepository(){let t=await gitOutput(e,[`config`,`--get`,`remote.origin.url`]),n=t===void 0?void 0:parseGitHubRemote(t),r=await gitOutput(e,[`symbolic-ref`,`--quiet`,`--short`,`refs/remotes/origin/HEAD`]),i=await gitOutput(e,[`rev-parse`,`--show-toplevel`]);return{...n,branch:r?.replace(/^origin\//u,``),directory:i===void 0?void 0:repositoryRelativeDirectory(i,e),remoteKind:t===void 0?`missing`:n===void 0?`other`:`github`}},async readConfig(){try{return await readFile(t,`utf8`)}catch(e){if(e.code===`ENOENT`)return;throw e}},writeConfig:e=>writeFile(t,e,`utf8`),async findOrCreateConnector(t){let n=await vercel(e,[`connect`,`list`,`-F`,`json`]);if(!n.ok)throw Error(`Vercel Connect requires an authenticated Vercel CLI linked to this project.`);let r=parseConnectors(n.stdout),i=`github/${t}`,a=r.find(e=>e.uid===i);if(a!==void 0){if(a.type!==`github`)throw Error(`The existing connector ${i} is not a GitHub connector.`);return a.uid}let o=await vercel(e,[`connect`,`create`,`github`,`--name`,t,`-F`,`json`]),s=o.ok?parseCreatedConnector(o.stdout):void 0;if(s===void 0||!s.startsWith(`github/`))throw Error(`Could not create a GitHub Vercel Connect connector.`);return s},async attachConnector(t){let n=await readLinkedProject(e);if(n===void 0)throw Error("Vercel Connect requires this directory to be linked to a Vercel project. Run `vercel link` and retry.");if(!(await vercel(e,[`connect`,`attach`,t,`--project`,n.projectId,`--environment`,`production`,`--yes`])).ok)throw Error(`Could not attach ${t} to the linked Vercel project for Production.`)}}}function parseCreatedConnector(e){try{let t=JSON.parse(e);return typeof t.uid==`string`?t.uid:void 0}catch{return}}function parseConnectors(e){try{let t=JSON.parse(e);return(Array.isArray(t.connectors)?t.connectors:[t]).flatMap(e=>typeof e==`object`&&e&&typeof e.uid==`string`&&typeof e.type==`string`?[{uid:e.uid,type:e.type}]:[])}catch{return[]}}async function vercel(e,t){try{return{ok:!0,stdout:(await runFile(`vercel`,t,{cwd:e})).stdout}}catch{return{ok:!1,stdout:``}}}async function readLinkedProject(e){try{let t=JSON.parse(await readFile(join(e,`.vercel`,`project.json`),`utf8`));return typeof t.projectId==`string`?{projectId:t.projectId}:void 0}catch{return}}function repositoryRelativeDirectory(e,t,n=relative){return n(e,t).replaceAll(`\\`,`/`)||`.`}function repositoryPartError(e){return/^[A-Za-z0-9_.-]+$/u.test(e)?void 0:`Enter a valid GitHub owner or repository name.`}function directoryError(e){return e===`.`||e.length>0&&!e.startsWith(`/`)&&!e.includes(`\\`)&&e.split(`/`).every(e=>e!==``&&e!==`.`&&e!==`..`)?void 0:`Enter a safe repository-relative directory or ".".`}function gitRefError(e){return/^[A-Za-z0-9][A-Za-z0-9._/-]*$/u.test(e)&&!e.endsWith(`.`)&&!e.endsWith(`/`)&&!e.includes(`..`)&&!e.includes(`//`)&&!e.includes(`@{`)?void 0:`Enter a valid branch name.`}async function gitOutput(e,t){try{return(await runFile(`git`,t,{cwd:e})).stdout.trim()||void 0}catch{return}}export{classifySelfModificationConfig,connectorName,defaultSelfModificationSetupOperations,directoryError,gitRefError,parseGitHubRemote,renderSelfModificationConfig,repositoryPartError,repositoryRelativeDirectory};
@@ -0,0 +1,2 @@
1
+ /** Serializes operations that require an exclusive view of one self-modification workspace. */
2
+ export declare function withSelfModificationWorkspaceLock<T>(workspaceKey: string, operation: () => Promise<T>): Promise<T>;
@@ -0,0 +1 @@
1
+ const workspaceTails=new Map;async function withSelfModificationWorkspaceLock(e,t){let n=workspaceTails.get(e)??Promise.resolve(),r,i=new Promise(e=>{r=e}),a=n.then(()=>i);workspaceTails.set(e,a),await n;try{return await t()}finally{r(),workspaceTails.get(e)===a&&workspaceTails.delete(e)}}export{withSelfModificationWorkspaceLock};
@@ -1 +1 @@
1
- import{DISCORD_SETUP}from"./discord/setup.js";import{FILE_MEMORY_SETUP}from"./file-memory/setup.js";import{GITHUB_SETUP}from"./github/setup.js";import{LINEAR_SETUP}from"./linear/setup.js";import{LINQ_SETUP}from"./linq/setup.js";import{PHOTON_SETUP}from"./photon/setup.js";import{SHOPIFY_SETUP}from"./shopify/setup.js";import{SLACK_SETUP}from"./slack/setup.js";import{WEB_SETUP}from"./web/setup.js";import{createSetupContexts,createSetupPresenter}from"./shared/ui.js";const SETUP_INTEGRATIONS=[WEB_SETUP,FILE_MEMORY_SETUP,SLACK_SETUP,DISCORD_SETUP,GITHUB_SETUP,LINEAR_SETUP,LINQ_SETUP,PHOTON_SETUP,SHOPIFY_SETUP];function setupIntegration(e){let t=SETUP_INTEGRATIONS.find(t=>t.kind===e);if(t===void 0)throw Error(`Integration setup "${e}" is not available in this version of eve. Upgrade eve and try again.`);return t}export{SETUP_INTEGRATIONS,createSetupContexts,createSetupPresenter,setupIntegration};
1
+ import{DISCORD_SETUP}from"./discord/setup.js";import{FILE_MEMORY_SETUP}from"./file-memory/setup.js";import{GITHUB_SETUP}from"./github/setup.js";import{LINEAR_SETUP}from"./linear/setup.js";import{LINQ_SETUP}from"./linq/setup.js";import{PHOTON_SETUP}from"./photon/setup.js";import{SELF_MODIFICATION_PRODUCTION_SETUP,SELF_MODIFICATION_SETUP}from"./self-modification/setup.js";import{SHOPIFY_SETUP}from"./shopify/setup.js";import{SLACK_SETUP}from"./slack/setup.js";import{WEB_SETUP}from"./web/setup.js";import{createSetupContexts,createSetupPresenter}from"./shared/ui.js";const SETUP_INTEGRATIONS=[WEB_SETUP,FILE_MEMORY_SETUP,SLACK_SETUP,DISCORD_SETUP,GITHUB_SETUP,LINEAR_SETUP,LINQ_SETUP,PHOTON_SETUP,SHOPIFY_SETUP,SELF_MODIFICATION_SETUP,SELF_MODIFICATION_PRODUCTION_SETUP];function setupIntegration(e){let t=SETUP_INTEGRATIONS.find(t=>t.kind===e);if(t===void 0)throw Error(`Integration setup "${e}" is not available in this version of eve. Upgrade eve and try again.`);return t}export{SETUP_INTEGRATIONS,createSetupContexts,createSetupPresenter,setupIntegration};
@@ -1 +1 @@
1
- import{createSetupContexts}from"./shared/ui.js";import{setupIntegration}from"./registry.js";import{describeIntegrationSetupEnvironment,integrationSetupEnvironment}from"./shared/environment.js";import{resolveIntegrationVercelProject}from"./shared/vercel-project.js";import{detectDeployment,projectResolutionFromDeployment}from"#setup/project-resolution.js";import{interactiveAsker}from"#setup/ask.js";import{getVercelAuthStatus}from"#setup/vercel-project.js";const defaultDeps={detectDeployment,getVercelAuthStatus};async function runIntegrationSetup(e,t,n=defaultDeps){let r=setupIntegration(e);t.prompter.intro(`Set up ${r.label}`,r.hint),t.prompter.log.message(`Checking Vercel setup...`);let[i,a]=await Promise.all([n.detectDeployment(t.appRoot,{signal:t.signal}),n.getVercelAuthStatus(t.appRoot,{signal:t.signal})]),o=projectResolutionFromDeployment(i),s=integrationSetupEnvironment(a,o);return t.prompter.log.info(describeIntegrationSetupEnvironment(s)),r.run(createSetupContexts({appRoot:t.appRoot,asker:t.asker??interactiveAsker(t.prompter),environment:s,prompter:t.prompter,resolveVercelProject:t.resolveVercelProject??(e=>resolveIntegrationVercelProject({appRoot:t.appRoot,integration:e,signal:t.signal})),signal:t.signal,force:t.force,beginExternalAction:t.beginExternalAction}))}export{runIntegrationSetup};
1
+ import{describeIntegrationSetupEnvironment,integrationSetupEnvironment}from"./shared/environment.js";import{createSetupContexts}from"./shared/ui.js";import{setupIntegration}from"./registry.js";import{resolveIntegrationVercelProject}from"./shared/vercel-project.js";import{detectDeployment,projectResolutionFromDeployment}from"#setup/project-resolution.js";import{interactiveAsker}from"#setup/ask.js";import{getVercelAuthStatus}from"#setup/vercel-project.js";const defaultDeps={detectDeployment,getVercelAuthStatus};async function runIntegrationSetup(e,t,n=defaultDeps){let r=setupIntegration(e);t.prompter.intro(`Set up ${r.label}`,r.hint),t.prompter.log.message(`Checking Vercel setup...`);let[i,a]=await Promise.all([n.detectDeployment(t.appRoot,{signal:t.signal}),n.getVercelAuthStatus(t.appRoot,{signal:t.signal})]),o=projectResolutionFromDeployment(i),s=integrationSetupEnvironment(a,o);return t.prompter.log.info(r.describeEnvironment?.(s)??describeIntegrationSetupEnvironment(s)),r.run(createSetupContexts({appRoot:t.appRoot,asker:t.asker??interactiveAsker(t.prompter),environment:s,prompter:t.prompter,resolveVercelProject:t.resolveVercelProject??(e=>resolveIntegrationVercelProject({appRoot:t.appRoot,integration:e,signal:t.signal})),signal:t.signal,force:t.force,beginExternalAction:t.beginExternalAction}))}export{runIntegrationSetup};
@@ -0,0 +1,29 @@
1
+ import { type SelfModificationSetupOperations, type SelfModificationSetupValues } from "#self-modification/setup.js";
2
+ import { type SetupApplyContext, type SetupPrepareContext } from "../types.js";
3
+ type SelfModificationSetupPlan = {
4
+ readonly kind: "authored";
5
+ } | {
6
+ readonly kind: "local";
7
+ } | {
8
+ readonly kind: "deployed";
9
+ readonly connectorName: string;
10
+ readonly values: SelfModificationSetupValues;
11
+ };
12
+ export declare function prepareSelfModificationSetup(context: SetupPrepareContext, operations?: SelfModificationSetupOperations): Promise<SelfModificationSetupPlan>;
13
+ export declare function applySelfModificationSetup(plan: SelfModificationSetupPlan, context: SetupApplyContext, operations?: SelfModificationSetupOperations): Promise<{
14
+ facts: {
15
+ label: string;
16
+ value: string;
17
+ }[];
18
+ deploymentRequired?: undefined;
19
+ } | {
20
+ deploymentRequired: true;
21
+ facts: {
22
+ label: string;
23
+ value: string;
24
+ }[];
25
+ }>;
26
+ export declare function prepareLocalSelfModificationSetup(context: SetupPrepareContext, operations?: SelfModificationSetupOperations): Promise<SelfModificationSetupPlan>;
27
+ export declare const SELF_MODIFICATION_SETUP: import("../types.js").SetupIntegration;
28
+ export declare const SELF_MODIFICATION_PRODUCTION_SETUP: import("../types.js").SetupIntegration;
29
+ export {};
@@ -0,0 +1 @@
1
+ import{defineSetupIntegration}from"../types.js";import{describeIntegrationSetupEnvironment}from"../shared/environment.js";import{confirm,text}from"#setup/ask.js";import{classifySelfModificationConfig,connectorName,defaultSelfModificationSetupOperations,directoryError,gitRefError,renderSelfModificationConfig,repositoryPartError}from"#self-modification/setup.js";import{SELF_MODIFICATION_CONFIG_PATH}from"#self-modification/git-workspace.js";function validationResult(e){return e??null}async function prepareSelfModificationSetup(e,t=defaultSelfModificationSetupOperations(e.appRoot)){let n=await t.readConfig();if(classifySelfModificationConfig(n)===`authored`)return e.presenter.note(`The existing ${SELF_MODIFICATION_CONFIG_PATH} contains authored configuration and was not overwritten.`,`Manual update required`,{tone:`warning`}),{kind:`authored`};let r=await t.detectGitRepository(),i=await e.asker.ask(text({key:`self-modification-repository-owner`,message:`GitHub repository owner`,detected:r.owner,required:!0,validate:e=>validationResult(repositoryPartError(e))})),a=await e.asker.ask(text({key:`self-modification-repository-name`,message:`GitHub repository name`,detected:r.repo,required:!0,validate:e=>validationResult(repositoryPartError(e))})),o=await e.asker.ask(text({key:`self-modification-repository-directory`,message:`Application directory relative to the repository root`,detected:r.directory??`.`,required:!0,validate:e=>validationResult(directoryError(e))})),s=await e.asker.ask(text({key:`self-modification-target-branch`,message:`Target branch`,detected:r.branch??`main`,required:!0,validate:e=>validationResult(gitRefError(e))})),c=connectorName(i,a),l={branch:s,connector:`github/${c}`,directory:o,repository:`github.com/${i}/${a}`};return e.presenter.note(renderSelfModificationConfig(l),`Generated ${SELF_MODIFICATION_CONFIG_PATH}`),e.presenter.note(`Vercel Connect will issue short-lived GitHub App credentials restricted to this repository. Install the managed GitHub App and select only this repository. Review, merge, and deployment remain separate operator boundaries.`,`Security summary`),await e.asker.ask(confirm({key:`self-modification-confirm`,message:`Create or attach this GitHub connector and write this configuration?`,recommended:!1,required:!0}))?{kind:`deployed`,connectorName:c,values:l}:{kind:`local`}}async function applySelfModificationSetup(e,t,n=defaultSelfModificationSetupOperations(t.appRoot)){if(e.kind===`authored`)return{facts:[{label:`Self-modification`,value:`manual configuration update required`}]};if(e.kind===`local`)return{facts:[{label:`Self-modification`,value:`local editing`}]};let r=await n.findOrCreateConnector(e.connectorName);return await n.attachConnector(r),await n.writeConfig(renderSelfModificationConfig({...e.values,connector:r})),t.presenter.log.success(`Updated ${SELF_MODIFICATION_CONFIG_PATH}.`),t.presenter.nextSteps([`Install the managed GitHub App for the configured repository, then redeploy.`]),{deploymentRequired:!0,facts:[{label:`Repository`,value:e.values.repository},{label:`Application directory`,value:e.values.directory},{label:`Target branch`,value:e.values.branch},{label:`Credential`,value:r}]}}async function prepareLocalSelfModificationSetup(e,t=defaultSelfModificationSetupOperations(e.appRoot)){let n=await t.readConfig();return classifySelfModificationConfig(n)===`authored`?(e.presenter.note(`The existing ${SELF_MODIFICATION_CONFIG_PATH} contains authored configuration and was not overwritten.`,`Manual update required`,{tone:`warning`}),{kind:`authored`}):{kind:`local`}}function describeEnvironment(e){if(e.vercel.kind===`available`)return describeIntegrationSetupEnvironment(e);switch(e.vercel.reason){case`logged-out`:return`No authenticated Vercel account found. Local editing remains available; deployed proposals require Vercel Connect.`;case`cli-missing`:return`Vercel CLI not found. Local editing remains available; deployed proposals require Vercel Connect.`;case`unavailable`:return`Could not verify the Vercel account. Local editing remains available; deployed proposals require Vercel Connect.`}}const SELF_MODIFICATION_SETUP=defineSetupIntegration({kind:`self-modification`,label:`Self-modification`,hint:`Local source editing is enabled`,describeEnvironment,prepare:prepareLocalSelfModificationSetup,apply:applySelfModificationSetup}),SELF_MODIFICATION_PRODUCTION_SETUP=defineSetupIntegration({kind:`self-modification-production`,label:`Self-modification production`,hint:`Configure deployed draft pull requests`,describeEnvironment,prepare:prepareSelfModificationSetup,apply:applySelfModificationSetup});export{SELF_MODIFICATION_PRODUCTION_SETUP,SELF_MODIFICATION_SETUP,applySelfModificationSetup,prepareLocalSelfModificationSetup,prepareSelfModificationSetup};
@@ -39,6 +39,7 @@ interface SetupIntegrationDefinition<Plan> {
39
39
  readonly kind: string;
40
40
  readonly label: string;
41
41
  readonly hint?: string;
42
+ describeEnvironment?(environment: IntegrationSetupEnvironment): string;
42
43
  prepare(context: SetupPrepareContext): Promise<Plan>;
43
44
  apply(plan: Plan, context: SetupApplyContext): Promise<RegistrySetupCompletion>;
44
45
  }
@@ -46,6 +47,7 @@ export interface SetupIntegration {
46
47
  readonly kind: string;
47
48
  readonly label: string;
48
49
  hint?: string;
50
+ describeEnvironment?(environment: IntegrationSetupEnvironment): string;
49
51
  run(input: {
50
52
  prepare: SetupPrepareContext;
51
53
  apply: SetupApplyContext;
@@ -1 +1 @@
1
- import{WizardCancelledError}from"#setup/step.js";function defineSetupIntegration(e){let t={kind:e.kind,label:e.label,async run(t){try{let n=await e.prepare(t.prepare);return{kind:`done`,completion:await e.apply(n,t.apply)}}catch(e){if(e instanceof WizardCancelledError)return{kind:`cancelled`};throw e}}};return e.hint!==void 0&&(t.hint=e.hint),t}export{defineSetupIntegration};
1
+ import{WizardCancelledError}from"#setup/step.js";function defineSetupIntegration(e){let t={kind:e.kind,label:e.label,async run(t){try{let n=await e.prepare(t.prepare);return{kind:`done`,completion:await e.apply(n,t.apply)}}catch(e){if(e instanceof WizardCancelledError)return{kind:`cancelled`};throw e}}};return e.hint!==void 0&&(t.hint=e.hint),e.describeEnvironment!==void 0&&(t.describeEnvironment=e.describeEnvironment),t}export{defineSetupIntegration};
@@ -1,4 +1,4 @@
1
- import{pinnedNodeEngineMajor}from"../../node-engine.js";import{parseChatGptModelSelection}from"../../../shared/chatgpt-model.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{pathExists,writeTextFile}from"../files.js";import{blockingCreateInPlaceEntries}from"../create-in-place.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{mkdir,readdir,stat}from"node:fs/promises";import{basename,join,resolve}from"node:path";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,DEFAULT_AI_PACKAGE_VERSION=`^7.0.82`,DEFAULT_CONNECT_PACKAGE_VERSION=`1.0.0`,DEFAULT_ZOD_PACKAGE_VERSION=`4.5.4`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.52.3`,nodeEngine:`>=24`};function resolveEvePackageContract(e=DEFAULT_EVE_PACKAGE_CONTRACT){return{version:resolveVersionToken(`evePackage.version`,e.version),nodeEngine:resolveVersionToken(`evePackage.nodeEngine`,e.nodeEngine)}}function modelProviderSlug(e){let t=(e.split(`/`)[0]??``).replaceAll(/[^A-Za-z0-9._-]/gu,``);return t.length>0?t:`anthropic`}function byokProviderEnvVar(e){let t=modelProviderSlug(e).toUpperCase().replaceAll(/[^A-Z0-9]/gu,`_`);return`${/^[0-9]/.test(t)?`_`:``}${t}_API_KEY`}function agentTemplateFiles(e,t){return{"agent/agent.ts":renderAgentTemplate(e,t),"agent/channels/eve.ts":WEB_APP_TEMPLATE_FILES[`agent/channels/eve.ts`],"agent/instructions.md":AGENT_INSTRUCTIONS_TEMPLATE}}function renderAgentTemplate(e,t){let n=parseChatGptModelSelection(e);return n===void 0?BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(t)):`import { defineAgent } from "eve";\nimport { chatgpt } from "eve/models/openai";\n\nexport default defineAgent({\n model: chatgpt(${JSON.stringify(n)}),\n${reasoningTemplateLine(t)}});\n`}function reasoningTemplateLine(e){return e===void 0||e===`provider-default`?``:` reasoning: "${e}",\n`}function renderTemplate(e,t){return e===BASE_AGENT_TEMPLATE&&parseChatGptModelSelection(t.model)!==void 0?renderAgentTemplate(t.model,t.reasoning):e.replaceAll(`__EVE_INIT_APP_NAME__`,t.appName).replaceAll(`__EVE_INIT_MODEL__`,t.model).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(t.reasoning)).replaceAll(`__EVE_INIT_BYOK_PROVIDER__`,modelProviderSlug(t.model)).replaceAll(`__EVE_INIT_BYOK_ENV_VAR__`,byokProviderEnvVar(t.model)).replaceAll(`__EVE_INIT_PACKAGE_VERSION__`,formatEveDependencySpecifier(t.eveVersion)).replaceAll(`__EVE_INIT_AI_SDK_VERSION__`,t.aiPackageVersion).replaceAll(`__EVE_INIT_CONNECT_VERSION__`,t.connectPackageVersion).replaceAll(`__EVE_INIT_ZOD_VERSION__`,t.zodPackageVersion).replaceAll(`__EVE_INIT_TYPESCRIPT_VERSION__`,t.typescriptPackageVersion).replaceAll(`__EVE_INIT_TYPES_NODE_VERSION__`,t.nodeTypesVersion).replaceAll(`__EVE_INIT_NODE_ENGINE__`,t.nodeEngine)}function formatEveDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}const BASE_AGENT_TEMPLATE=`import { defineAgent } from "eve";
1
+ import{pinnedNodeEngineMajor}from"../../node-engine.js";import{parseChatGptModelSelection}from"../../../shared/chatgpt-model.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{pathExists,writeTextFile}from"../files.js";import{blockingCreateInPlaceEntries}from"../create-in-place.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{mkdir,readdir,stat}from"node:fs/promises";import{basename,join,resolve}from"node:path";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,DEFAULT_AI_PACKAGE_VERSION=`^7.0.82`,DEFAULT_CONNECT_PACKAGE_VERSION=`1.0.0`,DEFAULT_ZOD_PACKAGE_VERSION=`4.5.4`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.52.4`,nodeEngine:`>=24`};function resolveEvePackageContract(e=DEFAULT_EVE_PACKAGE_CONTRACT){return{version:resolveVersionToken(`evePackage.version`,e.version),nodeEngine:resolveVersionToken(`evePackage.nodeEngine`,e.nodeEngine)}}function modelProviderSlug(e){let t=(e.split(`/`)[0]??``).replaceAll(/[^A-Za-z0-9._-]/gu,``);return t.length>0?t:`anthropic`}function byokProviderEnvVar(e){let t=modelProviderSlug(e).toUpperCase().replaceAll(/[^A-Z0-9]/gu,`_`);return`${/^[0-9]/.test(t)?`_`:``}${t}_API_KEY`}function agentTemplateFiles(e,t){return{"agent/agent.ts":renderAgentTemplate(e,t),"agent/channels/eve.ts":WEB_APP_TEMPLATE_FILES[`agent/channels/eve.ts`],"agent/instructions.md":AGENT_INSTRUCTIONS_TEMPLATE}}function renderAgentTemplate(e,t){let n=parseChatGptModelSelection(e);return n===void 0?BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(t)):`import { defineAgent } from "eve";\nimport { chatgpt } from "eve/models/openai";\n\nexport default defineAgent({\n model: chatgpt(${JSON.stringify(n)}),\n${reasoningTemplateLine(t)}});\n`}function reasoningTemplateLine(e){return e===void 0||e===`provider-default`?``:` reasoning: "${e}",\n`}function renderTemplate(e,t){return e===BASE_AGENT_TEMPLATE&&parseChatGptModelSelection(t.model)!==void 0?renderAgentTemplate(t.model,t.reasoning):e.replaceAll(`__EVE_INIT_APP_NAME__`,t.appName).replaceAll(`__EVE_INIT_MODEL__`,t.model).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(t.reasoning)).replaceAll(`__EVE_INIT_BYOK_PROVIDER__`,modelProviderSlug(t.model)).replaceAll(`__EVE_INIT_BYOK_ENV_VAR__`,byokProviderEnvVar(t.model)).replaceAll(`__EVE_INIT_PACKAGE_VERSION__`,formatEveDependencySpecifier(t.eveVersion)).replaceAll(`__EVE_INIT_AI_SDK_VERSION__`,t.aiPackageVersion).replaceAll(`__EVE_INIT_CONNECT_VERSION__`,t.connectPackageVersion).replaceAll(`__EVE_INIT_ZOD_VERSION__`,t.zodPackageVersion).replaceAll(`__EVE_INIT_TYPESCRIPT_VERSION__`,t.typescriptPackageVersion).replaceAll(`__EVE_INIT_TYPES_NODE_VERSION__`,t.nodeTypesVersion).replaceAll(`__EVE_INIT_NODE_ENGINE__`,t.nodeEngine)}function formatEveDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}const BASE_AGENT_TEMPLATE=`import { defineAgent } from "eve";
2
2
 
3
3
  export default defineAgent({
4
4
  model: "__EVE_INIT_MODEL__",
@@ -1 +1 @@
1
- const EMPTY_DELIVERY_SENTINEL=`<eve-empty-delivery/>`,CONDITIONAL_DELIVERY_INSTRUCTION=`Conditional delivery\nOnly when the current task explicitly makes delivery conditional and there is nothing new to report, reply with exactly ${EMPTY_DELIVERY_SENTINEL} and no other text. This includes results already delivered or incorporated into an earlier response; do not send an acknowledgement of that redundancy. Do not use this marker for ordinary conversations, after input or approval responses, or to omit commentary from a response that still needs delivery. Never return an empty response; use the marker to intentionally deliver nothing.`;function hasEmptyDeliverySentinel(e){return e?.includes(`<eve-empty-delivery/>`)===!0||e?.includes(`&lt;eve-empty-delivery/&gt;`)===!0}export{CONDITIONAL_DELIVERY_INSTRUCTION,EMPTY_DELIVERY_SENTINEL,hasEmptyDeliverySentinel};
1
+ const EMPTY_DELIVERY_SENTINEL=`<eve-empty-delivery/>`,CONDITIONAL_DELIVERY_INSTRUCTION=`Conditional delivery\nOnly when the current task explicitly makes delivery conditional and there is nothing new to report, reply with exactly ${EMPTY_DELIVERY_SENTINEL} and no other text. This includes results already delivered or incorporated into an earlier response; do not send an acknowledgement of that redundancy. Do not use this marker for ordinary conversations, after input or approval responses, or to omit commentary from a response that still needs delivery. Never return an empty response; use the marker to intentionally deliver nothing.`;function hasEmptyDeliverySentinel(e){let t=e?.trim();return t===`<eve-empty-delivery/>`||t===`&lt;eve-empty-delivery/&gt;`}export{CONDITIONAL_DELIVERY_INSTRUCTION,EMPTY_DELIVERY_SENTINEL,hasEmptyDeliverySentinel};
@@ -0,0 +1,16 @@
1
+ import type { SandboxNetworkPolicy } from "./sandbox-network-policy.js";
2
+ /** Returns whether a value is a complete Git object SHA. */
3
+ export declare function isFullGitSha(value: string): boolean;
4
+ /** Returns whether a value can safely be used as a Git ref. */
5
+ export declare function isValidGitRef(value: string): boolean;
6
+ /** Builds the token-free HTTPS remote used by GitHub fetches. */
7
+ export declare function gitHubRemoteUrl(input: {
8
+ readonly owner: string;
9
+ readonly repo: string;
10
+ }): string;
11
+ /**
12
+ * Brokers a GitHub installation token at the sandbox firewall without exposing
13
+ * it to the process running git. codeload.github.com is required for redirects
14
+ * from shallow fetches.
15
+ */
16
+ export declare function gitHubGitBrokerNetworkPolicy(token: string): SandboxNetworkPolicy;
@@ -0,0 +1 @@
1
+ import{Buffer}from"node:buffer";function isFullGitSha(e){return/^[a-f0-9]{40}$/iu.test(e)}function isValidGitRef(e){return!(e.length===0||e.startsWith(`-`)||e.endsWith(`.`)||e.endsWith(`/`)||e.includes(`..`)||e.includes(`//`)||e.includes(`@{`)||e.includes(`\\`)||e.split(`/`).some(e=>e.length===0||e.endsWith(`.lock`))||/[\x00-\x20~^:?*[]/u.test(e))}function gitHubRemoteUrl(e){return`https://github.com/${e.owner}/${e.repo}.git`}function gitHubGitBrokerNetworkPolicy(e){let t=[{transform:[{headers:{Authorization:`Basic ${Buffer.from(`x-access-token:${e}`).toString(`base64`)}`}}]}];return{allow:{"*":[],"github.com":t,"codeload.github.com":t}}}export{gitHubGitBrokerNetworkPolicy,gitHubRemoteUrl,isFullGitSha,isValidGitRef};
@@ -0,0 +1,2 @@
1
+ /** Wraps a value in POSIX single quotes, escaping embedded single quotes. */
2
+ export declare function shellQuote(value: string): string;
@@ -0,0 +1 @@
1
+ function shellQuote(e){return`'${e.replaceAll(`'`,`'\\''`)}'`}export{shellQuote};
@@ -1 +1 @@
1
- import{mkdir,readFile}from"node:fs/promises";import{EVE_ROUTE_PREFIX}from"#protocol/routes.js";import{dirname,join,relative}from"node:path";import{EVE_INTERNAL_BUILD_OUTPUT_DIRECTORY_ENV,EVE_INTERNAL_HOST_BUILD_OUTPUT_DIRECTORY_ENV}from"#internal/application/paths.js";import{findClosestLinkedVercelDirectory}from"#shared/vercel-output-directory.js";import{resolveEveBinaryPath}from"#shared/resolve-eve-binary.js";const VERCEL_JSON_FILE_NAME=`vercel.json`,EVE_SERVICE_ROUTE_SRC=`^${EVE_ROUTE_PREFIX}/(.*)$`,EVE_SERVICE_ROUTE_PATH=`${EVE_ROUTE_PREFIX}/$1`;function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function toPosixRelative(e,t){let n=relative(e,t);return n.length===0?`.`:n.replaceAll(`\\`,`/`)}function quoteShellArgument(e){return`'${e.replaceAll(`'`,`'\\''`)}'`}function isNamedServiceConfigArray(e){return Array.isArray(e)}function createServiceConfigRecord(e){if(e===void 0)return{};if(isNamedServiceConfigArray(e)){let t={};for(let n of e)if(typeof n.name==`string`&&n.name.trim().length>0){let{name:e,...r}=n;t[e]=r}return t}return e}function normalizeVercelJsonConfig(e){if(!isRecord(e))throw Error(`${VERCEL_JSON_FILE_NAME} must contain a JSON object.`);let t=e.services;if(t!==void 0&&!isRecord(t)&&!(Array.isArray(t)&&t.every(e=>isRecord(e)&&typeof e.name==`string`&&e.name.trim().length>0)))throw Error(`${VERCEL_JSON_FILE_NAME} services must be a JSON object or named service array.`);return e}async function readVercelJsonConfig(e){try{return normalizeVercelJsonConfig(JSON.parse(await readFile(e,`utf8`)))}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return{};throw e}}function findEveService(e){return Object.values(e).find(e=>e.framework===`eve`)}function assertRootServicesIncludeEve(e,t){if(findEveService(e)===void 0)throw Error(`${VERCEL_JSON_FILE_NAME} already defines services, so the eve ${t} integration cannot add a generated eve service. Add an eve service (framework "eve") and a rewrite from ${EVE_ROUTE_PREFIX}/(.*) to it in ${VERCEL_JSON_FILE_NAME}, or remove services from ${VERCEL_JSON_FILE_NAME}.`)}function createEveServiceRoute(e=`eve`){return{destination:{service:e,type:`service`},src:EVE_SERVICE_ROUTE_SRC}}function createEveServiceRequestPathRoute(){return{src:EVE_SERVICE_ROUTE_SRC,transforms:[{args:EVE_SERVICE_ROUTE_PATH,op:`set`,type:`request.path`}]}}function isEveServiceRoute(e,t){let n=e.destination;return e.src===EVE_SERVICE_ROUTE_SRC&&isRecord(n)&&n.type===`service`&&n.service===t}function insertEveServiceRoute(e,t){let n=e.filter(e=>!(isRecord(e)&&isEveServiceRoute(e,t))),r=n.findIndex(e=>isRecord(e)&&e.handle===`filesystem`);return r===-1?[createEveServiceRoute(t),...n]:[...n.slice(0,r),createEveServiceRoute(t),...n.slice(r)]}function insertEveServiceRequestPathRoute(e){let t=(e??[]).filter(e=>e.src!==EVE_SERVICE_ROUTE_SRC);return[createEveServiceRequestPathRoute(),...t]}function createGeneratedServiceBuild(e){let t=join(e.hostRoot,`.eve/vercel-services`,`eve`),n=join(t,`.vercel`,`output`),r=join(e.hostRoot,`.vercel`,`output`),i=toPosixRelative(t,e.appRoot),a=toPosixRelative(e.appRoot,n),o=toPosixRelative(e.appRoot,r),s=e.eveBuildCommand??`node ${quoteShellArgument(toPosixRelative(e.appRoot,resolveEveBinaryPath(e.hostRoot)))} build`;return{buildCommand:`cd ${quoteShellArgument(i)} && export ${EVE_INTERNAL_BUILD_OUTPUT_DIRECTORY_ENV}=${quoteShellArgument(a)} && export ${EVE_INTERNAL_HOST_BUILD_OUTPUT_DIRECTORY_ENV}=${quoteShellArgument(o)} && ${s}`,root:toPosixRelative(e.hostRoot,t),rootDirectory:t}}async function ensureEveVercelServicesConfig(e){let t=await findClosestLinkedVercelDirectory(e.hostRoot),n=t===void 0?e.hostRoot:dirname(t),r=await readVercelJsonConfig(join(e.hostRoot,VERCEL_JSON_FILE_NAME)),i=n===e.hostRoot||Object.keys(createServiceConfigRecord(r.services)).length>0?r:await readVercelJsonConfig(join(n,VERCEL_JSON_FILE_NAME)),a=createServiceConfigRecord(i.services);if(Object.keys(a).length>0)return assertRootServicesIncludeEve(a,e.frameworkName),{mode:`root`};i.experimentalServices!==void 0&&console.warn(`[eve] ${VERCEL_JSON_FILE_NAME} defines experimentalServices, which Vercel no longer routes. The eve ${e.frameworkName} integration now generates the stable services config automatically — remove experimentalServices from ${VERCEL_JSON_FILE_NAME}.`);let o=createGeneratedServiceBuild(e);return await mkdir(o.rootDirectory,{recursive:!0}),{mode:`generated`,services:{eve:{buildCommand:o.buildCommand,framework:`eve`,routes:[createEveServiceRequestPathRoute()],root:o.root}}}}function mergeEveVercelConfig(e,t){let n=e?.services??{},r=Object.entries(n).find(([e,t])=>e===`eve`||t.framework===`eve`),i=r?.[0]??`eve`,a=r?{...n,[i]:{...r[1],routes:insertEveServiceRequestPathRoute(r[1].routes)}}:{...n,...t.services};return{version:3,...e,routes:insertEveServiceRoute(e?.routes??[],i),services:a}}export{createEveServiceRequestPathRoute,createEveServiceRoute,ensureEveVercelServicesConfig,mergeEveVercelConfig};
1
+ import{mkdir,readFile}from"node:fs/promises";import{EVE_ROUTE_PREFIX}from"#protocol/routes.js";import{dirname,join,relative}from"node:path";import{EVE_INTERNAL_BUILD_OUTPUT_DIRECTORY_ENV,EVE_INTERNAL_HOST_BUILD_OUTPUT_DIRECTORY_ENV}from"#internal/application/paths.js";import{shellQuote}from"#shared/shell-quote.js";import{findClosestLinkedVercelDirectory}from"#shared/vercel-output-directory.js";import{resolveEveBinaryPath}from"#shared/resolve-eve-binary.js";const VERCEL_JSON_FILE_NAME=`vercel.json`,EVE_SERVICE_ROUTE_SRC=`^${EVE_ROUTE_PREFIX}/(.*)$`,EVE_SERVICE_ROUTE_PATH=`${EVE_ROUTE_PREFIX}/$1`;function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function toPosixRelative(e,t){let n=relative(e,t);return n.length===0?`.`:n.replaceAll(`\\`,`/`)}function isNamedServiceConfigArray(e){return Array.isArray(e)}function createServiceConfigRecord(e){if(e===void 0)return{};if(isNamedServiceConfigArray(e)){let t={};for(let n of e)if(typeof n.name==`string`&&n.name.trim().length>0){let{name:e,...r}=n;t[e]=r}return t}return e}function normalizeVercelJsonConfig(e){if(!isRecord(e))throw Error(`${VERCEL_JSON_FILE_NAME} must contain a JSON object.`);let t=e.services;if(t!==void 0&&!isRecord(t)&&!(Array.isArray(t)&&t.every(e=>isRecord(e)&&typeof e.name==`string`&&e.name.trim().length>0)))throw Error(`${VERCEL_JSON_FILE_NAME} services must be a JSON object or named service array.`);return e}async function readVercelJsonConfig(e){try{return normalizeVercelJsonConfig(JSON.parse(await readFile(e,`utf8`)))}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return{};throw e}}function findEveService(e){return Object.values(e).find(e=>e.framework===`eve`)}function assertRootServicesIncludeEve(e,t){if(findEveService(e)===void 0)throw Error(`${VERCEL_JSON_FILE_NAME} already defines services, so the eve ${t} integration cannot add a generated eve service. Add an eve service (framework "eve") and a rewrite from ${EVE_ROUTE_PREFIX}/(.*) to it in ${VERCEL_JSON_FILE_NAME}, or remove services from ${VERCEL_JSON_FILE_NAME}.`)}function createEveServiceRoute(e=`eve`){return{destination:{service:e,type:`service`},src:EVE_SERVICE_ROUTE_SRC}}function createEveServiceRequestPathRoute(){return{src:EVE_SERVICE_ROUTE_SRC,transforms:[{args:EVE_SERVICE_ROUTE_PATH,op:`set`,type:`request.path`}]}}function isEveServiceRoute(e,t){let n=e.destination;return e.src===EVE_SERVICE_ROUTE_SRC&&isRecord(n)&&n.type===`service`&&n.service===t}function insertEveServiceRoute(e,t){let n=e.filter(e=>!(isRecord(e)&&isEveServiceRoute(e,t))),r=n.findIndex(e=>isRecord(e)&&e.handle===`filesystem`);return r===-1?[createEveServiceRoute(t),...n]:[...n.slice(0,r),createEveServiceRoute(t),...n.slice(r)]}function insertEveServiceRequestPathRoute(e){let t=(e??[]).filter(e=>e.src!==EVE_SERVICE_ROUTE_SRC);return[createEveServiceRequestPathRoute(),...t]}function createGeneratedServiceBuild(e){let t=join(e.hostRoot,`.eve/vercel-services`,`eve`),n=join(t,`.vercel`,`output`),r=join(e.hostRoot,`.vercel`,`output`),i=toPosixRelative(t,e.appRoot),a=toPosixRelative(e.appRoot,n),o=toPosixRelative(e.appRoot,r),s=e.eveBuildCommand??`node ${shellQuote(toPosixRelative(e.appRoot,resolveEveBinaryPath(e.hostRoot)))} build`;return{buildCommand:`cd ${shellQuote(i)} && export ${EVE_INTERNAL_BUILD_OUTPUT_DIRECTORY_ENV}=${shellQuote(a)} && export ${EVE_INTERNAL_HOST_BUILD_OUTPUT_DIRECTORY_ENV}=${shellQuote(o)} && ${s}`,root:toPosixRelative(e.hostRoot,t),rootDirectory:t}}async function ensureEveVercelServicesConfig(e){let t=await findClosestLinkedVercelDirectory(e.hostRoot),n=t===void 0?e.hostRoot:dirname(t),r=await readVercelJsonConfig(join(e.hostRoot,VERCEL_JSON_FILE_NAME)),i=n===e.hostRoot||Object.keys(createServiceConfigRecord(r.services)).length>0?r:await readVercelJsonConfig(join(n,VERCEL_JSON_FILE_NAME)),a=createServiceConfigRecord(i.services);if(Object.keys(a).length>0)return assertRootServicesIncludeEve(a,e.frameworkName),{mode:`root`};i.experimentalServices!==void 0&&console.warn(`[eve] ${VERCEL_JSON_FILE_NAME} defines experimentalServices, which Vercel no longer routes. The eve ${e.frameworkName} integration now generates the stable services config automatically — remove experimentalServices from ${VERCEL_JSON_FILE_NAME}.`);let o=createGeneratedServiceBuild(e);return await mkdir(o.rootDirectory,{recursive:!0}),{mode:`generated`,services:{eve:{buildCommand:o.buildCommand,framework:`eve`,routes:[createEveServiceRequestPathRoute()],root:o.root}}}}function mergeEveVercelConfig(e,t){let n=e?.services??{},r=Object.entries(n).find(([e,t])=>e===`eve`||t.framework===`eve`),i=r?.[0]??`eve`,a=r?{...n,[i]:{...r[1],routes:insertEveServiceRequestPathRoute(r[1].routes)}}:{...n,...t.services};return{version:3,...e,routes:insertEveServiceRoute(e?.routes??[],i),services:a}}export{createEveServiceRequestPathRoute,createEveServiceRoute,ensureEveVercelServicesConfig,mergeEveVercelConfig};
@@ -10,7 +10,7 @@ import { type TaskMetadata, type TaskView } from "#tasks/types.js";
10
10
  * threads through step results, while callback routes and child
11
11
  * executors must update tasks without holding the current snapshot.
12
12
  */
13
- export declare const SESSION_TASKS_STATE_KEY = "eve.tasks";
13
+ export { SESSION_TASKS_STATE_KEY } from "#tasks/session-task-cohorts.js";
14
14
  /**
15
15
  * One task owned by this session. Immutable model-safe metadata keeps the
16
16
  * task-to-agent join available before the task run publishes its first view.
@@ -1 +1 @@
1
- import{z}from"#compiled/zod/index.js";import{sameTaskMetadata}from"#tasks/types.js";const SESSION_TASKS_STATE_KEY=`eve.tasks`,taskMetadataSchema=z.looseObject({kind:z.string().min(1),name:z.string().min(1)}),taskViewBaseShape={executor:z.strictObject({binding:z.strictObject({data:z.record(z.string(),z.custom()),kind:z.string().min(1)}).optional()}).optional(),metadata:taskMetadataSchema,taskId:z.string().min(1),usage:z.strictObject({cacheReadTokens:z.number().nonnegative(),cacheWriteTokens:z.number().nonnegative(),inputTokens:z.number().nonnegative(),outputTokens:z.number().nonnegative()}).optional()},taskViewSchema=z.discriminatedUnion(`status`,[z.strictObject({...taskViewBaseShape,lastOutput:z.strictObject({data:z.custom(),type:z.literal(`result`)}),status:z.literal(`completed`)}),z.strictObject({...taskViewBaseShape,lastOutput:z.strictObject({data:z.custom(),type:z.literal(`error`)}),status:z.literal(`failed`)}),z.strictObject({...taskViewBaseShape,status:z.literal(`cancelled`)})]),sessionTaskIndexEntrySchema=z.strictObject({taskInboxToken:z.string().min(1),createdByStepIndex:z.number().int().nonnegative().optional(),createdByTurnId:z.string().min(1),executor:z.strictObject({data:z.record(z.string(),z.custom()),kind:z.string().min(1)}).optional(),metadata:taskMetadataSchema,taskId:z.string().min(1),taskRunId:z.string().min(1),terminalView:taskViewSchema.optional()}),sessionTaskIndexSchema=z.strictObject({tasks:z.array(sessionTaskIndexEntrySchema),version:z.literal(2)}).refine(e=>new Set(e.tasks.map(e=>e.taskId)).size===e.tasks.length,{message:`Task ids must be unique.`}).refine(e=>e.tasks.every(e=>e.terminalView===void 0||e.terminalView.taskId===e.taskId&&sameTaskMetadata(e.terminalView.metadata,e.metadata)),{message:`Cached terminal views must match their task index entry.`});function getSessionTaskIndex(e){let t=e?.[SESSION_TASKS_STATE_KEY];if(t===void 0)return[];let n=typeof t==`object`&&t?Reflect.get(t,`version`):void 0;if(n!==2)throw Error(`Unsupported task index version ${JSON.stringify(n)} under session state key "${SESSION_TASKS_STATE_KEY}"; expected version 2.`);let r=sessionTaskIndexSchema.safeParse(t);if(!r.success)throw Error(`Corrupt task index under session state key "${SESSION_TASKS_STATE_KEY}": ${r.error.message}`);return r.data.tasks}function cacheTerminalTaskView(e,t){if(!isValidTerminalView(t))throw Error(`Cannot cache invalid terminal task "${t.taskId}".`);let n=getSessionTaskIndex(e),r=n.findIndex(e=>e.taskId===t.taskId);if(r<0)return e;if(!sameTaskMetadata(n[r].metadata,t.metadata))throw Error(`Task view metadata does not match index entry "${t.taskId}".`);let i=[...n];return i[r]={...i[r],terminalView:t},{...e,[SESSION_TASKS_STATE_KEY]:{tasks:i,version:2}}}function isValidTerminalView(e){if(e.inputRequests!==void 0)return!1;switch(e.status){case`completed`:return e.lastOutput?.type===`result`;case`failed`:return e.lastOutput?.type===`error`;case`cancelled`:return e.lastOutput===void 0;case`working`:return!1}}function findSessionTaskEntry(e,t){return getSessionTaskIndex(e).find(e=>e.taskId===t)}function recordSessionTask(e,t){let n=[...getSessionTaskIndex(e.state).filter(e=>e.taskId!==t.taskId),t];return{...e,state:{...e.state,[SESSION_TASKS_STATE_KEY]:{tasks:n,version:2}}}}export{SESSION_TASKS_STATE_KEY,cacheTerminalTaskView,findSessionTaskEntry,getSessionTaskIndex,recordSessionTask};
1
+ import{z}from"#compiled/zod/index.js";import{SESSION_TASKS_STATE_KEY,SESSION_TASKS_STATE_KEY as SESSION_TASKS_STATE_KEY$1,SESSION_TASKS_STATE_VERSION}from"#tasks/session-task-cohorts.js";import{sameTaskMetadata}from"#tasks/types.js";const taskMetadataSchema=z.looseObject({kind:z.string().min(1),name:z.string().min(1)}),taskViewBaseShape={executor:z.strictObject({binding:z.strictObject({data:z.record(z.string(),z.custom()),kind:z.string().min(1)}).optional()}).optional(),metadata:taskMetadataSchema,taskId:z.string().min(1),usage:z.strictObject({cacheReadTokens:z.number().nonnegative(),cacheWriteTokens:z.number().nonnegative(),inputTokens:z.number().nonnegative(),outputTokens:z.number().nonnegative()}).optional()},taskViewSchema=z.discriminatedUnion(`status`,[z.strictObject({...taskViewBaseShape,lastOutput:z.strictObject({data:z.custom(),type:z.literal(`result`)}),status:z.literal(`completed`)}),z.strictObject({...taskViewBaseShape,lastOutput:z.strictObject({data:z.custom(),type:z.literal(`error`)}),status:z.literal(`failed`)}),z.strictObject({...taskViewBaseShape,status:z.literal(`cancelled`)})]),sessionTaskIndexEntrySchema=z.strictObject({taskInboxToken:z.string().min(1),createdByStepIndex:z.number().int().nonnegative().optional(),createdByTurnId:z.string().min(1),executor:z.strictObject({data:z.record(z.string(),z.custom()),kind:z.string().min(1)}).optional(),metadata:taskMetadataSchema,taskId:z.string().min(1),taskRunId:z.string().min(1),terminalView:taskViewSchema.optional()}),sessionTaskIndexSchema=z.strictObject({tasks:z.array(sessionTaskIndexEntrySchema),version:z.literal(SESSION_TASKS_STATE_VERSION)}).refine(e=>new Set(e.tasks.map(e=>e.taskId)).size===e.tasks.length,{message:`Task ids must be unique.`}).refine(e=>e.tasks.every(e=>e.terminalView===void 0||e.terminalView.taskId===e.taskId&&sameTaskMetadata(e.terminalView.metadata,e.metadata)),{message:`Cached terminal views must match their task index entry.`});function getSessionTaskIndex(e){let t=e?.[SESSION_TASKS_STATE_KEY$1];if(t===void 0)return[];let n=typeof t==`object`&&t?Reflect.get(t,`version`):void 0;if(n!==SESSION_TASKS_STATE_VERSION)throw Error(`Unsupported task index version ${JSON.stringify(n)} under session state key "${SESSION_TASKS_STATE_KEY$1}"; expected version ${SESSION_TASKS_STATE_VERSION}.`);let r=sessionTaskIndexSchema.safeParse(t);if(!r.success)throw Error(`Corrupt task index under session state key "${SESSION_TASKS_STATE_KEY$1}": ${r.error.message}`);return r.data.tasks}function cacheTerminalTaskView(e,t){if(!isValidTerminalView(t))throw Error(`Cannot cache invalid terminal task "${t.taskId}".`);let n=getSessionTaskIndex(e),r=n.findIndex(e=>e.taskId===t.taskId);if(r<0)return e;if(!sameTaskMetadata(n[r].metadata,t.metadata))throw Error(`Task view metadata does not match index entry "${t.taskId}".`);let i=[...n];return i[r]={...i[r],terminalView:t},{...e,[SESSION_TASKS_STATE_KEY$1]:{tasks:i,version:SESSION_TASKS_STATE_VERSION}}}function isValidTerminalView(e){if(e.inputRequests!==void 0)return!1;switch(e.status){case`completed`:return e.lastOutput?.type===`result`;case`failed`:return e.lastOutput?.type===`error`;case`cancelled`:return e.lastOutput===void 0;case`working`:return!1}}function findSessionTaskEntry(e,t){return getSessionTaskIndex(e).find(e=>e.taskId===t)}function recordSessionTask(e,t){let n=[...getSessionTaskIndex(e.state).filter(e=>e.taskId!==t.taskId),t];return{...e,state:{...e.state,[SESSION_TASKS_STATE_KEY$1]:{tasks:n,version:SESSION_TASKS_STATE_VERSION}}}}export{SESSION_TASKS_STATE_KEY,cacheTerminalTaskView,findSessionTaskEntry,getSessionTaskIndex,recordSessionTask};
@@ -0,0 +1,10 @@
1
+ import type { SessionStateMap } from "#harness/types.js";
2
+ /** Session-state key for the parent's task index; mutable task records live in task runs. */
3
+ export declare const SESSION_TASKS_STATE_KEY = "eve.tasks";
4
+ export declare const SESSION_TASKS_STATE_VERSION = 2;
5
+ /**
6
+ * Reads only the identities needed for workflow-side completion batching.
7
+ * Full task validation stays in getSessionTaskIndex on the step side, so
8
+ * the workflow bundle does not retain the task schemas and their dependencies.
9
+ */
10
+ export declare function getSessionTaskCohorts(state: SessionStateMap | undefined): ReadonlyMap<string, string>;
@@ -0,0 +1 @@
1
+ import{isNonEmptyString,isObject}from"#shared/guards.js";const SESSION_TASKS_STATE_KEY=`eve.tasks`,SESSION_TASKS_STATE_VERSION=2;function getSessionTaskCohorts(e){let t=new Map,n=e?.[SESSION_TASKS_STATE_KEY];if(n===void 0)return t;if(!isObject(n)||n.version!==2)throw Error(`Unsupported task index version under session state key "${SESSION_TASKS_STATE_KEY}".`);if(!Array.isArray(n.tasks))throw Error(`Corrupt task index under session state key "${SESSION_TASKS_STATE_KEY}": expected tasks array.`);for(let e of n.tasks){if(!isObject(e)||!isNonEmptyString(e.taskId)||!isNonEmptyString(e.createdByTurnId)||t.has(e.taskId))throw Error(`Corrupt task index under session state key "${SESSION_TASKS_STATE_KEY}": invalid task cohort identity.`);t.set(e.taskId,e.createdByTurnId)}return t}export{SESSION_TASKS_STATE_KEY,SESSION_TASKS_STATE_VERSION,getSessionTaskCohorts};
@@ -11,8 +11,11 @@ export interface AgentInput {
11
11
  readonly outputSchema?: JsonObject;
12
12
  readonly target: string;
13
13
  }
14
- /** Context supplied only to a defineWorkflowTool executor, inside its durable run. */
15
- export type WorkflowToolContext = Pick<ToolContext, "abortSignal" | "callId" | "session" | "toolName"> & {
14
+ /**
15
+ * Context supplied to a workflow tool. Pass it directly to a step helper for
16
+ * getToken/requireAuth; those capabilities throw in the workflow body itself.
17
+ */
18
+ export type WorkflowToolContext = Pick<ToolContext, "abortSignal" | "callId" | "session" | "toolName" | "getToken" | "requireAuth"> & {
16
19
  /** Invoke a visible subagent. The key must be unique within this workflow run. */
17
20
  agent(input: AgentInput): Promise<JsonValue>;
18
21
  /** Ask the human on the session's channel; awaiting the answer suspends the run. */
@@ -95,6 +95,8 @@ Note: consider the privacy, confidentiality, and user-experience implications fo
95
95
 
96
96
  `message.completed` can fire more than once in a turn: the agent often emits interim assistant text before a tool call. To tell tool-call narration from a terminal reply, check `message.completed.data.finishReason`. `step.completed.data.finishReason` mirrors the step outcome, and usage lives on `step.completed`.
97
97
 
98
+ When a task explicitly requires conditional delivery and there is nothing new to report, the agent can finish with exactly `<eve-empty-delivery/>`. eve emits `message.completed` with `message: null` for that intentional silence. The marker must be the entire response, apart from surrounding whitespace; the HTML-escaped form `&lt;eve-empty-delivery/&gt;` is also accepted. A response that quotes the marker in prose or code is delivered normally.
99
+
98
100
  A delegated subagent publishes progress on its own child-session stream. The parent emits `subagent.called` with a `childSessionId`, which a client uses to attach. `subagent.completed` carries a working task receipt after admission; later updates and outcomes arrive as task-triggered `message.received` notifications.
99
101
 
100
102
  `step.failed` and `turn.failed` carry `{ code, message, details? }` for the failed fragment or turn, and `session.failed` is the terminal session-level variant. `turn.cancelled` is not a failure: the cancelled turn ends without any failure event, `session.waiting` follows, and the session accepts the next message normally. Whatever the turn streamed before cancellation stays on the stream. Durable history keeps the accepted user input and previously settled work, but discards incomplete assistant output and unfinished tool state. When a turn requested an output schema, the finalized payload lands on `result.completed` as `data.result` before the turn boundary. `authorization.required` carries the sign-in challenge (`data.authorization` may include `url`, `userCode`, `expiresAt`, `instructions`), and `authorization.completed` carries `data.outcome` (`"authorized" | "declined" | "failed" | "timed-out"`).
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: "Reporters"
3
- description: "Ship eval results to Braintrust experiments or JUnit XML. eve runs and scores everything itself."
3
+ description: "Ship eval results to Braintrust, Datadog, or JUnit XML. eve runs and scores everything itself."
4
4
  ---
5
5
 
6
6
  eve runs and grades everything itself; reporters ship the results out. The CLI prints a console summary by default (one line per eval, with failed assertions and their messages), and reporters from `eve/evals/reporters` add destinations on top.
@@ -44,6 +44,25 @@ A reporter instance observes the evals that reference it. Share one instance acr
44
44
 
45
45
  Braintrust needs its SDK installed in the app and credentials in the environment: install the `braintrust` package (`npm install braintrust`) and set `BRAINTRUST_API_KEY`. Pass `--skip-report` to run the eval without shipping results, which also suppresses config reporters and is useful locally when iterating.
46
46
 
47
+ ## Datadog
48
+
49
+ `Datadog(...)` uploads eval assertion scores to a Datadog LLM Observability Experiment. Put one instance in the config so it covers the whole run:
50
+
51
+ ```ts title="evals/evals.config.ts"
52
+ import { defineEvalConfig } from "eve/evals";
53
+ import { Datadog } from "eve/evals/reporters";
54
+
55
+ export default defineEvalConfig({
56
+ reporters: [Datadog({ projectName: "weather-agent" })],
57
+ });
58
+ ```
59
+
60
+ The reporter creates one Datadog Experiment, submits one synthetic experiment span per completed eve eval, associates that eval's assertion scores as experiment metrics, and prints the Datadog Experiment URL after the run completes. Without input recording, the external Experiment uses a placeholder dataset and spans are submitted as evals finish. With `recordInputs: true`, the reporter instead creates and pushes a versioned Datadog dataset after the evals finish, adds one record per eval, starts the Experiment against that dataset version, passes each dataset record id to its corresponding experiment span, and prints both Dataset and Experiment URLs. Buffering is necessary because an imperative eval's first `t.send(...)` input is only known after that eval executes. `dd-trace` generates dataset record, experiment trace, and experiment span identifiers; the reporter does not mutate or link the agent runtime's OpenTelemetry spans.
61
+
62
+ Assertion metrics use descriptive assertion names by default: characters outside letters, numbers, underscores, and hyphens are normalized to underscores, gate labels receive a `gate_` prefix, and repeated or reserved labels receive numeric suffixes. For example, `succeeded` becomes `gate_succeeded` and `calledTool(get_stock_quote)` becomes `gate_calledTool_get_stock_quote`. Authors can use `.label("stable name")` on an assertion handle to choose a stable metric name. Because assertion names can contain authored expectations, review them before exporting sensitive evals. Pass `recordAssertionDetails: true` only when the destination is also approved for raw assertion-name tags and failed assertion messages in row metadata.
63
+
64
+ Datadog needs `dd-trace` installed in the app and Datadog credentials in the environment. The reporter is tested against `dd-trace@6.13.0`; install it with `npm install dd-trace@6.13.0` and set `DD_API_KEY`, `DD_APP_KEY`, and `DD_SITE` as appropriate. By default, the reporter records assertion scores, eval metadata, and the target URL origin only. Pass `recordInputs: true`, `recordOutputs: true`, `recordExpectedOutputs: true`, or `recordErrors: true` if your destination is approved for eval prompts, outputs, authored expectations, or execution error messages. `recordInputs` stores the eval input in both the linked dataset record and experiment span. Input is read from the eval's first `t.send(...)` message, falling back to the eval description when no message event is available. When `recordExpectedOutputs` is enabled, expected output is read from eval `metadata.expectedOutput`, `metadata.expected`, or `metadata.expected_output` and stored in both the dataset record and experiment span; when no expected output is authored, the input-only dataset record is still valid. Those expected-output keys are excluded from the general metadata payload. Target URL credentials, paths, query parameters, and fragments are never reported.
65
+
47
66
  ## JUnit
48
67
 
49
68
  `JUnit({ filePath })` writes JUnit XML for CI annotations. The `--junit <path>` CLI flag does the same thing without touching the eval file, usually the better fit because CI owns the output path, not the eval:
package/docs/sandbox.mdx CHANGED
@@ -289,6 +289,8 @@ Custom backend handles implement the same boundary in `delete()`: remove the ses
289
289
 
290
290
  Session sandboxes are keyed per durable session, not per deployment, so redeploying your app does not by itself discard them. A definition change to the authored sandbox source, workspace seed content, or `revalidationKey` replaces the sandbox on the next turn and runs `onSession` again.
291
291
 
292
+ For sandboxes with `bootstrap`, unrelated agent changes preserve the template and session sandbox keys even when there are no skill or workspace seed files. You do not need to add a seed file or `revalidationKey` solely to preserve reuse across those changes.
293
+
292
294
  Reattachment still depends on the backend retaining its physical sandbox state. If a persisted Vercel sandbox is no longer available, eve creates a replacement, using the current template when one is configured. Files and other changes made after the original sandbox was created are not restored automatically. Because the durable session still has the same sandbox key, `onSession` does not run again for this replacement. Persist important artifacts outside the sandbox, and do not rely on `onSession` as the only place that applies security-critical configuration.
293
295
 
294
296
  When the eve server stops, no sandbox compute outlives it. `eve dev` stops the sandboxes it started when the dev server closes, and a self-hosted production server stops every open sandbox on shutdown (`SIGTERM`/`SIGINT`). Session state persists across the stop — the next server start reattaches each durable session from its stopped container, VM, or snapshot. Custom `SandboxBackend` adapters implement `stop()` for authored runtime calls and `shutdown()` for server teardown. Both stop the underlying compute while keeping the session reattachable from persisted state where the backend supports it; authored `stop()` failures reject, while process-wide shutdown collects and logs failures without blocking teardown.
@@ -5,6 +5,16 @@ description: "Delegate work to root-agent copies or declared specialists with th
5
5
 
6
6
  eve supports two ways to delegate work: the root-only built-in `agent` tool, which starts or continues a copy of the root agent, and declared subagents, which are specialists with their own directories. Use a subagent to run independent work in parallel, narrow the available tools, or give a task to a specialist.
7
7
 
8
+ ## Completion batching
9
+
10
+ eve automatically combines adjacent successful completions already queued from
11
+ tasks launched in the same parent turn. Every result is retained, and the parent
12
+ responds to the batch in one turn. No configuration is required.
13
+
14
+ There is no debounce timer or waiting for unfinished tasks. Failures, input
15
+ requests, explicit updates, user messages, and different task cohorts remain
16
+ separate delivery boundaries.
17
+
8
18
  ## The built-in `agent` tool
9
19
 
10
20
  The root session receives `agent` by default. The model calls it to delegate a task to a new copy of the root agent or continue an existing copy:
@@ -79,8 +79,8 @@ or days later, the run resumes, deploys, and returns. The model sees one tool re
79
79
  `start`, `getRun`, and `resumeHook` from `workflow/api` belong in steps. Your app does not install
80
80
  the SDK; for types, new projects list `eve/workflow-modules` in the tsconfig `types`.
81
81
  - In the body, `ctx` has `session`, `callId`, `toolName`, `abortSignal`, `agent`, and `ask`.
82
- `getSandbox`, `getSkill`, `getToken`, and `requireAuth` are not part of `WorkflowToolContext`.
83
- Read credentials from `process.env` in a step; session-scoped workflow authorization is not yet available.
82
+ `getToken` and `requireAuth` work inside a `"use step"` helper that receives `ctx` as a direct argument;
83
+ they throw in the workflow body. `getSandbox` and `getSkill` remain unavailable.
84
84
  - The tool's input must be a JSON object. Workflow bodies are for static tools under `agent/tools/`,
85
85
  not tools returned from `defineDynamic` resolvers.
86
86
 
@@ -154,6 +154,65 @@ Answering resumes the body in either mode.
154
154
  Promise or Node.js timer inside a step also does not create a durable workflow suspension; use
155
155
  the workflow operations for waits that must survive a restart.
156
156
 
157
+ ## Authorize inside a step
158
+
159
+ Pass `ctx` directly to a step helper and call `ctx.getToken(provider)` there. User-scoped providers
160
+ resolve as whoever launched this workflow tool, even if another person speaks in the session while it waits.
161
+ The provider declaration and the API request both stay inside the step:
162
+
163
+ ```ts
164
+ import { connect } from "@vercel/connect/eve";
165
+ import type { WorkflowToolContext } from "eve/tools";
166
+
167
+ async function readRepository(ctx: WorkflowToolContext, repository: string) {
168
+ "use step";
169
+ const provider = connect("github/my-agent");
170
+ const { token } = await ctx.getToken(provider);
171
+ const response = await fetch(`https://api.github.com/repos/${repository}`, {
172
+ headers: { Authorization: `Bearer ${token}` },
173
+ });
174
+ if (response.status === 401) ctx.requireAuth(provider);
175
+ if (!response.ok) throw new Error(`GitHub returned ${response.status}`);
176
+ return response.json();
177
+ }
178
+ ```
179
+
180
+ Connections discovered through `connection_search`, ordinary tools, and workflow steps use the same
181
+ authorization machinery for requester identity, token caching, callback completion, and rejection
182
+ after sign-in. The execution runtime owns the wait: an agent returns to its model after authorization,
183
+ while a workflow retries the interrupted step and continues the authored body.
184
+
185
+ The workflow body calls `await readRepository(ctx, repository)`.
186
+
187
+ <Callout type="warning" title="Keep tokens out of step results">
188
+ Step results enter the workflow's durable history, so do not return the token from the helper.
189
+ eve's token cache stays inside the step. The step input is recorded too and, after sign-in,
190
+ carries the provider's callback parameters, such as a one-time authorization code. This matches
191
+ how agent turns record callbacks. Bearer tokens are never written.
192
+ </Callout>
193
+
194
+ When sign-in is required, the step attempt ends and the workflow waits on its own callback hook,
195
+ without holding compute. The channel renders the sign-in challenge. After the callback, eve retries
196
+ **the whole interrupted step**, resolves the token, and continues. Previously completed steps are
197
+ not rerun. Resolve auth before other side effects in that step, and make operations before
198
+ `requireAuth` safe to retry. A token rejected immediately after sign-in fails instead of prompting
199
+ again. Provider declarations can be shared imports, but context must be passed directly, not nested
200
+ inside another argument or captured in a closure.
201
+
202
+ After a successful callback exchange, eve records a completion marker before returning to authored
203
+ code. If that code later fails and the step retries, eve reads the token from the provider instead
204
+ of exchanging the same callback again. The provider must persist the grant or token; the marker
205
+ itself contains no credentials.
206
+
207
+ A background task becomes `input_required` during sign-in. The callback resumes that task; it does
208
+ not rely on the launching agent turn still being active. Cancelling an authorization wait withdraws
209
+ its callback. Cancellation uses the existing turn or task cancellation path rather than a separate
210
+ authorization completion event.
211
+
212
+ Background workflow authorization requires a new session after upgrading. In older sessions,
213
+ `ctx.getToken` and `ctx.requireAuth` fail immediately with an instruction to start a new session.
214
+ Blocking workflows and background workflows without auth are unaffected.
215
+
157
216
  ## Ask a human: `ctx.ask`
158
217
 
159
218
  ```ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eve",
3
- "version": "0.52.3",
3
+ "version": "0.52.4",
4
4
  "private": false,
5
5
  "description": "Filesystem-first framework for durable backend AI agents that run anywhere.",
6
6
  "keywords": [
@@ -290,6 +290,11 @@
290
290
  "import": "./dist/src/public/context/index.js",
291
291
  "default": "./dist/src/public/context/index.js"
292
292
  },
293
+ "./internal/workflow-step-execution": {
294
+ "types": "./dist/src/execution/tools/workflow/step-execution.d.ts",
295
+ "import": "./dist/src/execution/tools/workflow/step-execution.js",
296
+ "default": "./dist/src/execution/tools/workflow/step-execution.js"
297
+ },
293
298
  "./internal/programmatic-source-loader": {
294
299
  "types": "./dist/src/internal/programmatic-source-loader.d.ts",
295
300
  "import": "./dist/src/internal/programmatic-source-loader.js",
@@ -420,6 +425,12 @@
420
425
  "types": "./dist/src/setup/index.d.ts",
421
426
  "import": "./dist/src/setup/index.js",
422
427
  "default": "./dist/src/setup/index.js"
428
+ },
429
+ "./self-modification/config": {
430
+ "eve-source": "./src/self-modification/config.ts",
431
+ "types": "./dist/src/self-modification/config.d.ts",
432
+ "import": "./dist/src/self-modification/config.js",
433
+ "default": "./dist/src/self-modification/config.js"
423
434
  }
424
435
  },
425
436
  "publishConfig": {
@@ -478,6 +489,7 @@
478
489
  "chat": "4.34.0",
479
490
  "chokidar": "5.0.0",
480
491
  "commander": "14.0.3",
492
+ "dd-trace": "6.13.0",
481
493
  "emulate": "0.6.0",
482
494
  "env-runner": "0.1.16",
483
495
  "eventsource-parser": "3.1.0",
@@ -507,6 +519,7 @@
507
519
  "@opentelemetry/api": "^1.0.0",
508
520
  "ai": "^7.0.82",
509
521
  "braintrust": "^3.0.0",
522
+ "dd-trace": "^6.13.0",
510
523
  "just-bash": "^3.1.0",
511
524
  "microsandbox": "^0.5.0"
512
525
  },
@@ -517,6 +530,9 @@
517
530
  "braintrust": {
518
531
  "optional": true
519
532
  },
533
+ "dd-trace": {
534
+ "optional": true
535
+ },
520
536
  "just-bash": {
521
537
  "optional": true
522
538
  },
@@ -1,2 +0,0 @@
1
- /** Runs `task` after every previously queued authored-source mutation settles. */
2
- export declare function withAuthoredSourceLock<T>(task: () => Promise<T>): Promise<T>;
@@ -1 +0,0 @@
1
- let queue=Promise.resolve();async function withAuthoredSourceLock(e){let t=queue.then(e,e);return queue=t.catch(()=>void 0),await t}export{withAuthoredSourceLock};