Current section
Files
Jump to
Current section
Files
lib/asm/extensions/provider_sdk/cursor.ex
defmodule ASM.Extensions.ProviderSDK.Cursor do
@moduledoc """
Discovery metadata and strict derivation helpers for the optional
Cursor-native ASM extension namespace.
Cursor's SDK lane is enabled once `cursor_cli_sdk` is present. Core-lane
Cursor execution remains owned by `CliSubprocessCore.ProviderProfiles.Cursor`.
"""
alias ASM.Extensions.ProviderSDK.{Derivation, Extension}
alias ASM.ProviderRegistry
@sdk_app :cursor_cli_sdk
@sdk_module :"Elixir.CursorCliSdk"
@sdk_options_module :"Elixir.CursorCliSdk.Options"
@runtime_module :"Elixir.CursorCliSdk.Runtime.CLI"
@native_capabilities [:mcp, :plugins, :worktrees]
@native_surface_modules [@runtime_module]
@asm_derived_option_keys [
:model,
:model_payload,
:cli_command,
:cwd,
:execution_surface,
:timeout_ms
]
@spec extension() :: Extension.t()
def extension do
Extension.new!(
id: :cursor,
provider: :cursor,
namespace: __MODULE__,
sdk_app: @sdk_app,
sdk_module: @sdk_module,
description: "Optional Cursor-native extension namespace above the normalized ASM kernel.",
sdk_available?: available?(),
native_capabilities: @native_capabilities,
native_surface_modules: @native_surface_modules
)
end
@spec available?() :: boolean()
def available?, do: ProviderRegistry.sdk_available?(:cursor)
@spec sdk_app() :: atom()
def sdk_app, do: @sdk_app
@spec sdk_module() :: module()
def sdk_module, do: @sdk_module
@spec native_capabilities() :: [atom()]
def native_capabilities, do: @native_capabilities
@spec native_surface_modules() :: [module()]
def native_surface_modules, do: @native_surface_modules
@doc """
Derives `CursorCliSdk.Options` from strict common ASM options.
Cursor-native controls such as `:mode`, `:sandbox`, `:approve_mcps`,
worktree flags, plugin directories, and headers belong in `:native_overrides`.
"""
@spec derive_options(keyword(), keyword()) :: {:ok, struct()} | {:error, term()}
def derive_options(asm_common, opts \\ [])
when is_list(asm_common) and is_list(opts) do
native_overrides = Keyword.get(opts, :native_overrides, [])
with {:ok, preflight} <- Derivation.strict_common(:cursor, asm_common),
:ok <-
Derivation.ensure_native_override_boundary(
native_overrides,
@asm_derived_option_keys,
"Cursor"
) do
attrs =
preflight.common
|> sdk_option_attrs()
|> Keyword.merge(native_overrides)
Derivation.build_sdk_options(@sdk_options_module, attrs, "Cursor")
end
end
defp sdk_option_attrs(common) when is_map(common) do
[]
|> Derivation.maybe_put(:model, Map.get(common, :model))
|> Derivation.maybe_put(:cli_command, Map.get(common, :cli_path))
|> Derivation.maybe_put(:cwd, Map.get(common, :cwd))
|> Derivation.maybe_put(:execution_surface, Map.get(common, :execution_surface))
|> Derivation.maybe_put(:timeout_ms, Map.get(common, :transport_timeout_ms))
end
end