UNPKG

abyss-ai

Version:

Autonomous AI coding agent - enhanced OpenCode with autonomous capabilities

156 lines (136 loc) 5.09 kB
import path from "path" import { Global } from "../global" import fs from "fs/promises" import { z } from "zod" import { NamedError } from "../util/error" import { lazy } from "../util/lazy" import { Log } from "../util/log" import { ZipReader, BlobReader, BlobWriter } from "@zip.js/zip.js" export namespace Fzf { const log = Log.create({ service: "fzf" }) const VERSION = "0.62.0" const PLATFORM = { darwin: { extension: "tar.gz" }, linux: { extension: "tar.gz" }, win32: { extension: "zip" }, } as const export const ExtractionFailedError = NamedError.create( "FzfExtractionFailedError", z.object({ filepath: z.string(), stderr: z.string(), }), ) export const UnsupportedPlatformError = NamedError.create( "FzfUnsupportedPlatformError", z.object({ platform: z.string(), }), ) export const DownloadFailedError = NamedError.create( "FzfDownloadFailedError", z.object({ url: z.string(), status: z.number(), }), ) const state = lazy(async () => { let filepath = Bun.which("fzf") if (filepath) { log.info("found", { filepath }) return { filepath } } filepath = path.join( Global.Path.bin, "fzf" + (process.platform === "win32" ? ".exe" : ""), ) const file = Bun.file(filepath) if (!(await file.exists())) { const archMap = { x64: "amd64", arm64: "arm64" } as const const arch = archMap[process.arch as keyof typeof archMap] ?? "amd64" const config = PLATFORM[process.platform as keyof typeof PLATFORM] if (!config) throw new UnsupportedPlatformError({ platform: process.platform }) const version = VERSION const platformName = process.platform === "win32" ? "windows" : process.platform const filename = `fzf-${version}-${platformName}_${arch}.${config.extension}` const url = `https://github.com/junegunn/fzf/releases/download/v${version}/${filename}` const response = await fetch(url) if (!response.ok) throw new DownloadFailedError({ url, status: response.status }) const buffer = await response.arrayBuffer() const archivePath = path.join(Global.Path.bin, filename) await Bun.write(archivePath, buffer) if (config.extension === "tar.gz") { const proc = Bun.spawn(["tar", "-xzf", archivePath, "fzf"], { cwd: Global.Path.bin, stderr: "pipe", stdout: "pipe", }) await proc.exited if (proc.exitCode !== 0) throw new ExtractionFailedError({ filepath, stderr: await Bun.readableStreamToText(proc.stderr), }) } if (config.extension === "zip") { try { const zipFileReader = new ZipReader(new BlobReader(new Blob([await Bun.file(archivePath).arrayBuffer()]))); const entries = await zipFileReader.getEntries(); let fzfEntry: any; // Look for fzf.exe in the zip archive for (const entry of entries) { if (entry.filename === "fzf.exe" || entry.filename.endsWith("/fzf.exe")) { fzfEntry = entry; break; } } if (!fzfEntry) { // Log available entries for debugging const availableFiles = entries.map(e => e.filename).join(", "); log.warn("fzf.exe not found in zip archive", { availableFiles }); throw new ExtractionFailedError({ filepath: archivePath, stderr: `fzf.exe not found in zip archive. Available files: ${availableFiles}`, }); } const fzfBlob = await fzfEntry.getData(new BlobWriter()); if (!fzfBlob) { throw new ExtractionFailedError({ filepath: archivePath, stderr: "Failed to extract fzf.exe from zip archive", }); } await Bun.write(filepath, await fzfBlob.arrayBuffer()); await zipFileReader.close(); // Verify the extracted file exists and is executable const extractedFile = Bun.file(filepath); if (!(await extractedFile.exists())) { throw new ExtractionFailedError({ filepath: archivePath, stderr: "Extracted fzf.exe file not found after extraction", }); } log.info("successfully extracted fzf.exe for Windows", { filepath }); } catch (error) { log.error("Windows zip extraction failed", { error, archivePath }); throw new ExtractionFailedError({ filepath: archivePath, stderr: `Windows zip extraction failed: ${error instanceof Error ? error.message : String(error)}`, }); } } await fs.unlink(archivePath) if (process.platform !== "win32") await fs.chmod(filepath, 0o755) } return { filepath, } }) export async function filepath() { const { filepath } = await state() return filepath } }