Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
132 changes: 125 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ indicatif = "0.17.7"
libloading = "0.8.1"
uuid = { version = "1.6.1", features = ["v4"] }
hidapi = { version = "2.6.5", optional = true }
hex = "0.4.3"
zxcvbn = "=3.1.0"
sha2 = "0.10"
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "json", "fmt"] }
Expand Down
103 changes: 93 additions & 10 deletions DEVELOPER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,99 @@ Complete guide for developers contributing to or extending StarForge.

## Table of Contents

1. [Getting Started](#getting-started)
2. [Development Setup](#development-setup)
3. [Project Structure](#project-structure)
4. [Code Style Guide](#code-style-guide)
5. [Adding New Features](#adding-new-features)
6. [Testing](#testing)
7. [Documentation](#documentation)
8. [Common Tasks](#common-tasks)
9. [Debugging](#debugging)
10. [Release Process](#release-process)
1. [Plugin Version Compatibility](#plugin-version-compatibility)
2. [Getting Started](#getting-started)
3. [Development Setup](#development-setup)
4. [Project Structure](#project-structure)
5. [Code Style Guide](#code-style-guide)
6. [Adding New Features](#adding-new-features)
7. [Testing](#testing)
8. [Documentation](#documentation)
9. [Common Tasks](#common-tasks)
10. [Debugging](#debugging)
11. [Release Process](#release-process)

---

## Plugin Version Compatibility

StarForge enforces version compatibility when loading plugins to prevent subtle
runtime failures caused by ABI or API mismatches.

### How it works

Every plugin shared library must export a `PLUGIN_DECLARATION` symbol (provided
automatically by the `export_plugin!` macro). When `starforge plugin load` runs,
the loader checks two fields in that declaration:

| Field | What is checked | Failure behaviour |
|---|---|---|
| `rustc_version` | Must match the exact rustc version used to build StarForge | Hard error — load aborted |
| `core_version` | **Major** version must match StarForge's own `CARGO_PKG_VERSION` | Hard error — load aborted |

The compatibility rule for `core_version` follows semantic versioning:

- `0.x.y` plugins are **only** compatible with a `0.x.y` StarForge core (major `0`).
- `1.x.y` plugins are **only** compatible with a `1.x.y` StarForge core (major `1`).
- Minor and patch bumps within the same major are considered backwards-compatible.

### Error messages

When a plugin fails the version check you will see a clear message, for example:

```
Error: Plugin version incompatibility in 'libmy_plugin.so':
Plugin was built for StarForge 0.1.0
Running StarForge 1.0.0

The major version must match. Rebuild the plugin against
StarForge 1.0.0 or install a compatible StarForge version.
See DEVELOPER_GUIDE.md § "Plugin Version Compatibility" for details.
```

### Writing a compatible plugin

1. **Pin the StarForge version** in your plugin's `Cargo.toml`:

```toml
[dependencies]
# Use the same major version as the StarForge binary your users will run.
starforge = "0.1"
```

2. **Use the `export_plugin!` macro** — it embeds both `rustc_version` and
`core_version` automatically at compile time:

```rust
use starforge::export_plugin;

export_plugin!(register);

fn register(registrar: &mut dyn starforge::plugins::PluginRegistrar) {
registrar.register_plugin(Box::new(MyPlugin));
}
```

3. **Rebuild when StarForge's major version changes.** Check the running version
with `starforge --version` and compare it to the version your plugin was built
against (shown in `starforge plugin load` output under "Built for StarForge").

4. **Use the same Rust toolchain** as the StarForge binary. The easiest way is
to keep a `rust-toolchain.toml` in your plugin repo that mirrors the one in
the StarForge repo.

### Checking compatibility without loading

```bash
# See which StarForge version is running
starforge --version

# See which version each installed plugin was built for
starforge plugin load
```

The `load` command prints a "Built for StarForge" line for every successfully
loaded plugin, and a descriptive error for any that fail the check.

---

Expand Down
6 changes: 5 additions & 1 deletion src/commands/plugin.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::plugins::interface::CORE_VERSION;
use crate::plugins::{registry, PluginManager};
use crate::utils::print as p;
use anyhow::{Context, Result};
Expand Down Expand Up @@ -58,6 +59,7 @@ fn list() -> Result<()> {
return Ok(());
}

p::kv("StarForge core version", CORE_VERSION);
p::separator();
for (i, pl) in reg.plugins.iter().enumerate() {
println!(" {:>2}. {}", i + 1, pl.name);
Expand Down Expand Up @@ -93,9 +95,11 @@ fn load() -> Result<()> {
return Ok(());
}

p::kv("StarForge core version", CORE_VERSION);
p::separator();
for (name, desc) in loaded {
for (name, desc, built_for) in loaded {
p::kv_accent(name, desc);
p::kv("Built for StarForge", built_for);
}
p::separator();
Ok(())
Expand Down
Loading