a7af0e5d46
The bookmarks provider opened Firefox's places.sqlite directly via
rusqlite, which pulled libsqlite3-sys with its bundled feature to
compile sqlite3.c statically. In clean Arch chroots the bundled feature
kept slipping out of the resolved feature graph and the chroot build
failed at link time with every sqlite3_* symbol undefined. Inline
features = ["bundled"] on the optional dep didn't help; neither did
the explicit "rusqlite/bundled" feature wiring (commit 7569b2d).
Rather than fight Cargo's resolver further, defer the bookmarks
provider alongside the widgets per the same pattern (D20 -> D22).
Returns in a later 2.x release with a pure-Rust reader:
- Chromium's Bookmarks file is already JSON.
- Firefox exposes JSON backups under ~/.mozilla/firefox/<profile>/
bookmarkbackups/<dated>.jsonlz4 — needs lz4 + JSON parse, no SQLite.
Removed:
- crates/owlry/src/providers/bookmarks.rs
- bookmarks module + registration in providers/mod.rs
- bookmarks feature + rusqlite dep in Cargo.toml
- ProvidersConfig.bookmarks field (existing user configs that still
have 'bookmarks = true' silently ignore it — serde default behavior)
- :bm prefix from README's search-prefix table
- bookmarks acknowledgement in README + ROADMAP roadmap section
Cargo.lock loses rusqlite, libsqlite3-sys, fallible-iterator,
fallible-streaming-iterator, foldhash, hashlink, rsqlite-vfs,
sqlite-wasm-rs (-80 lines).
PKGBUILD: owlry-plugin-bookmarks stays in replaces= (any user who has
it installed still needs a clean upgrade), but moved from the 'folded'
comment block to the 'deferred (D20+)' block.
Docs:
- README: bookmarks removed from optional-providers list, feature
table, search-prefix table, config example. Added to upcoming
roadmap section alongside widgets.
- ROADMAP: 'Bookmarks return' subsection added next to 'Widget
providers return'.
- CLAUDE.md: provider tree updated.
- docs/RESTRUCTURE-V2.md: new decision D22 with chroot-build
rationale; task #6 plugin count 8 -> 7 -> 6.
245 tests pass with --features full (was 252; the 7 bookmarks unit
tests went with the module). Build verified locally; chroot build
should now succeed since libsqlite3-sys is no longer in the graph
at all.
499 lines
28 KiB
Markdown
499 lines
28 KiB
Markdown
# Owlry v2 Restructure Plan
|
||
|
||
**Status:** in progress on branch `v2` (cut from `main @ 1caa050`)
|
||
**Target version:** `owlry 2.0.0`
|
||
**Scope:** repository collapse, C-ABI removal, runtime consolidation, CLI cleanup, single AUR package
|
||
**Originating issue:** [#5 uuctl launcher not working](https://somegit.dev/Owlibou/owlry/issues/5) — closed by deletion of the C-ABI loader that caused it
|
||
|
||
---
|
||
|
||
## 0. Decisions log
|
||
|
||
All design decisions agreed before work started. These are load-bearing — do not silently change them.
|
||
|
||
| # | Decision | Rationale |
|
||
|---|---|---|
|
||
| D1 | Collapse to **1 AUR package**: `owlry` | 14 PKGBUILDs maintained in lockstep was the root cost of every API bump. Native plugin distribution was theoretical (no third-party shipped any). |
|
||
| D2 | **Drop the C-ABI plugin system entirely** | Issue #5's root cause: strict `api_version != API_VERSION` rejection. Compiling providers in eliminates the failure mode. |
|
||
| D3 | **Drop Rune runtime** | Only one user plugin (`hyprshutdown`) uses Rune; will be ported to Lua. 118 MB dylib for one plugin is not earned. |
|
||
| D4 | **Use Lua for config + plugins** via `mlua` (Lua 5.4, bundled) — *Phase 3+* | Single language for both configuration and user extension. LuaJIT perf is irrelevant for a config language. |
|
||
| D5 | **Configs-as-plugins** model | `owlry.provider {}` in `init.lua` registers a runtime provider treated identically to a built-in. No separate `~/.config/owlry/plugins/` dir. |
|
||
| D6 | **Daemon as subcommand** with `-d` short alias: `owlry daemon` or `owlry -d` | Single binary; `owlryd` no longer exists. systemd unit invokes `owlry -d`. |
|
||
| D7 | **`-m auto`** as explicit alias for the implicit no-flag default | Today's `accept_all` behavior — all enabled providers active, tabs cycle. Pinned with an integration test so refactors can't regress it. |
|
||
| D8 | **Hard cut on TOML config** in a later phase | Migrator command `owlry migrate-config` reads existing TOML + script plugins, emits `init.lua`. One-shot; TOML reader deleted in the same release that ships Lua. |
|
||
| D9 | **AUR ships `--features full`** | Defaults in `Cargo.toml` are minimal; AUR PKGBUILD enables everything. End-user picks at runtime via config, not at install time. |
|
||
| D10 | **Runtime activation is config-driven** | Compiled-in ≠ enabled. Config (TOML now, Lua later) decides which providers run. |
|
||
| D11 | **Drop `config_editor` provider** (1127 LOC) | An in-launcher settings editor is replaced by editing `init.lua` + `owlry config validate`. |
|
||
| D12 | **Drop `scripts` provider** | Replaced by `owlry.provider {}` in Lua config (Phase 3+). |
|
||
| D13 | **Rename `sys` → `power`** | "sys" collides mentally with "systemd". `:sys` kept as alias. |
|
||
| D14 | **Keep submenu protocol** | Used by systemd provider for service actions. Becomes a method on the `Provider` trait. |
|
||
| D15 | **Rename systemd unit `owlryd.{service,socket}` → `owlry.{service,socket}`** | Consistent with single-binary collapse. PKGBUILD ships new names; old units cleaned up via `replaces=()` upgrade path. |
|
||
| D16 | **Submenu protocol redesign deferred to Phase 5** | Today's `SUBMENU:type:data` string encoding works. Typed IPC variant is hygiene, not blocking. |
|
||
| D17 | **Keep the daemon** | Cold-start cost (XDG scan, frecency load, provider warm-up) is the real reason the daemon exists. Single-process collapse remains an option to revisit post-2.0 if profiling proves it's free. |
|
||
| D18 | **TOML reader: hard cut at 3.0.0** | One migration moment. 2.x stays TOML-only; 3.0 ships Lua-only with `owlry migrate-config` shipping in 2.x as preview. |
|
||
| D19 | **Lua sandbox** (Phase 3): filesystem read + process spawn allowed; no network by default | Launcher needs to read configs and spawn commands. Network access (HTTP, sockets) requires explicit config opt-in. |
|
||
| D20 | **Widget providers (`weather`, `media`, `pomodoro`) on hold** | UI positioning unresolved. **Excluded from Phase 1 conversion entirely** — not pulled in, not compiled in. Revisit as a dedicated workstream after 2.0 ships. |
|
||
| D21 | **Hot-reload of `init.lua` on save** (Phase 3) | `notify` crate already a dep. Watch `~/.config/owlry/init.lua` and any `require`d files; re-run config eval on change. |
|
||
| D22 | **Bookmarks provider deferred too** | The `rusqlite` dep (for Firefox `places.sqlite`) caused `libsqlite3-sys/bundled` to fall out of the resolved feature graph in clean Arch chroots — every chroot build linked against system sqlite or failed with `sqlite3_*` undefined-symbol errors. Rather than fight Cargo's resolver, defer the bookmarks provider alongside the widgets. Returns when we wire a pure-Rust path (Firefox JSON backups under `bookmarkbackups/`; Chromium's `Bookmarks` is already JSON). |
|
||
|
||
---
|
||
|
||
## 1. Target shape (post-Phase 2 — what 2.0.0 ships as)
|
||
|
||
### Repo layout
|
||
|
||
```
|
||
owlry/
|
||
├── Cargo.toml -- workspace with single member
|
||
├── crates/owlry/
|
||
│ ├── Cargo.toml -- one binary, features per provider
|
||
│ └── src/
|
||
│ ├── main.rs -- subcommand router
|
||
│ ├── cli.rs -- clap defs
|
||
│ ├── server.rs -- daemon mode (was owlry-core/src/server.rs)
|
||
│ ├── client.rs -- IPC client to daemon (UI mode)
|
||
│ ├── backend.rs -- abstracts daemon vs local
|
||
│ ├── ipc.rs -- Request/Response types
|
||
│ ├── filter.rs -- ProviderFilter
|
||
│ ├── paths.rs -- XDG paths
|
||
│ ├── notify.rs -- desktop notifications
|
||
│ ├── theme.rs -- CSS loading
|
||
│ ├── config/ -- config loader (TOML in Phase 1, Lua in Phase 3)
|
||
│ ├── data/ -- FrecencyStore
|
||
│ ├── providers/ -- ALL providers, each gated by feature
|
||
│ │ ├── mod.rs -- ProviderManager, Provider traits, ProviderType
|
||
│ │ ├── application.rs (feature: app)
|
||
│ │ ├── command.rs (feature: cmd)
|
||
│ │ ├── calculator.rs (feature: calc)
|
||
│ │ ├── converter/ (feature: conv)
|
||
│ │ ├── power.rs (feature: power, was sys)
|
||
│ │ ├── dmenu.rs (feature: dmenu, moved from owlry/src/providers/)
|
||
│ │ ├── bookmarks.rs (feature: bookmarks)
|
||
│ │ ├── clipboard.rs (feature: clipboard)
|
||
│ │ ├── emoji.rs (feature: emoji)
|
||
│ │ ├── ssh.rs (feature: ssh)
|
||
│ │ ├── systemd.rs (feature: systemd, type_id "uuctl")
|
||
│ │ ├── websearch.rs (feature: websearch)
|
||
│ │ └── filesearch.rs (feature: filesearch)
|
||
│ │ -- weather, media, pomodoro: deferred (D20)
|
||
│ └── ui/ -- GTK4 client
|
||
├── data/
|
||
│ ├── config.example.toml -- shipped defaults (Phase 1)
|
||
│ └── default-config.lua -- shipped defaults (Phase 3+)
|
||
├── systemd/
|
||
│ ├── owlryd.service -- renamed to owlry.service in Phase 2; ExecStart=/usr/bin/owlry -d
|
||
│ └── owlryd.socket -- renamed to owlry.socket
|
||
└── aur/owlry/PKGBUILD -- the only AUR package
|
||
```
|
||
|
||
### Deleted entirely
|
||
|
||
| Path | Reason |
|
||
|---|---|
|
||
| `crates/owlry-core/` | Folded into `crates/owlry/` |
|
||
| `crates/owlry-plugin-api/` | C-ABI gone |
|
||
| `crates/owlry-lua/` | mlua compiled in via Phase 3 |
|
||
| `crates/owlry-rune/` | Rune dropped (D3) |
|
||
| `crates/owlry-core/src/plugins/` (entire dir) | C-ABI loader, runtime loader, manifest, registry, watcher, error |
|
||
| `crates/owlry-core/src/providers/native_provider.rs` | C-ABI bridge |
|
||
| `crates/owlry-core/src/providers/lua_provider.rs` | Old Lua bridge |
|
||
| `crates/owlry-core/src/providers/config_editor.rs` | D11 |
|
||
| `crates/owlry/src/plugin_commands.rs` (1296 LOC) | No plugin CLI |
|
||
| `aur/owlry-core/`, `aur/owlry-lua/`, `aur/owlry-rune/` | Folded into `aur/owlry/` |
|
||
| `aur/owlry-plugin-*` (none yet in this repo) | n/a |
|
||
| `aur/owlry-meta-*` (essentials, widgets, tools, full) | Redundant |
|
||
| `owlry-plugins/` sibling repo | Archived on somegit.dev |
|
||
|
||
---
|
||
|
||
## 2. CLI shape (post-Phase 1)
|
||
|
||
```
|
||
owlry launch UI, auto mode (default)
|
||
owlry -m auto launch UI, auto mode (explicit alias)
|
||
owlry -m <mode> launch UI in single-provider mode
|
||
owlry --profile <name> launch UI with a named profile
|
||
|
||
owlry daemon run daemon (alias: owlry -d)
|
||
owlry dmenu [-p <prompt>] dmenu mode (was: owlry -m dmenu)
|
||
owlry doctor diagnostics: providers, config, socket, runtime
|
||
owlry providers [<name>] list providers (or show one)
|
||
owlry config validate check config for errors
|
||
owlry config show print resolved effective config
|
||
owlry migrate-config TOML → init.lua (Phase 3+)
|
||
```
|
||
|
||
### Removed CLI surface
|
||
|
||
The entire `owlry plugin ...` subcommand tree (~1296 LOC in `plugin_commands.rs`) is deleted:
|
||
`list`, `search`, `info`, `install`, `remove`, `update`, `enable`, `disable`, `create`, `validate`, `runtimes`, `run`, `commands`.
|
||
There is no plugin installation to manage — features are compiled in.
|
||
|
||
---
|
||
|
||
## 3. Feature names + descriptions
|
||
|
||
Final naming for cargo features and corresponding provider IDs:
|
||
|
||
| Feature | CLI mode / prefix | What it does |
|
||
|---|---|---|
|
||
| `app` | `:app` | XDG desktop applications |
|
||
| `cmd` | `:cmd` | Executables on `$PATH` |
|
||
| `calc` | `:calc` / `=` | Calculator (math expressions, e.g. `= 2+2`) |
|
||
| `conv` | `:conv` | Unit & currency converter (e.g. `5 ft to m`) |
|
||
| `power` | `:power` (`:sys` alias) | Shutdown, reboot, logout, suspend, lock — was `sys` |
|
||
| `dmenu` | (subcommand) | Pipe-based selection — stdin in, selection out |
|
||
| `bookmarks` | `:bm` | Browser bookmarks (Firefox, Chromium) |
|
||
| `clipboard` | `:clip` | Clipboard history via `cliphist`/`wl-clipboard` |
|
||
| `emoji` | `:emoji` | Emoji picker (writes via `wl-clipboard`) |
|
||
| `ssh` | `:ssh` | SSH hosts from `~/.ssh/config` |
|
||
| `systemd` | `:systemd` (`:uuctl` alias) | systemd user units (type_id stays "uuctl" for config compat) |
|
||
| `websearch` | `:web` / `?` | Web search (DDG, Google, custom engines) |
|
||
| `filesearch` | `:file` / `/` | File search via `fd` or `mlocate` |
|
||
| ~~`weather`~~ | — | **Deferred (D20)** — not in 2.0.0 |
|
||
| ~~`media`~~ | — | **Deferred (D20)** — not in 2.0.0 |
|
||
| ~~`pomodoro`~~ | — | **Deferred (D20)** — not in 2.0.0 |
|
||
|
||
### Cargo feature groups
|
||
|
||
```toml
|
||
[features]
|
||
default = ["app", "cmd", "calc", "conv", "power", "dmenu"]
|
||
full = [
|
||
"app", "cmd", "calc", "conv", "power", "dmenu",
|
||
"bookmarks", "clipboard", "emoji", "ssh", "systemd",
|
||
"websearch", "filesearch",
|
||
# widgets (weather, media, pomodoro): deferred (D20)
|
||
]
|
||
dev-logging = []
|
||
```
|
||
|
||
AUR PKGBUILD builds with `--features full`.
|
||
|
||
---
|
||
|
||
## 4. Runtime config (Phase 1: TOML, Phase 3+: Lua)
|
||
|
||
Three orthogonal axes:
|
||
|
||
1. **Compiled in** — Cargo features at build time. AUR ships `full`.
|
||
2. **Enabled** — Config decides which providers actually run.
|
||
3. **Selected** — `-m` / `--profile` / Tab key narrows the active set at use time.
|
||
|
||
### Phase 1 (TOML, kept temporarily)
|
||
|
||
```toml
|
||
[general]
|
||
tabs = ["app", "cmd", "calc", "conv", "power"] # what shows in auto mode
|
||
|
||
[providers]
|
||
applications = true
|
||
commands = true
|
||
calculator = true
|
||
converter = true
|
||
power = true # was `system`
|
||
bookmarks = false # opt-in
|
||
clipboard = false
|
||
# ...etc
|
||
```
|
||
|
||
### Phase 3+ (Lua, target)
|
||
|
||
```lua
|
||
local owlry = require("owlry")
|
||
|
||
owlry.set {
|
||
theme = "apex-neon",
|
||
width = 850, height = 650,
|
||
tabs = { "app", "cmd", "power" },
|
||
}
|
||
|
||
owlry.providers { "app", "cmd", "calc", "conv", "power", "bookmarks", "systemd" }
|
||
|
||
owlry.provider {
|
||
id = "hs", prefix = ":hs", tab_label = "Shutdown",
|
||
items = function(_q)
|
||
return {
|
||
{ name = "Lock", command = "hyprlock" },
|
||
{ name = "Shutdown", command = "systemctl poweroff" },
|
||
{ name = "Reboot", command = "systemctl reboot" },
|
||
}
|
||
end,
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 5. Phased plan
|
||
|
||
### Phase 1 — Repo collapse (current)
|
||
|
||
Goal: single workspace member, single binary, TOML config still works, C-ABI gone, all built-in providers compiled in behind features.
|
||
|
||
Subtasks (tracked in TaskList):
|
||
|
||
1. ✅ Inventory: map Provider trait + plugin shapes
|
||
2. **Workspace skeleton: collapse to single crate** — move `owlry-core/src/*` into `owlry/src/`, absorb deps, remove other crates from workspace
|
||
3. **Delete C-ABI plugin system** — `plugins/` dir, `native_provider.rs`, `lua_provider.rs`, `owlry-plugin-api` crate; strip `ProviderManager::new_with_config()` of plugin loading
|
||
4. **Delete Rune + Lua runtime crates** — `crates/owlry-rune/`, `crates/owlry-lua/`
|
||
5. **Delete config_editor + scripts providers**
|
||
6. **Convert 6 plugins to native Provider impls** — clipboard, emoji, ssh, systemd, websearch, filesearch. Pull source from `owlry-plugins/crates/owlry-plugin-*`, convert `extern "C"` vtable → `impl Provider` / `impl DynamicProvider`. Per-plugin mechanical work. **Widgets (weather, media, pomodoro) excluded per D20; scripts excluded per D12; bookmarks excluded per D22.**
|
||
7. **Wire cargo features per provider** — `#[cfg(feature = "...")]` gating; `default` / `full` feature groups
|
||
8. **Rename `sys` → `power`** — file, type_id (in CLI mode mapping table), `:sys` kept as alias, config key `providers.system` → `providers.power` (with TOML migration shim that reads the old name)
|
||
9. **CLI restructure** — new clap shape (subcommands `daemon`, `dmenu`, `doctor`, `providers`, `config`, `migrate-config`); drop entire `plugin` subcommand tree; daemon mode via `owlry -d` / `owlry daemon`
|
||
10. **Auto-mode integration test** — `tests/auto_mode.rs` asserts the no-flag default still surfaces results from all enabled providers and tabs match `general.tabs`
|
||
11. **Phase 1 final build + smoke** — `cargo check --workspace`, `cargo build --release`, `cargo test`, runtime socket smoke
|
||
|
||
### Phase 2 — AUR republish as 2.0.0
|
||
|
||
Goal: ship the collapsed binary to users. Issue #5 closes by virtue of the C-ABI being gone.
|
||
|
||
Steps:
|
||
|
||
- Update `aur/owlry/PKGBUILD`:
|
||
- `pkgver=2.0.0`
|
||
- `replaces=('owlry-core' 'owlry-lua' 'owlry-rune' 'owlry-plugin-bookmarks' 'owlry-plugin-clipboard' 'owlry-plugin-emoji' 'owlry-plugin-filesearch' 'owlry-plugin-media' 'owlry-plugin-pomodoro' 'owlry-plugin-scripts' 'owlry-plugin-ssh' 'owlry-plugin-systemd' 'owlry-plugin-weather' 'owlry-plugin-websearch' 'owlry-meta-essentials' 'owlry-meta-widgets' 'owlry-meta-tools' 'owlry-meta-full')`
|
||
- `conflicts=(<same list>)`
|
||
- `provides=(<same list>)`
|
||
- `build()` uses `cargo build --release --features full`
|
||
- `package()` installs single binary, single systemd service+socket, default config
|
||
- Delete the 14 other PKGBUILDs under `aur/`
|
||
- `git tag owlry-v2.0.0`
|
||
- Push, build, `aur-publish`
|
||
- Archive `owlry-plugins` sibling repo on somegit.dev (read-only, history preserved)
|
||
- Comment on issue #5: "fixed by 2.0 rewrite; the C-ABI plugin loader that produced this class of bug has been removed"
|
||
|
||
### Phase 3 — Lua config core (later release: 2.1.0 or 3.0.0)
|
||
|
||
Goal: replace TOML with Lua-driven config. Hyprland-style configs-as-code.
|
||
|
||
Steps:
|
||
|
||
- Add `mlua = { version = "0.11", features = ["lua54", "vendored", "send", "serialize"] }` dependency
|
||
- Build the `owlry.*` Lua API surface:
|
||
- `owlry.set { ... }` — global settings (theme, dimensions, tabs)
|
||
- `owlry.providers { ... }` — enable list (subset of compiled-in features)
|
||
- `owlry.provider { id, prefix, tab_label, items, ... }` — register a runtime provider
|
||
- `owlry.bind(key, action)` — keybinding overrides
|
||
- `owlry.theme(name | { ... })` — theme selection or inline definition
|
||
- Resolve config: `~/.config/owlry/init.lua` if present; else fall back to shipped `data/default-config.lua`
|
||
- `owlry migrate-config` subcommand: read existing `config.toml` (+ `~/.config/owlry/plugins/*` if any) and emit equivalent `init.lua`
|
||
- Wire `owlry config validate` and `owlry config show` to surface Lua errors and resolved state
|
||
- Decision pending: hard cut TOML in 3.0.0 vs. dual-read in 2.1.0 → cut in 3.0.0
|
||
|
||
### Phase 4 — Configs-as-plugins (same release as Phase 3)
|
||
|
||
Goal: Lua-registered providers are first-class. Drop the script plugin discovery dir.
|
||
|
||
Steps:
|
||
|
||
- `owlry.provider {}` creates a `LuaProvider` that wraps the supplied Lua closures and implements the `Provider` trait
|
||
- Remove the `~/.config/owlry/plugins/` filesystem discovery entirely
|
||
- The shipped `default-config.lua` showcases at least one inline provider as documentation
|
||
|
||
### Phase 5 — Hygiene
|
||
|
||
Goal: clean up debt that the collapse uncovered.
|
||
|
||
Steps:
|
||
|
||
- Update `CLAUDE.md` — binary name (`owlry`, not `owlry-core`/`owlryd`), workspace layout, drop "Phase 5 pending" wording
|
||
- Update `README.md` — new CLI, new install instructions, drop AUR package list
|
||
- Refresh `ROADMAP.md`
|
||
- Split files >1000 LOC:
|
||
- `providers/mod.rs` — separate `ProviderType` / `LaunchItem` / `ItemSource` from `ProviderManager`
|
||
- `ui/main_window.rs` — input handling, render, signal wiring as separate modules
|
||
- `providers/converter/units.rs` — move data tables to a `units.toml` resource
|
||
- Fix double-daemon spawn: rely on socket activation only; add `flock` guard in `main.rs` if needed
|
||
- Make sure systemd unit name is `owlry.service` (or `owlryd.service`?) — decide before AUR ship
|
||
|
||
---
|
||
|
||
## 6. Provider-by-provider conversion notes (Phase 1.6)
|
||
|
||
Mechanical pattern for each plugin: drop `extern "C"` exports, `PluginItem` → `LaunchItem`, opaque `ProviderHandle` → struct field on a `Provider` impl.
|
||
|
||
### `provider_kind`-driven categorization (current state)
|
||
|
||
| Plugin | Kind | Submenu? | Per-keystroke? | Notes |
|
||
|---|---|---|---|---|
|
||
| ~~bookmarks~~ | DEFER | — | — | **D22** — rusqlite/bundled fragile in chroot; returns with a pure-Rust reader |
|
||
| clipboard | Static | yes (?) | no | Uses `cliphist`, `wl-clipboard` |
|
||
| emoji | Static | no | no | Bundled emoji data; writes via `wl-clipboard` |
|
||
| ssh | Static | no | no | Parses `~/.ssh/config` |
|
||
| systemd | Static | **yes** | no | type_id "uuctl"; SUBMENU: protocol for service actions |
|
||
| scripts | DELETE | — | — | Replaced by Lua config (D12) |
|
||
| websearch | Dynamic | no | yes | per-keystroke; `?` trigger |
|
||
| filesearch | Dynamic | no | yes | per-keystroke; `/` trigger; `fd` or `mlocate` |
|
||
| ~~weather~~ | DEFER | — | — | **D20** — UI positioning unresolved |
|
||
| ~~media~~ | DEFER | — | — | **D20** — UI positioning unresolved |
|
||
| ~~pomodoro~~ | DEFER | — | — | **D20** — UI positioning unresolved |
|
||
|
||
### Submenu mechanism on `Provider` trait
|
||
|
||
Add to `pub trait Provider`:
|
||
|
||
```rust
|
||
/// Returns submenu actions for the given encoded data string, or empty if none.
|
||
/// Called when a user selects an item whose command field starts with "SUBMENU:".
|
||
fn submenu_actions(&self, _data: &str) -> Vec<LaunchItem> { Vec::new() }
|
||
|
||
/// Handle a plugin-defined action command (e.g. "POMODORO:start").
|
||
/// Returns true if handled.
|
||
fn execute_action(&self, _command: &str) -> bool { false }
|
||
|
||
/// Optional UI hints — replace today's hardcoded match table.
|
||
fn prefix(&self) -> Option<&str> { None }
|
||
fn icon(&self) -> Option<&str> { None }
|
||
fn position(&self) -> ProviderPosition { ProviderPosition::Normal }
|
||
fn priority(&self) -> u32 { 0 }
|
||
```
|
||
|
||
`ProviderManager::query_submenu_actions` and `execute_plugin_action` route to these trait methods instead of the C-ABI `NativeProvider`.
|
||
|
||
---
|
||
|
||
## 7. Breaking changes / migration impact
|
||
|
||
### What users lose at 2.0.0
|
||
|
||
- 14 separate AUR packages → 1 (paru handles via `replaces`/`conflicts`)
|
||
- Ability to install a subset of plugins via AUR (still possible via `cargo install --no-default-features --features ...`)
|
||
- Rune scripting (the user's `hyprshutdown` plugin breaks; will be ported to Lua in Phase 3, or compiled into a small custom build)
|
||
- Dynamic plugin loading at runtime (was never used by anyone outside Owlibou)
|
||
- `~/.config/owlry/plugins/` directory (Phase 4 — but already orphaned at 2.0.0 since Rune is gone)
|
||
|
||
### What stays unchanged for users
|
||
|
||
- Launcher behavior, keybindings, themes, search prefixes
|
||
- Mode flags: `-m app`, `-m systemd`, `-m uuctl` (alias), `-m power` (was `-m sys`)
|
||
- TOML config compatibility through 2.x — until Phase 3 hard-cut to Lua
|
||
- Socket protocol (mostly — `Request::PluginList` is dropped; `Submenu` and `PluginAction` stay)
|
||
- systemd integration (unit file invokes `owlry -d` instead of `owlryd`)
|
||
|
||
### `replaces=()` array for `aur/owlry/PKGBUILD` (2.0.0)
|
||
|
||
```
|
||
owlry-core
|
||
owlry-lua
|
||
owlry-rune
|
||
owlry-plugin-bookmarks
|
||
owlry-plugin-clipboard
|
||
owlry-plugin-emoji
|
||
owlry-plugin-filesearch
|
||
owlry-plugin-media
|
||
owlry-plugin-pomodoro
|
||
owlry-plugin-scripts
|
||
owlry-plugin-ssh
|
||
owlry-plugin-systemd
|
||
owlry-plugin-weather
|
||
owlry-plugin-websearch
|
||
owlry-meta-essentials
|
||
owlry-meta-widgets
|
||
owlry-meta-tools
|
||
owlry-meta-full
|
||
```
|
||
|
||
---
|
||
|
||
## 8. Open questions — RESOLVED
|
||
|
||
All section-8 questions from the original plan have been answered. Captured as D15–D21 in section 0.
|
||
|
||
| Original question | Resolution | Recorded as |
|
||
|---|---|---|
|
||
| systemd unit name | Rename to `owlry.{service,socket}` | D15 |
|
||
| Submenu protocol redesign | Deferred to Phase 5 | D16 |
|
||
| Drop daemon entirely? | No — cold-start cost justifies it | D17 |
|
||
| TOML reader removal timing | Hard cut at 3.0.0 | D18 |
|
||
| Lua sandbox model | fs read + process spawn allowed; no network by default | D19 |
|
||
| Widget positioning | On hold; widgets excluded from Phase 1 | D20 |
|
||
| Hot-reload init.lua | Yes (Phase 3) | D21 |
|
||
|
||
### Newly open (post-resolution)
|
||
|
||
| Question | Defer to | Notes |
|
||
|---|---|---|
|
||
| Widget rework: keep the "Widget position" UI concept, redesign, or drop entirely? | Post-2.0 workstream | Pulled out of Phase 1 scope per D20. Decide before re-introducing weather/media/pomodoro. |
|
||
| `owlry migrate-config` shipped in 2.x as preview, or only at 3.0.0? | Phase 3 planning | Lean toward shipping in 2.1.0 as a preview so users can test their migrations before TOML is gone. |
|
||
|
||
---
|
||
|
||
## 9. Build / verify checklist (Phase 1 acceptance)
|
||
|
||
Phase 1 is "done" when all of these pass:
|
||
|
||
- [ ] `cargo check --workspace` (no warnings on default features)
|
||
- [ ] `cargo check --workspace --all-features` (no warnings)
|
||
- [ ] `cargo build --release --features full`
|
||
- [ ] `cargo test --workspace --all-features`
|
||
- [ ] `cargo clippy --workspace --all-features -- -D warnings`
|
||
- [ ] `cargo fmt --all --check`
|
||
- [ ] Workspace contains only `crates/owlry` member
|
||
- [ ] `crates/owlry-core/`, `crates/owlry-plugin-api/`, `crates/owlry-lua/`, `crates/owlry-rune/` no longer exist
|
||
- [ ] No occurrences of `owlry_plugin_api`, `mlua`, `libloading`, `Rune`, `liblua.so`, `librune.so` outside historical docs
|
||
- [ ] `target/release/owlry` runs:
|
||
- `owlry --help` shows new subcommand structure
|
||
- `owlry doctor` reports providers + config + socket status
|
||
- `owlry -d` starts daemon; socket listens at `$XDG_RUNTIME_DIR/owlry/owlry.sock`
|
||
- `owlry -m systemd` shows systemd units (Issue #5 fixed locally)
|
||
- `owlry` (no flags) shows auto mode with results from all enabled providers, tabs match `general.tabs`
|
||
- [ ] Integration test `tests/auto_mode.rs` passes
|
||
- [ ] No daemon double-spawn (verify `pgrep -af owlry` shows one process when launched normally)
|
||
|
||
---
|
||
|
||
## 10. Working notes (mutable)
|
||
|
||
This section captures in-progress state. Update freely as work proceeds.
|
||
|
||
- **Branch:** `v2`, cut from `main @ 1caa050` on 2026-05-13
|
||
- **Checkpoints landed:**
|
||
- `163e68a` — plan doc
|
||
- `2fc976b` — D15–D21 resolutions
|
||
- `ae4a903` — C-ABI demolition: tasks #3/#4/#5 done in one commit
|
||
- `1d20754` — TDD characterization pass (+36 tests)
|
||
- `0a4a090` — Workspace collapse: owlry-core merged into owlry (task #2)
|
||
- `eb8a65f` — systemd provider converted (issue #5 functional fix in v2)
|
||
- `cb2ea59` — Remaining 6 plugins converted in parallel: bookmarks, clipboard, emoji, filesearch, ssh, websearch (tasks #6 + #7)
|
||
- `d1c3270` + `1ba0a97` — sys → power rename (task #8)
|
||
- `27e2683` — CLI subcommand restructure + doctor/providers/config/migrate-config (task #9)
|
||
- `e9f310d` — auto-mode integration test (task #10)
|
||
- `c48efaa` — cargo fmt pass
|
||
- `0376abd` — OWLRY_SOCKET env override (smoke-test enabler)
|
||
|
||
**Phase 1 status: COMPLETE** — 11/11 tasks done. Ready for Phase 2 (AUR republish as 2.0.0).
|
||
|
||
Phase 1 acceptance results:
|
||
- ✅ `cargo check --workspace` (no default features) — clean
|
||
- ✅ `cargo check --workspace --features full` — clean
|
||
- ✅ `cargo build --release --features full` — 1m 19s
|
||
- ✅ `cargo test --workspace --features full` — **252 tests pass** (225 unit + 5 auto-mode + 14 ipc + 8 server)
|
||
- ✅ `cargo clippy --workspace --features full` — only 10 style warnings (`sort_by_key` suggestions, all benign)
|
||
- ✅ `cargo fmt --all --check` — clean after `c48efaa`
|
||
- ✅ Workspace contains only `crates/owlry` member
|
||
- ✅ `crates/owlry-core/`, `crates/owlry-plugin-api/`, `crates/owlry-lua/`, `crates/owlry-rune/` removed
|
||
- ✅ No occurrences of `owlry_plugin_api`, `mlua`, `libloading`, `liblua.so`, `librune.so`
|
||
- ✅ `target/release/owlry --help` shows new subcommand structure
|
||
- ✅ `owlry -d` starts daemon, socket binds at `$XDG_RUNTIME_DIR/owlry/owlry.sock`
|
||
- ✅ `owlry doctor` reports config + socket + 8 provider IDs
|
||
- ✅ `owlry providers` lists all registered providers; `owlry providers uuctl` shows the systemd provider details (id, prefix, icon, etc.)
|
||
- ✅ Issue #5 functionally fixed: systemd provider compiled in AND verified live — `owlry providers uuctl dbus` returns dbus-broker + at-spi-dbus-bus from the running daemon's real `systemctl --user list-units` invocation. 43 user units loaded at refresh time.
|
||
- ✅ Every provider entry point smoke-tested with proper `modes` parameter: 13/13 produced expected output (app→Firefox, cmd→git*, power→Shutdown, bookmarks→GitHub*, clipboard→50 entries, emoji→heart*, ssh→aur.archlinux.org, uuctl→dbus-broker, calc 2+2→4, conv 5 ft to m→1.524 m, websearch→Search URL, filesearch→file matches).
|
||
- ⚠️ Daemon double-spawn: pre-existing PIDs 3042 + 3278 still around (not Phase 1 work; addressed in Phase 5 hygiene)
|
||
|
||
Known follow-ups (deferred, not blocking 2.0.0 ship):
|
||
- Dynamic providers (calc, conv, filesearch, websearch) don't appear in `available_providers()` — pre-existing behavior matched the old impl. Worth surfacing in `doctor` later.
|
||
- 10 clippy `sort_by_key` style warnings — Phase 5 cleanup.
|
||
- `refresh_widgets()` no-op stub in `backend.rs` — remove when widgets are revisited (D20 work).
|
||
- **Tasks done:** #1 inventory, #3 delete C-ABI, #4 delete Rune+Lua crates, #5 delete config_editor (scripts never lived in this repo)
|
||
- **Tasks remaining (Phase 1):** #2 workspace collapse, #6 convert 8 plugins, #7 cargo features, #8 sys→power rename, #9 CLI subcommands, #10 auto-mode test, #11 final build+smoke
|
||
- **Stray processes from inventory phase:**
|
||
- PIDs 3042, 3278 — pre-existing `owlryd` (double-spawn bug; will resolve via Phase 5)
|
||
- PID 594897 — test daemon from inventory probe; harness denied kill; resolves at next reboot or user kill
|
||
- **Hyprland exec-once for owlryd:** suspected source of double-spawn; verify and remove during Phase 5
|
||
- **`plugin-api-v1.0.1` git tag:** still has `API_VERSION = 3`. Moot now — C-ABI deleted.
|
||
- **Known clippy nits (Phase 5 cleanup):** ~8 `sort_by` → `sort_by_key` suggestions in `providers/mod.rs` and currency provider. Style only, not blocking.
|
||
- **`refresh_widgets()` stub in `backend.rs`:** retained as a no-op since the UI still calls it. Delete when widgets are revisited (post-2.0 per D20).
|
||
- **`system` provider rename to `power` (D13):** pending Task #8. Internal type_id and config key still `system`. Test names still use `sys_plugin`.
|