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
This commit is contained in:
2026-05-13 12:39:48 +02:00
parent aa1a38bbcf
commit 35f6501de2
8 changed files with 307 additions and 33 deletions
+51 -8
View File
@@ -20,7 +20,17 @@ crates/owlry/ -- everything
│ ├── backend.rs -- SearchBackend abstraction
│ ├── app.rs -- GTK4 setup
│ ├── ui/ -- GTK widgets
│ ├── config/ -- TOML config loader
│ ├── config/ -- TOML + Lua config loader; defines LoadedConfig
│ ├── lua/ -- Lua config layer (feature: lua)
│ │ ├── api.rs -- owlry.set / providers / tabs / provider / theme / profiles
│ │ ├── config.rs -- LuaConfig accumulator + merge_into(Config)
│ │ ├── error.rs -- LuaConfigError (thiserror)
│ │ ├── migrate.rs -- TOML → owlry.lua serializer (deterministic)
│ │ ├── provider.rs -- LuaProvider impl Provider
│ │ ├── runtime.rs -- LuaContext (Arc<Lua>) + eval_file/snapshot
│ │ ├── util.rs -- owlry.util.{shell, read_file, glob, env, hostname, …}
│ │ ├── validate.rs -- ValidationReport with categorised findings
│ │ └── watcher.rs -- notify-based hot reload (desktop-notification errors)
│ ├── data/ -- FrecencyStore
│ ├── filter.rs -- ProviderFilter + prefix parser
│ ├── ipc.rs -- Request/Response types
@@ -47,27 +57,36 @@ There is no `crates/owlry-core`, `owlry-plugin-api`, `owlry-lua`, or `owlry-rune
## Build & development
```bash
# Default features (minimal — app, cmd, calc, conv, power, dmenu)
# Default features (minimal — app, cmd, calc, conv, power, dmenu, systemd)
cargo build
# Full features (matches AUR build)
# Full features (matches AUR build) — includes lua + every optional provider
cargo build --release --features full
# Lua-only opt-in on top of the default minimal set
cargo build --features lua
# Tests
cargo test --workspace --features full # 252+ tests
cargo test --workspace --no-default-features
cargo test --features full # 350+ tests including lua + watcher + migrate
cargo test --no-default-features
# Verbose dev logging
cargo run -- --features dev-logging -- -d
# Format + lint
cargo fmt --all
cargo clippy --workspace --features full
cargo clippy --features full
cargo clippy --no-default-features # must also stay silent
# Install locally (sudo)
just install-local
```
The `lua` cargo feature pulls in `mlua` (vendored Lua 5.4), `glob` (for
`owlry.util.glob`), and `notify` (for hot reload). It's part of the `full`
set; minimal builds (`cargo install` without flags) compile without it
and the `migrate-config` / Lua-load paths gracefully fall back to TOML.
The daemon binary is `owlry`. There is no separate `owlryd` binary anywhere — the daemon is `owlry -d` (or `owlry daemon`). The systemd user unit is `owlry.service` (pre-2.0 name: `owlryd.service`).
## Running locally without disturbing prod
@@ -94,13 +113,37 @@ owlry daemon run the daemon (alias: -d)
owlry dmenu [-p <prompt>] dmenu mode (reads stdin, prints selection)
owlry doctor config + socket + providers status
owlry providers [<id>] list providers (or show one)
owlry config validate parse config, report errors
owlry config validate parse config, report errors (1) and warnings (2)
owlry config show print resolved effective config
owlry migrate-config TOML → init.lua (stub; lands with Lua config)
owlry migrate-config [--force] TOML → owlry.lua (functional from 2.1; --force to overwrite)
```
The `owlry plugin ...` subcommand tree from 1.x is **gone** in 2.0. Nothing to install, manage, or run via the CLI.
## Lua config layer (2.1+)
`~/.config/owlry/owlry.lua` is the canonical config from 2.1 onwards.
`config.toml` remains supported but is ignored entirely when `owlry.lua`
exists (an info log at daemon start surfaces this). The daemon spawns a
`notify` watcher on the config dir; saves are debounced (200ms),
re-evaluated in a fresh `LuaContext`, and hot-swapped atomically. Eval
failures are kept off the live state and surfaced via both the journal
**and** a `notify-rust` desktop notification with the precise mlua
line/column. See [`docs/lua-api.md`](docs/lua-api.md) for the full API
surface (`owlry.set`, `owlry.providers`, `owlry.tabs`, `owlry.provider`,
`owlry.theme`, `owlry.profiles`, `owlry.util.*`).
Implementation notes worth keeping straight:
- `LuaContext::lua: Arc<Lua>``mlua::Function` references don't bump
the Lua refcount, so user providers hold their own `Arc<Lua>` clone
via `LuaContext::lua_handle()` to outlive the context.
- `LoadedConfig` (in `config/mod.rs`) is the resolution result that
keeps the `LuaContext` alive past `Config::load`. The daemon uses
this; `Config::load` itself drops the context after merging scalars
(so it can't be used to wire user providers — only `LoadedConfig`).
- `owlry config validate` runs `lua::validate::validate` against the
snapshot and exits 0 / 1 / 2 per `docs/lua-api.md` §8.
## Provider model
Two traits in `src/providers/mod.rs`:
+29 -6
View File
@@ -141,9 +141,9 @@ owlry -d run the daemon (alias: `owlry daemon`)
owlry dmenu [-p <prompt>] dmenu mode (reads stdin, prints selection)
owlry doctor diagnostics: config + socket + providers
owlry providers [<id>] list providers (or show details for one)
owlry config validate parse config, report errors
owlry config validate parse config, report errors (exit 1) and warnings (exit 2)
owlry config show print the resolved effective config as TOML
owlry migrate-config TOML → init.lua (stub in 2.0; lands in a later 2.x release)
owlry migrate-config [--force] TOML → owlry.lua (deterministic; refuses to overwrite without --force)
```
### Profiles
@@ -229,15 +229,37 @@ Owlry follows the [XDG Base Directory Specification](https://specifications.free
| Path | Purpose |
|------|---------|
| `~/.config/owlry/config.toml` | Main configuration |
| `~/.config/owlry/owlry.lua` | Lua configuration (preferred, takes precedence over `config.toml`) |
| `~/.config/owlry/config.toml` | TOML configuration (legacy; ignored when `owlry.lua` exists) |
| `~/.config/owlry/themes/*.css` | Custom themes |
| `~/.config/owlry/style.css` | CSS overrides |
| `~/.local/share/owlry/frecency.json` | Usage history |
| `$XDG_RUNTIME_DIR/owlry/owlry.sock` | IPC socket (overridable via `$OWLRY_SOCKET`) |
| `/usr/share/doc/owlry/config.example.toml` | Example configuration |
| `/usr/share/doc/owlry/owlry.example.lua` | Example Lua configuration |
| `/usr/share/doc/owlry/config.example.toml` | Example TOML configuration |
| `/usr/share/owlry/themes/` | Bundled themes |
### Quick Start
Config resolution order (per [`docs/lua-api.md`](docs/lua-api.md) §2): `owlry.lua``config.toml` → built-in defaults. When `owlry.lua` is present `config.toml` is ignored entirely (an info log notes this at daemon startup). The daemon watches `owlry.lua` and hot-reloads on save; broken edits surface as desktop notifications and keep the previous state alive.
### Quick Start (Lua config — preferred from 2.1+)
```bash
mkdir -p ~/.config/owlry
cp /usr/share/doc/owlry/owlry.example.lua ~/.config/owlry/owlry.lua
$EDITOR ~/.config/owlry/owlry.lua
owlry config validate
```
Already have a `config.toml`? Migrate it in one shot:
```bash
owlry migrate-config # writes owlry.lua; refuses to overwrite
owlry migrate-config --force # overwrite an existing owlry.lua
```
The migrator is deterministic, emits only values that differ from defaults, and normalises pre-v2 aliases (`system``power`, `badge_sys``badge_power`).
### Quick Start (TOML config — still supported in 2.x)
```bash
mkdir -p ~/.config/owlry
@@ -377,9 +399,10 @@ Set `OWLRY_SOCKET=/path/to/sock` to override the socket location — useful for
See [ROADMAP.md](ROADMAP.md) for feature ideas and [docs/RESTRUCTURE-V2.md](docs/RESTRUCTURE-V2.md) for the v2 rewrite story.
Headline upcoming work:
- **Lua-driven configuration** (2.1 / 3.0)`~/.config/owlry/init.lua` replaces TOML. User-defined providers via `owlry.provider {}` in the same file (Hyprland-style configs-as-code). `owlry migrate-config` lands at the same time.
- **Lua-driven configuration shipped in 2.1**`~/.config/owlry/owlry.lua` is the canonical config from 2.1, with TOML kept as a back-compat fallback until 3.0. User-defined providers via `owlry.provider {}`, host helpers under `owlry.util.*`, hot reload, named profiles, theme overrides, and `owlry migrate-config` are all live. See [`docs/lua-api.md`](docs/lua-api.md) for the full surface.
- **Widget providers return** — weather, MPRIS media controls, pomodoro timer. Deferred from 2.0 while the UI positioning is reworked.
- **Bookmarks return** — Firefox + Chromium. Deferred from 2.0 to avoid a hard rusqlite/`libsqlite3-sys` dep in the chroot build path; returns with a pure-Rust reader (likely via Firefox's JSON backup files).
- **Dynamic Lua providers** (2.2) — `owlry.provider { dynamic = true }` for per-keystroke items. 2.1 ships only static (`dynamic = false`) providers.
## License
+14 -6
View File
@@ -4,14 +4,20 @@ Feature ideas and future development plans. For the v2 rewrite story (where 14 p
## Locked-in for an upcoming 2.x release
### Lua-driven configuration (Phase 3)
Replace `config.toml` with `~/.config/owlry/init.lua`. The config is real Lua, evaluated at startup via embedded `mlua` (Lua 5.4). User-defined providers, keybindings, and theme overrides all live in the same file — Hyprland-style configs-as-code. Ships with `owlry migrate-config` (TOML → init.lua) and hot-reload on save.
### Lua-driven configuration — **shipped in 2.1**
`~/.config/owlry/owlry.lua` is the canonical config from 2.1 onwards (TOML stays supported as a back-compat fallback until 3.0). Real Lua 5.4 via vendored `mlua`. The full surface is documented in [`docs/lua-api.md`](docs/lua-api.md):
- `owlry.set` / `owlry.providers` / `owlry.tabs` / `owlry.theme` / `owlry.profiles` for declarative config
- `owlry.provider {}` for user-defined providers (Hyprland-style configs-as-code)
- `owlry.util.{shell, shell_lines, read_file, glob, env, hostname}` host helpers inside provider callbacks
- Hot reload on save via the `notify` crate — broken edits surface as desktop notifications and keep the previous state live
- `owlry migrate-config [--force]` — deterministic TOML → Lua migration
- `owlry config validate` — categorised report (errors exit 1, warnings exit 2)
```lua
local owlry = require("owlry")
owlry.set { theme = "owl", width = 850, tabs = { "app", "cmd", "uuctl" } }
owlry.providers { "app", "cmd", "power", "bookmarks", "systemd" }
owlry.set { theme = "owl", width = 850 }
owlry.providers { "app", "cmd", "power", "systemd" }
owlry.tabs { "app", "cmd", "uuctl" }
owlry.provider {
id = "hs", prefix = ":hs", tab_label = "Shutdown",
@@ -19,6 +25,8 @@ owlry.provider {
}
```
**2.2 follow-ups:** dynamic (per-keystroke) Lua providers via `dynamic = true`; `owlry.bind` for runtime keybindings; `owlry.util.http_get`.
### Widget providers return
Weather, MPRIS media controls, and pomodoro timer were deferred from 2.0 while the widget-row UI is redesigned. They'll come back as a feature group once the placement model is settled. ([D20 in the v2 plan](docs/RESTRUCTURE-V2.md).)
+1
View File
@@ -111,6 +111,7 @@ package() {
# Documentation + example configuration.
install -Dm644 README.md "$pkgdir/usr/share/doc/$pkgname/README.md"
install -Dm644 data/owlry.example.lua "$pkgdir/usr/share/doc/$pkgname/owlry.example.lua"
install -Dm644 data/config.example.toml "$pkgdir/usr/share/doc/$pkgname/config.example.toml"
install -Dm644 data/style.example.css "$pkgdir/usr/share/doc/$pkgname/style.example.css"
+1 -1
View File
@@ -24,7 +24,7 @@ EXAMPLES:
owlry providers [<id>] List providers (or show one)
owlry config validate Check config for errors
owlry config show Print resolved effective config
owlry migrate-config TOML → init.lua (Phase 3+; stub for now)
owlry migrate-config [--force] TOML → owlry.lua (--force to overwrite)
SEARCH PREFIXES (inside the UI):
:app firefox Search applications
+13 -3
View File
@@ -331,13 +331,23 @@ mod tests {
#[test]
fn pre_v2_aliases_are_known() {
// `sys` and `uuctl` resolve to power and systemd respectively.
// We only assert they're NOT reported as unknown ids — a
// compiled-out warning is environment-dependent (running this
// with `--no-default-features --features lua` omits the systemd
// feature, which legitimately flags uuctl as compiled-out).
let mut cfg = empty_cfg();
cfg.providers = Some(vec!["sys".into(), "uuctl".into()]);
cfg.tabs = Some(vec!["sys".into(), "uuctl".into()]);
let report = validate(&cfg);
assert!(
report.is_clean(),
"pre-v2 aliases must validate cleanly; got: {:?}",
let unknown_count = report
.warnings
.iter()
.filter(|w| w.contains("unknown id"))
.count();
assert_eq!(
unknown_count, 0,
"pre-v2 aliases must not be flagged as unknown ids; got: {:?}",
report.warnings
);
}
+54 -9
View File
@@ -32,6 +32,10 @@ Optional modes (depend on cargo features at build time):
.TP
.BI \-\-profile " NAME"
Launch the UI with a named profile. Profiles are defined under
.B owlry.profiles
in
.IR ~/.config/owlry/owlry.lua
or
.B [profiles.<NAME>]
in
.IR ~/.config/owlry/config.toml .
@@ -64,18 +68,45 @@ List all registered providers, or print details (icon, prefix, position, tab
label, search noun) for one. Requires a running daemon.
.TP
.B "config validate"
Parse the config file and report errors. Exits 0 on success, 1 on parse failure.
Parse the config file and report errors and warnings. When
.I ~/.config/owlry/owlry.lua
exists it is evaluated and the snapshot is checked for unknown keys,
unknown provider ids, tabs not in
.BR owlry.providers ,
duplicate
.B owlry.provider
ids, and providers compiled out of the running build. Exit codes:
.B 0
clean,
.B 1
on errors (syntax / eval / TOML parse failure),
.B 2
on warnings only.
.TP
.B "config show"
Print the resolved effective configuration (defaults merged with the user file)
as TOML.
.TP
.B migrate-config
Migrate TOML configuration to a future
.B init.lua
format. Stub in 2.0; functional once the Lua config layer lands in a later 2.x
release. See
.IR docs/RESTRUCTURE-V2.md .
.BR "migrate-config " [\fB\-\-force\fR]
Migrate
.I ~/.config/owlry/config.toml
to
.I ~/.config/owlry/owlry.lua
with equivalent settings. Output is deterministic and minimal — only values
differing from the built-in defaults are emitted. Pre-v2 aliases
.RB ( system " \(-> " power ,
.B badge_sys
\(->
.BR badge_power )
are normalised to v2 names. The migrator refuses to overwrite an existing
.B owlry.lua
unless
.B \-\-force
(or
.BR \-f )
is passed. See
.IR docs/lua-api.md
\(sc9 for the full mapping.
.SH ENVIRONMENT
.TP
.B XDG_RUNTIME_DIR
@@ -102,8 +133,19 @@ Auto-detected terminal for items marked as needing a terminal. Overridden by
in the config.
.SH FILES
.TP
.I ~/.config/owlry/owlry.lua
Lua configuration (preferred from 2.1). Takes precedence over
.B config.toml
when both exist; an info log notes this at daemon start. The daemon
hot-reloads on save; broken edits surface as desktop notifications and
keep the previous state alive. See
.IR docs/lua-api.md
for the API.
.TP
.I ~/.config/owlry/config.toml
Main configuration. See
TOML configuration (legacy; ignored when
.B owlry.lua
exists). See
.B owlry config show
for the effective state.
.TP
@@ -122,8 +164,11 @@ IPC Unix socket. See
.B OWLRY_SOCKET
to override.
.TP
.I /usr/share/doc/owlry/owlry.example.lua
Annotated example Lua configuration.
.TP
.I /usr/share/doc/owlry/config.example.toml
Annotated example configuration.
Annotated example TOML configuration.
.TP
.I /usr/share/owlry/themes/
Bundled themes.
+144
View File
@@ -0,0 +1,144 @@
-- ~/.config/owlry/owlry.lua — example configuration.
--
-- Drop this file in place to switch from config.toml to the Lua config
-- layer. owlry.lua takes precedence over config.toml when both exist
-- (info-logged at daemon start). The daemon watches this file and
-- hot-reloads on save; broken edits surface as desktop notifications
-- and keep the previous state alive.
--
-- Spec: https://somegit.dev/Owlibou/owlry/src/branch/main/docs/lua-api.md
-- ──────────────────────────────────────────────────────────────────────
-- 1. Global settings.
-- Every key here is OPTIONAL — defaults apply for anything you omit.
-- ──────────────────────────────────────────────────────────────────────
owlry.set {
theme = "owl", -- bundled themes: owl, catppuccin-mocha,
-- nord, rose-pine, dracula, gruvbox-dark,
-- tokyo-night, solarized-dark, one-dark,
-- apex-neon. Plus any *.css under
-- ~/.config/owlry/themes/.
width = 850,
height = 650,
font_size = 14,
border_radius = 12,
-- terminal = "kitty", -- omit to auto-detect ($TERMINAL → xdg-
-- terminal-exec → DE-native → fallback).
use_uwsm = false, -- launch desktop entries via `uwsm app --`
-- for proper systemd session integration.
show_icons = true,
max_results = 100,
frecency = true, -- boost recently / frequently launched items
frecency_weight = 0.3, -- 0.0 = off, 1.0 = strong
search_engine = "duckduckgo", -- google | duckduckgo | bing |
-- startpage | searxng | brave |
-- ecosia, or a custom "{query}" URL.
}
-- ──────────────────────────────────────────────────────────────────────
-- 2. Enabled providers.
-- Omit this call to enable every built-in provider (the default).
-- Listing a subset disables anything not mentioned. Pre-v2 aliases
-- (sys / system → power; uuctl → systemd) still work.
-- ──────────────────────────────────────────────────────────────────────
owlry.providers {
"app", "cmd", -- core launchers
"calc", "conv", -- = / > triggers
"power", -- shutdown / reboot / lock
"systemd", -- user units (:uuctl)
"ssh", "websearch", "filesearch", -- search-style providers
"emoji", "clipboard", -- pickers
}
-- ──────────────────────────────────────────────────────────────────────
-- 3. Tab bar order (subset of providers).
-- Omit to give every enabled provider a tab. Order is preserved;
-- Ctrl+1 jumps to the first entry, Ctrl+2 the second, and so on.
-- ──────────────────────────────────────────────────────────────────────
owlry.tabs { "app", "cmd", "uuctl" }
-- ──────────────────────────────────────────────────────────────────────
-- 4. Theme overrides.
-- owlry.theme("name") picks a bundled / user theme.
-- owlry.theme {} layers individual colour overrides on top.
-- Both forms compose — call as many times as you like.
-- ──────────────────────────────────────────────────────────────────────
-- owlry.theme {
-- background = "#1e1e2e",
-- background_secondary = "#313244",
-- border = "#45475a",
-- text = "#cdd6f4",
-- text_secondary = "#a6adc8",
-- accent = "#cba6f7",
-- accent_bright = "#f5c2e7",
-- -- Per-provider badges (each is optional):
-- badge_app = "#a6e3a1",
-- badge_cmd = "#fab387",
-- badge_power = "#f38ba8",
-- badge_uuctl = "#9ece6a",
-- }
-- ──────────────────────────────────────────────────────────────────────
-- 5. Named profiles, selected by `owlry --profile <name>`.
-- Each profile overrides the default enabled-provider set for that
-- launch but inherits owlry.set / owlry.theme / owlry.tabs.
-- ──────────────────────────────────────────────────────────────────────
-- owlry.profiles {
-- dev = { "app", "cmd", "ssh" },
-- media = { "emoji", "clipboard" },
-- minimal = { "app" },
-- }
-- ──────────────────────────────────────────────────────────────────────
-- 6. User-defined providers.
-- Register your own search source. Every field except `id` and
-- `items` is optional. `items` is called once at startup and the
-- results cached (dynamic per-keystroke providers land in 2.2).
-- ──────────────────────────────────────────────────────────────────────
-- owlry.provider {
-- id = "hs",
-- prefix = ":hs",
-- tab_label = "Shutdown",
-- icon = "system-shutdown",
-- search_noun = "shutdown actions",
-- items = function()
-- return {
-- { name = "Lock", command = "hyprlock" },
-- { name = "Shutdown", command = "systemctl poweroff" },
-- { name = "Reboot", command = "systemctl reboot" },
-- }
-- end,
-- }
-- ──────────────────────────────────────────────────────────────────────
-- 7. Host helpers (use inside provider `items` callbacks).
-- Available under owlry.util.*:
-- shell(cmd) -> string (stdout, trimmed)
-- shell_lines(cmd) -> {string}
-- read_file(path) -> string | nil
-- glob(pattern) -> {string} (~ expansion supported)
-- env(name, default?) -> string | nil
-- hostname() -> string
-- ──────────────────────────────────────────────────────────────────────
-- owlry.provider {
-- id = "docker-ps",
-- prefix = ":docker",
-- items = function()
-- local lines = owlry.util.shell_lines(
-- "docker ps --format '{{.Names}}\t{{.Image}}'"
-- )
-- local items = {}
-- for _, line in ipairs(lines) do
-- local name, image = line:match("([^\t]+)\t(.+)")
-- if name then
-- items[#items + 1] = {
-- name = name,
-- description = image,
-- command = "docker exec -it " .. name .. " bash",
-- terminal = true,
-- }
-- end
-- end
-- return items
-- end,
-- }