import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; type ReferenceConfig = { references: Array<{ source: string; target: string; }>; }; type ZipEntry = { name: string; content: Buffer; }; const scriptDir = path.dirname(fileURLToPath(import.meta.url)); const agentDir = path.resolve(scriptDir, '..'); const rootDir = path.resolve(agentDir, '../..'); const sourceDir = path.join(agentDir, 'source'); const tempDir = path.join(agentDir, '.tmp'); const packageName = 'frontend-architect'; const packageDir = path.join(tempDir, packageName); const publicAgentsDir = path.join(rootDir, 'public', 'agents'); const zipPath = path.join(publicAgentsDir, `${packageName}.zip`); function readJson(filePath: string): T { return JSON.parse(fs.readFileSync(filePath, 'utf8')) as T; } function copyFile(sourcePath: string, targetPath: string) { fs.mkdirSync(path.dirname(targetPath), { recursive: true }); fs.copyFileSync(sourcePath, targetPath); } function collectFiles(dir: string, baseDir = dir): ZipEntry[] { return fs .readdirSync(dir, { withFileTypes: true }) .flatMap((entry) => { const entryPath = path.join(dir, entry.name); if (entry.isDirectory()) { return collectFiles(entryPath, baseDir); } const relativePath = path.relative(baseDir, entryPath).split(path.sep).join('/'); return [ { name: `${packageName}/${relativePath}`, content: fs.readFileSync(entryPath), }, ]; }) .sort((a, b) => a.name.localeCompare(b.name)); } function createCrc32Table() { return Array.from({ length: 256 }, (_, index) => { let value = index; for (let bit = 0; bit < 8; bit += 1) { value = value & 1 ? 0xedb88320 ^ (value >>> 1) : value >>> 1; } return value >>> 0; }); } const crc32Table = createCrc32Table(); function crc32(buffer: Buffer) { let crc = 0xffffffff; for (const byte of buffer) { crc = crc32Table[(crc ^ byte) & 0xff] ^ (crc >>> 8); } return (crc ^ 0xffffffff) >>> 0; } function writeUInt16(value: number) { const buffer = Buffer.alloc(2); buffer.writeUInt16LE(value, 0); return buffer; } function writeUInt32(value: number) { const buffer = Buffer.alloc(4); buffer.writeUInt32LE(value >>> 0, 0); return buffer; } function createZip(entries: ZipEntry[]) { const localParts: Buffer[] = []; const centralParts: Buffer[] = []; const dosTime = 0; const dosDate = ((2026 - 1980) << 9) | (1 << 5) | 1; let offset = 0; for (const entry of entries) { const fileName = Buffer.from(entry.name, 'utf8'); const checksum = crc32(entry.content); const size = entry.content.length; const localHeader = Buffer.concat([ writeUInt32(0x04034b50), writeUInt16(20), writeUInt16(0), writeUInt16(0), writeUInt16(dosTime), writeUInt16(dosDate), writeUInt32(checksum), writeUInt32(size), writeUInt32(size), writeUInt16(fileName.length), writeUInt16(0), fileName, ]); localParts.push(localHeader, entry.content); const centralHeader = Buffer.concat([ writeUInt32(0x02014b50), writeUInt16(20), writeUInt16(20), writeUInt16(0), writeUInt16(0), writeUInt16(dosTime), writeUInt16(dosDate), writeUInt32(checksum), writeUInt32(size), writeUInt32(size), writeUInt16(fileName.length), writeUInt16(0), writeUInt16(0), writeUInt16(0), writeUInt16(0), writeUInt32(0), writeUInt32(offset), fileName, ]); centralParts.push(centralHeader); offset += localHeader.length + size; } const centralDirectory = Buffer.concat(centralParts); const endOfCentralDirectory = Buffer.concat([ writeUInt32(0x06054b50), writeUInt16(0), writeUInt16(0), writeUInt16(entries.length), writeUInt16(entries.length), writeUInt32(centralDirectory.length), writeUInt32(offset), writeUInt16(0), ]); return Buffer.concat([...localParts, centralDirectory, endOfCentralDirectory]); } function buildAgent() { const referencesConfig = readJson(path.join(sourceDir, 'references.json')); fs.rmSync(tempDir, { recursive: true, force: true }); fs.mkdirSync(packageDir, { recursive: true }); copyFile(path.join(sourceDir, 'AGENT.md'), path.join(packageDir, 'AGENT.md')); copyFile(path.join(sourceDir, 'manifest.json'), path.join(packageDir, 'manifest.json')); for (const reference of referencesConfig.references) { const sourcePath = path.join(rootDir, reference.source); if (!fs.existsSync(sourcePath)) { throw new Error(`Reference not found: ${reference.source}`); } copyFile(sourcePath, path.join(packageDir, reference.target)); } fs.mkdirSync(publicAgentsDir, { recursive: true }); fs.writeFileSync(zipPath, createZip(collectFiles(packageDir))); fs.rmSync(tempDir, { recursive: true, force: true }); console.log(`Built ${path.relative(rootDir, zipPath)}`); } buildAgent();