UNPKG

eve

Version:

Filesystem-first framework for durable backend AI agents that run anywhere.

1 lines 9.91 kB
import{join,resolve}from"node:path";import{createDiscoverErrorDiagnostic}from"#discover/diagnostics.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS,classifyAgentRootEntry,normalizeLogicalPath}from"#discover/filesystem.js";import{createDiskProjectSource}from"#discover/project-source.js";import{DISCOVER_EXTENSION_AGENT_CONFIG_UNSUPPORTED,DISCOVER_EXTENSION_MOUNT_AMBIGUOUS,DISCOVER_EXTENSION_MOUNT_MISSING_DECLARATION,DISCOVER_EXTENSION_NESTED_MOUNT_UNSUPPORTED,DISCOVER_EXTENSION_OVERRIDE_OUTSIDE_MOUNT,DISCOVER_EXTENSION_SANDBOX_UNSUPPORTED,DISCOVER_EXTENSION_SCHEDULE_UNSUPPORTED,locateExtensionMount,mountNamespace}from"#discover/extensions.js";import{createAgentSourceManifest,createModuleSourceRef}from"#discover/manifest.js";import{DISCOVER_CHANNELS_DIRECTORY_INVALID,DISCOVER_EXTENSIONS_DIRECTORY_INVALID,DISCOVER_HOOKS_DIRECTORY_INVALID,DISCOVER_TOOLS_DIRECTORY_INVALID,createChannelNameDiagnostic,createExtensionNameDiagnostic,createHookNameDiagnostic,createToolNameDiagnostic,createUnsupportedRootDirectoryDiagnostics,discoverFlatModuleSource,discoverInstructionsSource,discoverNamedSourceDirectory,readSortedDirectoryEntries}from"#discover/grammar.js";import{discoverConnectionSources}from"#discover/connections.js";import{discoverSubagents}from"#discover/discover-subagent.js";import{discoverLibSources}from"#discover/lib.js";import{discoverSandboxSource}from"#discover/sandbox.js";import{discoverScheduleSources}from"#discover/schedules.js";import{discoverSkills}from"#discover/skills.js";import{stripNpmPackageScope}from"#shared/package-name.js";async function discoverAgent(r){let a=r.source??createDiskProjectSource(),c=resolve(r.appRoot),l=resolve(r.agentRoot),d=r.role??`agent`,h=[],g=await tryReadPackageJsonName(a,c),_=await readSortedDirectoryEntries(a,l);h.push(...createUnsupportedRootDirectoryDiagnostics({classifyEntry:classifyAgentRootEntry,createUnsupportedDirectoryMessage(e){return`Ignoring unsupported directory "${e}/" in the agent root.`},rootEntries:_,rootPath:l}));let v=await discoverInstructionsSource({rootEntries:_,rootPath:l,source:a,required:d!==`extension`});h.push(...v.diagnostics);let y=discoverFlatModuleSource({rootEntries:_,rootPath:l,slotName:`agent`});h.push(...y.diagnostics);let b=await discoverNamedSourceDirectory({directoryName:`channels`,invalidDirectoryCode:DISCOVER_CHANNELS_DIRECTORY_INVALID,invalidDirectoryMessage:`Expected "${join(l,`channels`)}" to be a directory of authored channels.`,recursive:!0,rootEntries:_,rootPath:l,source:a,validateSegment:createChannelNameDiagnostic});h.push(...b.diagnostics);let x=await discoverLibSources({agentRoot:l,rootEntries:_,source:a});h.push(...x.diagnostics);let S=await discoverScheduleSources({agentRoot:l,rootEntries:_,source:a});h.push(...S.diagnostics);let C=await discoverConnectionSources({rootEntries:_,rootPath:l,source:a});h.push(...C.diagnostics);let w=await discoverSandboxSource({rootEntries:_,rootPath:l,source:a});if(h.push(...w.diagnostics),d===`extension`){y.module!==void 0&&h.push(createDiscoverErrorDiagnostic({code:DISCOVER_EXTENSION_AGENT_CONFIG_UNSUPPORTED,message:`An extension may not declare agent config (agent.ts) — model, limits, and sandbox are the consuming agent's to own.`,sourcePath:join(l,y.module.logicalPath)})),w.sandbox!==null&&h.push(createDiscoverErrorDiagnostic({code:DISCOVER_EXTENSION_SANDBOX_UNSUPPORTED,message:`An extension may not declare a sandbox — it is the consuming agent's to own.`,sourcePath:join(l,w.sandbox.logicalPath)}));let[t]=S.schedules;t!==void 0&&h.push(createDiscoverErrorDiagnostic({code:DISCOVER_EXTENSION_SCHEDULE_UNSUPPORTED,message:`An extension may not declare schedules — background scheduling runs on the consuming agent's deployment under its limits, so it is the consuming agent's to own.`,sourcePath:join(l,t.logicalPath)}))}let T=await discoverNamedSourceDirectory({directoryName:`tools`,invalidDirectoryCode:DISCOVER_TOOLS_DIRECTORY_INVALID,invalidDirectoryMessage:`Expected "${join(l,`tools`)}" to be a directory of authored tools.`,recursive:!0,rootEntries:_,rootPath:l,source:a,validateSegment:createToolNameDiagnostic});h.push(...T.diagnostics);let E=await discoverNamedSourceDirectory({directoryName:`hooks`,invalidDirectoryCode:DISCOVER_HOOKS_DIRECTORY_INVALID,invalidDirectoryMessage:`Expected "${join(l,`hooks`)}" to be a directory of authored hooks.`,recursive:!0,rootEntries:_,rootPath:l,source:a,validateSegment:createHookNameDiagnostic});h.push(...E.diagnostics);let D=await discoverNamedSourceDirectory({directoryName:`extensions`,invalidDirectoryCode:DISCOVER_EXTENSIONS_DIRECTORY_INVALID,invalidDirectoryMessage:`Expected "${join(l,`extensions`)}" to be a directory of extension mounts.`,recursive:!1,rootEntries:_,rootPath:l,source:a,validateSegment:createExtensionNameDiagnostic});h.push(...D.diagnostics);let O=await discoverSkills({agentRoot:l,source:a});h.push(...O.diagnostics);let k=await discoverSubagents({agentRoot:l,appRoot:c,source:a});h.push(...k.diagnostics);let A=await collectExtensionMounts({agentRoot:l,fileMounts:D.sources,rootEntries:_,source:a});h.push(...A.diagnostics),h.push(...detectRootNamespaceCollisions({agentRoot:l,namespaces:A.mounts.map(e=>e.namespace),sources:[...T.sources,...C.connections,...O.skills,...S.schedules]}));let j=[];if(d!==`agent`)for(let t of A.mounts)h.push(createDiscoverErrorDiagnostic({code:DISCOVER_EXTENSION_NESTED_MOUNT_UNSUPPORTED,message:`"${t.mountRef.logicalPath}" mounts an extension from inside an extension, which is not supported yet. Extensions cannot mount other extensions; remove the "extensions/" slot.`,sourcePath:join(l,t.mountRef.logicalPath)}));else for(let e of A.mounts){let t=await locateExtensionMount({source:a,agentRoot:l,appRoot:c,mount:e.mountRef,namespace:e.namespace});if(h.push(...t.diagnostics),t.location===void 0)continue;let n=await discoverAgent({agentRoot:t.location.sourceRoot,appRoot:t.location.packageRoot,source:a,role:`extension`});h.push(...n.diagnostics);let r;if(e.overridesRoot!==void 0){let t=await discoverAgent({agentRoot:e.overridesRoot,appRoot:c,source:a,role:`extension`});h.push(...t.diagnostics),r=t.manifest}let i={namespace:t.location.namespace,specifier:t.location.specifier,packageName:t.location.packageName,packageRoot:t.location.packageRoot,sourceRoot:t.location.sourceRoot,manifest:n.manifest};r!==void 0&&(i.overrides=r),j.push(i)}let M={agentRoot:l,appRoot:c,channels:b.sources,connections:C.connections,packageName:g,diagnostics:h,extensions:A.mounts.map(e=>e.mountRef),resolvedExtensions:j,hooks:E.sources,lib:x.lib,instructions:v.instructions,sandbox:w.sandbox,sandboxWorkspaces:w.sandboxWorkspace===null?[]:[w.sandboxWorkspace],schedules:S.schedules,skills:O.skills,tools:T.sources,subagents:k.subagents};return y.module!==void 0&&(M.configModule=y.module),{diagnostics:h,manifest:createAgentSourceManifest(M)}}async function discoverExtensionMountDeclarations(n){let r=n.source??createDiskProjectSource(),i=resolve(n.agentRoot),a=await readSortedDirectoryEntries(r,i),s=await discoverNamedSourceDirectory({directoryName:`extensions`,invalidDirectoryCode:DISCOVER_EXTENSIONS_DIRECTORY_INVALID,invalidDirectoryMessage:`Expected "${join(i,`extensions`)}" to be a directory of extension mounts.`,recursive:!1,rootEntries:a,rootPath:i,source:r,validateSegment:createExtensionNameDiagnostic}),c=await collectExtensionMounts({agentRoot:i,fileMounts:s.sources,rootEntries:a,source:r});return{diagnostics:[...s.diagnostics,...c.diagnostics],mounts:c.mounts}}async function collectExtensionMounts(t){let r=[],i=join(t.agentRoot,`extensions`),o=t.fileMounts.map(e=>({namespace:mountNamespace(e.logicalPath),mountRef:e})),s=new Set(o.map(e=>e.namespace)),u=t.rootEntries.find(e=>e.name===`extensions`),d=[],f=new Set;if(u?.isDirectory()===!0){let o=await readSortedDirectoryEntries(t.source,i);for(let c of o){if(!c.isDirectory())continue;let o=c.name,u=join(i,o),p=createExtensionNameDiagnostic(o,u);if(p!==null){r.push(p);continue}let m=discoverFlatModuleSource({rootEntries:await readSortedDirectoryEntries(t.source,u),rootPath:u,slotName:`extension`});if(r.push(...m.diagnostics),m.module===void 0){r.push(createDiscoverErrorDiagnostic({code:DISCOVER_EXTENSION_MOUNT_MISSING_DECLARATION,message:`Extension mount directory "extensions/${o}/" must declare its mount in "extension.ts" (or another supported module extension).`,sourcePath:u}));continue}s.has(o)&&f.add(o),d.push({namespace:o,mountRef:createModuleSourceRef({logicalPath:normalizeLogicalPath(join(`extensions`,o,m.module.logicalPath))}),overridesRoot:u})}}for(let e of f)r.push(createDiscoverErrorDiagnostic({code:DISCOVER_EXTENSION_MOUNT_AMBIGUOUS,message:`Extension namespace "${e}" is claimed by both a file mount ("extensions/${e}.ts") and a directory mount ("extensions/${e}/"). Keep only one.`,sourcePath:i}));return{diagnostics:r,mounts:[...o,...d].filter(e=>!f.has(e.namespace))}}function detectRootNamespaceCollisions(t){if(t.namespaces.length===0)return[];let r=[];for(let i of t.sources){let a=rootContributionName(i.logicalPath),o=t.namespaces.find(e=>a.startsWith(`${e}__`));o!==void 0&&r.push(createDiscoverErrorDiagnostic({code:DISCOVER_EXTENSION_OVERRIDE_OUTSIDE_MOUNT,message:`"${i.logicalPath}" uses the "${o}__" prefix reserved for the mounted extension "${o}". Override an extension's contributions inside its mount directory ("extensions/${o}/…"), not at the agent root.`,sourcePath:join(t.agentRoot,i.logicalPath)}))}return r}function rootContributionName(e){let t=e.slice(e.indexOf(`/`)+1),n=t.split(`/`)[0]??t;for(let e of SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS)if(n.toLowerCase().endsWith(e))return n.slice(0,n.length-e.length);return n}async function tryReadPackageJsonName(t,n){try{let r=join(n,`package.json`),i=JSON.parse(await t.readTextFile(r)).name;return typeof i!=`string`||i.length===0?void 0:stripNpmPackageScope(i)}catch{return}}export{discoverAgent,discoverExtensionMountDeclarations};