Commit Graph

291 Commits

Author SHA1 Message Date
vikingowl 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).
2026-05-13 03:52:06 +02:00
vikingowl 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.
2026-05-13 03:41:11 +02:00
vikingowl 60780f2fdd chore(aur): finalize owlry 2.0.0 PKGBUILD (real b2sum) 2026-05-13 03:29:17 +02:00
vikingowl 645a4ce637 Merge pull request 'owlry 2.0: single-binary rewrite' (#6) from v2 into main
Reviewed-on: #6
owlry-v2.0.0
2026-05-13 03:28:06 +02:00
vikingowl 2cac6556f3 chore(owlry): bump version to 2.0.0 2026-05-13 03:24:08 +02:00
vikingowl 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.
2026-05-13 03:19:14 +02:00
vikingowl 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 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.
2026-05-13 03:13:16 +02:00
vikingowl 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.
2026-05-13 03:06:39 +02:00
vikingowl 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.
2026-05-13 03:00:24 +02:00
vikingowl 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.
2026-05-13 02:57:46 +02:00
vikingowl 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.
2026-05-13 02:55:01 +02:00
vikingowl 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.
2026-05-13 02:43:22 +02:00
vikingowl 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.
2026-05-13 02:35:28 +02:00
vikingowl 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.
2026-05-13 02:35:13 +02:00
vikingowl 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 -> c48efaa)
- Each acceptance check (build, test, clippy, fmt, file layout, runtime
  smoke) with the result
- Three deferred follow-ups that don't block 2.0.0 ship: dynamic-provider
  visibility in doctor, clippy style nits, refresh_widgets stub

Next: Phase 2 (AUR republish as 2.0.0). The single owlry PKGBUILD
declares replaces/conflicts/provides for the 14 dropped packages and
builds with --features full.
2026-05-13 02:30:39 +02:00
vikingowl 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).
2026-05-13 02:30:10 +02:00
vikingowl 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.
2026-05-13 02:27:16 +02:00
vikingowl 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.
2026-05-13 02:26:23 +02:00
vikingowl 1ba0a97e6d docs(example): update config.example.toml for sys->power rename
Follow-up to d1c3270 — the prior commit missed the example config
because the Edit calls landed before a Read.
2026-05-13 02:23:31 +02:00
vikingowl 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.
2026-05-13 02:23:13 +02:00
vikingowl 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.
2026-05-13 02:17:42 +02:00
vikingowl 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.
2026-05-13 02:10:09 +02:00
vikingowl 0a4a09037e refactor(v2): collapse owlry-core into owlry single crate
Workspace shrinks from 2 members to 1. The daemon, IPC layer,
providers, config, frecency store, GTK4 UI, and CLI now live in a
single `crates/owlry` crate exposing both a library (so integration
tests can reach daemon types) and a binary.

Structural changes:
- crates/owlry-core/ deleted; all source moved into crates/owlry/src/
  via git mv to preserve history
- crates/owlry/src/lib.rs added with module declarations
- crates/owlry/src/main.rs rewritten as thin entry that uses owlry::*
- crates/owlry/src/providers/mod.rs absorbs owlry-core's providers/mod.rs
  and pulls dmenu into the same module tree
- All owlry_core:: refs in src/ rewritten to crate::
- All owlry_core:: refs in tests/ rewritten to owlry::
- systemd/owlryd.service: ExecStart=/usr/bin/owlry -d (single binary)
- justfile: drop owlry-core/owlry-lua/owlry-rune build steps; daemon
  runs via 'cargo run -p owlry -- -d'
- owlry version: 1.0.10 -> 2.0.0-dev

Tests: 178 still pass (156 lib + 14 ipc + 8 server). No test changes
needed — moved files retained their inline test modules.

Task #2 complete.
2026-05-13 02:05:26 +02:00
vikingowl 1d20754b66 test(v2): characterize demolition behavior
TDD cleanup pass for the C-ABI removal — pin down every behavior change
so subsequent phases can't silently regress.

owlry-core lib (providers/mod.rs, +14 tests):
- Provider trait default methods return documented values
- ProviderPosition::as_str matches IPC strings
- ProviderType::FromStr accepts plural aliases (apps/cmds)
- ItemSource::FromStr maps unknown (including legacy 'native_plugin') to Core
- ItemSource::as_str emits only supported variants
- add_provider refreshes and appends
- available_providers uses trait overrides for Plugin(id)
- query_submenu_actions: matches+actions / no match / empty actions
- execute_plugin_action: static handles / dynamic handles / nothing handles
- new with no providers does not panic

owlry-core integration (tests/ipc_test.rs, +2 tests):
- plugin_list Request must not deserialize (loud failure for old clients)
- plugin_list Response must not deserialize (clients can't accept stale daemon replies)

owlry CLI (src/cli.rs, +6 tests):
- no args yields UI launch defaults
- -d / --daemon enable daemon mode
- daemon flag conflicts with -m / --profile / -p
- mode flag parses known providers and unknown -> Plugin(id)
- plugin subcommand tree is no longer recognised

178 tests total (up from 142 baseline).
2026-05-13 02:00:37 +02:00
vikingowl ae4a90352e refactor(v2): demolish C-ABI plugin system
Delete the entire dynamic-loading infrastructure that produced issue #5
and the per-API-bump plugin breakage cycle:

- crates/owlry-plugin-api/  (ABI-stable interface, gone)
- crates/owlry-lua/         (Lua runtime cdylib, gone — replaced by mlua in Phase 3)
- crates/owlry-rune/        (Rune runtime cdylib, gone per D3)
- owlry-core/src/plugins/   (loader, manifest, registry, watcher — all gone)
- owlry-core/src/providers/native_provider.rs
- owlry-core/src/providers/lua_provider.rs
- owlry-core/src/providers/config_editor.rs   (per D11, 1127 LOC)
- owlry/src/plugin_commands.rs                (per CLI restructure, 1296 LOC)

Provider trait gains submenu_actions(), execute_action(), prefix(),
icon(), position(), priority() as default methods so future built-in
providers can declare their UI metadata directly instead of relying on
the hardcoded match table.

ProviderManager simplified: drops native_providers,
static_native_providers, dynamic_providers, widget_providers,
runtimes, runtime_type_ids, plugin_registry fields and the
reload_runtimes / find_native_provider / get_widget_item /
widget_type_ids methods. ProviderPosition enum carries the Normal/
Widget distinction on the trait instead.

IPC Request::PluginList and Response::PluginList removed; Submenu
and PluginAction stay (route to Provider trait methods now).

owlry -d / --daemon flag added as the future daemon entry point; the
old owlryd binary is still produced from owlry-core for Phase 1
compatibility but will fold into the single binary in task #2.

Workspace shrinks from 5 members to 2. Tests: 142 passed.
LOC: -13,796 / +273 (net -13,523).

Tasks #3, #4, #5 complete.
2026-05-13 01:54:33 +02:00
vikingowl 2fc976b969 docs(v2): resolve section 8 open questions as D15-D21
- D15: rename systemd unit owlryd.{service,socket} -> owlry.{...}
- D16: defer submenu protocol redesign to Phase 5
- D17: keep daemon (cold-start cost justifies it)
- D18: TOML reader hard cut at 3.0.0
- D19: Lua sandbox: fs read + process spawn; no network default
- D20: widgets (weather, media, pomodoro) on hold; excluded from Phase 1
- D21: hot-reload init.lua on save (Phase 3)

Phase 1 plugin conversion shrinks from 11 -> 8 plugins (widgets dropped).
2026-05-13 01:45:21 +02:00
vikingowl 163e68af9e docs(v2): lock down restructure plan
Comprehensive plan covering all 5 phases of the v2 restructure:
decisions log, target shape, CLI layout, feature naming, conversion
notes, breaking changes, deferred questions, and acceptance checklist.

This document is the source of truth for the v2 work; future sessions
read this first to recover context.
2026-05-13 01:36:55 +02:00
vikingowl 1caa0506a2 chore(aur): update PKGBUILDs 2026-04-09 21:18:51 +02:00
vikingowl 61411cd094 chore(owlry): bump version to 1.0.10 owlry-core-v1.3.6 owlry-lua-v1.1.5 owlry-rune-v1.1.6 owlry-v1.0.10 2026-04-09 21:16:48 +02:00
vikingowl 4e310223cf chore(owlry-rune): bump version to 1.1.6 2026-04-09 21:16:45 +02:00
vikingowl 6446a253e8 chore(owlry-lua): bump version to 1.1.5 2026-04-09 21:16:42 +02:00
vikingowl 72dcd74e65 chore(owlry-core): bump version to 1.3.6 2026-04-09 21:16:39 +02:00
vikingowl 774b2a4700 feat: configurable tab labels and search nouns from plugin metadata
Script plugins can now declare tab_label and search_noun in their
plugin.toml [[providers]] section. These flow through the Provider
trait, IPC ProviderDesc, and into the UI via provider_meta::resolve().
Unknown plugins auto-generate labels from type_id instead of showing
a generic "Plugin" label.
2026-04-09 21:16:36 +02:00
vikingowl 34d156fb7d chore(owlry-rune): bump version to 1.1.5 owlry-core-v1.3.5 owlry-lua-v1.1.4 owlry-rune-v1.1.5 owlry-v1.0.9 2026-04-09 18:31:29 +02:00
vikingowl afe248c66f chore(owlry-lua): bump version to 1.1.4 2026-04-09 18:31:05 +02:00
vikingowl 2c3c8b8e51 chore(owlry-core): bump version to 1.3.5 2026-04-09 18:31:00 +02:00
vikingowl 3d328d8fa0 chore(owlry): bump version to 1.0.9 2026-04-09 18:30:59 +02:00
vikingowl fab0e288ae chore(aur): remove deleted meta-bundle packages
owlry-meta-essentials, owlry-meta-full, owlry-meta-tools, and
owlry-meta-widgets have been accepted for deletion on AUR.
2026-04-09 18:27:52 +02:00
vikingowl 3069c5aa5a fix(tests): skip config.save() in config_editor unit tests
Tests using execute_action() triggered Config::save() with a default
Config, silently overwriting ~/.config/owlry/config.toml on every
`cargo test` run. Guard the save call with #[cfg(not(test))].
2026-04-09 16:51:19 +02:00
vikingowl e11fac3619 chore: replace meval with expr-solver-lib, drop reqwest from runtimes, fix AUR deps
- owlry-core: swap meval → expr-solver-lib for calculator and Lua math API;
  add ln() alias for meval compatibility
- owlry-lua: remove reqwest and meval (network features belong in plugins);
  add vendored feature flag so distro builds can link against system lua54
- owlry-rune: remove reqwest (same reason)
- aur/owlry-rune: fix depends (gcc-libs only; owlry-core → optdepends)
- aur/owlry-lua: fix depends (gcc-libs + lua54; owlry-core → optdepends)
- aur/owlry: add chmod -R a+rX for example plugins
- justfile: log aur-local-test output to build-logs/
- .gitignore: exclude build-logs/ and test-build-output files
- README: minor improvements (SIGHUP reload hint, plugin_config example)
2026-04-09 16:51:12 +02:00
vikingowl 7275fcab35 fix: implement all 24 FIX_PLAN issues across 6 phases
Phase 1 — Critical Safety:
- #11: bounded IPC reads via read_bounded_line (server + client)
- #13: sound Send+Sync via Arc<Mutex<RuntimeHandle>>; remove unsafe impl Sync
- #10: ItemSource enum (Core/NativePlugin/ScriptPlugin) on LaunchItem;
  script plugin allowlist guard in launch_item()

Phase 2 — Config System Overhaul:
- #6: remove dead enabled_plugins field
- #1: replace #[serde(flatten)] with explicit Config::plugin_config
- #4: Server.config Arc<RwLock<Config>>; ConfigProvider shares same Arc
- #2/#3: atomic config save (temp+rename); TOCTOU fixed — write lock held
  across mutation and save() in config_editor
- #23: fs2 lock_exclusive() on .lock sidecar file in Config::save()
- #16: SIGHUP handler reloads config; ExecReload in systemd service

Phase 3 — Plugin Architecture:
- #7: HostAPI v4 with get_config_string/int/bool; PLUGIN_CONFIG OnceLock
  in native_loader, set_shared_config() called from Server::bind()
- #5: PluginEntry + Request::PluginList + Response::PluginList; plugin_registry
  in ProviderManager tracks active and suppressed native plugins;
  cmd_list_installed shows both script and native plugins
- #9: suppressed native plugin log level info! → warn!
- #8: ProviderType doc glossary; plugins/mod.rs terminology table

Phase 4 — Data Integrity:
- #12: all into_inner() in server.rs + providers/mod.rs → explicit Response::Error;
  watcher exits on poisoned lock
- #14: FrecencyStore::prune() (180-day age + 5000-entry cap) called on load
- #17: empty command guard in launch_item(); warn in lua_provider
- #24: 5-min periodic frecency save thread; SIGTERM/SIGINT saves frecency
  before exit (replaces ctrlc handler)

Phase 5 — UI & UX:
- #19: provider_meta.rs ProviderMeta + meta_for(); three match blocks collapsed
- #18: desktop file dedup via seen_basenames HashSet in ApplicationProvider
- #20: search_filtered gains tag_filter param; non-frecency path now filters
- #15: widget refresh 5s→10s; skip when user is typing

Phase 6 — Hardening:
- #22: catch_unwind removed from reload_runtimes(); direct drop()
- #21: AtomicUsize + RAII ConnectionGuard; MAX_CONNECTIONS = 16

Deps: add fs2 = "0.4"; remove ctrlc and toml_edit from owlry-core
2026-04-08 16:43:52 +02:00
vikingowl 4d7e913657 chore(aur): update all packages to latest versions 2026-04-06 02:42:09 +02:00
vikingowl f8d011447e chore(owlry): bump version to 1.0.8 owlry-core-v1.3.4 owlry-lua-v1.1.3 owlry-rune-v1.1.4 owlry-v1.0.8 2026-04-06 02:39:19 +02:00
vikingowl 9163b1ea6c chore(owlry-rune): bump version to 1.1.4 2026-04-06 02:38:47 +02:00
vikingowl 6586f5d6c2 fix(plugins): close remaining gaps in new plugin format support
- Fix cmd_runtimes() help text: init.lua/init.rn → main.lua/main.rn
- Add .lua extension validation to owlry-lua manifest (mirrors Rune)
- Replace eprintln! with log::warn!/log::debug! in owlry-lua loader
- Add log = "0.4" dependency to owlry-lua
- Add tests: [[providers]] deserialization in owlry-core manifest,
  manifest provider fallback in owlry-lua and owlry-rune loaders,
  non-runtime plugin filtering in both runtimes
2026-04-06 02:38:42 +02:00
vikingowl a6e94deb3c fix(runtime): prevent dlclose() to avoid SIGSEGV on runtime teardown
Wrap LoadedRuntime._library in ManuallyDrop so dlclose() is never called.
dlclose() unmaps the library code; thread-local destructors inside liblua.so
then SIGSEGV when they try to run against the unmapped addresses.

Also filter out non-.lua plugins in the Lua runtime's discover_plugins()
so liblua.so does not attempt to load Rune plugins.
2026-04-06 02:26:12 +02:00
vikingowl de74cac67d chore(owlry-lua): bump version to 1.1.3 2026-04-06 02:22:08 +02:00
vikingowl 2f396306fd chore(owlry-core): bump version to 1.3.4 2026-04-06 02:22:07 +02:00
vikingowl 133d5264ea feat(plugins): update plugin format to new entry_point + [[providers]] style
- owlry-core/manifest: add entry_point alias for entry field, add ProviderSpec
  struct for [[providers]] array, change default entry to main.lua
- owlry-lua/manifest: add ProviderDecl struct and providers: Vec<ProviderDecl>
  for [[providers]] support
- owlry-lua/loader: fall back to manifest [[providers]] when script has no API
  registrations; fall back to global refresh() for manifest-declared providers
- owlry-lua/api: expose call_global_refresh() that calls the top-level Lua
  refresh() function directly
- owlry/plugin_commands: update create templates to emit new format:
  entry_point instead of entry, [[providers]] instead of [provides],
  main.rn/main.lua instead of init.rn/init.lua, Rune uses Item::new() builder
  pattern, Lua uses standalone refresh() function
- cmd_validate: accept [[providers]] declarations as a valid provides source
2026-04-06 02:22:03 +02:00
vikingowl a16c3a0523 fix(just): skip meta packages without PKGBUILD in aur-publish-all 2026-04-06 02:11:32 +02:00