eve
Version:
Filesystem-first framework for durable backend AI agents that run anywhere.
1 lines • 6.29 kB
JavaScript
import{join,relative,resolve}from"node:path";import{classifySkillPackageEntry,classifySkillsDirectoryEntry,getDirectoryEntryType,getSupportedModuleBaseName,normalizeLogicalPath}from"#discover/filesystem.js";import{toErrorMessage}from"#shared/errors.js";import{createDiscoverErrorDiagnostic}from"#discover/diagnostics.js";import{createDiskProjectSource}from"#discover/project-source.js";import{createModuleSourceRef,createPathDerivedSourceId,createSkillPackageSourceRef}from"#discover/manifest.js";import{readSortedDirectoryEntries}from"#discover/grammar.js";import{lowerSkillMarkdown}from"#internal/helpers/markdown.js";const DISCOVER_SKILLS_DIRECTORY_INVALID=`discover/skills-directory-invalid`,DISCOVER_SKILL_COLLISION=`discover/skill-collision`,DISCOVER_SKILL_ENTRY_NOT_DIRECTORY=`discover/skill-entry-not-directory`,DISCOVER_SKILL_FRONTMATTER_INVALID=`discover/skill-frontmatter-invalid`,DISCOVER_SKILL_MARKDOWN_MISSING=`discover/skill-markdown-missing`;async function discoverSkills(e){let t=e.source??createDiskProjectSource(),n=resolve(e.agentRoot),r=resolve(e.skillsDirectoryPath??join(n,`skills`)),i=normalizeLogicalPath(e.skillsLogicalPath??relative(n,r)),a=await t.stat(r);if(a===`missing`)return{diagnostics:[],skills:[]};if(a!==`directory`)return{diagnostics:[createDiscoverErrorDiagnostic({code:DISCOVER_SKILLS_DIRECTORY_INVALID,message:`Expected "${r}" to be a directory of authored skills.`,sourcePath:r})],skills:[]};let o=[],s=new Set,c=new Map,l=await readSortedDirectoryEntries(t,r);for(let e of l){let n=await discoverOneSkill({entryName:e.name,entryType:getDirectoryEntryType(e),skillsDirectoryPath:r,skillsLogicalPath:i,source:t});if(o.push(...n.diagnostics),n.skill===null||n.skillId===null||s.has(n.skillId))continue;let a=c.get(n.skillId);if(a!==void 0){o.push(createDiscoverErrorDiagnostic({code:DISCOVER_SKILL_COLLISION,message:`Found conflicting authored skill sources for "${n.skillId}": "${a.logicalPath}" and "${n.logicalPath}".`,sourcePath:join(r,n.skillId)})),s.add(n.skillId),c.delete(n.skillId);continue}c.set(n.skillId,{logicalPath:n.logicalPath,skill:n.skill})}return{diagnostics:o,skills:[...c.values()].map(e=>e.skill)}}async function discoverOneSkill(e){let t=join(e.skillsDirectoryPath,e.entryName);switch(classifySkillsDirectoryEntry(e.entryName,e.entryType)){case`skill-package-directory`:return discoverPackagedSkill({logicalSkillsPath:e.skillsLogicalPath,skillId:e.entryName,skillRootPath:t,source:e.source});case`flat-skill-markdown`:return discoverFlatMarkdownSkill({logicalSkillsPath:e.skillsLogicalPath,skillFileName:e.entryName,skillFilePath:t,source:e.source});case`flat-skill-module`:return discoverFlatModuleSkill({logicalSkillsPath:e.skillsLogicalPath,skillFileName:e.entryName});case`ignored-declaration`:return{diagnostics:[],logicalPath:normalizeLogicalPath(join(e.skillsLogicalPath,e.entryName)),skill:null,skillId:null};default:return{diagnostics:[createDiscoverErrorDiagnostic({code:DISCOVER_SKILL_ENTRY_NOT_DIRECTORY,message:`Expected "${t}" to be a skill directory containing SKILL.md or a flat ".md", ".ts", ".cts", ".mts", ".js", ".cjs", or ".mjs" skill file.`,sourcePath:t})],logicalPath:normalizeLogicalPath(join(e.skillsLogicalPath,e.entryName)),skill:null,skillId:null}}}async function discoverPackagedSkill(e){let t=(await readSortedDirectoryEntries(e.source,e.skillRootPath)).find(e=>e.isFile()&&e.name.toLowerCase()===`skill.md`)?.name,n=join(e.skillRootPath,t??`SKILL.md`),r=normalizeLogicalPath(join(e.logicalSkillsPath,e.skillId,t??`SKILL.md`));if(t===void 0)return{diagnostics:[createDiscoverErrorDiagnostic({code:DISCOVER_SKILL_MARKDOWN_MISSING,message:`Expected "${n}" to exist for the "${e.skillId}" skill.`,sourcePath:e.skillRootPath})],logicalPath:r,skill:null,skillId:null};let i;try{i=lowerSkillMarkdown(await e.source.readTextFile(n))}catch(e){return{diagnostics:[createDiscoverErrorDiagnostic({code:DISCOVER_SKILL_FRONTMATTER_INVALID,message:formatSkillDiscoveryError(n,e),sourcePath:n})],logicalPath:r,skill:null,skillId:null}}let a=await discoverSkillPackagePaths(e.source,e.skillRootPath),o={description:i.description,logicalPath:r,markdown:i.markdown,name:e.skillId,rootPath:e.skillRootPath,skillFilePath:n,skillId:e.skillId,sourceId:createPathDerivedSourceId(r)};return a.assetsPath!==void 0&&(o.assetsPath=a.assetsPath),i.license!==void 0&&(o.license=i.license),i.metadata!==void 0&&(o.metadata=i.metadata),a.referencesPath!==void 0&&(o.referencesPath=a.referencesPath),a.scriptsPath!==void 0&&(o.scriptsPath=a.scriptsPath),{diagnostics:[],logicalPath:r,skill:createSkillPackageSourceRef(o),skillId:e.skillId}}async function discoverFlatMarkdownSkill(e){let t=stripMarkdownExtension(e.skillFileName),n=normalizeLogicalPath(join(e.logicalSkillsPath,e.skillFileName)),r;try{r=lowerSkillMarkdown(await e.source.readTextFile(e.skillFilePath),{slug:t})}catch(t){return{diagnostics:[createDiscoverErrorDiagnostic({code:DISCOVER_SKILL_FRONTMATTER_INVALID,message:formatSkillDiscoveryError(e.skillFilePath,t),sourcePath:e.skillFilePath})],logicalPath:n,skill:null,skillId:null}}return{diagnostics:[],logicalPath:n,skill:{definition:r,sourceKind:`markdown`,logicalPath:n,sourceId:createPathDerivedSourceId(n)},skillId:t}}async function discoverFlatModuleSkill(e){let t=getSupportedModuleBaseName(e.skillFileName),n=normalizeLogicalPath(join(e.logicalSkillsPath,e.skillFileName));return t===null?{diagnostics:[],logicalPath:n,skill:null,skillId:null}:{diagnostics:[],logicalPath:n,skill:createModuleSourceRef({logicalPath:n}),skillId:t}}async function discoverSkillPackagePaths(e,t){let n=await e.readDirectory(t),r={};for(let e of n)if(e.isDirectory())switch(classifySkillPackageEntry(e.name,getDirectoryEntryType(e))){case`skill-assets-directory`:r.assetsPath=join(t,e.name);break;case`skill-references-directory`:r.referencesPath=join(t,e.name);break;case`skill-scripts-directory`:r.scriptsPath=join(t,e.name)}return r}function formatSkillDiscoveryError(e,t){return`Invalid authored skill frontmatter in "${e}": ${toErrorMessage(t)}`}function stripMarkdownExtension(e){return e.toLowerCase().endsWith(`.md`)?e.slice(0,-3):e}export{DISCOVER_SKILLS_DIRECTORY_INVALID,DISCOVER_SKILL_COLLISION,DISCOVER_SKILL_ENTRY_NOT_DIRECTORY,DISCOVER_SKILL_FRONTMATTER_INVALID,DISCOVER_SKILL_MARKDOWN_MISSING,discoverSkills};