main
319 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
5ae5bb8b87 | chore(aur): update owlry to 2.1.0 | ||
|
|
bee64dc082 | chore(owlry): bump version to 2.1.0 owlry-v2.1.0 | ||
|
|
52833c1a33 | Merge pull request 'owlry 2.1.0: Lua config layer (Phase 3)' (#8) from feat/lua-config into main | ||
|
|
02c3281afe |
feat(doctor): surface config source + migrate hint + legacy artifacts
User feedback after running `owlry doctor` against a TOML-only setup:
the report said "[config] OK" with no indication that owlry.lua is the
canonical format from 2.1+ — or that a `migrate-config` command
existed. Doctor is the natural place to nudge.
commands.rs:
- New `print_config_source_info()` runs after the "OK" line on a
successful Config::load(). Cases:
* owlry.lua present → "source: Lua (path)". When config.toml is
also present, an extra "note: …toml is present alongside —
ignored." line surfaces the precedence rule.
* owlry.lua absent, config.toml present → "source: TOML (path)" +
a 3-line hint pointing at `owlry migrate-config` (deterministic,
`--force` to overwrite, TOML works until 3.0).
* Neither file → "source: built-in defaults (no user config found)".
- Also pulls in the same `lua::migrate::scan_legacy_artifacts` used by
`migrate-config` and emits a compact "legacy: N pre-v2 artifact(s)
detected" block listing each plugin / scripts dir with paths. Closing
line points at migrate-config for paste-ready snippets.
- `#[cfg(feature = "lua")]` branch covers the rich output; the non-lua
build emits a simpler note that owlry.lua is ignored without the
feature compiled in.
- Pluralisation: "1 entry"/"2 entries" and "1 artifact"/"2 artifacts"
(no more `(s)` stutter). Same nit also fixed in migrate-config's
"Heads up: detected N pre-v2 artifact(s)..." line for consistency.
Verified against three real scenarios:
1. config.toml + pre-v2 plugins/hyprshutdown + scripts/test.sh:
"OK / source: TOML / hint: migrate-config / legacy: 2 detected"
2. config.toml only, empty tempdir:
"OK / source: TOML / hint: migrate-config" (no legacy section)
3. No user config:
"OK / source: built-in defaults (no user config found)"
Clippy silent across --features full and --no-default-features.
|
||
|
|
aeafce157b |
style(migrate): fix '1 file(s)' stutter in scripts/ artifact report
Trivial: pluralise 'file' based on entries.len() rather than the lazy '(s)' suffix. The current output says '1 file(s)' which reads awkwardly. |
||
|
|
3e374e70f4 |
fix(migrate): emit valid Lua in the scripts/ legacy artifact snippet
The skeleton I generated for the legacy scripts/ directory used `:map(function(name) ... end)`, which is JS/Rust idiom — Lua tables don't have a built-in :map method. Anyone who pasted that into their owlry.lua would have hit a runtime error on the first refresh. Rewrite the snippet to use a standard `ipairs` loop with `table.insert`. Verified by piping the exact rendered snippet (against /tmp as the script dir) through `owlry config validate`: exit 0, "OK (Lua, ...)". The hyprshutdown plugin snippet was already valid Lua and didn't need any change. |
||
|
|
2ba06a7d2b |
feat(migrate): detect pre-v2 plugins + scripts/ and surface to user
User feedback after migrate-config: TOML migration was correct but
silently ignored the legacy `plugins/<name>/` (Rune / C-ABI) and
`scripts/` directories that v2 removed support for. The files still
exist on disk but aren't loaded — easy to miss what got broken.
lua/migrate.rs:
- New LegacyArtifact { path, kind } + LegacyKind { Plugin {..} |
ScriptsDir { entries } } types. Plugin variant carries id, name,
prefix, icon, entry_point pulled from the original plugin.toml so
the user has paste-ready data for the rewrite.
- scan_legacy_artifacts(config_dir) walks `plugins/` and `scripts/`
in alphabetical order:
* plugins/ — recognise a subdir as a plugin ONLY if it has a
plugin.toml. Skip dotfile dirs (.claude, .git, .cache, etc.)
even when they accidentally contain a manifest. This avoids
false positives like the user's `plugins/.claude/` (editor
config) and `plugins/docs/` (spec drafts under superpowers/).
* scripts/ — surfaced as a single ScriptsDir entry with the file
listing so the user sees what's there at a glance.
- parse_plugin_dir does a best-effort toml parse: malformed manifests
fall back to the directory name as id with everything else None.
- MigrateOutcome grows `legacy_artifacts: Vec<LegacyArtifact>`.
Empty when nothing matches.
commands.rs:
- New report_legacy_artifacts() prints a heads-up block per artifact
after the success summary. Each block includes the original
metadata AND a ready-to-paste `owlry.provider {}` skeleton:
* Plugin block fills in id/prefix/icon from the manifest and points
at the Rune entry_point as "this is what you need to translate".
* ScriptsDir block proposes a wrapper provider that iterates the
dir via owlry.util.shell_lines.
- Closing line links to docs/lua-api.md §4.4 (user providers) and
§5.1 (owlry.util.*).
Tests: 7 new (24/24 migrate tests green)
- scan_returns_empty_when_no_legacy_dirs
- scan_detects_plugin_with_full_manifest (id/name/prefix/icon/entry_point)
- scan_skips_directories_without_plugin_toml (was: fallback to dir name)
- scan_skips_dotfile_directories (covers `.claude` false positive)
- scan_tolerates_malformed_manifest
- scan_detects_scripts_directory_with_listing
- scan_reports_both_plugins_and_scripts_when_present
- migrate_outcome_includes_legacy_artifacts_field (end-to-end)
Verified against the real config (~/.config/owlry/ with a Rune-based
hyprshutdown plugin + a scripts/test.sh): output names both, the
hyprshutdown block surfaces its original `:hs` prefix and
system-shutdown icon, the scripts block lists test.sh and proposes a
wrapper provider. The earlier false positives (`.claude`, `docs`)
no longer appear.
359/359 lib tests green with --features full. Clippy silent across
--features full, --no-default-features, --no-default-features --features lua.
|
||
|
|
30713f065f |
fix(tests): add missing prefix field to Request::Query call sites
|
||
|
|
ad4e538a7a |
fix(aur): export RUSTFLAGS in PKGBUILD to actually pin ld.bfd
|
||
|
|
8383746a72 |
fix(cargo): pin ld.bfd to dodge LLD's arg-order strict mode (chroot fix)
THIRD attempt at the chroot build. The real root cause: rustc's link arg ordering plus Arch's `extra/rust` defaulting to `-fuse-ld=lld`. lua-src emits `cargo:rustc-link-lib=static:-bundle=lua5.4` (negative `-bundle` = "static, don't pack into the rlib") with a separate `cargo:rustc-link-search=native=$OUT_DIR/lib`. rustc serialises these into the final linker command line with `-llua5.4` appearing BEFORE `-L .../mlua-sys-*/out/lib`. Single-pass linkers (LLD) honour args left-to-right and fail to locate the archive at the time `-l` is processed → 60+ undefined symbols out of mlua. GNU `ld.bfd` does multi-pass resolution and finds the archive regardless of arg order. rustup's stable toolchain (used locally) defaults to bfd, which is why the bug never reproduced outside the chroot despite identical Cargo.toml / Cargo.lock / cargo / rustc versions. Add `.cargo/config.toml` at the workspace root pinning bfd for x86_64-unknown-linux-gnu via `rustflags = ["-C", "link-arg=-fuse-ld=bfd"]`. binutils (which ships bfd) is already a build-essential dep of the chroot — no new install cost. Local builds gain identical behaviour to chroot, which is a nice side effect. Verified locally: clean + frozen + features full → 84s, no link errors. Sequence to reproduce the fix: cargo clean cargo build --frozen --release --features full Reverts the previous two attempts to fix this: - |
||
|
|
b3764b308e |
fix(cargo): drop optional on mlua/glob/notify to dodge chroot resolver bug
Second chroot test still failed with the same `undefined symbol:
lua_gettop` linker errors after hoisting features to the cargo
feature row in
|
||
|
|
a4d4f30d1e |
fix(cargo): hoist mlua features to lua cargo feature row
Cargo's clean-chroot resolver drops inline `features = [...]` on optional deps under `--frozen` (the same gotcha that bit rusqlite during v2). When mlua's `vendored` feature got stripped the chroot build tried to link a system `liblua5.4` that doesn't exist, with 60+ undefined-symbol errors from `lua_gettop`, `lua_pcallk`, etc. Move lua54, vendored, send, and serialize out of the inline `mlua` dep spec and into the `lua` cargo feature row using `mlua/<feat>` syntax. cargo's resolver propagates these reliably whether or not the lock-file is frozen. Verified locally with `cargo clean && cargo build --frozen --release --features full` — full from-scratch compile of every dep including mlua + lua-src, links cleanly in 42s. 352/352 lib tests still pass. Cross-references the same lesson captured in memory under "Cargo optional-dep features need explicit dep/feature wiring". |
||
|
|
35f6501de2 |
docs(phase 3.10): owlry.example.lua + refresh user-facing docs
Documentation, example config, and one validator-test fix. Version bump and AUR push intentionally deferred. data/owlry.example.lua (new): - Annotated reference config exercising every surface (set / providers / tabs / theme / profiles / provider / util). Active section is minimal and validates clean. aur/owlry/PKGBUILD: - Ships data/owlry.example.lua to /usr/share/doc/owlry/owlry.example.lua. pkgver kept at 2.0.1. README.md: - Config table puts owlry.lua first (preferred from 2.1), config.toml marked legacy/fallback with precedence note linking lua-api.md §2. - New "Quick Start (Lua config)" section with migrate-config blurb. - migrate-config row: [--force], deterministic. config validate row: exit 1 errors / exit 2 warnings. - Roadmap section flips Lua config from "lands in 2.1/3.0" to "shipped in 2.1"; lists 2.2 follow-ups (dynamic providers, owlry.bind, util.http_get). CLAUDE.md: - Project shape tree expands lua/ module with per-file descriptions. - Build section documents the `lua` cargo feature. - CLI shape line for migrate-config: [--force]. config validate: exit codes 1/2 mentioned. - New "Lua config layer (2.1+)" section covers precedence, the notify-based watcher, desktop-notification errors, and the Arc<Lua> / LoadedConfig invariants. data/owlry.1: - --profile mentions both owlry.profiles (lua) and [profiles.<NAME>] (toml). - config validate paragraph describes the categorised report and lists 0/1/2 exit codes. - migrate-config description no longer says "stub" — covers determinism, --force/-f, pre-v2 alias normalisation, links §9. - FILES adds ~/.config/owlry/owlry.lua and the example .lua; config.toml labelled legacy. ROADMAP.md: - "Lua-driven configuration" reworded as shipped in 2.1; example uses owlry.lua and the v2 API; 2.2 follow-ups listed. cli.rs help: migrate-config stub-era text → "TOML → owlry.lua (--force to overwrite)". lua/validate.rs: loosen pre_v2_aliases_are_known to assert only that aliases aren't flagged as unknown ids. is_clean() failed under --no-default-features --features lua because uuctl correctly triggered the compiled-out warning (uuctl → systemd, systemd feature off → silently dropped at runtime). Test matrix (all green): - --features full 352 lib tests - --no-default-features 182 lib tests - --no-default-features --features lua 305 lib tests Clippy silent in all three configurations. Smoke (release build, isolated XDG): 1. config validate on the shipped owlry.example.lua → OK exit 0 2. migrate-config: TOML → owlry.lua with the precedence notice 3. Daemon loads, watcher armed; appending owlry.provider triggers hot-reload within the debounce window 4. :phase310 prefix routes the empty query to the new provider 5. config validate against the live file still OK |
||
|
|
aa1a38bbcf |
feat(lua): owlry config validate covers the Lua surface (Phase 3.9)
Implements the validator per docs/lua-api.md §8. Replaces the
TOML-only "load and pass/fail" check from 2.0 with categorised
findings: errors (exit 1), warnings (exit 2), clean (exit 0).
lua/config.rs:
- LuaConfig grows `duplicate_user_provider_ids: Vec<String>`. The dedup
in apply_provider would otherwise erase duplicates by the time the
snapshot is read.
lua/api.rs:
- apply_provider records the id on the duplicate list when replacing
an existing entry. The original warn! log is unchanged.
lua/validate.rs (new):
- ValidationReport { errors, warnings } with exit_code() honouring the
§8 codes (0/1/2).
- validate(cfg) is a pure function over a LuaConfig snapshot. Surfaces:
* Unknown keys in owlry.set
* Unknown colour keys in owlry.theme
* Unknown ids in owlry.providers (built-in alias table consulted;
user-provider ids are recognised)
* Providers compiled out — Cargo features checked via cfg! macros;
always-on ids (app, cmd, calc, conv, power, dmenu) skip the check
* Unknown / not-in-providers ids in owlry.tabs (user providers
auto-join the enabled set, so they pass when listed in tabs)
* Duplicate provider ids
* Unknown ids inside owlry.profiles values (per-profile label)
- canonical_provider_id() mirrors the apply_providers_list alias table
in lua/config.rs so an id accepted by the merger is never flagged.
commands.rs:
- run_config_validate now branches: when owlry.lua exists, build the
LoadedConfig, run validate::validate on the snapshot, print the
report with `<n> warning(s):` / `<n> error(s):` headers. Eval
failures print the chained mlua error (file path + line/col).
- TOML fallback path unchanged when no owlry.lua is present.
- Whole feature path is `#[cfg(feature = "lua")]`-gated.
Tests: 13 new in lua::validate::tests
- clean config emits nothing, exit 0
- unknown set key warns
- unknown theme key warns
- unknown provider id warns (and `app` passes through unflagged)
- user_provider ids in owlry.providers list are recognised
- tabs with unknown id warn
- tabs with id not in owlry.providers warn ("dropped from tab bar")
- tabs with user provider id passes (auto-joins enabled set)
- duplicate provider id warns
- profile with unknown id warns and names the profile
- pre-v2 aliases (sys, uuctl) validate cleanly
- always-compiled-in providers never trigger compile-out warning
- multi-warning report keeps every finding
Live smoke (release build, isolated XDG) for each category:
- clean → "config: OK (Lua, ...)", exit 0
- unknown set key → "owlry.set: unknown key `mystery_key` — ignored
(forward-compat for 2.2+ keys)", exit 2
- unknown provider id → "owlry.providers: unknown id `fictional_provider`
— not a built-in and not registered by any owlry.provider call", exit 2
- tabs not in providers → "owlry.tabs: `cmd` is not in owlry.providers
— it will be dropped from the tab bar", exit 2
- duplicate provider id → "owlry.provider: id `hs` was registered more
than once — the last definition wins (earlier registrations are
dropped)", exit 2
- profile with unknown id → "owlry.profiles.dev: unknown id `phantom`",
exit 2
- syntax error → "config: ERROR — Lua evaluation error in /.../
owlry.lua: syntax error: [string]:5: '}' expected (to close '{' at
line 2) near <eof>", exit 1
- 5-warning combo → all five surfaced with stable ordering, exit 2
352/352 lib tests with --features full. Clippy silent across full,
--features lua, and --no-default-features.
|
||
|
|
c200b1447c |
feat(lua): migrate-config writes owlry.lua from config.toml (Phase 3.8)
Implements the TOML → owlry.lua migrator per docs/lua-api.md §9. The
stub from 2.0 is gone; `owlry migrate-config [--force]` now reads
$XDG_CONFIG_HOME/owlry/config.toml and writes an equivalent owlry.lua.
cli.rs:
- MigrateConfig grew a `--force` / `-f` flag.
lua/migrate.rs (new, 700+ lines):
- MigrateRequest { toml_path, lua_path, force } + MigrateOutcome.
- migrate() validates paths, parses TOML via the existing
Config::load_from_toml pipeline (so pre-v2 aliases like `system` and
`badge_sys` normalise to v2 names through serde's #[serde(alias)]),
then calls generate_lua() and writes the file. Refuses to overwrite
without --force; refuses if no config.toml exists.
- generate_lua(cfg, raw_toml, src) is a pure function emitting Lua
text section-by-section. Properties:
* Deterministic — every list and map is alphabetically sorted, so
running the migrator twice on the same TOML produces byte-identical
output (locked in tests::migration_is_deterministic).
* Minimal — values matching Config::default() are omitted. A
config.toml with no overrides produces a Lua stub of just the
header comment.
* Round-trippable — the generated Lua, evaluated through LuaContext
and merged onto a default Config, matches the source Config's
scalars (tests::round_trip_preserves_scalars).
* Preserves leading `#` comment block from the source TOML by
re-emitting as `--` Lua comments under "Preserved from your
config.toml:". Other comments are intentionally dropped (cleanly,
without DROPPED placeholders).
- emit_table_key() bracket-quotes profile names that aren't valid Lua
identifiers (`my-media`, `media center`) and Lua 5.4 reserved words
(`end`, `for`, etc.), so the generated file always parses.
- lua_string() escapes \", \\, \n, \r, \t. Non-ASCII passes through
(Lua 5.4 strings are 8-bit clean).
commands.rs:
- run_migrate_config(force: bool) lives behind `#[cfg(feature = "lua")]`
with a clean stub on the no-lua build that tells the user how to
rebuild. Exit codes: 0 success, 1 destination-exists or no-TOML, 2
unrecoverable.
- Success output names both paths and bytes written, plus a one-liner
reminder that owlry.lua now takes precedence over config.toml.
Tests: 16 new in lua::migrate::tests
- lua_string escaping (quotes, backslashes, newlines, UTF-8 passthrough).
- header comment extraction (stops at first non-`#` non-empty line).
- default config → header-only output (no spurious blocks).
- emit_set only writes modified scalars.
- providers section omitted when all 11 built-ins are enabled.
- providers section emits alphabetically and excludes disabled ids.
- theme colours emit alphabetically (accent, background, badge_app order).
- profiles emit alphabetically (dev before minimal).
- profile names with hyphens get `["my-dev"]` bracket form.
- Lua reserved word `"end"` as profile name → bracket-quoted.
- determinism: twice on same Config → identical bytes.
- refuses existing destination without --force; preserves existing file.
- overwrites with --force.
- refuses when source TOML is missing.
- pre-v2 aliases (`system`, `badge_sys`) normalise to v2 names.
- round-trip: generate_lua → eval through LuaContext → merge onto
default Config → matches scalar fields of original.
Live smoke (release build, isolated XDG, pre-v2-flavoured TOML with
header comments, `system = false`, `badge_sys = "#f38ba8"`, hyphenated
`profiles."my-media"`):
- migrate-config writes 1044 bytes; output has the header block,
owlry.set with the 4 modified scalars, owlry.tabs, owlry.providers
(alphabetical, excluding power/ssh), owlry.theme with v2-named
badge_power, and owlry.profiles with `["my-media"]` bracket-quoted.
- Re-running without --force reports "already exists. Pass --force..."
and exits 1.
- Daemon launched against the generated file logs "Loaded Lua config"
and `config show` reports the migrated theme/scalars/profiles.
339/339 lib tests with --features full. Clippy silent across full,
--features lua, and --no-default-features.
|
||
|
|
eba590bad8 |
feat(lua): owlry.lua hot reload with desktop-notification errors (Phase 3.7)
Implements the hot-reload pipeline per docs/lua-api.md §7: the daemon
watches the user's owlry.lua and, on save, re-evaluates in a fresh
LuaContext. On success the new state hot-swaps atomically; on failure
the previous state is preserved and the user is told what broke via
BOTH the daemon log AND a desktop notification — no need to tail the
journal to discover the config is dead.
Cargo.toml:
- New optional dep `notify = "6"` gated by the `lua` feature alongside
mlua and glob. inotify backend on Linux; no platform-specific feature
flags needed.
lua/watcher.rs (new):
- ConfigWatcher::spawn(lua_path, config, pm, lua_ctx) wires a
notify::RecommendedWatcher on the parent directory (atomic-rename
saves from vim/JetBrains/etc rebind to a new inode, so watching the
file directly misses them) and spawns the event-pump thread.
- Debounce: 200ms after the first event, drain follow-ups, then reload
once. Coalesces burst saves into a single re-eval.
- reload() builds a fresh state in isolation; on Err keeps the old
Config/PM/LuaContext untouched.
- Swap order: config → ProviderManager → LuaContext. Old user-provider
Boxes inside the dropped PM retain the old Arc<Lua> until they
themselves drop, so the OLD Lua state survives the swap until the
OLD PM finishes dropping. New LuaProviders in new_pm hold the new
Arc<Lua>.
- report_reload_failure() formats the full error chain and fires a
notify_rust notification with summary/body/icon/urgency so the user
sees "config reload failed — /path/to/owlry.lua — <exact line>" the
moment a save breaks the file.
- Success path also emits a low-noise notification ("config reloaded").
lua/error.rs:
- LuaConfigError::Eval and ::Read no longer embed `{source}` in their
Display strings — error_chain() walks `.source()` already, and the
doubled rendering produced duplicated text in notifications and
logs. Comment explains why for the next reader.
server.rs:
- _lua_ctx changed from `Option<LuaContext>` to
`Arc<Mutex<Option<LuaContext>>>` so the watcher thread can atomically
replace it without taking the daemon down.
- New `_lua_watcher: Option<ConfigWatcher>` field, populated only when
loaded.lua_path is Some. Failure to spawn the watcher logs at warn
but doesn't fail Server::bind — the daemon stays usable even if
inotify is exhausted or perms are wrong.
- Mutex import feature-gated so --no-default-features stays
warning-free.
Tests: 5 new in lua::watcher::tests
- reload_swaps_in_new_config_state: change max_results in the file,
call reload() directly, verify Config got the new value.
- reload_failure_preserves_previous_state: write broken Lua, verify
Config is untouched.
- reload_replaces_user_providers_with_new_definitions: replace user
provider v1 with v2, verify a search for the v1 item returns nothing
and v2 is found (the websearch dynamic provider initially false-
positived on substring "v1 unique" via "Search: v1 unique" — locked
the test to the exact name "v1 unique item").
- event_touches_matches_only_watched_path: paths outside the watched
file are ignored.
- error_chain_renders_nested_causes: confirms chain walking works.
Live smoke (release build, isolated XDG, file edits via shell):
- v1 → save v2 → daemon log "hot-reload: applied"; :test prefix now
returns 2 v2 items.
- v2 → save broken Lua → daemon log "hot-reload: re-eval of /.../
owlry.lua failed, keeping previous config — Lua evaluation error in
/.../owlry.lua: syntax error: [string]:2: '}' expected (to close
'{' at line 1) near <eof>". Notification body shows the same
detail (file path + precise error). :test prefix still returns v2
items.
- Invalid provider id ("BadId With Spaces"): "runtime error: owlry.
provider: id 'BadId With Spaces' invalid — must be lowercase
alphanumeric with `-`/`_`". Old state preserved.
322/322 lib tests with --features full. Clippy silent across full,
--features lua, and --no-default-features.
|
||
|
|
82133edade |
feat(lua): owlry.util.* host helpers (Phase 3.6)
Implements the six host helpers per docs/lua-api.md §5.1: owlry.util.shell(cmd) -> string (stdout, trim_end) owlry.util.shell_lines(cmd) -> table (split, no trailing empty) owlry.util.read_file(path) -> string|nil (nil on any I/O error) owlry.util.glob(pattern) -> table (tilde-expanded; PatternError → Lua err) owlry.util.env(name, def?) -> string|nil owlry.util.hostname() -> string Cargo.toml: - New optional dep `glob = "0.3"` gated by the `lua` feature alongside mlua. Pure-Rust, no system Lua/C deps. lua/util.rs: - `build(lua) -> mlua::Result<Table>` constructs the owlry.util sub-table with every helper registered. Stateless; no Arc<Mutex<LuaConfig>> needed. - shell uses `sh -c`; stderr is logged at warn on non-zero exit but stdout is still returned (don't crash user configs on missing commands). - shell_lines drops the trailing empty element so a terminating newline doesn't produce a phantom "" item. - read_file extends "nil if missing" (per spec) to "nil on any I/O failure" — saves users wrapping every read in pcall. - glob expands a leading `~/` via `dirs::home_dir()`. `~user/`, embedded `~`, and env-var refs are intentionally left as-is (predictable surface). - hostname uses libc::gethostname directly (libc is already a hard dep). lua/api.rs: - install() now attaches `owlry.util = util::build(lua)?` to the parent owlry table. Tests: 17 new - util.rs (15): shell trim, interior newlines preserved, shell_lines split/empty cases, read_file present/missing, glob match/empty/error, env present/missing/default, hostname non-empty, tilde expansion positive/negative. - runtime.rs (2): owlry.util surface exists with all 6 functions after api::install; util helpers feed into a user provider's items() end-to-end (hostname-as-launch-item, via LuaProvider::refresh). Smoke (release build, isolated XDG, user provider :host_info using hostname/shell/env): daemon loads 4 items per the user provider — "host: cn-arch", "kernel: 7.0.5-zen1-1.1-zen", "home: /home/...", "user: cnachtigall". 317/317 lib tests with --features full. Clippy silent across all three feature configurations. |
||
|
|
32c6972a9e |
feat(lua): owlry.theme(...) + owlry.profiles {} (Phase 3.5)
Implements the theme selection and named-profile surface per
docs/lua-api.md §4.5 and §6.5:
owlry.theme("catppuccin-mocha") -- string form: theme name
owlry.theme { background = "#1e1e2e", -- table form: colour overrides
accent = "#cba6f7",
badge_app = "#a6e3a1" }
owlry.profiles { dev = { "app", "cmd", "ssh" }, media = {...} }
LuaConfig (lua/config.rs):
- theme_name: Option<String> (set by string form, last-write-wins)
- theme_colors: ThemeColors (table form, per-key last-write-wins)
- unknown_theme_keys: Vec<String> (forward-compat for 2.2+ palette)
- profiles: Option<HashMap<String, Vec<String>>> (replace-on-call)
- New KNOWN_THEME_KEYS const lists every recognised colour name.
- merge_into() applies theme name + colour overlay (Some-only fields)
and replaces base profiles when Lua sets them. Omitting `owlry.profiles`
leaves existing TOML/default profiles intact.
api.rs:
- owlry.theme dispatches on mlua::Value: Value::String → set name,
Value::Table → read colour keys. Other types raise a clean Lua
runtime error.
- Pre-v2 `badge_sys` alias normalises to `badge_power` (mirrors the
serde alias on ThemeColors).
- owlry.profiles: every value must be a table of strings; non-table
values produce a clear "list of provider ids" error message.
Tests: 19 new
- lua::config (6): theme name override, colours overlay only Some
fields, name+colours compose, profiles replace base, empty profiles
clears, omitted profiles preserves base.
- lua::runtime (13): string form, full colour table, name + table
compose, per-key merge across calls, badge_sys alias, unknown
forward-compat keys, wrong-arg-type error, multi-profile capture,
profiles replace, non-list value error, numeric coercion docs.
Smoke test (release build, isolated XDG): `owlry config show` reports
`theme = "nord"`, the four colour overrides under [appearance.colors],
and all three named profiles. 300/300 lib tests with --features full,
no new clippy warnings.
|
||
|
|
bfbce42eab |
fix(ipc): thread active_prefix through Query so daemon honours it (Phase 3.4.5)
The smoke test in Phase 3.4 surfaced a long-standing gap: parse_query
already routes `:smoke foo` → Plugin("smoke") via the dynamic-prefix
fallback (filter.rs:319-347), but the UI never told the daemon. The
UI's filter.active_prefix was set locally yet build_modes_param only
serialised filter.enabled, so the daemon rebuilt a fresh filter with
no active_prefix and searched across every provider. Same gap also
affected hardcoded plugin prefixes (`:emoji heart` etc.) — they only
appeared to work because their items outranked others on fuzzy score.
ipc.rs:
- Request::Query gains optional `prefix: Option<String>`, default None,
skip_serializing_if = "Option::is_none". Wire-format omits the field
when None so existing 2.0.x clients keep deserialising on a 2.1
daemon and vice-versa.
filter.rs:
- New test parse_query_routes_unknown_prefix_to_plugin_type_id locks
in the existing dynamic-fallback behaviour for `:smoke item`.
- New test build_prefix_param_round_trips_through_provider_type
proves Display + FromStr agree on the wire format.
client.rs:
- `query(text, modes, prefix)` — third arg added; 2 existing tests
updated. Two new tests with a capturing mock_server assert the
prefix field is serialised when set and elided when None.
backend.rs:
- QueryParams grows a `prefix: Option<String>`. New helper
build_prefix_param(filter) -> Option<String> mirrors set_prefix's
active_prefix to the wire. All three client.query call sites updated
(search, search_with_tag, query_async).
server.rs:
- Query handler destructures the new prefix field and applies it via
filter.set_prefix(ProviderType::from_str(prefix)). Unknown ids fall
through to ProviderType::Plugin(_) per the existing FromStr impl —
symmetric with the UI's dynamic-fallback path.
Live smoke (release build, isolated XDG + socket):
- prefix=smoke + text="item" → 3 items, all smoke (was: 100, mixed)
- prefix=smoke + text="one" → 1 item: "smoke one item"
- prefix=smoke + text="" → 3 smoke items, frecency-sorted
- prefix=app + text="firefox" → 1 firefox app item (regression
check; hardcoded prefix path still works)
7 new tests (ipc:3, client:2, filter:2). 283/283 lib tests green with
--features full. Both clippy configurations silent. Closes task #28.
|
||
|
|
270f02dd69 |
feat(lua): wire owlry.lua into Config::load + daemon (Phase 3.4)
Resolution order per docs/lua-api.md §2:
1. $XDG_CONFIG_HOME/owlry/owlry.lua -- defaults + Lua overlay; TOML ignored
2. $XDG_CONFIG_HOME/owlry/config.toml -- back-compat
3. Built-in defaults
When owlry.lua is present alongside config.toml, an info log notes that
TOML is being ignored ("Lua takes precedence"). 2.2 will upgrade this to
a warning; 3.0 removes TOML entirely.
paths.rs:
- New lua_config_file() -> $XDG_CONFIG_HOME/owlry/owlry.lua.
config/mod.rs:
- New LoadedConfig { config, lua, lua_path, user_providers } gated by
feature = "lua". Keeps the LuaContext alive so user-provider items
closures remain callable. Drop the context and mlua::Function refs
inside user_providers go invalid — that was the lifetime bug 3.3
uncovered.
- LoadedConfig::load() does the full resolution; load_or_default()
falls back to LoadedConfig::defaults() on error.
- Config::load() now consults owlry.lua first when feature enabled,
then falls through to the existing TOML path. The Lua context is
dropped after merge (read-only callers don't need user providers).
- Extracted load_from_toml() and detect_and_apply_terminal() so all
three load paths share the same terminal-detection tail.
- Manual Debug impl on LoadedConfig that doesn't try to format the
LuaContext (mlua::Lua doesn't impl Debug).
providers/mod.rs:
- new_with_config now takes a user_providers: Vec<Box<dyn Provider>>
parameter (callers pre-build them). Appended after the built-in set;
info-logs the count when non-empty.
server.rs:
- Server::bind switches to LoadedConfig::load_or_default() under the
lua feature, builds LuaProvider boxes from the captured specs using
the context's lua_handle(), and stores the LuaContext in a new
_lua_ctx field to keep it alive for the daemon's lifetime. Hot
reload (Phase 3.7) will use this field.
- Non-lua build keeps the existing Config::load_or_default() path
with an empty user_providers vec.
Tests: 7 new in config::loaded_config_tests
- defaults_apply_when_no_files_exist
- lua_path_overrides_defaults_with_set_values
- lua_providers_list_disables_unlisted_built_ins
- lua_user_provider_is_captured
- lua_provider_remains_callable_after_load (end-to-end: load → snapshot
→ build LuaProvider → refresh → assert items, with the LuaContext
field outliving the helper scope)
- lua_syntax_error_is_surfaced
- toml_only_load_returns_defaults_when_path_missing
- toml_only_load_parses_existing_file
Live smoke test (release build, $XDG_CONFIG_HOME=tempdir, custom
owlry.lua with one user provider): daemon logs "Loaded Lua config",
"Registering 1 user-defined provider(s)", "Provider 'smoke' loaded 2
items". IPC Providers returns the smoke provider; auto-mode fuzzy
query against the user-defined items succeeds.
Known limitation surfaced during smoke (task #28): UI prefix routing
via ProviderFilter::parse_query uses a hardcoded prefix table, so
typing `:smoke foo` in the UI doesn't narrow to the user provider.
Auto-mode is unaffected. Separate task tracks the parse_query
generalisation; not in 3.4 scope.
276/276 lib tests green with --features full. 174/174 with
--no-default-features. Clippy silent in both configurations.
|
||
|
|
cfcd201c35 |
chore(providers): clear standing clippy warnings
Pre-existing nits surfaced by recent clippy runs. No behavior change: - application/command/systemd: sort_by(|a,b| a.name.to_lowercase().cmp(...)) → sort_by_key(|i| i.name.to_lowercase()). The key form computes to_lowercase() once per element instead of twice per comparison. - providers/mod.rs (6 sites): descending score sort_by(|a,b| b.1.cmp(&a.1)) → sort_by_key(|x| std::cmp::Reverse(x.1)). - dmenu: add impl Default for DmenuProvider delegating to ::new(). cargo clippy now silent under --features full, --features lua, and --no-default-features. 268/268 lib tests still green. |
||
|
|
76524739e9 |
feat(lua): owlry.provider {} registers a static LuaProvider (Phase 3.3)
Implements the user-defined provider surface per docs/lua-api.md §4.4:
owlry.provider {
id = "hs",
prefix = ":hs",
items = function() return { { name = "Lock", command = "hyprlock" } } end,
}
Spec capture (lua/config.rs):
- New LuaProviderSpec carrying id / name / prefix / tab_label / icon /
search_noun / priority / dynamic + the mlua::Function `items` callback.
- LuaConfig grows a `user_providers: Vec<LuaProviderSpec>` accumulator.
- is_valid_provider_id() enforces the §4.4 grammar (lowercase a-z 0-9 - _).
Registration validation (lua/api.rs):
- `id` and `items` are required; missing field → clean Lua runtime error.
- Invalid id format rejected with a precise message.
- `dynamic = true` rejected in 2.1 (per spec: "lands in 2.2"). dynamic=false
explicit is accepted.
- Duplicate id: second wins, prior entry replaced, warning logged (§6.4).
- Multiple distinct ids accumulate in registration order.
Provider bridge (lua/provider.rs, new):
- LuaProvider impl Provider (Send + Sync, verified by static assertion).
- refresh() calls the Lua function with an empty query, parses each row,
drops items missing required name/command (warning per drop), caches.
- Errors from the user's items() are logged and result in an empty cache
for that refresh — daemon never crashes (§6.4).
- LaunchItem.source = ItemSource::ScriptPlugin (already reserved for
exactly this case in v2 demolition).
Lua-state lifetime fix (lua/runtime.rs):
- LuaContext now holds `Arc<Lua>`. mlua::Function references don't bump
the Lua refcount on their own, so providers built from a dropped context
would panic at call time. lua_handle() exposes the Arc so LuaProvider
can keep the state alive independently.
Tests: 18 new
- lua::config: 2 (id-validation positive/negative)
- lua::provider::tests: 9 (defaults, full spec, refresh happy/sad paths,
item field parsing, error handling, Send+Sync compile-time check)
- lua::provider::registration_tests: 8 (accumulation, duplicate replace,
missing-required errors, invalid-id, dynamic gate)
46/46 lua tests green. 267/267 lib tests green with --features full. No
new clippy warnings. ProviderManager wiring is Phase 3.4.
|
||
|
|
fabe60a7e0 |
feat(lua): set / providers / tabs read into LuaConfig (Phase 3.2)
Implements the three core owlry.* config-collection functions per
docs/lua-api.md §4.1-§4.3:
owlry.set { theme = "owl", width = 900, ... }
owlry.providers { "app", "cmd", "calc", "conv", "power" }
owlry.tabs { "app", "cmd", "uuctl" }
Accumulator: Arc<Mutex<LuaConfig>> shared between the three registered
Lua closures and the host. LuaConfig is a strongly-typed Option-fielded
struct mirroring the spec table in §4.1.
- owlry.set merges across calls (last-write-wins per key); unknown keys
are recorded in unknown_settings for `owlry config validate` (3.9).
- owlry.providers replaces the list on each call; v1 aliases
(sys/system/uuctl) honoured at merge time.
- owlry.tabs replaces the tab order list verbatim.
LuaConfig::merge_into(&mut Config) overlays the captured state onto
the existing TOML-derived Config without touching unset fields. This
is the data layer; Phase 3.4 wires it into Config::load().
require("owlry") returns the same table as the global `owlry` (via a
tiny package.preload shim) so both styles in the spec quick-reference
work.
Tests: 28 new (config: 11, runtime: 17) covering happy path, multi-call
merge semantics, unknown-key tolerance, type-error propagation, alias
expansion, empty lists, file reads, and error path reporting. 249/249
lib tests green with --features full. No new clippy warnings.
|
||
|
|
5b8bc8bac9 |
feat(lua): scaffold mlua-based config module (Phase 3.1)
Adds the lua cargo feature and a stubbed crates/owlry/src/lua/ module in preparation for Phase 3 (Lua config layer per docs/lua-api.md). - mlua 0.11 (lua54, vendored, send, serialize) as an optional dep so AUR clean-chroot builds don't depend on system Lua. - New `lua` feature gates the module; included in the `full` feature set so the AUR build ships it. Disabled by default so minimal `cargo install` consumers don't pay for the C compile. - Stub submodules: runtime (LuaContext), api (owlry.* surface), error (LuaConfigError), util (owlry.util.*). Every function is a no-op placeholder for the sub-phases that will wire them. - pub mod lua gated behind #[cfg(feature = "lua")] in lib.rs. cargo check passes with --no-default-features, --features lua, and --features full. 221/221 lib tests still green. Zero clippy warnings from the new module. |
||
|
|
d9cde0b3a4 | chore(aur): update PKGBUILD | ||
|
|
9921c5f280 |
Merge pull request 'owlry 2.0.1: doctor visibility + proactive migration hints' (#7) from fix/dynamic-providers-doctor into main
Reviewed-on: #7owlry-v2.0.1 |
||
|
|
0242e48707 |
chore(owlry): bump version to 2.0.1
Patch release covering: - fix(providers): dynamic providers (calc, conv, websearch, filesearch) now appear in owlry doctor and owlry providers <id> output - feat(aur/install-hook): proactive detection of stale owlryd references in user-level systemd units and compositor configs No behavioural changes beyond diagnostic visibility and upgrade-time warnings. No config or API breakage; safe drop-in upgrade. Cargo.toml + PKGBUILD bumped together; .SRCINFO regenerated; b2sum will be refreshed by 'just aur-update' once the tag is pushed. |
||
|
|
048c446b26 |
feat(aur/install-hook): proactive legacy-cruft detection
Common upgrade snags from pre-v2 setups that the 2.0.0 hook didn't
catch in time. Both detected read-only and reported with precise
remediation; the hook never modifies user files.
1. Stale ~/.config/systemd/user/owlry{,d}.{service,socket} overrides.
systemd-user gives precedence to ~/.config/systemd/user/* over
/usr/lib/systemd/user/*. A leftover dev-time override (e.g. from
'just install-local' in a 1.x tree) silently masks the AUR-shipped
unit. We classify them:
- references the deleted owlryd binary
- points at a dev-time target/debug or target/release path
- redundant override of the canonical /usr/bin/owlry
- non-standard ExecStart (flagged for review)
2. Compositor autostart referencing 'owlryd':
~/.config/hypr/hyprland.conf and any *.conf / *.hyprlang in hypr/
~/.config/sway/config
~/.config/i3/config
~/.config/river/init
~/.config/niri/config.kdl
Each affected user gets a banner with the exact rm + systemctl --user
commands to run (and what to replace 'owlryd' with in compositor
configs). The hook reads only — it never executes the cleanup itself.
Runs on:
- 1.x -> 2.x upgrades (alongside the existing rename banner)
- 2.0.0 -> 2.0.1 upgrade (re-runs the detection idempotently for
users who missed cleanup the first time around)
The 1.x banner copy is touched lightly: bookmarks now appears in the
'deferred' line alongside the widgets (D22).
|
||
|
|
e88525fa19 |
fix(providers): surface dynamic providers in doctor + providers list
ProviderManager::available_providers() and available_provider_types() iterated only the static `Vec<Box<dyn Provider>>` field, never the parallel `Vec<Box<dyn DynamicProvider>>`. Result: calc, conv, websearch, filesearch ran fine but were silently absent from `owlry doctor` and `owlry providers <id>` outputs. Fix: - Add prefix(), icon(), tab_label(), search_noun() as defaulted methods on the DynamicProvider trait (matching the static Provider trait shape). Default values: None / "application-x-addon" / None / None. - Override those methods on the four dynamic provider impls with sensible values (e.g. calculator: ":calc" / "accessories-calculator" / "Calc" / "math expression"). - Extend available_providers() and available_provider_types() to iterate builtin_dynamic too. Each dynamic provider always reports as ProviderType::Plugin(<type_id>) — Application/Command/Dmenu variants are static-only, but the match is defensive. Tests added (TDD characterization for 2.0.1): - available_providers_includes_dynamic_providers — synthetic DynRich provider with every overridable method set; asserts the descriptor comes back with the right id/prefix/icon/position/tab_label/search_noun. - available_provider_types_includes_dynamic_providers — verifies the type list returns both static and dynamic types. - dynamic_provider_trait_defaults_return_documented_values — minimal impl returns the documented defaults. After this fix, `owlry doctor` reports 11 providers instead of 7 on a default --features full build, and `owlry providers calc` returns the calculator's full metadata instead of 'No provider with id'. 248 tests pass with --features full (was 245). |
||
|
|
1075eefbf3 |
docs(phase-3): full Lua API spec + D23/D24 decisions
docs/lua-api.md (new, 380 lines):
- Section 1-2: Why Lua + file location (owlry.lua, NOT init.lua per D23)
- Section 3: Quick reference (one self-contained example covering every
surface)
- Section 4: API reference (owlry.set / providers / tabs / provider /
theme) with per-field tables and rules
- Section 5: Host API in scope (full stdlib + owlry.util convenience
helpers); no sandbox in 2.1
- Section 6: How providers/tabs/provider{} compose at runtime — the
three orthogonal axes (compiled in / enabled / shown as tab) made
explicit with a worked example and a what-if table
- Section 7: Hot reload via notify crate (re-added in Phase 3)
- Section 8: Validation via 'owlry config validate' / 'config show'
- Section 9: Migration via 'owlry migrate-config' with full TOML→Lua
mapping table
- Section 10: Open questions resolved before Phase 3 ships
- Section 11: Version compatibility roadmap (2.0 -> 2.1 -> 2.2 -> 3.0)
- Section 12: Implementation outline (handoff to engineering)
docs/RESTRUCTURE-V2.md:
- D23: config file named owlry.lua (brand identity over init.lua
convention; file is loaded explicitly, not via Lua's require)
- D24: owlry.providers vs owlry.tabs distinction made explicit — three
orthogonal axes (compiled in / enabled / shown as tab), full
composition spec lives in lua-api.md §6
The Lua API doc is intended as both the design spec we're committing to
AND the user-facing reference once Phase 3 ships.
|
||
|
|
60780f2fdd | chore(aur): finalize owlry 2.0.0 PKGBUILD (real b2sum) | ||
|
|
645a4ce637 |
Merge pull request 'owlry 2.0: single-binary rewrite' (#6) from v2 into main
Reviewed-on: #6owlry-v2.0.0 |
||
|
|
2cac6556f3 | chore(owlry): bump version to 2.0.0 | ||
|
|
41e794f4d5 |
build(aur): disable debug subpackage (options=!debug)
makepkg in clean chroots defaults to OPTIONS+=(debug), which tries to
split debug symbols into an owlry-debug subpackage. Cargo's release
profile already strips the binary at compile time (strip = true in
workspace Cargo.toml), so the debug split finds nothing and emits a
benign-but-noisy 'No debugging symbols' warning followed by an empty
owlry-debug-2.0.0-1-x86_64.pkg.tar.zst.
Set options=('!debug') so makepkg skips debug splitting entirely. The
released package is unchanged from the user's perspective; we just stop
producing the empty subpackage and the namcap warning that came with it.
Leaves the unrelated namcap warnings about transitively-satisfied deps
(glib2, openssl, pango, glibc, libgcc) untouched — those are normal for
Rust binaries pulled through GTK4 and don't need explicit listing in
depends=. The 'checkpkg: target not found: owlry' warning will auto-
resolve once 2.0.0 is published to AUR.
|
||
|
|
a7af0e5d46 |
feat(v2): defer bookmarks provider (D22) — drop rusqlite dep
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
|
||
|
|
7569b2d7f0 |
fix(bookmarks): force libsqlite3-sys bundled via explicit feature gate
The chroot build of owlry-2.0.0 failed at link time with every sqlite3_*
symbol undefined — libsqlite3-sys's build.rs was taking the
'build_linked' branch (which links to system libsqlite3) instead of
'build_bundled' (which compiles sqlite3.c statically). The host build
worked only because /usr/lib/libsqlite3.so happens to be installed.
The original Cargo.toml had:
rusqlite = { version = "0.39", features = ["bundled"], optional = true }
In theory this activates rusqlite/bundled which pulls libsqlite3-sys/bundled.
In practice — apparently a Cargo resolver edge case with optional deps in
edition 2024 — the bundled feature did not flow into the resolved feature
graph in a clean chroot build.
Fixed by declaring rusqlite without inline features and wiring the bundled
flag explicitly in the bookmarks feature row:
[dependencies]
rusqlite = { version = "0.39", optional = true }
[features]
bookmarks = ["dep:rusqlite", "rusqlite/bundled"]
Verified via 'cargo tree --features full -i libsqlite3-sys -e features':
the libsqlite3-sys 'bundled' feature now traces back to owlry/full ->
owlry/bookmarks -> rusqlite/bundled.
|
||
|
|
fa3f04e3fc |
build(justfile): rewrite for single-repo, single-package v2 reality
The pre-v2 justfile drove a 5-crate workspace and 15 AUR packages, with machinery to bump-all crates, iterate over aur/*/ subdirs, manage meta- package versions, and run a release-crate pipeline parameterised by crate name. None of that applies anymore — there is one crate and one PKGBUILD. Replaced with: - build / release / release-minimal — release defaults to --features full so dev builds match the AUR binary's feature set. - run / run-daemon / run-debug — run-debug uses dev-logging feature. - test — runs both feature axes (no-default-features and --features full) so contributors can't silently break either build. - check — cargo check on both axes + clippy on --features full. - install-local — installs the man page too now. - version / bump — single-crate operations, no 'crate' parameter. - tag / push-tags — tags owlry-v<version> directly. - aur-stage / aur-update / aur-publish / aur-status / aur-commit — all hardcoded to aur/owlry/, no pkg parameter. - aur-update fetches the tagged tarball, recomputes b2sum, regenerates .SRCINFO. Errors with a clear message if the tag isn't pushed yet. - aur-publish errors with a clone hint if aur/owlry/.git is missing. - release-owlry — full pipeline: bump -> push -> tag -> push-tags -> aur-update -> aur-commit -> push -> aur-publish. Drop-in replacement for the old release-crate recipe. Removed: - build-ui / build-daemon / release-daemon — no separate daemon crate. - show-versions / crate-version / bump-crate / bump-all — single crate. - tag-crate — there's no per-crate concept anymore. - aur-update-pkg / aur-update-all / aur-publish-pkg / aur-publish-all / aur-test-pkg-by-name / release-crate — collapsed since only aur/owlry exists. - bump-meta — meta-bundles dropped in the v2 collapse. aur-local-test now defaults its args to 'owlry' so 'just aur-local-test' without arguments does the right thing. |
||
|
|
1487a12c65 |
feat(man): ship owlry(1) man page
Hand-written groff man page documenting the v2 CLI surface, environment
variables, files, and examples. Sections:
NAME / SYNOPSIS / DESCRIPTION
OPTIONS -d, -m, --profile, -p, -h, -V
COMMANDS daemon, dmenu, doctor, providers, config, migrate-config
ENVIRONMENT XDG_RUNTIME_DIR, OWLRY_SOCKET, XDG_CONFIG_HOME,
XDG_DATA_HOME, TERMINAL
FILES config, themes, frecency, socket, docs, units
EXAMPLES UI launch, daemon background, dmenu pipeline,
doctor, side-by-side dev daemon via OWLRY_SOCKET
SEE ALSO / BUGS / AUTHORS
aur/owlry/PKGBUILD: install -Dm644 data/owlry.1 -> /usr/share/man/man1/owlry.1.
makepkg auto-gzips to owlry.1.gz in the final package.
Verified with groff -Tutf8 -man: no warnings or errors. Tested locally
via makepkg; man page lands at /usr/share/man/man1/owlry.1.gz in the
2.7 MB .pkg.tar.zst.
|
||
|
|
b22e1a52fb |
docs(v2): refresh README, ROADMAP, CLAUDE.md + expand replaces array
User-facing docs that lagged behind the v2 rewrite. Replaces the 1.x
package-mosaic narrative everywhere with the single-binary 2.0 reality.
README.md (rewrite):
- Highlights single binary + cargo-feature-gated providers
- Drops the 11-plugin Available Packages table (single package now)
- Drops Settings Editor section (config_editor was deleted)
- Drops Plugin Management CLI section (entire 'owlry plugin ...' tree
is gone; commands.rs handles doctor / providers / config / migrate)
- New cargo features table (matches owlry/Cargo.toml [features])
- Build-from-source uses cargo build --release --features full
- All owlryd refs -> owlry -d / owlry.service
- Search prefixes table updated for sys->power rename
- Architecture diagram redrawn for single binary
- New 'Roadmap' subsection pointing at upcoming Lua config + widgets
ROADMAP.md (revise):
- Drops 'Plugin hot-reload' (compiled-in providers can't hot-reload)
- Drops 'Plugin settings UI' (config_editor was the v1 equivalent; gone)
- Drops 'Plugin marketplace' / Lua plugin install via CLI (the install
surface itself was removed in v2; user extensions return via Phase 3
Lua config, not via a registry)
- Drops 'Split monorepo' / 'Plugin API backwards compatibility' /
'Per-plugin config' — all resolved by the v2 collapse
- Adds 'Lua-driven configuration' and 'Widget providers return' as the
next-up bets
- Notes Phase 5 hygiene items (file splits, submenu protocol redesign,
double-spawn) so they're not lost
CLAUDE.md (rewrite for v2):
- Project shape diagram = single crate, single binary
- Build commands use --features full
- OWLRY_SOCKET env var documented (smoke-test enabler)
- Naming-rules table covers the sys->power and owlryd->owlry transitions
so future AI assistants don't reinvent the old vocabulary
- Drops references to owlry-core, owlry-plugin-api, owlry-lua, owlry-rune
- Drops plugin CLI documentation (subcommand tree is gone)
aur/owlry/PKGBUILD:
- replaces / conflicts / provides arrays grow from 18 -> 21 entries.
- Adds three plugin packages I'd missed in the first pass:
owlry-plugin-calculator (pre-v2 transitional stub, pkgrel -99)
owlry-plugin-converter (same)
owlry-plugin-system (same — distinct from owlry-plugin-systemd!)
- Arrays now organised by reason (folded plugins / deferred widgets /
Lua-replaced / pre-v2 stubs / meta-bundles) with inline comments.
- .SRCINFO regenerated.
Local rebuild verified: makepkg produces owlry-2.0.0-1-x86_64.pkg.tar.zst
with 21 conflict= entries in .PKGINFO.
|
||
|
|
38057b36e3 |
build(v2): Phase 2 local prep — PKGBUILD, units rename, .install hook
Stages everything needed for the AUR 2.0.0 republish, without pushing
or publishing. The next checkpoint is a local makepkg test (task #2.5);
push/publish actions wait for explicit go-ahead (task #2.6).
aur/owlry/PKGBUILD:
- pkgver 1.0.10 -> 2.0.0; pkgrel 1
- depends drops owlry-core (now folded into owlry)
- optdepends cleaned: just cliphist, wl-clipboard, fd, mlocate — the
external tools providers shell out to. No more 11 plugin packages.
- build uses --features full (AUR ships everything compiled in; cargo
install consumers still get the minimal default)
- check runs cargo test --features full
- package installs single binary + renamed systemd units + docs/themes
- replaces/conflicts/provides cover 18 dropped packages: owlry-core,
owlry-lua, owlry-rune, 11 owlry-plugin-* (including the deferred
widgets per D20), 4 owlry-meta-*
aur/owlry/owlry.install (new):
- post_install message: how to start the daemon
- post_upgrade from 1.x: announce the systemd unit rename and tell the
user to disable old owlryd.service / enable new owlry.service. Includes
a banner with the v2 breaking changes (widgets gone, plugins built in)
- post_remove note: config stays
systemd/:
- owlryd.service -> owlry.service (per D15)
- owlryd.socket -> owlry.socket
crates/owlry/src/client.rs:
- connect_or_start invokes 'systemctl --user start owlry.service'
justfile:
- install-local installs renamed units
aur/owlry-{core,lua,rune}/:
- Tracked files (PKGBUILD, .SRCINFO, .gitignore) removed from main repo
- .gitignore entries added so the leftover local checkouts (still on
disk with their AUR-remote .git dirs) don't keep showing as untracked
- AUR remotes themselves unaffected; orphaning on aur.archlinux.org is
a separate manual step
aur/owlry/.SRCINFO regenerated via makepkg --printsrcinfo.
|
||
|
|
1dd945d0b5 |
docs(v2): record live smoke results across all 13 provider entry points
Updates Phase 1 acceptance section with the per-provider live verification done after the OWLRY_SOCKET env var landed. Replaces the earlier 'unit-tests-imply-correctness' note for issue #5 with the actual live-daemon evidence. |
||
|
|
0376abddae |
feat(paths): OWLRY_SOCKET env var to override the IPC socket path
Adds a one-shot override before XDG_RUNTIME_DIR resolution so smoke
tests (and side-by-side daemon instances during dev) can run without
disturbing a production daemon listening on the default socket.
- OWLRY_SOCKET=/tmp/foo.sock owlry -d
- OWLRY_SOCKET=/tmp/foo.sock owlry providers
Test added (owlry_socket_env_overrides_xdg_runtime) verifying the
env var takes precedence and restoring the previous value so it
doesn't leak across other tests in the module.
Used to verify Phase 1 live behavior across all 13 provider entry
points — each returned expected results, including uuctl resolving
to real systemd unit names ('dbus' -> dbus-broker, at-spi-dbus-bus).
Issue #5 confirmed fixed end-to-end.
|
||
|
|
a3e134e6b7 |
docs(v2): Phase 1 acceptance results + close-out
Phase 1 (repo collapse) of the v2 restructure is complete. All 11 tasks
landed; the acceptance checklist in section 9 passes end-to-end.
Captured in section 10:
- Per-task commit log (a4a903 ->
|
||
|
|
c48efaa7a5 |
style(v2): apply cargo fmt across the workspace
Routine formatting pass after the feature-gate / config / CLI / power work landed. Import ordering, line wrapping, and trailing-comma cleanup only — no behavior changes. `cargo fmt --all --check` is now clean. Part of Phase 1 task #11 (final build + smoke). |
||
|
|
e9f310d202 |
test(auto-mode): integration test guarding the no-flag default behavior
Per D7 and task #10 in the v2 plan. Five tests pinning down the `ProviderFilter` invariants that drive the default 'owlry' launch: - auto_mode_filter_accepts_every_provider_type: no CLI mode/profile yields accept_all=true; every provider type (including ones not in general.tabs) is searchable. - auto_mode_filter_with_empty_tabs_still_accepts_everything: even an empty tabs list doesn't silently drop providers from query routing. - auto_mode_changes_to_filtered_when_cli_mode_is_set: counterpoint — -m <provider> flips accept_all off and excludes others. - auto_mode_prefix_overrides_accept_all_for_routing: :uuctl prefix inside the UI narrows even when accept_all is true; clearing the prefix restores reach. - dash_m_auto_explicit_alias_is_equivalent_to_no_flag: 'auto' parses to Plugin('auto'); the value lives under user control and won't be silently remapped. 252 total tests with --features full. Task #10 complete. |
||
|
|
27e2683917 |
feat(cli): subcommand structure with doctor/providers/config/dmenu/migrate-config
Subcommand surface per docs/RESTRUCTURE-V2.md section 2: owlry UI, auto mode (default) owlry -m <mode> | --profile UI variants (unchanged) owlry -d Daemon (alias for 'daemon' subcommand) owlry daemon Daemon owlry dmenu [-p PROMPT] dmenu mode (canonical entry; -m dmenu still works) owlry doctor Diagnostics: config + socket + provider list owlry providers [<id>] List providers (or show details for one) owlry config validate Parse config; report errors owlry config show Print resolved effective config as TOML owlry migrate-config Stub; lands with Phase 3 (Lua config) New module crates/owlry/src/commands.rs holds the dispatchers. Each returns ! (calls process::exit) so main.rs is a thin router. doctor and providers connect to the daemon via the local socket and report what's registered. When the daemon is unreachable, doctor prints a hint; providers exits 1. config validate / show use the existing Config loader — no behavioral change to config parsing. Tests added (clap-level): 9 new tests in cli::tests covering each subcommand and the -d-vs-subcommand precedence. 247 total (up from 239) with --features full. Task #9 complete. |
||
|
|
1ba0a97e6d |
docs(example): update config.example.toml for sys->power rename
Follow-up to
|
||
|
|
d1c327002b |
refactor(power): rename sys provider to power (D13)
Per D13 in the v2 plan: 'sys' collides mentally with 'systemd'. The
power & session provider becomes 'power' everywhere. Pre-v2 names
('sys', 'system', badge_sys) remain accepted as serde aliases so
existing user configs keep parsing.
Also fixes a pre-existing bug: filter.rs mapped :sys/:system/:power
prefixes to the type_id 'system', but the provider exposed itself as
Plugin('sys'). The two never matched, so prefix filtering on this
provider was a no-op. Now everything (filter table, ProviderType
FromStr, provider's own provider_type, config key) agrees on 'power'.
Files renamed: providers/system.rs -> providers/power.rs
Struct renamed: SystemProvider -> PowerProvider
type_id: 'sys' -> 'power'
Item IDs: 'sys:shutdown' -> 'power:shutdown' (frecency for the 7
power items resets after upgrade — acceptable for a v2 break)
Config key: providers.system -> providers.power (alias 'system', 'sys')
Theme color: colors.badge_sys -> colors.badge_power (alias 'badge_sys').
theme.rs emits both --owlry-badge-power and --owlry-badge-sys so
existing stylesheets keep rendering.
UI provider_meta: 'system' arm becomes 'power' | 'system'
ProviderType::FromStr: 'power', 'sys', 'system' all -> Plugin('power')
(and 'uuctl', 'systemd' -> Plugin('uuctl') as parallel hygiene)
Tests added (TDD):
- provider_type_from_str_maps_power_aliases
- provider_type_from_str_maps_systemd_aliases
- providers_config_accepts_power_key
- providers_config_accepts_pre_v2_system_alias
- theme_colors_accepts_pre_v2_badge_sys_alias
- all_item_ids_use_power_prefix (in power.rs)
239 tests pass (up from 234) with --features full. Task #8 complete.
|
||
|
|
cb2ea5973b |
feat(providers): convert remaining 6 plugins from C-ABI to native impls
Closes the v2 plugin conversion. Six providers ported from the owlry-plugins sibling repo into the single owlry crate as feature- gated modules. Each follows the same pattern established by systemd: drop extern "C"/PluginItem/ProviderHandle/owlry_plugin! scaffolding, implement Provider or DynamicProvider directly on a regular struct. Static providers (Provider trait, populate via refresh): - providers/bookmarks.rs — Firefox + Chromium bookmarks via rusqlite, favicon cache preserved. dep: rusqlite (bundled), feature: bookmarks - providers/clipboard.rs — cliphist history. feature: clipboard - providers/emoji.rs — bundled emoji list with keyword tags. feature: emoji - providers/ssh.rs — ~/.ssh/config host extraction. feature: ssh Dynamic providers (DynamicProvider trait, generate per query): - providers/filesearch.rs — fd / mlocate shellout with extract_search_term for ':file' and '/' triggers. feature: filesearch - providers/websearch.rs — URL builder with DuckDuckGo/Google/custom engines. TODO: plumb engine through constructor once Lua config lands (Phase 3). feature: websearch Wiring: - Cargo.toml: 7 per-provider features + 'full' meta-feature. rusqlite added as optional dep (only pulled in with feature 'bookmarks'). - config/mod.rs: ProvidersConfig gains 6 new bool fields (defaults true) - providers/mod.rs: gated module declarations + new_with_config takes a config snapshot and registers each provider behind its feature flag Verification across feature axes: - --no-default-features: 178 tests pass (feature-gated modules excluded) - default (systemd only): 186 tests pass - --features full: 233 tests pass (+55 from the 6 new conversions) Tasks #6 and #7 complete. |
||
|
|
eb8a65f1fd |
feat(systemd): convert systemd provider from C-ABI to native Provider impl
First of 7 plugin conversions (task #6). Establishes the conversion pattern: drop extern "C" vtable + PluginItem + opaque ProviderHandle in favor of a regular struct that impls the Provider trait. Submenu support comes via the new submenu_actions() trait method instead of the old '?SUBMENU:' string-encoded query convention. - providers/systemd.rs: new module, type_id 'uuctl' (CLI back-compat) - Provider impl with prefix(:uuctl), icon(system-run), tab_label(Units), search_noun(systemd units), and submenu_actions for service controls - ProviderManager::new_with_config registers it when config and feature both enabled - config.providers.systemd added (alias 'uuctl' for back-compat) - cargo feature 'systemd' (in default and full feature sets) - 8 unit tests: parse_systemctl_output, provider_type, submenu for active/inactive/empty data, terminal flag on status/journal, clean_display_name edge cases Issue #5 fixed locally — 'owlry -m uuctl' will return systemd units once the binary is rebuilt and installed. 186 tests pass. |