defmodule Mix.Tasks.ZenQuant.Manifest do @shortdoc "Export ZenQuant API manifest as JSON" @moduledoc """ Exports the ZenQuant API manifest as a static JSON file. The manifest describes all ZenQuant modules and their public functions, including typespecs, documentation hints, and parameter metadata. Non-BEAM consumers (CI pipelines, other languages, EIP-8004 registration) can use this artifact to discover ZenQuant's capabilities. ## Usage mix zen_quant.manifest mix zen_quant.manifest --output /tmp/manifest.json """ use Mix.Task @default_output "api_manifest.json" @doc false @impl Mix.Task def run(args) do Mix.Task.run("app.start") {opts, _rest} = OptionParser.parse!(args, strict: [output: :string]) output_path = opts[:output] || @default_output manifest = ZenQuant.Manifest.build() json = manifest |> json_safe() |> JSON.encode!() File.write!(output_path, json) module_count = length(manifest[:modules]) func_count = Enum.sum_by(manifest[:modules], &length(&1[:functions])) Mix.shell().info("Wrote #{output_path} (#{module_count} modules, #{func_count} functions)") end defp json_safe(%_{} = value), do: value defp json_safe(value) when is_map(value) do Map.new(value, fn {key, val} -> {key, json_safe(val)} end) end defp json_safe(value) when is_list(value), do: Enum.map(value, &json_safe/1) defp json_safe(value) when is_tuple(value), do: value |> Tuple.to_list() |> Enum.map(&json_safe/1) defp json_safe(value), do: value end