export type { FileInfo, Manifest } from '@types' import type { FileInfo, Manifest } from '@types' import { loadGitignore } from '@gitignore' import { createHash } from 'crypto' import { readdirSync, readFileSync, statSync } from 'fs' import { join, relative } from 'path' export function computeHash(content: Buffer | string): string { return createHash('sha256').update(content).digest('hex') } export function generateManifest(appPath: string, appName: string): Manifest { const files: Record = {} const gitignore = loadGitignore(appPath) function walkDir(dir: string) { const entries = readdirSync(dir, { withFileTypes: true }) for (const entry of entries) { const fullPath = join(dir, entry.name) const relativePath = relative(appPath, fullPath) if (gitignore.shouldExclude(relativePath)) continue if (entry.isDirectory()) { walkDir(fullPath) } else if (entry.isFile()) { const content = readFileSync(fullPath) const stats = statSync(fullPath) files[relativePath] = { hash: computeHash(content), mtime: stats.mtime.toISOString(), size: stats.size, } } } } walkDir(appPath) return { name: appName, files, } }