diff --git a/plugins/claude-config/.claude-plugin/plugin.json b/plugins/claude-config/.claude-plugin/plugin.json index dbaba81c7c..5e7ff7b24b 100644 --- a/plugins/claude-config/.claude-plugin/plugin.json +++ b/plugins/claude-config/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "claude-config", - "version": "0.40.17", + "version": "0.40.18", "description": "Nine configuration-health skills (plus setup) for a repo's Claude Code configuration: audit (settings.json / .mcp.json / hooks / plugins / permissions drift), audit-automation-gaps (evidence-gated verdicts on automation gaps), audit-permission-grants (allow-rule / allowed-tools grants for auto-mode durability and portability), audit-permission-state (the permission rules actually in effect \u2014 every settings scope merged with per-rule provenance, what auto mode drops on entry, config written where nothing reads it, and which managed intents are enforced versus loosenable), draft-auto-mode-rules (interview and draft a paste-ready autoMode classifier block; prints only, never writes), audit-instructions (locally-owned instruction surfaces vs current model capability \u2014 proposes removals/rewrites of instructions the model no longer needs, and detects cross-surface instruction conflicts), audit-prompting-postures (the additive lane \u2014 posture guidance the prompting guide says a component's purpose needs but the component does not carry), audit-pass (one coordinated, ordered, resumable pass over a named target \u2014 three-scope inventory, run-time-derived exclusion set, stable finding identity, suppression memory, resume, one human gate \u2014 delegating every check to the plugin that owns it), and unhobble (the empirical bare-baseline experiment: reversibly strip a repo's standing instructions, log real stumbles against the current model, re-add only what evidence earns).", "author": { "name": "Melodic Software", diff --git a/plugins/claude-config/CHANGELOG.md b/plugins/claude-config/CHANGELOG.md index 4fce644110..59ef12748e 100644 --- a/plugins/claude-config/CHANGELOG.md +++ b/plugins/claude-config/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to the `claude-config` plugin are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. +## [0.40.18] + +### Changed + +- **Behavior-preserving simplification sweep (batch-simplify).** `audit-permission-state`'s + `automode-entry-diff.sh` drops a redundant command-substitution wrapper in the empty-prediction + guard (`[[ -z "$(printf '%s' "$predicted_dropped")" ]]` to `[[ -z "$predicted_dropped" ]]`); + the wrapper only stripped trailing newlines, and the value's grammar (non-empty rules each + followed by one newline) makes that stripping unobservable. Refutation-verified by static + reachability trace plus a 12-case empirical matrix; the suite's 63 checks and the + no-writes property tests pass. + ## [0.40.17] ### Changed diff --git a/plugins/claude-config/skills/audit-permission-state/scripts/automode-entry-diff.sh b/plugins/claude-config/skills/audit-permission-state/scripts/automode-entry-diff.sh index 5a2f40996d..db52d6e0f2 100755 --- a/plugins/claude-config/skills/audit-permission-state/scripts/automode-entry-diff.sh +++ b/plugins/claude-config/skills/audit-permission-state/scripts/automode-entry-diff.sh @@ -362,7 +362,7 @@ fi if [[ -z "$oracle_dropped" ]]; then echo "oracle NOTE: the session narrated the permission merge but emitted zero drop lines. If this machine has rules the prediction above says are dropped, the session was likely not in auto mode; treat the oracle as unavailable rather than as an empty drop set." - [[ -z "$(printf '%s' "$predicted_dropped")" ]] || exit 0 + [[ -z "$predicted_dropped" ]] || exit 0 fi # Compare on rule text over the union of both sets: one verdict line per rule, diff --git a/plugins/claude-ops/.claude-plugin/plugin.json b/plugins/claude-ops/.claude-plugin/plugin.json index e7448f97f9..fd76f40387 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.38.19", + "version": "0.38.20", "description": "Claude Code operations toolkit. Twelve skills: audit-skill-visibility (audit whether each installed skill is actually VISIBLE to the model, and diagnose why most of a fleet never gets used \u2014 a skill is invisible when its description is dropped by Claude Code's skill-listing context budget, which drops descriptions least-invoked-first so an unused skill loses the keywords that would let it be matched, from skills genuinely not wanted, from skills the run cannot observe at all; computes whether the listing overflows from documented settings, and withholds every cold verdict the data cannot support rather than reporting absence of data as absence of use), 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: 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 the fan-out layer, which covers a load-labelled no-op spawn baseline, every hook that will fire bucketed per-tool-call versus per-turn with its invocation shape, the configured statusline, subagent concurrency and spawn-depth ceilings against documented defaults, whether running sessions predate the settings file they are judged by, and orphan attribution by parent liveness rather than age; read against a bundled known-performance-issues reference that also records the causes tested and cleared; separates the four documented suspects of accumulated state, version regression, component bloat, and per-spawn fan-out cost, and routes remediation out; reports, never mutates, and never executes a discovered hook or statusline command), audit-native-overlap (map native Claude Code surfaces \u2014 built-in CLI commands, bundled skills, plugin-backed built-ins, session-provided skills \u2014 against the current repo's plugin skills and agents, so a custom component never silently duplicates what Claude Code itself ships; bare invocation is a read-only overlap report carrying the extraction's integrity floors and a shared-listing-budget exposure section, verdicts are human-gated in a committed store rendered into a generated registry whose every row carries an observable recheck trigger, and only an explicit apply step bakes presence-gated native references into descriptions and Boundary sections), 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 eight advisory *-audit hooks (API errors, config changes, instruction loads, permission denials, pre-compaction, skill usage, tool failures, and unsurfaced hook failures \u2014 the last also warns the user via systemMessage, since a hook that fails to launch enforces nothing and Claude Code surfaces the failure to nobody) 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 32a700304c..68501d98c8 100644 --- a/plugins/claude-ops/CHANGELOG.md +++ b/plugins/claude-ops/CHANGELOG.md @@ -3,6 +3,17 @@ 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.38.20] + +### Changed + +- **Behavior-preserving simplification sweep (batch-simplify).** `lanes`'s machine-behavior.sh + drops the WT_COUNT parallel counter (its two reads use `${#WT_LINES[@]}` directly, matching the + file's existing WANT_PLUGINS idiom); `observability`'s claude-observability.test.sh collapses two + case-based substring checks into the suite's own `assert_contains` helper. Both refutation-verified + (counter/array divergence structurally impossible; 26/26 and 33/33 suite checks byte-identical + old-vs-new including a glob-metacharacter probe matrix). + ## [0.38.19] ### Changed diff --git a/plugins/claude-ops/skills/lanes/scripts/machine-behavior.sh b/plugins/claude-ops/skills/lanes/scripts/machine-behavior.sh index 61b2f2e575..e2824d01a6 100755 --- a/plugins/claude-ops/skills/lanes/scripts/machine-behavior.sh +++ b/plugins/claude-ops/skills/lanes/scripts/machine-behavior.sh @@ -147,7 +147,6 @@ gh_identity() { # is no single deterministic "pattern" to infer — the raw list IS the pattern. CLONE_PATH="unavailable" CURRENT_WT="unavailable" -WT_COUNT=0 declare -a WT_LINES=() read_worktrees() { @@ -180,7 +179,6 @@ read_worktrees() { "") if [[ -n "$path" ]]; then WT_LINES+=("$path|${branch:-(detached)}") - WT_COUNT=$((WT_COUNT + 1)) path="" branch="" fi ;; @@ -240,8 +238,8 @@ printf '== MACHINE-BEHAVIOR ==\n' printf 'gh-identity: %s\n' "$(gh_identity)" printf 'clone-path: %s\n' "$CLONE_PATH" printf 'current-worktree: %s\n' "$CURRENT_WT" -printf 'worktree-count: %s\n' "$WT_COUNT" -if ((WT_COUNT)); then +printf 'worktree-count: %s\n' "${#WT_LINES[@]}" +if ((${#WT_LINES[@]})); then printf 'worktrees:\n' for local_line in "${WT_LINES[@]}"; do printf ' %s [%s]\n' "${local_line%%|*}" "${local_line#*|}" diff --git a/plugins/claude-ops/skills/observability/claude-observability.test.sh b/plugins/claude-ops/skills/observability/claude-observability.test.sh index 9769b22f59..19f0d875d6 100755 --- a/plugins/claude-ops/skills/observability/claude-observability.test.sh +++ b/plugins/claude-ops/skills/observability/claude-observability.test.sh @@ -226,10 +226,7 @@ assert_eq "skill-usage uses its own 365d window, not --keep-days" "4" "$(lines_i # 9s-c: dry-run reports the resolved target without modifying it. su_out=$(cd "$clean_test_dir" && bash "$CLEAN" --dry-run --skill-usage-scope repo 2>&1 || true) -case "$su_out" in -*"skill-usage target"*) assert_eq "clean --dry-run names the skill-usage target" "1" "1" ;; -*) assert_eq "clean --dry-run names the skill-usage target" "1" "0" ;; -esac +assert_contains "clean --dry-run names the skill-usage target" "$su_out" "skill-usage target" assert_eq "clean --dry-run preserves skill-usage" "4" "$(lines_in "$SU_FX")" # 9s-d: a short window does prune, so the branch is real and not inert. @@ -246,10 +243,7 @@ mkdir -p "$su_slug_dir" printf '{"ts":"%s","event":"SkillUse","skill":"old:one"}\n' "$OLD_45" >"$su_slug_dir/skill-usage.jsonl" printf '{"ts":"%s","event":"SkillUse","skill":"new:two"}\n' "$TODAY" >>"$su_slug_dir/skill-usage.jsonl" su_dd_out=$(cd "$clean_test_dir" && bash "$CLEAN" --dry-run --skill-usage-scope data-dir --skill-usage-data-root "$su_data_root" 2>&1 || true) -case "$su_dd_out" in -*"$su_data_root/skill-usage/"*) assert_eq "data-dir resolves under the plugin data root" "1" "1" ;; -*) assert_eq "data-dir resolves under the plugin data root" "1" "0" ;; -esac +assert_contains "data-dir resolves under the plugin data root" "$su_dd_out" "$su_data_root/skill-usage/" # 9s-e: data-dir refuses to guess a location. CLAUDE_PLUGIN_DATA in a skill # subprocess was observed pointing at an UNRELATED plugin's data directory, so a diff --git a/plugins/disk-hygiene/.claude-plugin/plugin.json b/plugins/disk-hygiene/.claude-plugin/plugin.json index 82e7523d45..a07ce756d6 100644 --- a/plugins/disk-hygiene/.claude-plugin/plugin.json +++ b/plugins/disk-hygiene/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "disk-hygiene", - "version": "0.20.33", + "version": "0.20.34", "description": "Context-aware disk hygiene for arbitrary directory trees: inventories orphaned and temporary artifacts, classifies evidence into review tiers, and offers exact-path cleanup only after a fresh safety preview and explicit per-tier approval. The target is read-only by default; OS-managed paths, links and mount points, VCS-tracked content without the complete checkout evidence bundle, changed entries, and live-handle uncertainty fail closed.", "author": { "name": "Melodic Software", diff --git a/plugins/disk-hygiene/CHANGELOG.md b/plugins/disk-hygiene/CHANGELOG.md index 32b8762810..bc09c42a8c 100644 --- a/plugins/disk-hygiene/CHANGELOG.md +++ b/plugins/disk-hygiene/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to the `disk-hygiene` plugin are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. +## [0.20.34] + +### Changed + +- **Behavior-preserving simplification sweep (batch-simplify).** The setup skill's + `test_python3_alias_probe.py` replaces `make_file`'s hand-rolled `open(path, "wb")` context + manager (with a dead zero-size guard) with the exact stdlib equivalent + `path.write_bytes(b"\0" * size)`. Byte-identical file contents and permissions verified + empirically for every size the suite uses; refutation-verified; 10/10 tests pass. + ## [0.20.33] ### Changed diff --git a/plugins/disk-hygiene/skills/setup/scripts/test_python3_alias_probe.py b/plugins/disk-hygiene/skills/setup/scripts/test_python3_alias_probe.py index bdb201bb97..4dd931d147 100755 --- a/plugins/disk-hygiene/skills/setup/scripts/test_python3_alias_probe.py +++ b/plugins/disk-hygiene/skills/setup/scripts/test_python3_alias_probe.py @@ -47,9 +47,7 @@ def setUp(self) -> None: def make_file(self, relative: str, size: int) -> Path: path = self.root / relative path.parent.mkdir(parents=True, exist_ok=True) - with open(path, "wb") as handle: - if size: - handle.write(b"\0" * size) + path.write_bytes(b"\0" * size) return path def run_probe(self, argv: list[str]) -> dict[str, object]: diff --git a/plugins/instruction-placement/.claude-plugin/plugin.json b/plugins/instruction-placement/.claude-plugin/plugin.json index c13a34e507..27c2a9d15a 100644 --- a/plugins/instruction-placement/.claude-plugin/plugin.json +++ b/plugins/instruction-placement/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "instruction-placement", - "version": "0.11.12", + "version": "0.11.13", "description": "Routes agent-instruction content to the surface that loads it at the right moment. The audit skill sweeps a repository's instruction layer and its ordinary markdown for content whose scope is narrower than the surface carrying it \u2014 conventions keyed to one file type or one subtree sitting in an always-loaded CLAUDE.md or AGENTS.md \u2014 and for normative conventions stranded in documentation Claude never loads at all, then classifies each against a routing rubric and proposes a destination whose `paths:` glob is machine-validated before it is ever offered. Safety-class content (irreversible actions, secrets, data integrity, external publication, compliance, agent authority) is hard-denied from demotion and reported as held back rather than proposed, because demotion trades guaranteed presence for conditional presence and deferred surfaces are invisible inside subagents and absent after compaction until re-triggered. Every accepted move regenerates an always-loaded index of deferred surfaces, which is what keeps a demoted rule reachable from a subagent that never receives its injection. The audit is read-only and emits a diffable findings artifact; realignment is a separate skill gated per item with no blanket-approve path; a deterministic check skill gates that every rule glob still resolves and the index is current; and a setup skill verifies the one thing no other gate can see \u2014 that the index target is a file Claude Code will actually read, since it reads CLAUDE.md and not AGENTS.md.", "author": { "name": "Melodic Software", diff --git a/plugins/instruction-placement/CHANGELOG.md b/plugins/instruction-placement/CHANGELOG.md index acf66874af..5d98d3c4d7 100644 --- a/plugins/instruction-placement/CHANGELOG.md +++ b/plugins/instruction-placement/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to the `instruction-placement` plugin are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. +## [0.11.13] + +### Changed + +- **Behavior-preserving simplification sweep (batch-simplify).** `detect.sh` collapses the + manual `--` argument-capture loop into the marketplace's precedented `EXPLICIT+=("$@"); break` + form and drops a dead `SECTION_COUNT=0` initializer (the variable is unconditionally + reassigned before its only read). Emitted rows, exit codes, and `--help` text unchanged; + refutation-verified across 23 argv edge cases and the full 40-case suite. + ## [0.11.12] ### Changed diff --git a/plugins/instruction-placement/scripts/detect.sh b/plugins/instruction-placement/scripts/detect.sh index c7de311f01..670f27be9e 100755 --- a/plugins/instruction-placement/scripts/detect.sh +++ b/plugins/instruction-placement/scripts/detect.sh @@ -101,10 +101,8 @@ while [[ $# -gt 0 ]]; do ;; --) shift - while [[ $# -gt 0 ]]; do - EXPLICIT+=("$1") - shift - done + EXPLICIT+=("$@") + break ;; -*) die "unknown argument: $1" ;; *) @@ -223,7 +221,6 @@ fi # --------------------------------------------------------------------------- ROWS="$(mktemp)" trap 'rm -f "$SKIP_ROWS" "$ROWS"' EXIT -SECTION_COUNT=0 RULE_COUNT=0 emit_file_facts() { diff --git a/plugins/knowledge/.claude-plugin/plugin.json b/plugins/knowledge/.claude-plugin/plugin.json index 5b20fc5026..b3506c7032 100644 --- a/plugins/knowledge/.claude-plugin/plugin.json +++ b/plugins/knowledge/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "knowledge", - "version": "0.13.24", + "version": "0.13.25", "description": "Ingest external knowledge into durable, synthesized artifacts. Ships a book-distillation pipeline (PDF/EPUB into concept-organized, author-attributed skill reference files), a video-digest pipeline (watch a single public video from YouTube or X, formerly Twitter: transcript, link harvest, and repo-applicability synthesis), a course-digest pipeline (extract and synthesize online video courses \u2014 Dometrain, Teachable \u2014 into repo-applicable recommendations), a docpage-digest pipeline (single online documentation page into a verified knowledge slice with dual verification \u2014 one cross-vendor verifier \u2014 and an interview handoff), and a map-corpus pipeline (multi-resource corpus into a classified link map, deterministic node manifests, gate-verified relevance inventory, and an approved queue of docpage-digest runs), plus a re-runnable setup action; a configurable library directory governs where synthesized artifacts land in the consuming repo.", "author": { "name": "Melodic Software", diff --git a/plugins/knowledge/CHANGELOG.md b/plugins/knowledge/CHANGELOG.md index b254b547bd..0a2f2cc1c3 100644 --- a/plugins/knowledge/CHANGELOG.md +++ b/plugins/knowledge/CHANGELOG.md @@ -4,6 +4,25 @@ All notable changes to the `knowledge` plugin are recorded here. The `version` i `.claude-plugin/plugin.json` is the delivery vehicle — a consumer receives a change only after that version increases. +## [0.13.25] + +### Changed + +- **Behavior-preserving simplification sweep (batch-simplify).** `docpage-digest`'s + digest_fences.py removes dead `unclosed` bookkeeping from parse_claims: the flag was assigned on + both arms of the try and the trailing `if unclosed: fence = None` could never change the already + computed value. Refutation-verified (per-block flag scoping ruled out cross-iteration leakage; + 18/18 parse comparisons and 10/10 end-to-end gate runs byte-identical; both suites, 30 tests, OK). +- **video-digest extraction, same sweep.** setup-deps.mjs drops a redundant per-directory + localeCompare sort inside computeStamp's walk (the final code-unit path sort alone determines + hash-input order; stamps verified byte-identical on the real vendor tree and an adversarial + fixture, including under forced readdir scrambling). acquisition/build-yt-dlp-args.js removes + the born-dead export `YT_DLP_CAPTION_ONLY_SLEEP_SUBTITLES_SEC` (zero references at any commit; + the consumed constant lives in acquire-retry-policy.js). acquisition/acquire.js drops a + double-defaulting spread at the acquireFullStaged call site (the spread's withThrottle value was + by construction mergedDeps' own value or the same default the callee re-derives; full + case-matrix refutation including the null/undefined split found no divergent reachable shape). + ## [0.13.24] ### Fixed diff --git a/plugins/knowledge/skills/docpage-digest/scripts/digest_fences.py b/plugins/knowledge/skills/docpage-digest/scripts/digest_fences.py index a5e54e2d1d..e74630e294 100644 --- a/plugins/knowledge/skills/docpage-digest/scripts/digest_fences.py +++ b/plugins/knowledge/skills/docpage-digest/scripts/digest_fences.py @@ -190,17 +190,12 @@ def parse_claims(section_body: str, *, start_line: int = 1) -> List[Claim]: fences = extract_fences(block, start_line=block_start) except ValueError: fences = [] - unclosed = True - else: - unclosed = False fence = fences[0] if fences else None prose = block if not fences else block.split("```", 1)[0] # Forbidden carriers are defects even when a later fence is valid — # a leftover blockquote/inline quote is still hook-corruptible. has_bq = bool(re.search(r"(?m)^>", prose)) has_inline = bool(re.search(r"(? { - for (const entry of fs.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) { + for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { const abs = path.join(dir, entry.name); if (entry.isDirectory()) walk(abs); else files.push(path.relative(here, abs).split(path.sep).join("/")); diff --git a/plugins/machine-health/.claude-plugin/plugin.json b/plugins/machine-health/.claude-plugin/plugin.json index 3714f9d846..34942ad591 100644 --- a/plugins/machine-health/.claude-plugin/plugin.json +++ b/plugins/machine-health/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "machine-health", - "version": "0.11.14", + "version": "0.11.15", "description": "Workstation health audit: OS-specific checks (disk, OS updates, security posture, CISA KEV correlation) run from a versioned catalog with trend-aware severity, approval-gated remediations, and dated markdown reports. Windows fully implemented; macOS/Linux scaffolded (report UNKNOWN and stop). Machine state persists in the plugin data directory; the report directory and check catalog are configurable.", "author": { "name": "Melodic Software", diff --git a/plugins/machine-health/CHANGELOG.md b/plugins/machine-health/CHANGELOG.md index 23441b601c..8a86c49eeb 100644 --- a/plugins/machine-health/CHANGELOG.md +++ b/plugins/machine-health/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to the `machine-health` plugin are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. +## [0.11.15] + +### Changed + +- **`Clear-TempFiles.Tests.ps1` now parses check output through the shared helper.** The suite + inlined its own `($raw | Where-Object { $_ }) -join "`n" | ConvertFrom-Json` where sixteen sibling + suites already dot-source `tests/helpers/Invoke-CheckScript.ps1` and call `ConvertFrom-CheckOutput`. + The helper's body is that same expression, so the parse is unchanged; one copy of it disappears. + Test-only, no product behavior change. + ## [0.11.14] ### Changed diff --git a/plugins/machine-health/skills/audit/tests/windows/remediations/Clear-TempFiles.Tests.ps1 b/plugins/machine-health/skills/audit/tests/windows/remediations/Clear-TempFiles.Tests.ps1 index a9b1d85140..7146a19de4 100644 --- a/plugins/machine-health/skills/audit/tests/windows/remediations/Clear-TempFiles.Tests.ps1 +++ b/plugins/machine-health/skills/audit/tests/windows/remediations/Clear-TempFiles.Tests.ps1 @@ -25,6 +25,7 @@ BeforeAll { $script:TestsRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) $script:SkillRoot = Split-Path -Parent $script:TestsRoot $script:ScriptPath = Join-Path $script:SkillRoot 'scripts\windows\remediations\Clear-TempFiles.ps1' + . (Join-Path $script:TestsRoot 'helpers\Invoke-CheckScript.ps1') function New-MockTempFile { param( @@ -48,9 +49,7 @@ BeforeAll { function Invoke-ClearTempFilesAsObject { param([int]$AgeDays = 7) - $raw = & $script:ScriptPath -AgeDays $AgeDays - $json = ($raw | Where-Object { $_ }) -join "`n" - return $json | ConvertFrom-Json + return ConvertFrom-CheckOutput (& $script:ScriptPath -AgeDays $AgeDays) } } diff --git a/plugins/planning/.claude-plugin/plugin.json b/plugins/planning/.claude-plugin/plugin.json index be28a8bc8b..67055ad462 100644 --- a/plugins/planning/.claude-plugin/plugin.json +++ b/plugins/planning/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "planning", - "version": "0.34.14", + "version": "0.34.15", "userConfig": { "use_ask_user_question": { "type": "boolean", diff --git a/plugins/planning/CHANGELOG.md b/plugins/planning/CHANGELOG.md index 1024037f66..47a43da007 100644 --- a/plugins/planning/CHANGELOG.md +++ b/plugins/planning/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to the `planning` plugin are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. +## [0.34.15] + +### Changed + +- **Behavior-preserving simplification sweep (batch-simplify).** The `check-open-questions` and + `goal-condition-length` test suites collapse their hand-rolled inline `--help` exit-code + assertions into each suite's own `expect_exit` helper, which every other exit-code case + already uses. Passing-path stdout, case labels, and PASS/FAIL counts are byte-identical; + refutation-verified including mutated-subject detection-power checks; both suites pass via + affected-tests.sh. + ## [0.34.14] ### Changed diff --git a/plugins/planning/scripts/check-open-questions.test.sh b/plugins/planning/scripts/check-open-questions.test.sh index bd802a7723..15c759d8d1 100755 --- a/plugins/planning/scripts/check-open-questions.test.sh +++ b/plugins/planning/scripts/check-open-questions.test.sh @@ -55,7 +55,7 @@ expect_stdout() { } # 1. --help exits 0. -if bash "$SUT" --help >/dev/null 2>&1; then pass "--help exits 0"; else fail "--help should exit 0"; fi +expect_exit "--help exits 0" 0 --help # 2. --help prints the usage header, not a truncated fragment. expect_stdout "--help prints usage" "Usage:" --help diff --git a/plugins/planning/scripts/goal-condition-length.test.sh b/plugins/planning/scripts/goal-condition-length.test.sh index 6a32695ea4..2a32487685 100755 --- a/plugins/planning/scripts/goal-condition-length.test.sh +++ b/plugins/planning/scripts/goal-condition-length.test.sh @@ -31,7 +31,7 @@ expect_exit() { } # 1. --help exits 0. -if bash "$SUT" --help >/dev/null 2>&1; then pass "--help exits 0"; else fail "--help should exit 0"; fi +expect_exit "--help exits 0" 0 "" --help # 2. Under limit -> exit 0. expect_exit "under limit -> 0" 0 "hello" --limit 50 diff --git a/plugins/repo-hygiene/.claude-plugin/plugin.json b/plugins/repo-hygiene/.claude-plugin/plugin.json index 41423e4f81..7c1833f378 100644 --- a/plugins/repo-hygiene/.claude-plugin/plugin.json +++ b/plugins/repo-hygiene/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "repo-hygiene", - "version": "0.10.17", + "version": "0.10.18", "description": "Repo hygiene action-router: /repo-hygiene:clean sweeps reclaimable caches, build artifacts, and stale git metadata, and can realign the working tree to a fresh-pull state — dry-run-first, with destructive tiers gated behind explicit confirmation and a session-scoped destructive-command guard. Ecosystem targets are detected at runtime; secrets, runtime dependencies, and skill data are preserved by default.", "author": { "name": "Melodic Software", diff --git a/plugins/repo-hygiene/CHANGELOG.md b/plugins/repo-hygiene/CHANGELOG.md index 846fb2829e..785b6bebda 100644 --- a/plugins/repo-hygiene/CHANGELOG.md +++ b/plugins/repo-hygiene/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to the `repo-hygiene` plugin are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. +## [0.10.18] + +### Changed + +- **`scan.sh` stale-refs line no longer repeats its own label.** A two-branch `if` printed the + literal `Git stale refs dry-run:` in both arms; it is now one `echo` with `${STALE_REFS:-none}`, + matching the sentinel form the preceding worktree line already uses. The label can no longer drift + between branches. Output bytes and exit status are unchanged, and the documented contract line in + the file header still holds. + ## [0.10.17] ### Changed diff --git a/plugins/repo-hygiene/skills/clean/scripts/scan.sh b/plugins/repo-hygiene/skills/clean/scripts/scan.sh index 0f4ed41e01..9153a94073 100755 --- a/plugins/repo-hygiene/skills/clean/scripts/scan.sh +++ b/plugins/repo-hygiene/skills/clean/scripts/scan.sh @@ -87,11 +87,7 @@ done < <(clean_build_candidates "$REPO_ROOT") WT_COUNT="$(git worktree list 2>/dev/null | wc -l | tr -d ' ')" echo "Git worktrees: ${WT_COUNT:-0}" STALE_REFS="$(git remote prune origin --dry-run 2>/dev/null | head -5 | tr '\n' '; ')" -if [[ -n "$STALE_REFS" ]]; then - echo "Git stale refs dry-run: $STALE_REFS" -else - echo "Git stale refs dry-run: none" -fi +echo "Git stale refs dry-run: ${STALE_REFS:-none}" echo "Tier: git" printf 'Total reclaimable: %s\n' "$TOTAL_BYTES" diff --git a/plugins/source-control/.claude-plugin/plugin.json b/plugins/source-control/.claude-plugin/plugin.json index 84847b64e0..01e496a6a7 100644 --- a/plugins/source-control/.claude-plugin/plugin.json +++ b/plugins/source-control/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "source-control", - "version": "0.55.30", + "version": "0.55.31", "description": "Git and GitHub delivery workflow: /commit (Conventional Commits + Co-authored-by trailer via safe heredoc mechanics), /pull-request (prep, create, CI monitoring, review-comment triage, merge, CI-log fetch), /babysit-prs (self-pacing fleet loop \u2014 safe by default; opt-in worker/autopilot tiers add gate-checked merge and thread resolution behind a deterministic Python engine), /babysit-loop (the loop-lane merge lane: a standing or drain loop that invokes babysit-prs per cycle, configured through repo-scoped babysit_loop_* keys on the layered source-control.md seam, with merge authority human-only until the target repo's tracked config adopts the lane, a gate-proven C2-mechanical baseline once adopted, and standing merge-rung raises binding from the team-tracked layer only \u2014 with one named exception, where an invocation line explicitly typing both the autopilot tier keyword and the dedicated raise argument --merge c3-this-run widens that single invocation's merge authority up to C3 behind a fresh independent frontier-tier resolver, while C4-structural and C5-untrusted-provenance stay unconditionally human-merge), /worktree (create, status, cleanup, audit for parallel-session isolation), /setup (check the effective commit-subject / PR-title convention merged across its config layers and the babysit-prs config, or apply \u2014 interview the repo and write the convention config to a chosen layer), and /resolve-conflicts (intent-first merge/rebase conflict resolution with a semantic-conflict sweep \u2014 never --abort). The commit-subject / PR-title convention is configurable via a source-control.md config written by a re-runnable setup skill, layered across a ~/.claude user-global file, the tracked team file, and a gitignored .claude/source-control.local.md personal overlay merged per key; Conventional Commits is the default when no convention is declared.", "author": { "name": "Melodic Software", diff --git a/plugins/source-control/CHANGELOG.md b/plugins/source-control/CHANGELOG.md index 5d2e7bc1db..99613ab2c8 100644 --- a/plugins/source-control/CHANGELOG.md +++ b/plugins/source-control/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to the `source-control` plugin are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. +## [0.55.31] + +### Changed + +- **`resolve_self_logins` dedupes with one container instead of two.** The order-preserving + case-insensitive dedupe kept a result list alongside a `seen` set whose only job was to track keys + the result already implied; it is now the `dict.setdefault` form the sibling + `babysit_gh.resolve_authors` already uses for the same job. First-occurrence-wins and insertion + order are unchanged, and the two case-insensitive-dedupe sites in the engine now read alike. + ## [0.55.30] ### Fixed diff --git a/plugins/source-control/skills/babysit-prs/scripts/pr_queue_snapshot.py b/plugins/source-control/skills/babysit-prs/scripts/pr_queue_snapshot.py index 414a25298f..aff5ae0a4b 100755 --- a/plugins/source-control/skills/babysit-prs/scripts/pr_queue_snapshot.py +++ b/plugins/source-control/skills/babysit-prs/scripts/pr_queue_snapshot.py @@ -117,14 +117,10 @@ def resolve_self_logins(self_csv: str | None, extra_self_csv: str | None) -> lis self_login = gh.resolve_author("@me") if self_login: source.append(self_login) - resolved: list[str] = [] - seen: set[str] = set() + resolved: dict[str, str] = {} for login in source: - key = login.casefold() - if key not in seen: - seen.add(key) - resolved.append(login) - return resolved + resolved.setdefault(login.casefold(), login) + return list(resolved.values()) def resolve_scope_repos( diff --git a/plugins/work-items/.claude-plugin/plugin.json b/plugins/work-items/.claude-plugin/plugin.json index ac71499548..1b65cf4834 100644 --- a/plugins/work-items/.claude-plugin/plugin.json +++ b/plugins/work-items/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "work-items", - "version": "0.39.39", + "version": "0.39.40", "description": "Manages development work items through a provider-neutral tracker seam that ships with the plugin (bundled dispatcher plus github, local-markdown, jira, gitea, and linear adapters; seam plugin-dir canonical, adapters consumer-local-first): dashboard, taxonomy-labeled creation, a race-safe assignee-plus-lease claim protocol, recurring-schedule checks, TODO scanning, stale-lease auditing, plan decomposition into vertical-slice items, a macro-journey router over spec containers (rollup, per-container execution shape, next-step routing), raw-intake triage (issues and unsolicited PRs through raw, verified, briefed, autonomous-eligible states), plus the two work-items loop lanes of the loop-lane convention: a self-paced autonomous work-loop drain (work-class admission gate, adaptive item cap, PR-only) and an attended attend-queue escalation lane. The re-runnable setup skill binds the provider (.work-item-tracker.json), seeds the recurring-schedule seam (.github/recurring-schedule.json), and remaps canonical role labels.", "author": { "name": "Melodic Software", diff --git a/plugins/work-items/CHANGELOG.md b/plugins/work-items/CHANGELOG.md index dc66a71afa..a62d0eb628 100644 --- a/plugins/work-items/CHANGELOG.md +++ b/plugins/work-items/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to the `work-items` plugin are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. +## [0.39.40] + +### Changed + +- **Three small redundancies removed in the work-item tracker.** The linear adapter's seam-hint + comment carried a duplicated clause that inverted its own meaning, where every sibling adapter + carries the sentence intact; the local-markdown `common.test.sh` recomputed a script directory the + line above had already stored in `SCRIPT_DIR`; and `lib/lease.test.sh` spelled a fixture's + renewal timestamp as `BOUNDARY_EXPIRY - BOUNDARY_TTL * 3600`, which is the injected fixed clock by + construction. Comment, test-scaffolding, and fixture-arithmetic only; no adapter behavior changes. + ## [0.39.39] ### Fixed diff --git a/plugins/work-items/tools/work-item-tracker/adapters/linear/common.sh b/plugins/work-items/tools/work-item-tracker/adapters/linear/common.sh index a845bd790a..c550a063e1 100644 --- a/plugins/work-items/tools/work-item-tracker/adapters/linear/common.sh +++ b/plugins/work-items/tools/work-item-tracker/adapters/linear/common.sh @@ -42,9 +42,9 @@ wit_linear_require_seam_lib() { # The `shellcheck source=` hints name the RELATIVE seam path rather than /dev/null: # where a vendored or bundled seam sits there, ShellCheck follows it and every # WIT_ID_* / WIT_SCHEMA_VERSION reference in this adapter's verb scripts resolves. -# Where it does not (a consumer-local adapter beside no vendored seam), ShellCheck -# resolves. Where it does not, SC1091 is disabled so the absence is quiet rather than -# an info per source line — the runtime check above is what actually enforces presence. +# Where it does not (a consumer-local adapter beside no vendored seam), SC1091 is +# disabled so the absence is quiet rather than an info per source line — the runtime +# check above is what actually enforces presence. wit_linear_require_seam_lib "$WIT_LINEAR_SEAM_LIB/id.sh" # shellcheck source=../../lib/id.sh disable=SC1091 source "$WIT_LINEAR_SEAM_LIB/id.sh" diff --git a/plugins/work-items/tools/work-item-tracker/adapters/local-markdown/common.test.sh b/plugins/work-items/tools/work-item-tracker/adapters/local-markdown/common.test.sh index b9bdb8186c..b34d966d99 100755 --- a/plugins/work-items/tools/work-item-tracker/adapters/local-markdown/common.test.sh +++ b/plugins/work-items/tools/work-item-tracker/adapters/local-markdown/common.test.sh @@ -7,7 +7,7 @@ set -uo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../../tests/lib.sh" +source "$SCRIPT_DIR/../../tests/lib.sh" # shellcheck source=common.sh source "$SCRIPT_DIR/common.sh" diff --git a/plugins/work-items/tools/work-item-tracker/lib/lease.test.sh b/plugins/work-items/tools/work-item-tracker/lib/lease.test.sh index 9046eb40cd..bed367ebdc 100755 --- a/plugins/work-items/tools/work-item-tracker/lib/lease.test.sh +++ b/plugins/work-items/tools/work-item-tracker/lib/lease.test.sh @@ -48,7 +48,7 @@ if wit_lease_is_live "$SUPERSEDED" "$NOW"; then fail "superseded lease not live" FIXED_NOW=1783828800 # 2026-07-12T04:00:00Z BOUNDARY_TTL=1 BOUNDARY_EXPIRY=$((FIXED_NOW + BOUNDARY_TTL * 3600)) -BOUNDARY_RENEWED_ISO="$(date -u -d "@$((BOUNDARY_EXPIRY - BOUNDARY_TTL * 3600))" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -r "$((BOUNDARY_EXPIRY - BOUNDARY_TTL * 3600))" +%Y-%m-%dT%H:%M:%SZ)" # portability-ok: GNU-first, BSD fallback (#1510) +BOUNDARY_RENEWED_ISO="$(date -u -d "@$FIXED_NOW" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -r "$FIXED_NOW" +%Y-%m-%dT%H:%M:%SZ)" # portability-ok: GNU-first, BSD fallback (#1510) BOUNDARY_LEASE="$(jq -cn --arg t "$BOUNDARY_RENEWED_ISO" --argjson ttl "$BOUNDARY_TTL" '{renewed_at:$t, ttl_hours:$ttl}')" if wit_lease_is_live "$BOUNDARY_LEASE" "$((BOUNDARY_EXPIRY - 1))"; then pass "boundary: expiry-1s is live"; else fail "boundary: expiry-1s is live" "live" "not live"; fi if wit_lease_is_live "$BOUNDARY_LEASE" "$BOUNDARY_EXPIRY"; then fail "boundary: exact expiry is dead" "not live" "live"; else pass "boundary: exact expiry is dead"; fi diff --git a/scripts/check-fleet-finding-test-coverage.sh b/scripts/check-fleet-finding-test-coverage.sh index 6a2ff740d5..4416da74ec 100755 --- a/scripts/check-fleet-finding-test-coverage.sh +++ b/scripts/check-fleet-finding-test-coverage.sh @@ -49,9 +49,8 @@ if [[ ! -f "$TEST" ]]; then fi emitted_tmp="$(mktemp)" -missing_tmp="$(mktemp)" baseline_tmp="$(mktemp)" -trap 'rm -f "$emitted_tmp" "$missing_tmp" "$baseline_tmp"' EXIT +trap 'rm -f "$emitted_tmp" "$baseline_tmp"' EXIT # Skip comment lines: prose in the collector names kinds while explaining them. grep -vE "^[[:space:]]*#" "$SCRIPT" | grep -oE "emit_finding [A-Z]+ [a-z-]+" | @@ -71,13 +70,6 @@ kind_asserted() { grep -Eq -- "Finding: ${kind}([^a-z-]|$)" "$TEST" } -while IFS= read -r kind; do - [[ -n "$kind" ]] || continue - if ! kind_asserted "$kind"; then - printf '%s\n' "$kind" >>"$missing_tmp" - fi -done <"$emitted_tmp" - declare -A baselined=() if [[ -f "$BASELINE" ]]; then while IFS= read -r line; do @@ -108,11 +100,11 @@ errors=0 while IFS= read -r kind; do [[ -n "$kind" ]] || continue - if [[ -z "${baselined[$kind]+x}" ]]; then + if ! kind_asserted "$kind" && [[ -z "${baselined[$kind]+x}" ]]; then echo "UNCOVERED FINDING KIND: $kind (emitted by $SCRIPT, no Finding: assertion in $TEST)" >&2 errors=$((errors + 1)) fi -done <"$missing_tmp" +done <"$emitted_tmp" # Stale baseline: entry no longer shadows a missing kind (either covered now, or # no longer emitted).