8 changed files with 52 additions and 6 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ hl.config({
kb_layout = prefs.get("keyboardLayout", "us"),
kb_variant = prefs.get("keyboardVariant", ""),
kb_model = "",
kb_options = prefs.get("keyboardOptions", ""),
kb_options = prefs.get("keyboardOptions", "caps:escape_shifted_capslock"),
kb_rules = "",
numlock_by_default = prefs.get("numlockByDefault", true),
@@ -436,7 +436,7 @@ Singleton {
hypr: { path: ["input", "kb_variant"], option: "input:kb_variant", readAs: "str" }
},
{
key: "keyboardOptions", type: "string", def: "", group: "input",
key: "keyboardOptions", type: "string", def: "caps:escape_shifted_capslock", group: "input",
// XKB option names are colon-separated pairs in a comma-separated
// list, e.g. "compose:ralt,caps:escape".
pattern: "^$|^[a-z0-9_]+:[a-z0-9_]+(,[a-z0-9_]+:[a-z0-9_]+)*$",
+16 -2
View File
@@ -130,7 +130,7 @@ RUNTIME_LINK_TARGETS = (
("vicinae", Path("config/dot/vicinae")),
)
REPAIR_IDS = frozenset((*REPAIR_COMMANDS.keys(), "panama.runtime-links", "panama.vicinae-commands", "panama.caffeine"))
PROCESS_NAMES = ("quickshell", "vicinae", "hyprpaper", "hypridle")
PROCESS_NAMES = ("vicinae", "hyprpaper", "hypridle")
VERSION_PATTERN = re.compile(r"\b\d+(?:\.\d+){0,3}(?:[-+._][A-Za-z0-9._-]+)?\b")
REVISION_PATTERN = re.compile(r"\b[0-9a-f]{7,40}\b", re.IGNORECASE)
PROBE_ENVIRONMENT_KEYS = (
@@ -436,7 +436,21 @@ def executable_check(check_id: str, title: str, executable: str, config: DoctorC
def check_processes(config: DoctorConfig) -> Check:
counts: list[int] = []
# `qs` is both the long-running shell and every short-lived IPC client.
# Counting it with pgrep races the other parallel health probes and reports
# duplicates whenever one of them happens to call `qs ipc`. The instance
# list is the authoritative view and contains only actual shells.
quickshell = run_command(("qs", "list"), config)
if quickshell.state == "ok":
quickshell_count = sum(
line.startswith("Instance ") for line in quickshell.stdout.splitlines()
)
elif quickshell.state == "failed":
quickshell_count = 0
else:
return Check("panama.processes", "panama-tools", "Panama processes", "warning", "Process probe is unavailable.")
counts: list[int] = [quickshell_count]
for name in PROCESS_NAMES:
result = run_command(("pgrep", "-u", str(os.getuid()), "-x", name), config)
if result.state == "ok":
+17
View File
@@ -165,6 +165,23 @@ ShellRoot {
function repair(id: string): bool { return Health.repair(id, true); }
}
// Health checks the wallpaper service through the same typed IPC boundary
// as capture and clipboard. This is deliberately read-only: choosing an
// image remains an explicit Settings action.
IpcHandler {
target: "wallpaper"
function refresh(): void { Wallpaper.refreshActive(); }
function status(): string {
return JSON.stringify({
active: Wallpaper.active,
configured: Wallpaper.configured,
availableCount: Wallpaper.available.length,
lastError: Wallpaper.lastError
});
}
}
// A small diagnostics surface doubles as a deterministic contract harness.
// Real producers call StatusEvents.publish() directly; fixtures never run
// unless explicitly requested over IPC by the test suite.
+7
View File
@@ -4,6 +4,13 @@ set -euo pipefail
case "${1:-}" in
--version) printf '%s\n' "${PANAMA_DOCTOR_FIXTURE_QS_VERSION:-Quickshell 0.2.0}" ;;
list)
case ",${PANAMA_DOCTOR_FIXTURE_PROCESSES:-}," in
*,qs:duplicate,*) printf '%s\n' 'Instance fixture-one:' 'Instance fixture-two:' ;;
*,qs:missing,*) ;;
*) printf '%s\n' 'Instance fixture-one:' ;;
esac
;;
ipc)
if [[ "${PANAMA_DOCTOR_FIXTURE_QS:-ready}" == "malformed" ]]; then
printf 'fixture-secret-token AA:BB:CC:DD:EE:FF\n'
@@ -47,6 +47,8 @@ fail() {
[[ -f "$service" ]] || fail 'Health.qml is missing'
[[ -f "$source_harness" ]] || fail 'health harness is missing'
[[ -f "$shell" ]] || fail 'shell.qml is missing'
rg -q 'target: "wallpaper"' "$shell" \
|| fail 'wallpaper health target is not exported by the shell'
# shell.qml is not started here: it is the active desktop shell. Keep this
# contract static while pinning the typed, redacted IPC boundary it exports.
+4 -1
View File
@@ -216,11 +216,14 @@ jq -e '.checks[] | select(.id == "panama.caffeine")
|| fail 'Caffeine detail exposed inhibitor PIDs'
# Process counts use only exact authored names and never expose command lines or PIDs.
duplicated_processes="$(PANAMA_DOCTOR_FIXTURE_PROCESSES=quickshell:duplicate run_doctor --json)"
duplicated_processes="$(PANAMA_DOCTOR_FIXTURE_PROCESSES=qs:duplicate run_doctor --json)"
check_status "$duplicated_processes" panama.processes warning
! jq -r '.checks[] | select(.id == "panama.processes") | .detail' <<<"$duplicated_processes" | grep -Eq '[0-9]{3,}' \
|| fail 'process detail exposed a PID'
missing_quickshell_process="$(PANAMA_DOCTOR_FIXTURE_PROCESSES=qs:missing run_doctor --json)"
check_status "$missing_quickshell_process" panama.processes error
# Invalid output for a non-Quickshell authored process is not a normal zero
# count that can be hidden by the running Quickshell process.
malformed_processes="$(PANAMA_DOCTOR_FIXTURE_PROCESSES=hyprpaper:malformed run_doctor --json)"
+4 -1
View File
@@ -9,6 +9,7 @@ set -euo pipefail
repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
page="$repo_dir/config/dot/quickshell/modules/settings/ShortcutsPage.qml"
input="$repo_dir/config/dot/hypr/input.lua"
schema="$repo_dir/config/dot/quickshell/config/PreferenceSchema.qml"
fail() {
printf 'xkb presets contract: %s\n' "$1" >&2
@@ -37,7 +38,9 @@ rg -Fq 'option.indexOf(prefix) !== 0' "$page" \
rg -Fq 'kb_variant = prefs.get("keyboardVariant", "")' "$input" \
|| fail 'Hyprland does not replay the stored keyboard variant'
rg -Fq 'kb_options = prefs.get("keyboardOptions", "")' "$input" \
rg -Fq 'key: "keyboardOptions", type: "string", def: "caps:escape_shifted_capslock"' "$schema" \
|| fail 'the shipped XKB default no longer matches the migrated GNOME behavior'
rg -Fq 'kb_options = prefs.get("keyboardOptions", "caps:escape_shifted_capslock")' "$input" \
|| fail 'Hyprland does not replay the stored keyboard options'
printf 'xkb presets contract: PASS\n'