|
| 1 | +# Omarchy shell plugin |
| 2 | + |
| 3 | +A bar widget for [omarchy-shell](https://omarchy.org/manual/shell-plugins/) |
| 4 | +that answers one question offline: how much of the local gadak mirror is |
| 5 | +open, and how much of that has been sitting in the same status for more |
| 6 | +than seven days. |
| 7 | + |
| 8 | +This is not a “my assigned tickets” widget. A standalone workspace has no |
| 9 | +account (`gadak init --standalone` clears `AccountID`), and the competing |
| 10 | +community plugins (`tmn73.jira`, Linear, Todoist, ClickUp, `37signals.basecamp`) |
| 11 | +all need a cloud token and a live network. This one runs `gadak sql --json` |
| 12 | +against the on-disk mirror and nothing else. |
| 13 | + |
| 14 | +**No Omarchy machine has run this plugin yet.** The gate below is offline |
| 15 | +(manifest, grep contracts, the real query against `examples/demo.db`). Load, |
| 16 | +placement, click-to-open, and `omarchy-plugin-validate` on a guest are |
| 17 | +unproven. |
| 18 | + |
| 19 | +## What the widget shows |
| 20 | + |
| 21 | +Two numbers in a short bar label, `open·stuck`: |
| 22 | + |
| 23 | +| number | meaning | |
| 24 | +| --- | --- | |
| 25 | +| **open** | rows in `issues_full` whose `status_category` is not `done` | |
| 26 | +| **stuck** | those same rows whose `status_changed_at` is older than 7 days | |
| 27 | + |
| 28 | +`status_category` is one of `new`, `inprogress`, `done`. Do not rewrite the |
| 29 | +query to filter on a status display name — that is empty on a Korean-language |
| 30 | +account (`AGENTS.md`, `CLAUDE.md`). `time-in-status` is not a stored column; |
| 31 | +age is `julianday('now') - julianday(status_changed_at)`. NULL |
| 32 | +`status_changed_at` is not counted as stuck. |
| 33 | + |
| 34 | +The query lives in one file: [`gadak/query.sql`](gadak/query.sql). |
| 35 | +`BarWidget.qml` runs that file through `gadak sql --json`. `verify.sh` |
| 36 | +runs the same file. There is no second copy of the SQL. |
| 37 | + |
| 38 | +`--json` is NDJSON (one object per line, `cmd/gadak/sql.go`). A stale-mirror |
| 39 | +warning goes to stderr; the widget parses stdout only. |
| 40 | + |
| 41 | +### Degrade states (never an empty badge) |
| 42 | + |
| 43 | +| condition | badge | tooltip | |
| 44 | +| --- | --- | --- | |
| 45 | +| `gadak` not on `PATH` | `no gadak` | install the Linux tarball from GitHub Releases | |
| 46 | +| `gadak` exits with `no mirror at … — run gadak sync` (`cmd/gadak/sql.go`) | `not synced` | run `gadak sync` | |
| 47 | +| non-zero exit, or stdout is not NDJSON with `open`/`stuck` | `sql err` | the command failed | |
| 48 | +| first poll still in flight | `…` | reading | |
| 49 | +| success | `12·3` | `12 open · 3 stuck >7d` | |
| 50 | + |
| 51 | +Left click opens `http://127.0.0.1:7777`. That is the default `--addr` of |
| 52 | +`gadak serve` (`cmd/gadak/serve.go:41`). Right click re-runs the query. |
| 53 | + |
| 54 | +`gadak://` is not the click target. `gadak views open` prints a |
| 55 | +`gadak://view/…` deeplink (`cmd/gadak/views.go` `deepLinkURL`) that needs |
| 56 | +the macOS app bundle to register the scheme. Nothing on this desktop does. |
| 57 | +The bind is still `127.0.0.1:7777`; `gadak.localhost:7777` is only a |
| 58 | +display URL when the resolver maps that name to loopback |
| 59 | +(`cmd/gadak/main.go` `prettyOpenURL`). |
| 60 | + |
| 61 | +The plugin makes no outbound network call. Telemetry is forbidden |
| 62 | +(`SECURITY.md`). |
| 63 | + |
| 64 | +## Data contract |
| 65 | + |
| 66 | +Read **only** with `gadak sql --json`. The mirror file is a disposable |
| 67 | +cache whose schema is not a 0.x promise (`specs/000-product/data-model.md`). |
| 68 | +Opening it from QML would break on a migration and can read a half-written |
| 69 | +file mid-sync. The three 0.x promises are `issues_full` + the RECIPES |
| 70 | +queries, the `gadak sql` stdout format, and `views open --keys -`. |
| 71 | + |
| 72 | +## Install |
| 73 | + |
| 74 | +On an Omarchy machine, from a clone of this repository: |
| 75 | + |
| 76 | +```bash |
| 77 | +bash contrib/omarchy/install.sh |
| 78 | +``` |
| 79 | + |
| 80 | +The script: |
| 81 | + |
| 82 | +- refuses with one line if `/etc/os-release` `ID` is not `omarchy` |
| 83 | + (`docs/runbooks/omarchy-vm.md`) |
| 84 | +- copies `gadak/` to `~/.config/omarchy/plugins/io.github.midagedev.gadak/` |
| 85 | + (a copy, not a symlink — `omarchy-plugin-validate` rejects symlinks |
| 86 | + inside a plugin folder) |
| 87 | +- runs `omarchy-plugin-validate` when that CLI exists |
| 88 | +- `omarchy-shell shell rescanPlugins` then `omarchy-plugin-enable` |
| 89 | +- offers `omarchy-webapp-install gadak http://127.0.0.1:7777 web-browser` |
| 90 | + (three arguments; fewer opens an interactive `gum` prompt — |
| 91 | + `bin/omarchy-webapp-install`) |
| 92 | +- prints `gadak install-service` as the way to keep `serve` up (systemd |
| 93 | + **user** unit on Linux; `cmd/gadak/service.go`). It does not install |
| 94 | + that unit itself. |
| 95 | + |
| 96 | +`omarchy-plugin-clone` clones a **built-in** plugin into |
| 97 | +`~/.config/omarchy/plugins/<user>.<id>/`. It is the wrong verb here. |
| 98 | +`omarchy-plugin-add` clones a git URL whose root is a `manifest.json`; |
| 99 | +this plugin is a subdirectory of the gadak repo, so add cannot see it |
| 100 | +until it is published as its own repository. |
| 101 | + |
| 102 | +If `gadak` is missing, the script prints the install options that exist |
| 103 | +today and still copies the plugin (the badge will say `no gadak`): |
| 104 | + |
| 105 | +- **not** an AUR package — new AUR registration is closed |
| 106 | + (`docs/INSTALL.md`) |
| 107 | +- Linux tarball from |
| 108 | + <https://github.com/midagedev/gadak/releases/latest>: |
| 109 | + `gadak_<version>_linux_amd64.tar.gz` / `linux_arm64` plus |
| 110 | + `checksums.txt` (`README.md`) |
| 111 | +- `brew install midagedev/tap/gadak-cli` |
| 112 | +- in-repo `contrib/aur/gadak-bin` + `makepkg -si` (fetches that tarball) |
| 113 | + |
| 114 | +Idempotent: a second run overwrites the copy, skips enable if already |
| 115 | +enabled, skips the desktop file if it exists. |
| 116 | + |
| 117 | +```bash |
| 118 | +bash contrib/omarchy/uninstall.sh |
| 119 | +``` |
| 120 | + |
| 121 | +Disables and removes the plugin (`omarchy-plugin-remove --yes`) and the |
| 122 | +`gadak.desktop` web app. It does not remove the gadak binary or an |
| 123 | +`install-service` unit. |
| 124 | + |
| 125 | +The hyphenated CLIs (`omarchy-plugin-enable`, `-validate`, `-remove`, |
| 126 | +`-list`) live in `basecamp/omarchy` `bin/` on branch `quattro`. |
| 127 | +`omarchy plugin …` is the documented dispatcher for the same scripts |
| 128 | +(`omarchy:alias` headers). This recipe calls the hyphenated names. |
| 129 | + |
| 130 | +Plugins run **unsandboxed** inside `omarchy-shell`. Read the plugin |
| 131 | +before you enable it |
| 132 | +([Omarchy manual](https://omarchy.org/manual/shell-plugins/)). |
| 133 | + |
| 134 | +## Offline gate |
| 135 | + |
| 136 | +```bash |
| 137 | +bash contrib/omarchy/verify.sh |
| 138 | +``` |
| 139 | + |
| 140 | +Runs on macOS and Linux with no Omarchy present. Builds this repo's |
| 141 | +`gadak`, points a temp `GADAK_HOME` at a copy of `examples/demo.db`, |
| 142 | +and executes `gadak/query.sql`. CI: |
| 143 | +[`.github/workflows/omarchy.yml`](../../.github/workflows/omarchy.yml) |
| 144 | +(`actions/setup-go` + this script, path-scoped like the Scoop and AUR |
| 145 | +workflows). `qmllint` is skipped with a printed reason when the tool |
| 146 | +is absent. |
| 147 | + |
| 148 | +## Community directory (later, not this round) |
| 149 | + |
| 150 | +Listing at [omarchyplugins.com](https://omarchyplugins.com) / |
| 151 | +[HANCORE-linux/omarchy-plugin-marketplace](https://github.com/HANCORE-linux/omarchy-plugin-marketplace) |
| 152 | +is a lead step after this directory exists. Submission is an issue form |
| 153 | +plus maintainer review. The marketplace states that it does **not** |
| 154 | +security-audit plugins; they run as unsandboxed code. A listing also |
| 155 | +wants a standalone public git repo with `manifest.json` at the root, |
| 156 | +which this in-repo path is not. |
0 commit comments