Files
clientCommands/docs/development.md
T
lyuksovannyyandClaude Opus 5.5 46a1f6ee1f Client Commands: telegram-panel slash commands with Discord-style parameters
Lists the panel account's client commands as Telegram slash commands (hourly
refresh, cached on the device), shows their parameters while typing, runs
complete commands on the panel instead of sending them and shows the answer
as an "Only visible to you" message (latest 20 kept in memory). Holding send
offers Run / Send as message / Send response in chat (red ! badge); an
answer's menu starts with Send in chat. Other plugins register their own
commands through the client_commands library module.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 16:19:20 +02:00

3.8 KiB

Development

Writing your own plugin

  1. Run python3 tools/bundle.py --check once. It enables the git hooks that auto-bump the version on commit (see Git hooks and versioning).
  2. Edit plugin.json (id, name, description, etc.).
  3. Write your plugin under src/, with src/main.py as the entry module (absolute imports only — it's executed at plugin-module top level, not inside a package).
  4. python3 tools/bundle.py --release && python3 tools/verify_bundle.py dist/<id>.plugin (substitute your id from plugin.json).
  5. bash scripts/deploy.sh --enable with a device connected.

Repo layout

plugin.json         single source of truth for plugin metadata
src/                the plugin, written as an ordinary Python package
  main.py           entry module: the plugin class, settings, the send hook
  api.py            telegram-panel client API (/api/v1/client/commands)
  catalog.py        each account's commands: the panel's (hourly, cached on disk) + plugins'
  library.py        the `client_commands` module other plugins register commands with
  runner.py         runs a command on the panel or on the device, shows or sends the response
  commands/         pure Python, tested offline: model, parser (in step with the panel's), HTML
  hooks/            the app's UI: suggestion list, message field, local responses
tools/
  bundle.py         compiles plugin.json + src/ into dist/<id>.plugin
  devclient.py      speaks the on-device dev-server protocol (127.0.0.1:42690)
  verify_bundle.py  offline harness that proves a built bundle behaves correctly, no phone needed
  release.py        publishes a built bundle to a Gitea release (used by CI)
  icon_png.py       renders images/icon.svg to a square PNG
images/icon.svg     the plugin icon, source of truth for any PNG export
.gitea/workflows/   CI that builds, verifies and publishes the .plugin to Releases
scripts/            ADB debug-loop automation and the git hooks
docs/               these notes + sdk-notes.md, the condensed SDK API surface

The three commands that matter

python3 tools/bundle.py --release          # compile src/ -> dist/<id>.plugin
python3 tools/verify_bundle.py dist/<id>.plugin   # offline proof the bundle works, no device needed
bash scripts/deploy.sh --enable            # build (--dev) + push to a connected device + enable + reload

bundle.py walks src/ recursively, embeds every .py file's source and dotted module name into a compressed, base64-encoded payload, and appends a small runtime preamble that installs a private import hook (scoped to a per-module __builtins__ dict, never touching sys.modules) so cross-module and cross-package imports resolve exactly as they would if the files were still on disk. --dev (the default) embeds absolute local paths so a debugger resolves breakpoints against your real source files; --release embeds repo-relative paths for distribution. Both modes produce byte-reproducible output for a given src/ + plugin.json. Its first run in a clone also enables the repo's git hooks (see Git hooks and versioning).

Exporting the icon as PNG

tools/icon_png.py renders images/icon.svg to images/icon.png, 512x512 by default. --resolution sets the size of both sides, so --resolution 1024 gives 1024x1024:

python3 tools/icon_png.py                    # images/icon.png, 512x512
python3 tools/icon_png.py --resolution 1024  # images/icon.png, 1024x1024
python3 tools/icon_png.py some.svg -o out.png

The output is always PNG; any other -o extension is rejected. The script itself is stdlib only and hands the rendering to the first renderer it finds: the cairosvg Python package, rsvg-convert (librsvg), ImageMagick or Inkscape. Install any one of them.