acyclic-plugin 0.1.3

One Acyclic CLI, service, hook runner, MCP bridge, and installer
Documentation
#!/usr/bin/env node
"use strict";

const { createHash } = require("node:crypto");
const { closeSync, existsSync, openSync, readFileSync, readSync } = require("node:fs");
const { join } = require("node:path");

function linuxLibc(report = process.report?.getReport?.()) {
  return typeof report?.header?.glibcVersionRuntime === "string"
    && report.header.glibcVersionRuntime.length > 0 ? "gnu" : "musl";
}

function hostTarget() {
  const arch = { x64: "x64", arm64: "arm64" }[process.arch];
  const os = { win32: "win32", darwin: "darwin", linux: "linux" }[process.platform];
  if (!arch || !os) throw new Error(`unsupported Acyclic platform: ${process.platform}/${process.arch}`);
  return os === "linux" ? `${os}-${arch}-${linuxLibc()}` : `${os}-${arch}`;
}

function targetExecutables(directory) {
  const schema = JSON.parse(readFileSync(join(directory, "targets.json"), "utf8"));
  if (schema.version !== 1 || !schema.targets || Array.isArray(schema.targets)) {
    throw new Error("unsupported Acyclic target schema");
  }
  return schema.targets;
}

function sha256File(path) {
  const hash = createHash("sha256");
  const buffer = Buffer.allocUnsafe(256 * 1024);
  const handle = openSync(path, "r");
  try {
    for (;;) {
      const count = readSync(handle, buffer, 0, buffer.length, null);
      if (count === 0) break;
      hash.update(buffer.subarray(0, count));
    }
  } finally {
    closeSync(handle);
  }
  return hash.digest("hex");
}

function resolveTarget(directory, target = hostTarget()) {
  const manifestPath = join(directory, "platform-binaries.json");
  if (!existsSync(manifestPath)) throw new Error("Acyclic platform manifest is missing");
  const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
  if (manifest.version !== 1 || typeof manifest.targets !== "object") {
    throw new Error("unsupported Acyclic platform manifest");
  }
  const targets = targetExecutables(directory);
  const entry = manifest.targets[target];
  if (!entry) throw new Error(`@acyclic-labs/plugin does not contain the ${target} binary`);
  const executable = targets[target];
  if (!executable) throw new Error(`unsupported Acyclic target: ${target}`);
  const expected = `${target}/${executable}`;
  if (entry.path !== expected) throw new Error("invalid Acyclic binary path in platform manifest");
  const source = join(directory, ...entry.path.split("/"));
  if (!existsSync(source)) throw new Error(`Acyclic binary is missing: ${entry.path}`);
  return { source, manifest };
}

function verifyTarget(directory, target = hostTarget()) {
  const resolved = resolveTarget(directory, target);
  const { source, manifest } = resolved;
  const entry = manifest.targets[target];
  const actual = sha256File(source);
  if (actual !== entry.sha256) throw new Error("Acyclic binary checksum verification failed");
  return resolved;
}

module.exports = { hostTarget, linuxLibc, resolveTarget, sha256File, verifyTarget };

if (require.main === module) {
  verifyTarget(__dirname, process.argv[2]);
}