Skip to content
Merged
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
20 changes: 20 additions & 0 deletions doc/changelog/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,26 @@ not deferred to release. `release-tag.sh` promotes `[Unreleased]` →

### Added

- **Five desktop-only modules for the small-tools modularization program:
`vlc`, `ibus-rime`, `cheese`, `v4l-utils`,
`gnome-shell-extension-manager`** (`module/<name>.module.sh` +
`test/unit/module/<name>_spec.bats` each). All five are apt-archetype
(`module_use_apt_archetype`) `optional` modules scoped to
`SUPPORTED_PLATFORMS=("desktop")`, each installing its named apt package
(`vlc`, `ibus-rime`, `cheese`, `v4l-utils`,
`gnome-shell-extension-manager`), with module-defined `detect()` and a
desktop-gated `is_recommended()` (recommended only on the `desktop` form
factor). Each ships a real `doctor()` that goes beyond the dpkg check by
verifying the runtime binary actually resolves on PATH — `command -v vlc`,
`command -v cheese`, `command -v v4l2-ctl` (binary name differs from the
package), `command -v extension-manager` (likewise); `ibus-rime` is a
data/engine package with no like-named binary, so its doctor probes the
`ibus` framework binary plus the Rime engine data directory. Each declares
an en + zh-TW `DESCRIPTION`, `SUPPORTED_UBUNTU=("22.04" "24.04" "26.04")`,
and a `TEST_VERIFY_CMD` matching its doctor probe. Both standalone- and
engine-invocable; all satisfy the 10-function module contract (ADR-0002,
enforced by `test/unit/module/contract_conformance_spec.bats` / #305).
`doc/module/INDEX.md` regenerated (69 modules).
- **Six more apt-archetype CLI/utility modules for the small-tools
modularization program: `ag`, `asciidoctor`, `xclip`, `xsel`, `ansifilter`,
`tealdeer`** (`module/<name>.module.sh` +
Expand Down
7 changes: 6 additions & 1 deletion doc/module/INDEX.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

# Module Index

70 modules. Columns come from each module's metadata block
75 modules. Columns come from each module's metadata block
(`NAME` / `CATEGORY` / `TAGS` / `DESCRIPTION[en]`, doc/module-spec.md §3).
Per-module pages will land in a later milestone; until then each name links
to the module source.
Expand All @@ -18,6 +18,7 @@ to the module source.
| [bmon](../../module/bmon.module.sh) | optional | monitoring | bmon — bandwidth monitor (real-time per-interface traffic, apt bmon package) |
| [btop](../../module/btop.module.sh) | optional | monitoring | btop — modern resource monitor (CPU / memory / disk / net, apt btop package) |
| [build-essential](../../module/build-essential.module.sh) | base | build | build-essential — C/C++ compiler toolchain metapackage (gcc, g++, make) |
| [cheese](../../module/cheese.module.sh) | optional | media | Cheese — GNOME webcam app for photos and videos (apt cheese package) |
| [claude-code-config](../../module/claude-code-config.module.sh) | optional | agent config dotfile | Personal Claude Code settings (~/.claude: settings.json + statusline) |
| [claude-code](../../module/claude-code.module.sh) | optional | agent | Anthropic Claude Code CLI agent (official native installer, self-updating) |
| [claude-monitor](../../module/claude-monitor.module.sh) | optional | agent cli | claude-monitor — real-time Claude Code token/cost usage monitor TUI (pipx) |
Expand All @@ -37,8 +38,10 @@ to the module source.
| [git-lfs](../../module/git-lfs.module.sh) | optional | git vcs | git-lfs — Git Large File Storage (versions large files via pointers) |
| [git](../../module/git.module.sh) | base | vcs | git — distributed version control system (apt git package) |
| [glow](../../module/glow.module.sh) | optional | cli-essentials | glow — render markdown on the CLI (yazi markdown-preview dependency) |
| [gnome-shell-extension-manager](../../module/gnome-shell-extension-manager.module.sh) | optional | gnome desktop | Extension Manager — browse and manage GNOME Shell extensions (binary: extension-manager) |
| [gum](../../module/gum.module.sh) | optional | cli-essentials tui | gum — a tool for glamorous shell scripts (preferred modern TUI backend) |
| [htop](../../module/htop.module.sh) | base | monitor | htop — interactive process viewer (apt htop package) |
| [ibus-rime](../../module/ibus-rime.module.sh) | optional | input-method desktop | Rime input method engine for IBus — pulls in the ibus framework (apt ibus-rime package) |
| [ifstat](../../module/ifstat.module.sh) | optional | monitoring | ifstat — report network interface bandwidth statistics (apt ifstat package) |
| [iftop](../../module/iftop.module.sh) | optional | monitoring | iftop — display network bandwidth usage by host (apt iftop package) |
| [iotop](../../module/iotop.module.sh) | optional | monitoring | iotop — per-process disk I/O monitor (apt iotop package) |
Expand Down Expand Up @@ -73,7 +76,9 @@ to the module source.
| [trash-maintenance](../../module/trash-maintenance.module.sh) | optional | maintenance trash cron | Daily trash cleanup: age + size cap (single source of truth vs GNOME auto-delete) |
| [tree](../../module/tree.module.sh) | optional | cli filesystem | tree — recursive directory listing as an indented tree |
| [unzip](../../module/unzip.module.sh) | base | archive | unzip — extractor for .zip archives (apt unzip package) |
| [v4l-utils](../../module/v4l-utils.module.sh) | optional | media hardware | v4l-utils — Video4Linux tools to inspect and control cameras (binary: v4l2-ctl) |
| [vim](../../module/vim.module.sh) | base | editor | vim — Vi IMproved terminal text editor (apt vim package) |
| [vlc](../../module/vlc.module.sh) | optional | media | VLC — cross-platform media player for audio and video (apt vlc package) |
| [vscode](../../module/vscode.module.sh) | optional | editor | Visual Studio Code — Microsoft's GUI code editor (Microsoft apt repo) |
| [wget](../../module/wget.module.sh) | base | http | wget — non-interactive network downloader (apt wget package) |
| [xclip](../../module/xclip.module.sh) | optional | cli clipboard | xclip — command-line interface to the X11 clipboard/selection |
Expand Down
105 changes: 105 additions & 0 deletions module/cheese.module.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/usr/bin/env bash
# module/cheese.module.sh — Cheese — GNOME webcam photo / video app (apt cheese package) [archetype: apt]
#
# Part of the small-tools modularization program: each desktop tool is an
# independently installable / removable module. Ubuntu ships the `cheese`
# package; the binary is `cheese`. Desktop-only (SUPPORTED_PLATFORMS).
#
# Standalone usage:
# bash module/cheese.module.sh install [--dry-run]
# bash module/cheese.module.sh upgrade / remove / purge / verify / doctor
# bash module/cheese.module.sh detect / is-installed / is-recommended / is-outdated
# bash module/cheese.module.sh info / status (read-only metadata views)
#
# Engine usage (resolves DEPENDS_ON, batches with state.json):
# setup_ubuntu install cheese

# ── Dual-mode header ────────────────────────────────────────────────────────
MODULE_STANDALONE="true"
[[ "${BASH_SOURCE[0]:-}" != "${0:-}" ]] && MODULE_STANDALONE="false"
if [[ "${MODULE_STANDALONE}" == "true" ]]; then
# shellcheck source=../lib/module_bootstrap.sh
source "${LIB_DIR:-$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../lib" && pwd -P)}/module_bootstrap.sh"
module_bootstrap
fi
# Static-analysis hint (never executed: the guard is always false; wrapped in
# kcov-exclude so the dead line is not counted against coverage). module_bootstrap
# sources the lib helpers at runtime, but shellcheck cannot trace that 2-level
# dynamic source — this guarded line lets `shellcheck -x` follow module_helper.sh
# so it sees the metadata + archetype vars below are used externally (avoids SC2034).
# kcov-exclude-start
# shellcheck source=../lib/module_helper.sh
[[ -n "${__module_lint_hint:-}" ]] && source "${LIB_DIR}/module_helper.sh"
# kcov-exclude-end

# ── Metadata (doc/module-spec.md §3) ────────────────────────────────────────
NAME="cheese"
VERSION_PROVIDED="apt-managed"
CATEGORY="optional"
TAGS=("media")
HOMEPAGE="https://apps.gnome.org/Cheese/"
declare -gA DESCRIPTION=(
[en]="Cheese — GNOME webcam app for photos and videos (apt cheese package)"
[zh-TW]="Cheese — GNOME 網路攝影機應用程式,可拍照與錄影(apt cheese 套件)"
)
declare -gA POST_INSTALL_MESSAGE=()
declare -gA WARN_MESSAGE=()
SUPPORTED_UBUNTU=("22.04" "24.04" "26.04")
SUPPORTED_PLATFORMS=("desktop")
DEPENDS_ON=()
CONFLICTS_WITH=()
SUPPORTS_USER_HOME=false
RISK_LEVEL="low"
REBOOT_REQUIRED=false
INSTALL_TARGET_DEFAULT="sudo"
TEST_VERIFY_CMD="command -v cheese"

# Engine-consumed metadata: the registry/runner read these post-source, and
# the i18n arrays are dereferenced indirectly via module_i18n_get. Reference
# them once so the linter sees an in-file use (SC2034) without a disable.
: "${DESCRIPTION[*]:-}" "${POST_INSTALL_MESSAGE[*]:-}" "${WARN_MESSAGE[*]:-}" \
"${SUPPORTS_USER_HOME}" "${INSTALL_TARGET_DEFAULT}"

# ── Archetype A — apt ───────────────────────────────────────────────────────
APT_PKGS=("cheese")
APT_PPA=""
CONFIG_PATHS=("${HOME}/.config/cheese" "${HOME}/.local/share/cheese")
module_use_apt_archetype

# ── Required hooks (detect + is_recommended stay module-specific) ────────────
detect() {
command -v apt-get >/dev/null 2>&1
}

# Desktop-only recommendation gate (module-spec.md §4.3.1): a webcam GUI app is
# pointless on headless / SBC form factors.
is_recommended() {
case "${INIT_UBUNTU_FORM_FACTOR:-}" in
desktop)
! is_installed
;;
*)
return 1
;;
esac
}

# doctor: real runtime health — the tool must be installed AND the binary must
# actually resolve on PATH (`command -v cheese`), catching a half-configured
# dpkg state. Warns (read-only) on Sidecar drift (ADR-0001).
doctor() {
module_dryrun_guard doctor "is_installed + command -v cheese + Sidecar consistency" \
&& return 0
is_installed || { log_warn "[${NAME}] doctor: cheese is not installed"; return 1; }
command -v cheese >/dev/null 2>&1 \
|| { log_warn "[${NAME}] doctor: cheese is present in dpkg but not runnable on PATH"; return 1; }
if ! module_sidecar_get_version "${NAME}" >/dev/null 2>&1; then
log_warn "[${NAME}] doctor: Sidecar missing (ADR-0001 drift; re-run install/upgrade to heal)"
fi
return 0
}

# ── Standalone footer ───────────────────────────────────────────────────────
if [[ "${MODULE_STANDALONE:-false}" == "true" ]]; then
module_standalone_main "$@"
fi
108 changes: 108 additions & 0 deletions module/gnome-shell-extension-manager.module.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#!/usr/bin/env bash
# module/gnome-shell-extension-manager.module.sh — Extension Manager — GNOME Shell extension browser / manager (apt gnome-shell-extension-manager package) [archetype: apt]
#
# Part of the small-tools modularization program: each desktop tool is an
# independently installable / removable module. Ubuntu ships the
# `gnome-shell-extension-manager` package; the binary is `extension-manager`
# (package name != binary name). Desktop-only (SUPPORTED_PLATFORMS): a GNOME
# Shell tool has no meaning on headless / SBC form factors.
#
# Standalone usage:
# bash module/gnome-shell-extension-manager.module.sh install [--dry-run]
# bash module/gnome-shell-extension-manager.module.sh upgrade / remove / purge / verify / doctor
# bash module/gnome-shell-extension-manager.module.sh detect / is-installed / is-recommended / is-outdated
# bash module/gnome-shell-extension-manager.module.sh info / status (read-only metadata views)
#
# Engine usage (resolves DEPENDS_ON, batches with state.json):
# setup_ubuntu install gnome-shell-extension-manager

# ── Dual-mode header ────────────────────────────────────────────────────────
MODULE_STANDALONE="true"
[[ "${BASH_SOURCE[0]:-}" != "${0:-}" ]] && MODULE_STANDALONE="false"
if [[ "${MODULE_STANDALONE}" == "true" ]]; then
# shellcheck source=../lib/module_bootstrap.sh
source "${LIB_DIR:-$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../lib" && pwd -P)}/module_bootstrap.sh"
module_bootstrap
fi
# Static-analysis hint (never executed: the guard is always false; wrapped in
# kcov-exclude so the dead line is not counted against coverage). module_bootstrap
# sources the lib helpers at runtime, but shellcheck cannot trace that 2-level
# dynamic source — this guarded line lets `shellcheck -x` follow module_helper.sh
# so it sees the metadata + archetype vars below are used externally (avoids SC2034).
# kcov-exclude-start
# shellcheck source=../lib/module_helper.sh
[[ -n "${__module_lint_hint:-}" ]] && source "${LIB_DIR}/module_helper.sh"
# kcov-exclude-end

# ── Metadata (doc/module-spec.md §3) ────────────────────────────────────────
NAME="gnome-shell-extension-manager"
VERSION_PROVIDED="apt-managed"
CATEGORY="optional"
TAGS=("gnome" "desktop")
HOMEPAGE="https://github.com/mjakeman/extension-manager"
declare -gA DESCRIPTION=(
[en]="Extension Manager — browse and manage GNOME Shell extensions (binary: extension-manager)"
[zh-TW]="Extension Manager — 瀏覽與管理 GNOME Shell 擴充功能(執行檔:extension-manager)"
)
declare -gA POST_INSTALL_MESSAGE=()
declare -gA WARN_MESSAGE=()
SUPPORTED_UBUNTU=("22.04" "24.04" "26.04")
SUPPORTED_PLATFORMS=("desktop")
DEPENDS_ON=()
CONFLICTS_WITH=()
SUPPORTS_USER_HOME=false
RISK_LEVEL="low"
REBOOT_REQUIRED=false
INSTALL_TARGET_DEFAULT="sudo"
TEST_VERIFY_CMD="command -v extension-manager"

# Engine-consumed metadata: the registry/runner read these post-source, and
# the i18n arrays are dereferenced indirectly via module_i18n_get. Reference
# them once so the linter sees an in-file use (SC2034) without a disable.
: "${DESCRIPTION[*]:-}" "${POST_INSTALL_MESSAGE[*]:-}" "${WARN_MESSAGE[*]:-}" \
"${SUPPORTS_USER_HOME}" "${INSTALL_TARGET_DEFAULT}"

# ── Archetype A — apt ───────────────────────────────────────────────────────
APT_PKGS=("gnome-shell-extension-manager")
APT_PPA=""
CONFIG_PATHS=()
module_use_apt_archetype

# ── Required hooks (detect + is_recommended stay module-specific) ────────────
detect() {
command -v apt-get >/dev/null 2>&1
}

# Desktop-only recommendation gate (module-spec.md §4.3.1): a GNOME Shell tool
# is meaningless on headless / SBC form factors.
is_recommended() {
case "${INIT_UBUNTU_FORM_FACTOR:-}" in
desktop)
! is_installed
;;
*)
return 1
;;
esac
}

# doctor: real runtime health — the package must be installed AND its binary
# `extension-manager` must actually resolve on PATH (package name differs from
# the binary, so this catches a partial install). Warns (read-only) on Sidecar
# drift (ADR-0001).
doctor() {
module_dryrun_guard doctor "is_installed + command -v extension-manager + Sidecar consistency" \
&& return 0
is_installed || { log_warn "[${NAME}] doctor: gnome-shell-extension-manager is not installed"; return 1; }
command -v extension-manager >/dev/null 2>&1 \
|| { log_warn "[${NAME}] doctor: installed in dpkg but extension-manager is not on PATH"; return 1; }
if ! module_sidecar_get_version "${NAME}" >/dev/null 2>&1; then
log_warn "[${NAME}] doctor: Sidecar missing (ADR-0001 drift; re-run install/upgrade to heal)"
fi
return 0
}

# ── Standalone footer ───────────────────────────────────────────────────────
if [[ "${MODULE_STANDALONE:-false}" == "true" ]]; then
module_standalone_main "$@"
fi
Loading
Loading