osp-cli 1.5.1

CLI and REPL for querying and managing OSP infrastructure data
Documentation
# Plugin Packaging

This document defines how to ship `osp` with optional bundled plugins.

## Distribution Modes

- Base: `osp`
  - Backbone only, no bundled plugins.
- Downstream distro: `osp-acme`
  - Same `osp` binary plus bundled `osp-*` plugin executables.

## Discovery Order

Discovery order is deterministic, but command dispatch no longer auto-selects the
first provider when multiple active plugins expose the same command.

1. `--plugin-dir <dir>` (explicit CLI override)
2. `OSP_PLUGIN_PATH` (colon-separated directories)
3. Bundled plugins dir (package-owned)
4. `<platform-config-dir>/osp/plugins` (for example
   `~/.config/osp/plugins` on Linux)
5. `PATH` (`osp-*` executables) only when
   `extensions.plugins.discovery.path = true`

Conflict rule:
- If exactly one active plugin provides a command, dispatch uses it.
- If multiple active plugins provide a command, dispatch requires either:
  - a one-shot override via `osp <command> --plugin-provider <plugin-id> ...`
    (`--plugin-provider` is accepted anywhere before `--`)
  - or a persisted default via `osp plugins select-provider <command> <plugin-id>`
- `osp plugins commands` and REPL help/completion surface unresolved conflicts
  without inventing a merged grammar.
- Conflicts are surfaced by `osp plugins doctor`.

## Bundled Layout (Suggested)

```text
<install-root>/
  bin/osp
  lib/osp/plugins/
    osp-acme-inventory
    osp-acme-assets
    manifest.toml
```

## Manifest (V1)

```toml
protocol_version = 1

[[plugin]]
id = "acme-inventory"
exe = "osp-acme-inventory"
version = "0.1.0"
enabled_by_default = true
checksum_sha256 = "..."
commands = ["inventory"]

[[plugin]]
id = "acme-assets"
exe = "osp-acme-assets"
version = "0.1.0"
enabled_by_default = true
checksum_sha256 = "..."
commands = ["assets"]
```

## Manifest Validation Rules (Current)

When a bundled plugin directory is used, `osp` validates each plugin against
`manifest.toml`:

- `manifest.toml` must exist for bundled plugin directories that contain
  `osp-*` binaries.
- `protocol_version` must be `1`.
- `plugin.id`, `plugin.exe`, `plugin.version` must be non-empty.
- `plugin.commands` must not be empty.
- `plugin.id` and `plugin.exe` must be unique in the manifest.
- If `checksum_sha256` is set, executable SHA-256 must match before
  `osp` runs the plugin for `--describe`.
- Plugin `--describe` output must then match manifest `id`, `version`,
  and command list.

On mismatch, plugin is marked unhealthy and excluded from command dispatch.

## Scoped Command State

Plugin routing is regular config now, not a sidecar JSON file. State is scoped
by the same profile and terminal rules as the rest of the config.

Example:

```toml
[profile.default.plugins.inventory]
state = "enabled"
provider = "acme-inventory"

[terminal.repl.profile.default.plugins.inventory]
provider = "acme-inventory-beta"
```

Backbone behavior:
- `plugins.<command>.state = "enabled" | "disabled"` controls whether the
  command is available in the active scope.
- `plugins.<command>.provider = "<plugin-id>"` selects the preferred provider
  when multiple healthy plugins expose the same command.
- More specific scopes override less specific scopes.

## Operational Commands

- `osp plugins list`
- `osp plugins commands`
- `osp plugins enable <command>`
- `osp plugins disable <command>`
- `osp plugins clear-state <command>`
- `osp plugins select-provider <command> <plugin-id>`
- `osp plugins clear-provider <command>`
- `osp plugins doctor`