Current section

Files

Jump to
opencode_sdk lib mix tasks opencode.gen.client.ex
Raw

lib/mix/tasks/opencode.gen.client.ex

defmodule Mix.Tasks.Opencode.Gen.Client do
@moduledoc """
Generates Elixir client code from OpenCode CLI OpenAPI specification.
This task:
1. Fetches the OpenAPI spec from the OpenCode CLI (or uses a local spec file)
2. Generates Elixir client code using oapi_generator
## Usage
mix opencode.gen.client
## Options
--spec PATH Path to local OpenAPI spec JSON file (optional)
## Examples
# Generate from running OpenCode CLI
mix opencode.gen.client
# Generate from local spec file
mix opencode.gen.client --spec priv/opencode_openapi.json
"""
use Mix.Task
require Logger
@spec_file "priv/opencode_openapi.json"
@impl Mix.Task
def run(args) do
{opts, _, _} =
OptionParser.parse(args,
switches: [spec: :string],
aliases: [s: :spec]
)
spec_path = opts[:spec] || fetch_spec_from_cli()
unless File.exists?(spec_path) do
Mix.raise("""
OpenAPI spec not found at: #{spec_path}
Please either:
1. Start the OpenCode CLI and run: mix opencode.gen.client
2. Provide a local spec file: mix opencode.gen.client --spec path/to/spec.json
""")
end
Mix.shell().info("🔧 Generating OpenCode client from: #{spec_path}")
Mix.shell().info("")
# Run the OpenAPI generator using the opencode profile
Mix.Task.run("api.gen", ["opencode", spec_path])
Mix.shell().info("")
Mix.shell().info("✅ Client generation complete!")
Mix.shell().info("")
Mix.shell().info("Generated files in: lib/opencode/generated/")
Mix.shell().info("")
Mix.shell().info("Next steps:")
Mix.shell().info(" 1. Review the generated code")
Mix.shell().info(" 2. Run: mix compile")
Mix.shell().info(" 3. Update your code to use the new client module")
:ok
end
defp fetch_spec_from_cli do
# Check if opencode CLI is available in common locations
cli_paths =
[
# From system PATH
System.find_executable("opencode"),
# Local development
"./opencode-cli"
]
|> Enum.reject(&is_nil/1)
|> Enum.filter(&File.exists?/1)
case cli_paths do
[cli_path | _] ->
Mix.shell().info("✓ Found OpenCode CLI at: #{cli_path}")
# Create priv directory if needed
File.mkdir_p!(Path.dirname(@spec_file))
# Generate OpenAPI spec from CLI
case System.cmd(cli_path, ["dev", "generate"], stderr_to_stdout: true) do
{output, 0} ->
File.write!(@spec_file, output)
Mix.shell().info("✓ Fetched OpenAPI spec from CLI")
@spec_file
{error, _} ->
Mix.raise("""
Failed to generate OpenAPI spec from CLI:
#{error}
Make sure the OpenCode CLI is running or provide a local spec file:
mix opencode.gen.client --spec path/to/spec.json
""")
end
[] ->
# Try HTTP endpoint if CLI not found
fetch_spec_from_http()
end
end
defp fetch_spec_from_http do
base_url = System.get_env("OPENCODE_BASE_URL", "http://127.0.0.1:3000")
url = "#{base_url}/openapi.json"
Mix.shell().info("CLI not found, trying HTTP endpoint: #{url}")
case Req.get(url, receive_timeout: 5000) do
{:ok, %{status: 200, body: body}} when is_map(body) ->
File.mkdir_p!(Path.dirname(@spec_file))
File.write!(@spec_file, Jason.encode!(body))
Mix.shell().info("✓ Fetched OpenAPI spec from HTTP endpoint")
@spec_file
{:ok, %{status: status}} ->
Mix.raise("""
HTTP endpoint returned status #{status}
Make sure OpenCode CLI is running at #{base_url}
or provide a local spec file:
mix opencode.gen.client --spec path/to/spec.json
""")
{:error, error} ->
Mix.raise("""
Failed to fetch OpenAPI spec: #{inspect(error)}
Please either:
1. Start the OpenCode CLI and ensure it's accessible
2. Provide a local spec file: mix opencode.gen.client --spec path/to/spec.json
""")
end
end
end