Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions plugins/registry.json
Original file line number Diff line number Diff line change
Expand Up @@ -1381,6 +1381,36 @@
],
"lastUpdated": "2026-11-08",
"upstream": "https://github.com/mysweetpea/prayer-times"
},
{
"id": "zimaos",
"name": "ZimaOS",
"version": "0.1.16",
"path": "plugins/zimaos",
"author": "Felix <eu@leandrofelix.dev.br>",
"upstream": "https://github.com/leandrofelix-dev/ryoku-zima-client",
"summary": "QS Bar card for a ZimaOS server: device name, link rate, storage, and a shortcut to the dashboard.",
"description": "QS Bar card for a ZimaOS server: device name, link rate, storage, and a shortcut to the dashboard.",
"tags": [
"zimaos",
"nas",
"bar-widget"
],
"accent": "#8f8378",
"surface": "#101010",
"preview": "assets/preview-widget.png",
"screenshots": [
"assets/preview-widget.png"
],
"manifest": "product-manifest.json",
"manifestSha256": "60419e62d301345829f8579a2e3f2cb86c42be55252659cf00e0b0e298916fa8",
"official": false,
"tagline": "QS Bar card for a ZimaOS server: device name, link rate, storage, and a shortcut to the dashboard.",
"icon": "archive",
"hosts": [
"topbarGlyph"
],
"lastUpdated": "2026-11-09"
}
]
}
5 changes: 5 additions & 0 deletions plugins/zimaos/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.DS_Store
*.log
*.tmp
__pycache__/
*.pyc
98 changes: 98 additions & 0 deletions plugins/zimaos/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Agent guide for the zimaos plugin

This folder is a Ryoku shell plugin. If you are an AI agent editing it, follow
every rule below. They are the same rules `ryoku plugin validate` enforces, so
work that breaks one will not install. This file is self-contained: you do not
need any other document to work here.

## The rules

R1 Place. A plugin is one folder named after its id. Author it under
`$(xdg-user-dir DOCUMENTS)/ryoku-plugins/<id>/` (fallback `~/ryoku-plugins/<id>/`);
`ryoku plugin new <id>` creates it there. Never write into
`~/.local/share/ryoku/plugins/` (the store's install root, receipt-owned) or
`~/.config/quickshell/` (the shipped shell).

R2 Shape. `manifest.json` at the root; `service/Main.qml` (logic, no UI);
`content/Widget.qml` (the one view); optional `content/Panel.qml` (a bar panel);
`README.md`; `LICENSE`; `assets/preview-widget.png` (a real capture); scripts
only under `bin/` with a shebang and the exec bit. Every extra file listed in
manifest `files`.

R3 Id. Lowercase `[a-z0-9][a-z0-9-]*`, unique, not a built-in widget id.

R4 Imports. Only `QtQuick*`, `Quickshell*`, `Ryoku.PluginKit`,
`Ryoku.PluginKit.Singletons`, and files inside the plugin folder. Never
`shell.*`, `Ryoku.Ui*` internals, or a relative import that climbs out of the
folder.

R5 Settings. Declared in `metadata.settings` (types the bar renders: toggle,
choice, multi, int, text); read through `pluginApi.pluginSettings` behind a
default; written only through `pluginApi.saveSetting(key, value)`. Never edit
`shell.json` or `plugins.json` directly.

R6 Commands. Every external program the plugin runs is either in its own `bin/`
or listed in `dependencies.commands`. No `sudo`, `doas`, `su`. A privileged
action is allowed only through `pkexec`, only on an explicit click, only when
listed in manifest `capabilities.privileged` (exact command strings) and
explained in README.

R7 Network. Every host the plugin talks to is listed in
`capabilities.network`. No `curl … | sh`, no downloading and running code.

R8 Files. Write only under `pluginApi.stateDir`
(`$XDG_STATE_HOME/ryoku/plugins/<id>`), `$XDG_CACHE_HOME/ryoku/plugins/<id>`, or
a temp dir. Never touch `~/.ssh`, `/etc`, shell rc files, or another plugin's
folder.

R9 Shell. No `sh -c` with a string built from settings or program output
(injection). Pass argv arrays.

R10 Secrets and binaries. No tokens, keys or credentials in the tree; no
compiled binaries (ELF/Mach-O/.so); scripts only.

R11 Honesty. `official` is never true for a community plugin. `author` is
`Name <mail>`. README says what runs, what it reads, what it writes, and every
privileged/network capability.

## The workflow

1. `ryoku plugin new <id> [--bar|--desktop|--popout|--sidebar]` scaffolds this
folder (already done). This scaffold selected `topbarGlyph`.
2. Edit `service/Main.qml` for logic and `content/Widget.qml` for the view.
Edit `content/Panel.qml` only for a bar plugin. Capture
`assets/preview-widget.png`.
3. `ryoku plugin validate <dir>` and fix every blocking finding (warnings are
advisory but read them).
4. `ryoku plugin add <dir> --yes`, then enable and place it under
**Ryoku Settings > Add-ons**. For a bar plugin, `--bar` enables it on the
current bar immediately.
5. `ryoku plugin share <id>` ONLY when the user asks to publish. Never share a
plugin unless asked.

## What the host sets

Ryoku ships four hosts: `topbarGlyph`, `desktopWidget`, `framePopout`, and
`sidebarCard`. They all mount `content/Widget.qml`; only a bar plugin may add
`content/Panel.qml`.

The bar, desktop, and popout hosts set `pluginApi`, `s`, `active`, `density`, and
`widthBudget`. Read them; never assign them.

For `sidebarCard`, the widget root is an `Item` with
`pragma ComponentBehavior: Bound`. The host sets `s`, `open`, `reveal`,
`tabActive`, `width`, and `pluginApi`; the card reports `implicitHeight` and
declares `signal requestClose()`. Read host-set values and never assign them.
There is no `content/Sidebar.qml`. Ryoku draws the card plate and owns its
position, size, motion, and chrome.

`pluginApi` exposes:

- `mainInstance`: the live `service/Main.qml` instance every view shares.
- `pluginSettings`: the resolved settings object; read behind a default.
- `pluginDir`: this plugin's folder.
- `stateDir`: `$XDG_STATE_HOME/ryoku/plugins/<id>`; the only place to write.
- `saveSetting(key, value)`: persist one setting.
- `panelOpen` (bool), `openPanel()`, `closePanel()`, `togglePanel()`: the bar
panel controls (present but inert off the bar). The sanctioned bar-widget
click is `onClicked: pluginApi.togglePanel()`.
4 changes: 4 additions & 0 deletions plugins/zimaos/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# CLAUDE.md

Read `AGENTS.md` in this folder before editing anything here.
It holds every rule this plugin must follow and the full authoring workflow.
21 changes: 21 additions & 0 deletions plugins/zimaos/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 Felix

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
39 changes: 39 additions & 0 deletions plugins/zimaos/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# ZimaOS

Plugin da QS Bar para um servidor ZimaOS. O ícone na barra é o nome ZIMA, num tom só, igual aos outros glifos, e abre o painel. Antes de entrar, o painel pede o endereço, o usuário e a senha. Depois de entrar, mostra o cartão do aparelho.

## O que aparece

Antes do login: **IP**, **Usuário** e **Senha**, e o botão **Entrar**. O IP fica preenchido quando já existe um endereço salvo. O exemplo do campo é só um placeholder.

Depois do login, no ZimaOS 1.8:

- Nome do aparelho, versão e modelo, lidos de `GET /v2/zimaos/device/info`. A foto do aparelho vem de `device_image` nesse mesmo JSON e é baixada de `/v2/zimaos/device/image?model=…&type=client`. O PNG fica em `$XDG_STATE_HOME/ryoku/plugins/zimaos/device.png` e só é baixado de novo quando o modelo muda.
- Interface e endereço IPv4 do caminho em uso (`GET /v2/zimaos/network/connection-status`). Os quatro ícones ao lado de LAN são remoto, Wi-Fi, Ethernet e Thunderbolt: o acento marca o caminho em uso, o tom claro marca um caminho disponível, e o tom apagado marca o que está desligado.
- Atalho **Ir ao painel** para a página inicial do servidor.
- Atalho **Abrir** o armazenamento (`/modules/icewhale_files/`), com o espaço livre do maior volume. O nome do volume só aparece depois do login.
- **Backup**, quando o app grid devolve um link; senão abre o painel.
- **PeerDrop** abre o módulo do servidor em `/modules/icewhale_peerdrop/`.
- **Sair** volta à mesma tela de entrar, com o IP salvo preenchido e a senha vazia.
- O cartão usa a superfície da própria barra: a mesma borda e o mesmo vidro do painel de música. Os blocos de dentro são um escurecimento leve, não uma placa opaca.

## O que corre, lê e escreve

- `bin/zima` (Python 3, biblioteca padrão). Um IP ou nome da rede local, sem esquema, continua em HTTP (por exemplo `192.168.0.180`). `http://` é o mesmo. `https://` usa HTTPS e verifica o certificado; a verificação não é desligada. Recusa caminho, `@` e qualquer outro esquema. Não segue redirecionamentos, para o token não ir para outro host.
- Caminhos: `POST /v1/users/login`, `POST /v1/users/refresh`, `GET /v1/sys/utilization`, `GET /v2/zimaos/network/interfaces`, `GET /v2/zimaos/network/connection-status`, `GET /v2/local_storage/storages`, `GET /v2/app_management/web/appgrid` e o device info acima.
- `xdg-open`, só quando você clica num atalho.
- O endereço é gravado com `pluginApi.saveSetting` na chave `host`. A senha não é gravada nem registrada.
- A sessão (usuário e tokens) fica em `$XDG_STATE_HOME/ryoku/plugins/zimaos/session.json`, modo `0600`. A foto do aparelho fica ao lado, em `device.png`.

Não há comando privilegiado. Não há host fixo em `capabilities.network`: o validador do Ryoku só exige essa lista para endereços `http://` ou `https://` escritos no código, e este plugin não tem nenhum. O servidor é o que a pessoa digita.

## Instalar

Outra pessoa com Ryoku copia esta pasta e roda, dentro dela:

```
ryoku plugin validate .
ryoku plugin add . --bar --yes
```

O glifo entra na barra. Abra o painel, informe o IP do ZimaOS, o usuário e a senha, e toque em **Entrar**. O mesmo plugin fica em **QS Bar Settings → Community**.
Binary file added plugins/zimaos/assets/preview-widget.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading