# kpm registry — schema_version 1
#
# Package definitions pulled by `kpm registry refresh` / `kpm search` /
# `kpm install` / `kpm sync`. Definitions only — never binaries; the actual
# KoboRoot.tgz comes from each package's own release page over TLS.
# Format reference: https://github.com/wolffshots/kpm/blob/main/REGISTRY.md
schema_version = 1

# kpm itself — carries the canonical source so `kpm install kpm --adopt`
# wires up self-update on-device (closes the bootstrap placeholder in the
# shipped kpm.toml).
[packages.kpm]
name        = "kpm"
description = "Kobo package manager — install and update mods from the device"
source      = "github.com/wolffshots/kpm"
forge       = "github"
asset       = "KoboRoot.tgz"
tested_fw   = "4.45.23697"
nh_name     = "NickelKPM"

# NickelClock ships its KoboRoot.tgz wrapped in a release zip (kpm >= 0.4.0
# unwraps those) and self-uninstalls when its shipped trigger file is deleted
# ("delete the uninstall file from the .adds/nickelclock directory, then
# restart your Kobo" — README).
[packages.nickelclock]
name        = "NickelClock"
description = "Show the current time in the reading header/footer"
source      = "github.com/shermp/NickelClock"
forge       = "github"
asset       = "NickelClock-*.zip"
min_kpm     = "0.4.0"
tested_fw   = "4.45.23697"
nh_name     = "NickelClock"

  [packages.nickelclock.uninstall]
  method      = "marker-remove"
  marker_file = "/mnt/onboard/.adds/nickelclock/uninstall"
  purge_paths = ["/mnt/onboard/.adds/nickelclock/**"]

  # Clock/battery display options; NickelClock re-reads them at boot.
  [[packages.nickelclock.configs]]
  name        = "Settings"
  path        = "/mnt/onboard/.adds/nickelclock/settings.ini"
  format      = "ini"
  reload      = "reboot"
  description = "Clock and battery display options."

# NickelDBus self-uninstalls when its shipped version-marker file is deleted
# ("delete the file called nickeldbus in the .adds directory, and reboot").
[packages.nickeldbus]
name        = "NickelDBus"
description = "D-Bus interface for scripting and automating the Nickel UI"
source      = "github.com/shermp/NickelDBus"
forge       = "github"
asset       = "KoboRoot.tgz"
min_kpm     = "0.4.0"
tested_fw   = "4.45.23697"
nh_name     = "NickelDBus"

  [packages.nickeldbus.uninstall]
  method      = "marker-remove"
  marker_file = "/mnt/onboard/.adds/nickeldbus"

# NickelNote ships its KoboRoot.tgz wrapped in a release zip (kpm >= 0.4.0
# unwraps those). Its documented uninstall is a /mnt/onboard/nn_uninstall
# trigger file, which sits outside kpm's deletable allowlist (.adds/.kobo only),
# so removal goes through the manifest instead — the tarball's sole payload is
# the imageformats plugin, and purge_paths clears the user's templates dir the
# mod's own uninstaller would have removed.
[packages.nickelnote]
name        = "NickelNote"
description = "Show a custom note on the sleep/lock screen"
source      = "github.com/onatbas/nickelnote"
forge       = "github"
asset       = "NickelNote-*.zip"
min_kpm     = "0.4.0"
# tested_fw is an estimate: v0.0.4 (2024-05) predates FW 4.45 and is confirmed
# NON-functional on 4.45.23697 (Libra Colour). 4.38.23429 is a real firmware
# from the mod's era used as an upper bound so the "untested on your firmware"
# warning fires. Not a first-party pass.
tested_fw   = "4.38.23429"
nh_name     = "NickelNote"

  [packages.nickelnote.uninstall]
  method      = "manifest"
  purge_paths = ["/mnt/onboard/.adds/nickelnote/**"]

  # User-created templates: kpm may create them on first save (create = true).
  # The sleep-screen note needs both content and style present to render.
  [[packages.nickelnote.configs]]
  name        = "Note content"
  path        = "/mnt/onboard/.adds/nickelnote/content.template"
  format      = "text"
  reload      = "auto"
  create      = true
  description = "Rich text shown on the sleep screen. Needs Style too."
  template = '''
<span>Your Name</span><br />
<span style="font-size: 32px">If found, Please return at</span><br />
<span style="font-size: 32px;">+1 555 000 0000</span>
'''

  [[packages.nickelnote.configs]]
  name        = "Style"
  path        = "/mnt/onboard/.adds/nickelnote/style.template"
  format      = "text"
  reload      = "auto"
  create      = true
  description = "Stylesheet for the sleep-screen note."
  template = '''
#infoWidget {
  color: black;
  background-color: rgba(255,255,255,170);
  min-height: 290px;
  max-height: 290px;

  margin-top: 200px;
  margin-left: -30px;
}

#infoWidget[powerOffView=true]{
  background-color: rgba(0,0,0,170);
}

QLabel{
	min-width: 400px;
	min-height: 300px;
}
'''

  [[packages.nickelnote.configs]]
  name        = "PIN screen message"
  path        = "/mnt/onboard/.adds/nickelnote/pin.template"
  format      = "text"
  reload      = "auto"
  create      = true
  description = "Message shown on the lock-PIN screen."
  template = '''
<p style="font-size: 32px;">
This tablet is protected and belongs to <br/>
<b>Your Name</b>
<br/>
<br/>
If found, please return to <br/>
US: +1 555 000 0000<br/>
CA: +1 555 000 0000<br/>
</p>
'''

# Uninstall is NickelMenu's own: create .adds/nm/uninstall (nh_info.uninstall_flag
# = NM_CONFIG_DIR "/uninstall" in src/nickelmenu.cc, and the shipped .adds/nm/doc
# says the same) and reboot. NickelHook then unlinks that file and deletes
# libnm.so; NickelMenu registers no nh uninstall callback, so nothing else goes.
[packages.nickelmenu]
name        = "NickelMenu"
description = "Add custom entries to the Kobo home and reading menus"
source      = "github.com/pgaskin/NickelMenu"
forge       = "github"
asset       = "KoboRoot.tgz"
tested_fw   = "4.45.23697"
nh_name     = "NickelMenu"

  [packages.nickelmenu.uninstall]
  method      = "marker"
  marker_file = "/mnt/onboard/.adds/nm/uninstall"
  # No purge_paths, for two independent reasons — both traps for any future
  # `marker` entry:
  #  1. Execute writes the marker BEFORE running deletions, so purge_paths
  #     covering the marker's own directory would delete the very trigger file
  #     the next reboot is supposed to act on, and the uninstall would silently
  #     never happen. A `marker` entry must never purge its marker's tree.
  #  2. .adds/nm is SHARED, not NickelMenu's private tree: kpm itself
  #     (.adds/nm/kpm), Kscribbler (.adds/nm/kscribbler) and Kobo Wi-Fi Remote
  #     (.adds/nm/wifiremote) all install menu fragments there, so a recursive
  #     purge would delete other packages' files.
  # NickelMenu's shipped .adds/nm/doc and the user's own menu config files are
  # therefore left in place, exactly as an upstream uninstall leaves them.

# Uninstall per README: create .adds/screensaver/uninstall.txt, reboot; the
# generated .kobo/screensaver png is an artifact kpm removes alongside.
[packages.nickel-screensaver]
name        = "Nickel Screensaver"
description = "Use your own images as the Kobo sleep/screensaver screen"
source      = "github.com/redphx/nickel-screensaver"
forge       = "github"
asset       = "KoboRoot.tgz"
# nh_name has an embedded space (the mod's nh_info.name is "Nickel Screensaver",
# not a CamelCase token) — set explicitly so doctor's dump-log glob matches; the
# display-name fallback would wrongly strip the space to "NickelScreensaver".
nh_name     = "Nickel Screensaver"

  [packages.nickel-screensaver.uninstall]
  method      = "marker"
  marker_file = "/mnt/onboard/.adds/screensaver/uninstall.txt"
  extra_paths = ["/mnt/onboard/.kobo/screensaver/nickel-screensaver.png"]

# NickelTypeFix self-uninstalls when its shipped trigger file is deleted
# ("Delete KOBOeReader/.adds/nickel-type-fix/uninstall and reboot").
[packages.nickeltypefix]
name        = "NickelTypeFix"
description = "Correct inconsistent font weights in the Nickel UI"
source      = "github.com/nicoverbruggen/NickelTypeFix"
forge       = "github"
asset       = "KoboRoot.tgz"
min_kpm     = "0.4.0"
nh_name     = "NickelTypeFix"

  [packages.nickeltypefix.uninstall]
  method      = "marker-remove"
  marker_file = "/mnt/onboard/.adds/nickel-type-fix/uninstall"
  purge_paths = ["/mnt/onboard/.adds/nickel-type-fix/**"]

# NickelHardcover's documented uninstall is a trigger file at the partition root
# ("create a file called nickelhardcover_uninstall on the root of your device and
# manually restart your Kobo" — README), i.e. /mnt/onboard/nickelhardcover_uninstall.
# That path sits outside kpm's deletable allowlist (.adds/.kobo only) — the same
# situation as nickelnote's nn_uninstall — so this must NOT be converted to
# method = "marker": Compute requires marker_file to classify as allowed and
# would refuse the plan outright. Removal goes through the manifest instead; the
# tarball ships .adds/NickelHardcover/{cli,config_example.ini} plus the
# imageformats plugin, and purge_paths clears the user's config dir.
[packages.nickelhardcover]
name        = "NickelHardcover"
description = "Sync your Kobo reading progress to a Hardcover account"
source      = "codeberg.org/StrayRose/NickelHardcover"
forge       = "forgejo"
asset       = "KoboRoot.tgz"
tested_fw   = "4.45.23697"
nh_name     = "NickelHardcover"

  [packages.nickelhardcover.uninstall]
  method      = "manifest"
  purge_paths = ["/mnt/onboard/.adds/NickelHardcover/**"]

# Requires NickelMenu — its menu entries are the only way to invoke it. No
# uninstall mechanism of its own, so removal is by manifest: the tarball ships
# .adds/kscribbler/{config.env.example,toggle-debug.sh,upgrade.sh},
# .adds/nm/kscribbler and the /opt/bin/kscribbler binary. purge_paths clears the
# runtime files the manifest can't know about (config.env with the Hardcover API
# token, kscribblerdb, kscribbler.log); extra_paths catches the extra NickelMenu
# fragment that toggle-debug.sh writes when debug options are switched on.
[packages.kscribbler]
name        = "Kscribbler"
description = "Sync your Kobo highlights and notes to a Hardcover account"
source      = "github.com/GianniBYoung/kscribbler"
forge       = "github"
asset       = "KoboRoot.tgz"
tested_fw   = "4.45.23697"

  [packages.kscribbler.uninstall]
  method      = "manifest"
  extra_paths = ["/mnt/onboard/.adds/nm/kscribbler-debug"]
  purge_paths = ["/mnt/onboard/.adds/kscribbler/**"]

# Ships its KoboRoot.tgz wrapped in a release zip alongside LICENSE, README.html
# and an Uninstaller.zip — only the single inner *.tgz is unwrapped, the other
# entries are ignored (kpm >= 0.4.0). The daemon is started by its udev rule, so
# NickelMenu is a convenience entry here, not a requirement. Upstream's own
# uninstaller only drops the udev rule and leaves the daemon to self-clean on the
# next boot, which kpm can't trigger — manifest removal takes out everything the
# tarball placed (/etc/udev/rules.d/98-wifiremote.rules, .adds/wifiremote,
# .adds/nm/wifiremote, /opt/wifiremote) directly instead.
[packages.kobowifiremote]
name        = "Kobo Wi-Fi Remote"
description = "Web-based remote control and page-turner served over Wi-Fi"
source      = "github.com/sublipri/kobo-wifi-remote"
forge       = "github"
asset       = "KoboWiFiRemote-*.zip"
min_kpm     = "0.4.0"

  [packages.kobowifiremote.uninstall]
  method      = "manifest"
  purge_paths = ["/mnt/onboard/.adds/wifiremote/**"]

# NickelDissolve self-uninstalls when its shipped trigger file is deleted
# ("delete the file KOBOeReader/.adds/nickel-dissolve/uninstall and reboot" —
# README); the trigger is present in the tarball, confirmed.
[packages.nickel-dissolve]
name        = "NickelDissolve"
description = "Add Kindle-style page-turn animations to supported Kobo devices"
source      = "github.com/nicoverbruggen/NickelDissolve"
forge       = "github"
asset       = "KoboRoot.tgz"
tested_fw   = "4.45.23697"
nh_name     = "NickelDissolve"

  [packages.nickel-dissolve.uninstall]
  method      = "marker-remove"
  marker_file = "/mnt/onboard/.adds/nickel-dissolve/uninstall"
  purge_paths = ["/mnt/onboard/.adds/nickel-dissolve/**"]

# NickelHome uninstalls when a trigger file is CREATED (nh_info.uninstall_flag =
# NHM_CONFIG_DIR "/uninstall" in src/nickelhome.cc); the tarball ships only doc +
# default, no trigger, so this is "marker", not "marker-remove".
# Deliberately no purge_paths: the marker is written into this same directory and
# Execute creates it before running deletions, so purging the tree would remove
# the trigger before the reboot that acts on it. NickelHome registers no
# NickelHook uninstall callback, so the reboot removes only the marker and
# libnickelhome.so — .adds/nickel-home/{doc,default,config} stay behind.
[packages.nickel-home]
name        = "NickelHome"
description = "Hide configurable widgets and rows on the Kobo home screen"
source      = "github.com/nicoverbruggen/NickelHome"
forge       = "github"
asset       = "KoboRoot.tgz"
nh_name     = "NickelHome"

  [packages.nickel-home.uninstall]
  method      = "marker"
  marker_file = "/mnt/onboard/.adds/nickel-home/uninstall"

# kobo-tweaks auto-uninstalls NickelClock as part of its own install, which
# would delete a kpm-tracked package's files behind kpm's back. min_kpm is
# mandatory: an older kpm ignores `conflicts` and would let that happen.
# Verified in v1.1.1's shipped libtweaks.so and in src/tweaks.cc:41-49:
# tweaksInit() unconditionally deletes /usr/local/Kobo/imageformats/
# libnickelclock.so and its .failsafe sibling whenever they exist — on every
# Nickel start, not only the first — and that .so is the whole of NickelClock's
# binary payload and a recorded manifest entry, so kpm would be left with a
# nickelclock state record whose files are gone.
[packages.kobo-tweaks]
name        = "Kobo Tweaks"
description = "Header/footer tweaks, reading widgets, custom bookmarks and dark mode"
source      = "github.com/redphx/kobo-tweaks"
forge       = "github"
asset       = "KoboRoot.tgz"
conflicts   = ["nickelclock"]
min_kpm     = "0.10.0"
# nh_name has an embedded space (nh_info.name is "Kobo Tweaks"), the same case
# as nickel-screensaver — set explicitly so doctor's dump-log glob matches; the
# display-name fallback strips the space to "KoboTweaks".
nh_name     = "Kobo Tweaks"

  # Uninstall is upstream's own: delete .adds/tweaks/DELETE_TO_UNINSTALL.txt and
  # restart (README §Uninstallation). The file is shipped in the tarball
  # (confirmed in v1.1.1) and is nh_info.uninstall_xflag, so its ABSENCE is the
  # trigger — marker-remove, not marker. Do NOT switch this to method = "marker"
  # on the mod's other trigger (.adds/tweaks/uninstall, nh_info.uninstall_flag):
  # Execute writes the marker before running deletions, so a marker in this same
  # directory plus the purge below would delete the trigger the next reboot is
  # supposed to act on. NickelHook removes libtweaks.so itself at that reboot.
  # .adds/tweaks is private to this mod (DATA_DIR in src/common.h — settings.ini,
  # images/ and the two trigger files; no other tracked package writes there), so
  # the recursive purge cannot reach another package's files.
  [packages.kobo-tweaks.uninstall]
  method      = "marker-remove"
  marker_file = "/mnt/onboard/.adds/tweaks/DELETE_TO_UNINSTALL.txt"
  purge_paths = ["/mnt/onboard/.adds/tweaks/**"]

# KOReader is the first app-tree package: it ships no KoboRoot.tgz, just a plain
# directory tree in a release zip that kpm extracts itself into dest. min_kpm is
# mandatory — an older kpm has no [install] handling and would try to stage the
# zip as a tarball. Verified against v2026.07 / koreader-kobo-v2026.07.zip:
# 1045 entries, 83.9 MiB uncompressed, max depth 7, no symlinks, and exactly two
# zip roots — "koreader/" (1044 entries, the tree) and "koreader.png" (the KFMon
# launcher icon). root = "koreader" installs only the tree; the icon belongs at
# the root of the user partition, outside kpm's writable allowlist (.adds/.kobo
# only), so KFMon users must copy it over USB themselves. NickelMenu users do not
# need it at all — the drop-in below launches KOReader directly. dest is also the
# exact path KFMon's shipped koreader.ini already runs, so an existing KFMon
# install keeps working.
#
# The hyphen after "kobo" in the asset glob is load-bearing: "koreader-kobo*.zip"
# (no hyphen) also matches koreader-kobov5-v2026.07.zip, the firmware-5.x build,
# and kpm refuses an ambiguous glob rather than guess between 23 per-platform
# assets. A firmware-5.x device needs a separate id with its own glob.
#
# No tested_fw: nobody has installed this through kpm on a device yet, and per
# the 2026-07-23 correction that field means "positively confirmed working" and
# must never be asserted from convenience. The cost is that a firmware-5.x device
# gets no "untested on your firmware" note and installs the 4.x build silently;
# adding tested_fw = "4.45.23697" after a real 4.x device test restores it.
#
# On firmware >= 4.17 Nickel indexes hidden folders, so KOReader's files can show
# up in the library. The fix is an ExcludeSyncFolders line in .kobo/Kobo/Kobo
# eReader.conf, which kpm deliberately does NOT write and does not declare as an
# editable config: Nickel owns that file and reverts edits made while it runs.
# "kpm doctor" prints the exact line to add.
#
# Settings, statistics, annotations and downloaded plugins all live INSIDE
# .adds/koreader and are not in the install manifest, so a plain uninstall
# removes exactly the files kpm wrote and purge_paths clears user data only on an
# explicit --purge.
[packages.koreader]
name        = "KOReader"
description = "Full-featured alternative document reader (EPUB, PDF, DjVu, CBZ) — new to kpm, not yet tested on a device, feedback welcome"
source      = "github.com/koreader/koreader"
forge       = "github"
asset       = "koreader-kobo-*.zip"
min_kpm     = "0.11.0"

  [packages.koreader.install]
  method = "app-tree"
  root   = "koreader"
  dest   = "/mnt/onboard/.adds/koreader"

    [packages.koreader.install.launcher]
    nm_file  = "/mnt/onboard/.adds/nm/koreader"
    nm_entry = "menu_item:main:KOReader:cmd_spawn:quiet:exec /mnt/onboard/.adds/koreader/koreader.sh"

  [packages.koreader.uninstall]
  method      = "manifest"
  purge_paths = ["/mnt/onboard/.adds/koreader/**"]

# Plato is the second app-tree package. Its release zip is FLAT (no root folder),
# so [install] omits root ("" is the default and writing root = "" would be
# noise) and the whole zip lands in dest. Verified against 0.9.45 /
# plato-0.9.45.zip: 209 entries, 44.5 MiB uncompressed, max depth 3, no symlinks,
# 13 explicit directory entries and 17 top-level names (bin, css, dictionaries,
# fonts, hyphenation-patterns, icons, keyboard-layouts, libs, resources, scripts,
# plus the plato binary, plato.sh, nickel.sh, config-sample.sh,
# convert-dictionary.sh, Settings-sample.toml and LICENSE-AGPLv3). One of those
# directory entries — dictionaries/ — is empty and Plato expects it to exist; kpm
# honours explicit zip directory entries, so it is created.
#
# dest is the exact path KFMon's shipped plato.ini already runs, so an existing
# KFMon install keeps working. Plato's icons/ are its own UI SVGs, not a launcher
# icon: KFMon watches /mnt/onboard/icons/plato.png, which is not in this zip and
# is outside kpm's writable allowlist anyway.
#
# No tested_fw, for the same reason as koreader — no curator has run this through
# kpm on a device.
#
# Runtime files live in the tree and are not in the manifest: Settings.toml (from
# the shipped Settings-sample.toml), config.sh (from config-sample.sh), the
# css/{epub,html,dictionary}-user.css overrides and whatever the user drops into
# dictionaries/. A plain uninstall leaves all of them and --purge clears them.
[packages.plato]
name        = "Plato"
description = "Lightweight alternative document reader and library manager — new to kpm, not yet tested on a device, feedback welcome"
source      = "github.com/baskerville/plato"
forge       = "github"
asset       = "plato-*.zip"
min_kpm     = "0.11.0"

  [packages.plato.install]
  method = "app-tree"
  dest   = "/mnt/onboard/.adds/plato"

    [packages.plato.install.launcher]
    nm_file  = "/mnt/onboard/.adds/nm/plato"
    nm_entry = "menu_item:main:Plato:cmd_spawn:quiet:exec /mnt/onboard/.adds/plato/plato.sh"

  [packages.plato.uninstall]
  method      = "manifest"
  purge_paths = ["/mnt/onboard/.adds/plato/**"]
