# `MingaEditor.Shell.Registry`
[🔗](https://github.com/jsmestad/minga/blob/main/lib/minga_editor/shell/registry.ex#L1)

Source-owned registry for workspace shells.

The active editor shell is read on input and render hot paths, so the registry stores a validated, sorted snapshot in `persistent_term`. Registration and cleanup may do validation work; reads are simple map/list lookups and never call extension code.

# `register_attrs`

```elixir
@type register_attrs() :: keyword() | map()
```

# `register_error`

```elixir
@type register_error() ::
  {:duplicate_id, shell_id()}
  | {:duplicate_module, module(), shell_id()}
  | {:duplicate_default, shell_id()}
  | {:missing_default, term()}
  | {:invalid_entry, term()}
  | :source_required
  | :not_owner
```

# `shell_id`

```elixir
@type shell_id() :: atom()
```

# `source`

```elixir
@type source() :: Minga.Extension.ContributionCleanup.contribution_source()
```

# `available?`

```elixir
@spec available?(shell_id()) :: boolean()
```

Returns true when the id is currently registered.

# `default`

```elixir
@spec default() :: MingaEditor.Shell.Entry.t()
```

Returns the default shell entry, falling back to Traditional when the registry is empty.

# `get`

```elixir
@spec get(shell_id()) :: MingaEditor.Shell.Entry.t() | nil
```

Returns a shell entry by id.

# `id_for_module`

```elixir
@spec id_for_module(module()) :: shell_id() | nil
```

Returns the shell id registered for a module, or nil.

# `list`

```elixir
@spec list() :: [MingaEditor.Shell.Entry.t()]
```

Returns registered shells in deterministic display order.

# `module_for`

```elixir
@spec module_for(shell_id()) :: module() | nil
```

Returns the registered module for an id, or nil.

# `register`

```elixir
@spec register(source(), register_attrs()) :: :ok | {:error, register_error()}
```

Registers a shell contribution.

# `reset_for_test`

```elixir
@spec reset_for_test([MingaEditor.Shell.Entry.t()]) :: :ok
```

Resets registry state. Intended for tests that need isolated registry setup.

# `seed_builtin`

```elixir
@spec seed_builtin() :: :ok
```

Registers the built-in shell contributions. Safe to call more than once.

# `supports?`

```elixir
@spec supports?(shell_id(), atom()) :: boolean()
```

Returns true when the shell supports a capability atom.

# `unregister`

```elixir
@spec unregister(shell_id()) :: :ok | {:error, :builtin_shell | :source_required}
```

Unregisters a shell by id. Built-in shells are intentionally preserved. Extension shells must use unregister/2.

# `unregister`

```elixir
@spec unregister(source(), shell_id()) :: :ok | {:error, :builtin_shell | :not_owner}
```

Unregisters a shell owned by the given source.

# `unregister_source`

```elixir
@spec unregister_source(source()) :: :ok
```

Unregisters all shells owned by a source. Built-in shells are intentionally preserved.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
