UNPKG

eve

Version:

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

1 lines 4.29 kB
import{existsSync}from"node:fs";import{dirname,join,normalize,resolve,sep}from"node:path";import{toErrorMessage}from"#shared/errors.js";import{getDevelopmentEnvironmentFilePaths}from"#cli/dev/environment.js";import{AUTHORED_ARTIFACTS_UPDATED_LOG_LINE,STRUCTURAL_RELOAD_LOG_LINE,formatChangeDetectedLogLine}from"#internal/nitro/host/dev-watcher-log.js";import{resolveDevelopmentSourceSnapshotWatchPaths}from"#internal/nitro/dev-runtime-source-snapshot.js";import{resolveTsConfigDependencyPaths}from"#internal/application/tsconfig-dependencies.js";import{watch as watch$1}from"#compiled/chokidar/index.js";const WATCHED_LOCKFILE_NAMES=[`pnpm-lock.yaml`,`package-lock.json`,`yarn.lock`,`bun.lock`,`bun.lockb`],WATCH_ROOT_MARKER_NAMES=[`.git`,`pnpm-workspace.yaml`],WATCHER_IGNORED_DIRECTORY_NAMES=new Set([`.generated`,`.eve`,`.git`,`.next`,`.output`,`.turbo`,`.vercel`,`build`,`dist`,`node_modules`]);async function startAuthoredSourceWatcher(e){let t=e.preparedHost,n=!1,r=Promise.resolve(),i,a=!1,o=new Map,s=new Set,c=await resolveAuthoredWatchPaths(t),l=createWatchPathMap(c),u=watch$1(c,{awaitWriteFinish:{pollInterval:50,stabilityThreshold:160},followSymlinks:!1,ignoreInitial:!0,ignored:e=>shouldIgnoreWatcherPath(e,t.workspaceExtensions)}),d=waitForWatcherReady(u),rebuild=async i=>{n||(r=r.then(async()=>{if(n)return;let r=[...o.values()];if(!i&&r.length===0)return;let a=[...s];o.clear(),s.clear();let c=t;r.length>0&&console.log(formatChangeDetectedLogLine(c.appRoot,r));try{let n=await e.coordinator.rebuild({changedPaths:a});t=n.host,n.kind===`structural`?console.log(STRUCTURAL_RELOAD_LOG_LINE):console.log(AUTHORED_ARTIFACTS_UPDATED_LOG_LINE),l=syncWatcherPaths({nextWatchPaths:await resolveAuthoredWatchPaths(t),previousWatchPathsByKey:l,watcher:u})}catch(e){console.error(`[eve:dev] rebuild failed: ${toErrorMessage(e)}`)}}).catch(e=>{console.error(`[eve:dev] rebuild queue error: ${toErrorMessage(e)}`)}),await r)},flush=async()=>{i!==void 0&&(clearTimeout(i),i=void 0),await rebuild(!1)};return u.on(`all`,(e,t)=>{n||!a||e===`addDir`||e===`unlinkDir`||(o.set(`${e}:${t}`,{event:e,path:t}),s.add(t),i!==void 0&&clearTimeout(i),i=setTimeout(()=>{i=void 0,flush()},120))}),await d,a=!0,{async close(){n=!0,i!==void 0&&(clearTimeout(i),i=void 0),await u.close(),await r},flush,rebuild:async()=>{i!==void 0&&(clearTimeout(i),i=void 0),await rebuild(!0)}}}async function waitForWatcherReady(e){await new Promise((t,n)=>{e.on(`ready`,()=>{t()}),e.on(`error`,e=>{n(e)})})}async function resolveAuthoredWatchPaths(e){let t=new Set([e.compileResult.project.agentRoot,join(e.appRoot,`package.json`),join(e.appRoot,`jsconfig.json`),join(e.appRoot,`tsconfig.json`),join(e.appRoot,`tsconfig.*.json`)]),r=await resolveTsConfigWatchPaths(e.appRoot),i=await resolveDevelopmentSourceSnapshotWatchPaths(e.appRoot);for(let n of e.workspaceExtensions){t.add(n.config.sourceRoot);for(let e of n.buildConfigPaths)t.add(e)}for(let n of getDevelopmentEnvironmentFilePaths(e.appRoot))t.add(n);for(let e of i)t.add(e);for(let e of r)t.add(e);for(let r of resolveLockfileSearchDirectories(e.appRoot))for(let e of WATCHED_LOCKFILE_NAMES)t.add(join(r,e));return[...t].sort((e,t)=>e.localeCompare(t))}function createWatchPathMap(e){let t=new Map;for(let n of e)t.set(toWatchPathKey(n),n);return t}function syncWatcherPaths(e){let t=createWatchPathMap(e.nextWatchPaths),n=[],r=[];for(let[r,i]of t)e.previousWatchPathsByKey.has(r)||n.push(i);for(let[n,i]of e.previousWatchPathsByKey)t.has(n)||r.push(i);return n.length>0&&e.watcher.add(n),r.length>0&&e.watcher.unwatch(r),t}function toWatchPathKey(e){return normalize(resolve(e))}function resolveLockfileSearchDirectories(e){let n=resolve(e),r=[n],a=n;for(;;){if(hasWatchRootMarker(a))return r;let e=dirname(a);if(e===a)return[n];a=e,r.push(a)}}function hasWatchRootMarker(t){return WATCH_ROOT_MARKER_NAMES.some(r=>existsSync(join(t,r)))}async function resolveTsConfigWatchPaths(e){return await resolveTsConfigDependencyPaths(e)}function shouldIgnoreWatcherPath(e,t){return normalize(e).split(sep).filter(Boolean).some(e=>WATCHER_IGNORED_DIRECTORY_NAMES.has(e))||t.some(t=>isPathInsideOrEqual(e,t.config.outDir))}function isPathInsideOrEqual(e,t){let n=resolve(e),r=resolve(t);return n===r||n.startsWith(`${r}${sep}`)}export{startAuthoredSourceWatcher};