diff --git a/lib/hook-utils.sh b/lib/hook-utils.sh index 0776e2f766..41a9b28420 100644 --- a/lib/hook-utils.sh +++ b/lib/hook-utils.sh @@ -1443,26 +1443,30 @@ hook::git_resolve_index() { ;; sudo) # sudo's own chdir is -D/--chdir (its -C is close-from, -R is --chroot). - # Only the unclustered spellings are read here; sudo's valueless short set - # is large and release-dependent, so peeling a cluster the way the env - # branch does would be guesswork rather than grammar. - # Known gap, fail-open: a clustered `sudo -bD dir git …` loses the chdir, - # and `-i` relocates to the target user's home without naming a directory - # at all. + # GNU sudo clusters short options, so `-bD dir` carries a chdir that no + # exact `-D` match sees. Peel the documented valueless shorts (-A/-B/-b/-e/-E + # -H/-K/-k/-l/-n/-P/-s/-S/-v/-V, per `sudo --help`) off a single-dash token + # so the value-taking tail (-D/--chdir, -u/-g/-h/-p/-C/-R/-T) reaches its own + # branch. `-h` is value-taking (`-h host` / `--host=`) and must not be peeled. + # `-i` relocates to the target user's home without naming a directory at all. ((i++)) - local sudo_ci=-1 + local sudo_ci=-1 stok while ((i < n)) && [[ "${w[i]}" == -* ]]; do - case "${w[i]}" in + stok="${w[i]}" + if [[ "$stok" == -[!-]* ]]; then + while [[ "$stok" =~ ^-[ABbeEHKklnPsSvV](.+)$ ]]; do stok="-${BASH_REMATCH[1]}"; done + fi + case "$stok" in -D | --chdir) ((i + 1 < n)) && hook::wrapper_chdir_record sudo_ci "${w[i + 1]}" ((i += 2)) ;; --chdir=*) - hook::wrapper_chdir_record sudo_ci "${w[i]#--chdir=}" + hook::wrapper_chdir_record sudo_ci "${stok#--chdir=}" ((i++)) ;; -D*) - hook::wrapper_chdir_record sudo_ci "${w[i]#-D}" + hook::wrapper_chdir_record sudo_ci "${stok#-D}" ((i++)) ;; -u | -g | -h | -p | -C | -R | -T | --user | --group) ((i += 2)) ;; diff --git a/lib/hook-utils.test.sh b/lib/hook-utils.test.sh index b7a43a660f..7bb8a5bc7f 100755 --- a/lib/hook-utils.test.sh +++ b/lib/hook-utils.test.sh @@ -2163,6 +2163,10 @@ fi resolve_dirs_are "sudo -D DIR reports the chdir" "other" sudo -D other git commit resolve_dirs_are "sudo --chdir=DIR reports the chdir" "other" sudo --chdir=other git commit resolve_dirs_are "sudo -C fd is not a chdir" "" sudo -C 3 git commit +resolve_dirs_are "sudo -bD DIR peels the valueless short and reports the chdir" "other" sudo -bDother git commit +resolve_dirs_are "sudo -nD DIR peels -n and reports the chdir" "other" sudo -nDother git commit +resolve_dirs_are "sudo -AD DIR peels -A and reports the chdir" "other" sudo -ADother git commit +resolve_dirs_are "sudo -hD DIR does not peel -h and does not treat git as chdir" "" sudo -hD git commit # Nested wrappers each contribute, in execution order, for the caller to compose. resolve_dirs_are "nested wrappers report both chdirs in order" "a|b" env -C a sudo -D b git commit # `-S` exists so a shebang line can pass OPTIONS to env (`#!/usr/bin/env -S -i diff --git a/plugins/actionlint/.claude-plugin/plugin.json b/plugins/actionlint/.claude-plugin/plugin.json index a86e1d4749..a5d31308db 100644 --- a/plugins/actionlint/.claude-plugin/plugin.json +++ b/plugins/actionlint/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "actionlint", - "version": "0.8.7", + "version": "0.8.9", "description": "Lint GitHub Actions workflow files on edit via actionlint, surfacing findings as advisory context.", "author": { "name": "Melodic Software", diff --git a/plugins/actionlint/CHANGELOG.md b/plugins/actionlint/CHANGELOG.md index d1cb9e9b43..13e77d2390 100644 --- a/plugins/actionlint/CHANGELOG.md +++ b/plugins/actionlint/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to the `actionlint` plugin are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. +## [0.8.9] + +### Changed + +- **Synced `hook-utils.sh`:** peel sudo clustered short options for chdir resolution (#1811); widen the valueless-short peel set and keep `-h` value-taking. + +## [0.8.8] + +### Changed + +- **Synced `hook-utils.sh`:** peel sudo clustered short options for chdir resolution (#1811). + ## [0.8.7] ### Changed diff --git a/plugins/actionlint/hooks/hook-utils.sh b/plugins/actionlint/hooks/hook-utils.sh index 0776e2f766..41a9b28420 100644 --- a/plugins/actionlint/hooks/hook-utils.sh +++ b/plugins/actionlint/hooks/hook-utils.sh @@ -1443,26 +1443,30 @@ hook::git_resolve_index() { ;; sudo) # sudo's own chdir is -D/--chdir (its -C is close-from, -R is --chroot). - # Only the unclustered spellings are read here; sudo's valueless short set - # is large and release-dependent, so peeling a cluster the way the env - # branch does would be guesswork rather than grammar. - # Known gap, fail-open: a clustered `sudo -bD dir git …` loses the chdir, - # and `-i` relocates to the target user's home without naming a directory - # at all. + # GNU sudo clusters short options, so `-bD dir` carries a chdir that no + # exact `-D` match sees. Peel the documented valueless shorts (-A/-B/-b/-e/-E + # -H/-K/-k/-l/-n/-P/-s/-S/-v/-V, per `sudo --help`) off a single-dash token + # so the value-taking tail (-D/--chdir, -u/-g/-h/-p/-C/-R/-T) reaches its own + # branch. `-h` is value-taking (`-h host` / `--host=`) and must not be peeled. + # `-i` relocates to the target user's home without naming a directory at all. ((i++)) - local sudo_ci=-1 + local sudo_ci=-1 stok while ((i < n)) && [[ "${w[i]}" == -* ]]; do - case "${w[i]}" in + stok="${w[i]}" + if [[ "$stok" == -[!-]* ]]; then + while [[ "$stok" =~ ^-[ABbeEHKklnPsSvV](.+)$ ]]; do stok="-${BASH_REMATCH[1]}"; done + fi + case "$stok" in -D | --chdir) ((i + 1 < n)) && hook::wrapper_chdir_record sudo_ci "${w[i + 1]}" ((i += 2)) ;; --chdir=*) - hook::wrapper_chdir_record sudo_ci "${w[i]#--chdir=}" + hook::wrapper_chdir_record sudo_ci "${stok#--chdir=}" ((i++)) ;; -D*) - hook::wrapper_chdir_record sudo_ci "${w[i]#-D}" + hook::wrapper_chdir_record sudo_ci "${stok#-D}" ((i++)) ;; -u | -g | -h | -p | -C | -R | -T | --user | --group) ((i += 2)) ;; diff --git a/plugins/autonomy/.claude-plugin/plugin.json b/plugins/autonomy/.claude-plugin/plugin.json index 37ffc5f907..9d8181d69d 100644 --- a/plugins/autonomy/.claude-plugin/plugin.json +++ b/plugins/autonomy/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "autonomy", - "version": "0.16.6", + "version": "0.16.7", "description": "Governed autonomous agent operation: role-topology, binding-seam, wiring-vs-advisor, telemetry, return-accounting, trigger-dispatch, per-work-class guardrail-matrix, standing-routine-catalog, and design-only runner-charter contracts for climbing the AI-adoption ladder, plus a guided-setup skill that discovers an adopting org's state, writes its schema-versioned binding, wires standards-pinned OTLP emission with a zero-cost file-artifact default, wires human-attested return capture at the task boundary, wires signal adapters with one governed dispatch entrypoint, binds the five-class guardrail matrix to an org's isolation substrates with an in-boundary live-validation probe before recording each fail-closed binding, and stands up standing-routine-catalog classes as scheduled temporal signal adapters behind the one governed queue with free scheduling defaults wired as reviewable changes and each routine's work-class mapping homed on the security surface.", "author": { "name": "Melodic Software", diff --git a/plugins/autonomy/CHANGELOG.md b/plugins/autonomy/CHANGELOG.md index 0ea29b3340..a3d62f0bd5 100644 --- a/plugins/autonomy/CHANGELOG.md +++ b/plugins/autonomy/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to the `autonomy` plugin are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. +## [0.16.7] + +### Changed + +- **Synced `hook-utils.sh`:** peel sudo clustered short options for chdir resolution (#1811); widen the valueless-short peel set and keep `-h` value-taking. + ## [0.16.6] ### Fixed diff --git a/plugins/autonomy/hooks/hook-utils.sh b/plugins/autonomy/hooks/hook-utils.sh index 0776e2f766..41a9b28420 100644 --- a/plugins/autonomy/hooks/hook-utils.sh +++ b/plugins/autonomy/hooks/hook-utils.sh @@ -1443,26 +1443,30 @@ hook::git_resolve_index() { ;; sudo) # sudo's own chdir is -D/--chdir (its -C is close-from, -R is --chroot). - # Only the unclustered spellings are read here; sudo's valueless short set - # is large and release-dependent, so peeling a cluster the way the env - # branch does would be guesswork rather than grammar. - # Known gap, fail-open: a clustered `sudo -bD dir git …` loses the chdir, - # and `-i` relocates to the target user's home without naming a directory - # at all. + # GNU sudo clusters short options, so `-bD dir` carries a chdir that no + # exact `-D` match sees. Peel the documented valueless shorts (-A/-B/-b/-e/-E + # -H/-K/-k/-l/-n/-P/-s/-S/-v/-V, per `sudo --help`) off a single-dash token + # so the value-taking tail (-D/--chdir, -u/-g/-h/-p/-C/-R/-T) reaches its own + # branch. `-h` is value-taking (`-h host` / `--host=`) and must not be peeled. + # `-i` relocates to the target user's home without naming a directory at all. ((i++)) - local sudo_ci=-1 + local sudo_ci=-1 stok while ((i < n)) && [[ "${w[i]}" == -* ]]; do - case "${w[i]}" in + stok="${w[i]}" + if [[ "$stok" == -[!-]* ]]; then + while [[ "$stok" =~ ^-[ABbeEHKklnPsSvV](.+)$ ]]; do stok="-${BASH_REMATCH[1]}"; done + fi + case "$stok" in -D | --chdir) ((i + 1 < n)) && hook::wrapper_chdir_record sudo_ci "${w[i + 1]}" ((i += 2)) ;; --chdir=*) - hook::wrapper_chdir_record sudo_ci "${w[i]#--chdir=}" + hook::wrapper_chdir_record sudo_ci "${stok#--chdir=}" ((i++)) ;; -D*) - hook::wrapper_chdir_record sudo_ci "${w[i]#-D}" + hook::wrapper_chdir_record sudo_ci "${stok#-D}" ((i++)) ;; -u | -g | -h | -p | -C | -R | -T | --user | --group) ((i += 2)) ;; diff --git a/plugins/bash-format/.claude-plugin/plugin.json b/plugins/bash-format/.claude-plugin/plugin.json index c662aea452..841f48733c 100644 --- a/plugins/bash-format/.claude-plugin/plugin.json +++ b/plugins/bash-format/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "bash-format", - "version": "0.7.9", + "version": "0.7.10", "description": "Auto-format and lint shell scripts on edit via shfmt + ShellCheck, using the consuming repo's own .editorconfig and .shellcheckrc.", "author": { "name": "Melodic Software", diff --git a/plugins/bash-format/CHANGELOG.md b/plugins/bash-format/CHANGELOG.md index 0ea336b3ea..b3351bda64 100644 --- a/plugins/bash-format/CHANGELOG.md +++ b/plugins/bash-format/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to the `bash-format` plugin are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. +## [0.7.10] + +### Changed + +- **Synced `hook-utils.sh`:** peel sudo clustered short options for chdir resolution (#1811); widen the valueless-short peel set and keep `-h` value-taking. + ## [0.7.9] ### Added diff --git a/plugins/bash-format/hooks/hook-utils.sh b/plugins/bash-format/hooks/hook-utils.sh index 0776e2f766..41a9b28420 100644 --- a/plugins/bash-format/hooks/hook-utils.sh +++ b/plugins/bash-format/hooks/hook-utils.sh @@ -1443,26 +1443,30 @@ hook::git_resolve_index() { ;; sudo) # sudo's own chdir is -D/--chdir (its -C is close-from, -R is --chroot). - # Only the unclustered spellings are read here; sudo's valueless short set - # is large and release-dependent, so peeling a cluster the way the env - # branch does would be guesswork rather than grammar. - # Known gap, fail-open: a clustered `sudo -bD dir git …` loses the chdir, - # and `-i` relocates to the target user's home without naming a directory - # at all. + # GNU sudo clusters short options, so `-bD dir` carries a chdir that no + # exact `-D` match sees. Peel the documented valueless shorts (-A/-B/-b/-e/-E + # -H/-K/-k/-l/-n/-P/-s/-S/-v/-V, per `sudo --help`) off a single-dash token + # so the value-taking tail (-D/--chdir, -u/-g/-h/-p/-C/-R/-T) reaches its own + # branch. `-h` is value-taking (`-h host` / `--host=`) and must not be peeled. + # `-i` relocates to the target user's home without naming a directory at all. ((i++)) - local sudo_ci=-1 + local sudo_ci=-1 stok while ((i < n)) && [[ "${w[i]}" == -* ]]; do - case "${w[i]}" in + stok="${w[i]}" + if [[ "$stok" == -[!-]* ]]; then + while [[ "$stok" =~ ^-[ABbeEHKklnPsSvV](.+)$ ]]; do stok="-${BASH_REMATCH[1]}"; done + fi + case "$stok" in -D | --chdir) ((i + 1 < n)) && hook::wrapper_chdir_record sudo_ci "${w[i + 1]}" ((i += 2)) ;; --chdir=*) - hook::wrapper_chdir_record sudo_ci "${w[i]#--chdir=}" + hook::wrapper_chdir_record sudo_ci "${stok#--chdir=}" ((i++)) ;; -D*) - hook::wrapper_chdir_record sudo_ci "${w[i]#-D}" + hook::wrapper_chdir_record sudo_ci "${stok#-D}" ((i++)) ;; -u | -g | -h | -p | -C | -R | -T | --user | --group) ((i += 2)) ;; diff --git a/plugins/biome-format/.claude-plugin/plugin.json b/plugins/biome-format/.claude-plugin/plugin.json index f4c437df85..587650810e 100644 --- a/plugins/biome-format/.claude-plugin/plugin.json +++ b/plugins/biome-format/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "biome-format", - "version": "0.6.8", + "version": "0.6.9", "description": "Auto-format and lint JS/TS/JSX/JSON on edit via Biome, only when a biome.json governs the repo \u2014 using the consuming repo's own Biome config.", "author": { "name": "Melodic Software", diff --git a/plugins/biome-format/CHANGELOG.md b/plugins/biome-format/CHANGELOG.md index 4dd675651c..8ec16416c3 100644 --- a/plugins/biome-format/CHANGELOG.md +++ b/plugins/biome-format/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to the `biome-format` plugin are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. +## [0.6.9] + +### Changed + +- **Synced `hook-utils.sh`:** peel sudo clustered short options for chdir resolution (#1811); widen the valueless-short peel set and keep `-h` value-taking. + ## [0.6.8] ### Added diff --git a/plugins/biome-format/hooks/hook-utils.sh b/plugins/biome-format/hooks/hook-utils.sh index 0776e2f766..41a9b28420 100644 --- a/plugins/biome-format/hooks/hook-utils.sh +++ b/plugins/biome-format/hooks/hook-utils.sh @@ -1443,26 +1443,30 @@ hook::git_resolve_index() { ;; sudo) # sudo's own chdir is -D/--chdir (its -C is close-from, -R is --chroot). - # Only the unclustered spellings are read here; sudo's valueless short set - # is large and release-dependent, so peeling a cluster the way the env - # branch does would be guesswork rather than grammar. - # Known gap, fail-open: a clustered `sudo -bD dir git …` loses the chdir, - # and `-i` relocates to the target user's home without naming a directory - # at all. + # GNU sudo clusters short options, so `-bD dir` carries a chdir that no + # exact `-D` match sees. Peel the documented valueless shorts (-A/-B/-b/-e/-E + # -H/-K/-k/-l/-n/-P/-s/-S/-v/-V, per `sudo --help`) off a single-dash token + # so the value-taking tail (-D/--chdir, -u/-g/-h/-p/-C/-R/-T) reaches its own + # branch. `-h` is value-taking (`-h host` / `--host=`) and must not be peeled. + # `-i` relocates to the target user's home without naming a directory at all. ((i++)) - local sudo_ci=-1 + local sudo_ci=-1 stok while ((i < n)) && [[ "${w[i]}" == -* ]]; do - case "${w[i]}" in + stok="${w[i]}" + if [[ "$stok" == -[!-]* ]]; then + while [[ "$stok" =~ ^-[ABbeEHKklnPsSvV](.+)$ ]]; do stok="-${BASH_REMATCH[1]}"; done + fi + case "$stok" in -D | --chdir) ((i + 1 < n)) && hook::wrapper_chdir_record sudo_ci "${w[i + 1]}" ((i += 2)) ;; --chdir=*) - hook::wrapper_chdir_record sudo_ci "${w[i]#--chdir=}" + hook::wrapper_chdir_record sudo_ci "${stok#--chdir=}" ((i++)) ;; -D*) - hook::wrapper_chdir_record sudo_ci "${w[i]#-D}" + hook::wrapper_chdir_record sudo_ci "${stok#-D}" ((i++)) ;; -u | -g | -h | -p | -C | -R | -T | --user | --group) ((i += 2)) ;; diff --git a/plugins/claude-ops/.claude-plugin/plugin.json b/plugins/claude-ops/.claude-plugin/plugin.json index c54f220cf7..8b5d4679be 100644 --- a/plugins/claude-ops/.claude-plugin/plugin.json +++ b/plugins/claude-ops/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "claude-ops", - "version": "0.31.3", + "version": "0.31.5", "description": "Claude Code operations toolkit. Ten skills: inventory (read-only enumeration of the complete invocable surface \u2014 every built-in CLI command with aliases and hidden/gated status, every bundled skill, and every component of every installed plugin across all marketplaces; reads the shipped binary because upstream publishes no built-in command list, and carries an integrity verdict so a drifted build reports counts as floors rather than silently short totals), audit-install-state (read-only audit of the machine-scope ~/.claude installation directory and ~/.claude.json \u2014 full inventory split into an authored surface and rolled-up bulk trees, product-managed retention vs genuinely unmanaged state, filename-scheme resolution before any process-liveness check, and deliberate/mid-experiment detection; reports, never deletes), audit-performance (read-only slowness-diagnostic capture run at the moment the machine or a session feels slow \u2014 CLI version, retention-sweep health including the silent unparsable-settings pause, a timed census walk of the install tree as a sweep-cost proxy, active-session and plugin-fleet counts, a process census, and a bundled known-performance-issues reference; separates the three documented suspects \u2014 accumulated state, version regression, component bloat \u2014 and routes remediation out; reports, never mutates), observability (read locally captured telemetry \u2014 OTEL store, collector, hook-event JSONL, ccusage \u2014 with trend reports and store pruning), known-issues (search known Claude product GitHub bugs, check service health, maintain a persistent tracked-issue registry), changelog (ingest Claude Code changelog entries and integrate them into the current repo), plugins (bring a machine's plugin fleet current on demand \u2014 marketplace refresh, effective-scope updates including in-repo project/local installs, new-plugin install per policy, scope-divergence detection and explicit convergence), morning-brief (read-only gh-based operator morning view \u2014 queue-label counts, merge-ready PRs, parked decisions with their RECOMMENDED lines, and loop-lane telemetry freshness), lanes (start/restart/stop/status loop lanes as named background Claude Code sessions seeded from canonical prompt files, with per-lane model/effort, a repo-pull + marketplace-refresh launch step, and a consume-restarts action \u2014 an OS-schedulable reader that relaunches stopped lanes whose telemetry carries a restart_request), and a re-runnable setup action that settles where the known-issues registry lives. Plus a family of seven advisory *-audit telemetry-emitter hooks (API errors, config changes, instruction loads, permission denials, pre-compaction, skill usage, tool failures) that emit the shared hook-telemetry envelope, and a reference sink that maps envelopes into the hook-events.jsonl the observability skill reads.", "author": { "name": "Melodic Software", diff --git a/plugins/claude-ops/CHANGELOG.md b/plugins/claude-ops/CHANGELOG.md index 7ad9cc0bca..1b44d98429 100644 --- a/plugins/claude-ops/CHANGELOG.md +++ b/plugins/claude-ops/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to the `claude-ops` plugin are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. +## [0.31.5] + +### Changed + +- **Synced `hook-utils.sh`:** peel sudo clustered short options for chdir resolution (#1811); widen the valueless-short peel set and keep `-h` value-taking. + +## [0.31.4] + +### Changed + +- **Synced `hook-utils.sh`:** peel sudo clustered short options for chdir resolution (#1811). + ## [0.31.3] ### Changed diff --git a/plugins/claude-ops/hooks/hook-utils.sh b/plugins/claude-ops/hooks/hook-utils.sh index 0776e2f766..41a9b28420 100644 --- a/plugins/claude-ops/hooks/hook-utils.sh +++ b/plugins/claude-ops/hooks/hook-utils.sh @@ -1443,26 +1443,30 @@ hook::git_resolve_index() { ;; sudo) # sudo's own chdir is -D/--chdir (its -C is close-from, -R is --chroot). - # Only the unclustered spellings are read here; sudo's valueless short set - # is large and release-dependent, so peeling a cluster the way the env - # branch does would be guesswork rather than grammar. - # Known gap, fail-open: a clustered `sudo -bD dir git …` loses the chdir, - # and `-i` relocates to the target user's home without naming a directory - # at all. + # GNU sudo clusters short options, so `-bD dir` carries a chdir that no + # exact `-D` match sees. Peel the documented valueless shorts (-A/-B/-b/-e/-E + # -H/-K/-k/-l/-n/-P/-s/-S/-v/-V, per `sudo --help`) off a single-dash token + # so the value-taking tail (-D/--chdir, -u/-g/-h/-p/-C/-R/-T) reaches its own + # branch. `-h` is value-taking (`-h host` / `--host=`) and must not be peeled. + # `-i` relocates to the target user's home without naming a directory at all. ((i++)) - local sudo_ci=-1 + local sudo_ci=-1 stok while ((i < n)) && [[ "${w[i]}" == -* ]]; do - case "${w[i]}" in + stok="${w[i]}" + if [[ "$stok" == -[!-]* ]]; then + while [[ "$stok" =~ ^-[ABbeEHKklnPsSvV](.+)$ ]]; do stok="-${BASH_REMATCH[1]}"; done + fi + case "$stok" in -D | --chdir) ((i + 1 < n)) && hook::wrapper_chdir_record sudo_ci "${w[i + 1]}" ((i += 2)) ;; --chdir=*) - hook::wrapper_chdir_record sudo_ci "${w[i]#--chdir=}" + hook::wrapper_chdir_record sudo_ci "${stok#--chdir=}" ((i++)) ;; -D*) - hook::wrapper_chdir_record sudo_ci "${w[i]#-D}" + hook::wrapper_chdir_record sudo_ci "${stok#-D}" ((i++)) ;; -u | -g | -h | -p | -C | -R | -T | --user | --group) ((i += 2)) ;; diff --git a/plugins/context-guard/.claude-plugin/plugin.json b/plugins/context-guard/.claude-plugin/plugin.json index 8cd30a856c..b1a6818e92 100644 --- a/plugins/context-guard/.claude-plugin/plugin.json +++ b/plugins/context-guard/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "context-guard", - "version": "0.7.5", + "version": "0.7.7", "description": "Per-session context-window observability plus the first shipped consumer: a statusline wrapper tees each session's context_window fields to a per-session snapshot file, a zone resolver classifies usage into smart/acceptable/dumb bands (percentage bands plus window-class token bands, conservative-min combination, zones.json SSOT with shipped defaults), a reader contract fixes how consuming sessions interpret the snapshots, and zone-crossing hooks report once per transition into a worse zone across two channels \u2014 the continuation menu to the operator, who owns that choice, and to the model only the zone determination plus the counter-steer that a zone word is not a decay signal (advisory by default; an optional blocking mode gates new mutating work on a fresh dumb-zone snapshot with handoff-writing exempt), with a PostCompact hook persisting an evidence-degraded marker.", "author": { "name": "Melodic Software", diff --git a/plugins/context-guard/CHANGELOG.md b/plugins/context-guard/CHANGELOG.md index 00c9d19a16..3bcfe555dd 100644 --- a/plugins/context-guard/CHANGELOG.md +++ b/plugins/context-guard/CHANGELOG.md @@ -5,6 +5,18 @@ All notable changes to the `context-guard` plugin. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [0.7.7] + +### Changed + +- **Synced `hook-utils.sh`:** peel sudo clustered short options for chdir resolution (#1811); widen the valueless-short peel set and keep `-h` value-taking. + +## [0.7.6] + +### Changed + +- **Synced `hook-utils.sh`:** peel sudo clustered short options for chdir resolution (#1811). + ## [0.7.5] ### Changed diff --git a/plugins/context-guard/hooks/hook-utils.sh b/plugins/context-guard/hooks/hook-utils.sh index 0776e2f766..41a9b28420 100755 --- a/plugins/context-guard/hooks/hook-utils.sh +++ b/plugins/context-guard/hooks/hook-utils.sh @@ -1443,26 +1443,30 @@ hook::git_resolve_index() { ;; sudo) # sudo's own chdir is -D/--chdir (its -C is close-from, -R is --chroot). - # Only the unclustered spellings are read here; sudo's valueless short set - # is large and release-dependent, so peeling a cluster the way the env - # branch does would be guesswork rather than grammar. - # Known gap, fail-open: a clustered `sudo -bD dir git …` loses the chdir, - # and `-i` relocates to the target user's home without naming a directory - # at all. + # GNU sudo clusters short options, so `-bD dir` carries a chdir that no + # exact `-D` match sees. Peel the documented valueless shorts (-A/-B/-b/-e/-E + # -H/-K/-k/-l/-n/-P/-s/-S/-v/-V, per `sudo --help`) off a single-dash token + # so the value-taking tail (-D/--chdir, -u/-g/-h/-p/-C/-R/-T) reaches its own + # branch. `-h` is value-taking (`-h host` / `--host=`) and must not be peeled. + # `-i` relocates to the target user's home without naming a directory at all. ((i++)) - local sudo_ci=-1 + local sudo_ci=-1 stok while ((i < n)) && [[ "${w[i]}" == -* ]]; do - case "${w[i]}" in + stok="${w[i]}" + if [[ "$stok" == -[!-]* ]]; then + while [[ "$stok" =~ ^-[ABbeEHKklnPsSvV](.+)$ ]]; do stok="-${BASH_REMATCH[1]}"; done + fi + case "$stok" in -D | --chdir) ((i + 1 < n)) && hook::wrapper_chdir_record sudo_ci "${w[i + 1]}" ((i += 2)) ;; --chdir=*) - hook::wrapper_chdir_record sudo_ci "${w[i]#--chdir=}" + hook::wrapper_chdir_record sudo_ci "${stok#--chdir=}" ((i++)) ;; -D*) - hook::wrapper_chdir_record sudo_ci "${w[i]#-D}" + hook::wrapper_chdir_record sudo_ci "${stok#-D}" ((i++)) ;; -u | -g | -h | -p | -C | -R | -T | --user | --group) ((i += 2)) ;; diff --git a/plugins/desktop-notification/.claude-plugin/plugin.json b/plugins/desktop-notification/.claude-plugin/plugin.json index df4c54c759..3f13358292 100644 --- a/plugins/desktop-notification/.claude-plugin/plugin.json +++ b/plugins/desktop-notification/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "desktop-notification", - "version": "0.6.7", + "version": "0.6.9", "description": "Alert you when Claude Code needs input \u2014 an audible terminal bell, an OSC 9 terminal notification, and an OS-native toast (macOS/Linux) on permission and idle prompts.", "author": { "name": "Melodic Software", diff --git a/plugins/desktop-notification/CHANGELOG.md b/plugins/desktop-notification/CHANGELOG.md index d017e23fe7..f4badb7b8e 100644 --- a/plugins/desktop-notification/CHANGELOG.md +++ b/plugins/desktop-notification/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to the `desktop-notification` plugin are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. +## [0.6.9] + +### Changed + +- **Synced `hook-utils.sh`:** peel sudo clustered short options for chdir resolution (#1811); widen the valueless-short peel set and keep `-h` value-taking. + +## [0.6.8] + +### Changed + +- **Synced `hook-utils.sh`:** peel sudo clustered short options for chdir resolution (#1811). + ## [0.6.7] ### Changed diff --git a/plugins/desktop-notification/hooks/hook-utils.sh b/plugins/desktop-notification/hooks/hook-utils.sh index 0776e2f766..41a9b28420 100644 --- a/plugins/desktop-notification/hooks/hook-utils.sh +++ b/plugins/desktop-notification/hooks/hook-utils.sh @@ -1443,26 +1443,30 @@ hook::git_resolve_index() { ;; sudo) # sudo's own chdir is -D/--chdir (its -C is close-from, -R is --chroot). - # Only the unclustered spellings are read here; sudo's valueless short set - # is large and release-dependent, so peeling a cluster the way the env - # branch does would be guesswork rather than grammar. - # Known gap, fail-open: a clustered `sudo -bD dir git …` loses the chdir, - # and `-i` relocates to the target user's home without naming a directory - # at all. + # GNU sudo clusters short options, so `-bD dir` carries a chdir that no + # exact `-D` match sees. Peel the documented valueless shorts (-A/-B/-b/-e/-E + # -H/-K/-k/-l/-n/-P/-s/-S/-v/-V, per `sudo --help`) off a single-dash token + # so the value-taking tail (-D/--chdir, -u/-g/-h/-p/-C/-R/-T) reaches its own + # branch. `-h` is value-taking (`-h host` / `--host=`) and must not be peeled. + # `-i` relocates to the target user's home without naming a directory at all. ((i++)) - local sudo_ci=-1 + local sudo_ci=-1 stok while ((i < n)) && [[ "${w[i]}" == -* ]]; do - case "${w[i]}" in + stok="${w[i]}" + if [[ "$stok" == -[!-]* ]]; then + while [[ "$stok" =~ ^-[ABbeEHKklnPsSvV](.+)$ ]]; do stok="-${BASH_REMATCH[1]}"; done + fi + case "$stok" in -D | --chdir) ((i + 1 < n)) && hook::wrapper_chdir_record sudo_ci "${w[i + 1]}" ((i += 2)) ;; --chdir=*) - hook::wrapper_chdir_record sudo_ci "${w[i]#--chdir=}" + hook::wrapper_chdir_record sudo_ci "${stok#--chdir=}" ((i++)) ;; -D*) - hook::wrapper_chdir_record sudo_ci "${w[i]#-D}" + hook::wrapper_chdir_record sudo_ci "${stok#-D}" ((i++)) ;; -u | -g | -h | -p | -C | -R | -T | --user | --group) ((i += 2)) ;; diff --git a/plugins/eol-normalizer/.claude-plugin/plugin.json b/plugins/eol-normalizer/.claude-plugin/plugin.json index c6ac3d1910..c04b9395ab 100644 --- a/plugins/eol-normalizer/.claude-plugin/plugin.json +++ b/plugins/eol-normalizer/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "eol-normalizer", - "version": "0.6.7", + "version": "0.6.9", "description": "Normalize a written file's working-tree line endings to its .gitattributes eol value on edit \u2014 symmetric CRLF/LF driven by git check-attr, advisory and never blocking.", "author": { "name": "Melodic Software", diff --git a/plugins/eol-normalizer/CHANGELOG.md b/plugins/eol-normalizer/CHANGELOG.md index 6a22fa29f7..7c4bf260f0 100644 --- a/plugins/eol-normalizer/CHANGELOG.md +++ b/plugins/eol-normalizer/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to the `eol-normalizer` plugin are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. +## [0.6.9] + +### Changed + +- **Synced `hook-utils.sh`:** peel sudo clustered short options for chdir resolution (#1811); widen the valueless-short peel set and keep `-h` value-taking. + +## [0.6.8] + +### Changed + +- **Synced `hook-utils.sh`:** peel sudo clustered short options for chdir resolution (#1811). + ## [0.6.7] ### Changed diff --git a/plugins/eol-normalizer/hooks/hook-utils.sh b/plugins/eol-normalizer/hooks/hook-utils.sh index 0776e2f766..41a9b28420 100644 --- a/plugins/eol-normalizer/hooks/hook-utils.sh +++ b/plugins/eol-normalizer/hooks/hook-utils.sh @@ -1443,26 +1443,30 @@ hook::git_resolve_index() { ;; sudo) # sudo's own chdir is -D/--chdir (its -C is close-from, -R is --chroot). - # Only the unclustered spellings are read here; sudo's valueless short set - # is large and release-dependent, so peeling a cluster the way the env - # branch does would be guesswork rather than grammar. - # Known gap, fail-open: a clustered `sudo -bD dir git …` loses the chdir, - # and `-i` relocates to the target user's home without naming a directory - # at all. + # GNU sudo clusters short options, so `-bD dir` carries a chdir that no + # exact `-D` match sees. Peel the documented valueless shorts (-A/-B/-b/-e/-E + # -H/-K/-k/-l/-n/-P/-s/-S/-v/-V, per `sudo --help`) off a single-dash token + # so the value-taking tail (-D/--chdir, -u/-g/-h/-p/-C/-R/-T) reaches its own + # branch. `-h` is value-taking (`-h host` / `--host=`) and must not be peeled. + # `-i` relocates to the target user's home without naming a directory at all. ((i++)) - local sudo_ci=-1 + local sudo_ci=-1 stok while ((i < n)) && [[ "${w[i]}" == -* ]]; do - case "${w[i]}" in + stok="${w[i]}" + if [[ "$stok" == -[!-]* ]]; then + while [[ "$stok" =~ ^-[ABbeEHKklnPsSvV](.+)$ ]]; do stok="-${BASH_REMATCH[1]}"; done + fi + case "$stok" in -D | --chdir) ((i + 1 < n)) && hook::wrapper_chdir_record sudo_ci "${w[i + 1]}" ((i += 2)) ;; --chdir=*) - hook::wrapper_chdir_record sudo_ci "${w[i]#--chdir=}" + hook::wrapper_chdir_record sudo_ci "${stok#--chdir=}" ((i++)) ;; -D*) - hook::wrapper_chdir_record sudo_ci "${w[i]#-D}" + hook::wrapper_chdir_record sudo_ci "${stok#-D}" ((i++)) ;; -u | -g | -h | -p | -C | -R | -T | --user | --group) ((i += 2)) ;; diff --git a/plugins/go-format/.claude-plugin/plugin.json b/plugins/go-format/.claude-plugin/plugin.json index 101d8effd1..ebb25fd110 100644 --- a/plugins/go-format/.claude-plugin/plugin.json +++ b/plugins/go-format/.claude-plugin/plugin.json @@ -1,8 +1,8 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "go-format", - "version": "0.3.8", - "description": "Auto-fix Go formatting and import management on edit via goimports — runs unconditionally (no consumer-config gate), skipping generated files.", + "version": "0.3.10", + "description": "Auto-fix Go formatting and import management on edit via goimports \u2014 runs unconditionally (no consumer-config gate), skipping generated files.", "author": { "name": "Melodic Software", "email": "info@melodicsoftware.com" diff --git a/plugins/go-format/CHANGELOG.md b/plugins/go-format/CHANGELOG.md index e438718324..43b49e3a69 100644 --- a/plugins/go-format/CHANGELOG.md +++ b/plugins/go-format/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to the `go-format` plugin are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. +## [0.3.10] + +### Changed + +- **Synced `hook-utils.sh`:** peel sudo clustered short options for chdir resolution (#1811); widen the valueless-short peel set and keep `-h` value-taking. + +## [0.3.9] + +### Changed + +- **Synced `hook-utils.sh`:** peel sudo clustered short options for chdir resolution (#1811). + ## [0.3.8] ### Added diff --git a/plugins/go-format/hooks/hook-utils.sh b/plugins/go-format/hooks/hook-utils.sh index 0776e2f766..41a9b28420 100644 --- a/plugins/go-format/hooks/hook-utils.sh +++ b/plugins/go-format/hooks/hook-utils.sh @@ -1443,26 +1443,30 @@ hook::git_resolve_index() { ;; sudo) # sudo's own chdir is -D/--chdir (its -C is close-from, -R is --chroot). - # Only the unclustered spellings are read here; sudo's valueless short set - # is large and release-dependent, so peeling a cluster the way the env - # branch does would be guesswork rather than grammar. - # Known gap, fail-open: a clustered `sudo -bD dir git …` loses the chdir, - # and `-i` relocates to the target user's home without naming a directory - # at all. + # GNU sudo clusters short options, so `-bD dir` carries a chdir that no + # exact `-D` match sees. Peel the documented valueless shorts (-A/-B/-b/-e/-E + # -H/-K/-k/-l/-n/-P/-s/-S/-v/-V, per `sudo --help`) off a single-dash token + # so the value-taking tail (-D/--chdir, -u/-g/-h/-p/-C/-R/-T) reaches its own + # branch. `-h` is value-taking (`-h host` / `--host=`) and must not be peeled. + # `-i` relocates to the target user's home without naming a directory at all. ((i++)) - local sudo_ci=-1 + local sudo_ci=-1 stok while ((i < n)) && [[ "${w[i]}" == -* ]]; do - case "${w[i]}" in + stok="${w[i]}" + if [[ "$stok" == -[!-]* ]]; then + while [[ "$stok" =~ ^-[ABbeEHKklnPsSvV](.+)$ ]]; do stok="-${BASH_REMATCH[1]}"; done + fi + case "$stok" in -D | --chdir) ((i + 1 < n)) && hook::wrapper_chdir_record sudo_ci "${w[i + 1]}" ((i += 2)) ;; --chdir=*) - hook::wrapper_chdir_record sudo_ci "${w[i]#--chdir=}" + hook::wrapper_chdir_record sudo_ci "${stok#--chdir=}" ((i++)) ;; -D*) - hook::wrapper_chdir_record sudo_ci "${w[i]#-D}" + hook::wrapper_chdir_record sudo_ci "${stok#-D}" ((i++)) ;; -u | -g | -h | -p | -C | -R | -T | --user | --group) ((i += 2)) ;; diff --git a/plugins/guardrails/.claude-plugin/plugin.json b/plugins/guardrails/.claude-plugin/plugin.json index a63cc4f343..f454d66ea3 100644 --- a/plugins/guardrails/.claude-plugin/plugin.json +++ b/plugins/guardrails/.claude-plugin/plugin.json @@ -135,5 +135,5 @@ "min": 1 } }, - "version": "0.28.11" + "version": "0.28.12" } diff --git a/plugins/guardrails/CHANGELOG.md b/plugins/guardrails/CHANGELOG.md index a8f9dbca64..07020b99b6 100644 --- a/plugins/guardrails/CHANGELOG.md +++ b/plugins/guardrails/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to the `guardrails` plugin are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. +## [0.28.12] + +### Fixed + +- **`hook::git_resolve_index` sudo cluster peel (#1811).** Peel documented valueless sudo + short options off clustered tokens so `sudo -bD