diff --git a/plugins/ai-slop/.claude-plugin/plugin.json b/plugins/ai-slop/.claude-plugin/plugin.json index 93f817e50..a4bf25024 100644 --- a/plugins/ai-slop/.claude-plugin/plugin.json +++ b/plugins/ai-slop/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "ai-slop", - "version": "0.5.4", + "version": "0.5.5", "description": "Detects and removes AI-writing tells (slop) in checked-in markdown prose: em dashes, emoji formatting, AI vocabulary, negative parallelisms, chatbot phrases, filler, stacked hedging, citation artifacts, model-era phrases, and the rest of a catalog distilled from Wikipedia's Signs of AI writing plus a repo-owned, evidence-graded inventory of current-generation model vocabulary. Read-only audit by default with a deterministic detector plus a judgment rubric; an explicit fix action rewrites findings behind a semantic-diff guard. Findings conform to the detector-findings convention so the review fanout fix relay can consume them.", "author": { "name": "Melodic Software", diff --git a/plugins/ai-slop/CHANGELOG.md b/plugins/ai-slop/CHANGELOG.md index 32b3e808f..a59510299 100644 --- a/plugins/ai-slop/CHANGELOG.md +++ b/plugins/ai-slop/CHANGELOG.md @@ -1,5 +1,52 @@ # Changelog +## [0.5.5] + +### Fixed + +- **`audit`: the `detector unavailable` token fired on a healthy detector, from any directory, with + no configuration required.** 0.5.4 gave the effective-config probe a guard, + `detect.sh --show-config >/dev/null 2>&1 && detect.sh --show-config 2>/dev/null | head -8 || echo + "detector unavailable"`. Under `set -o pipefail` the `&&` list takes the pipeline's exit status, + and `detect.sh --show-config` emits 10 lines against a `head -8` cap while writing them one at a + time, so `head` closes the pipe mid-run every time and the script dies of SIGPIPE. Measured here: + `PIPESTATUS` is `141 0`. The probe rendered the full, correct eight-line config and then appended + `detector unavailable` under it. This was not latent and not a corner case: it was the observed + behaviour of the shipped line in this repository, and unlike 0.5.4's defect it does not render an + empty value, it asserts a failure that did not happen. + + Reproduced and fixed by execution in three states, each with and without `pipefail`. Skill + directory absent: both shapes render `detector unavailable` under both settings. A two-line + detector (under the cap): both shapes render the two lines, no token, under both settings. The + real detector (10 lines, over the cap): without `pipefail` both render eight lines and no token; + with `pipefail` the 0.5.4 shape renders nine lines, the ninth being `detector unavailable`, and + this one renders eight lines and no token. + + The filter pipeline now sits in a brace group closed by `:`, a command that cannot fail, so the + `||` is reachable only by the guard short-circuiting. This is the shape `docs-hygiene` 0.21.23 and + `code-tidying` 0.14.13 established; the fleet gains no new idiom. No `$` expansion is introduced, + so the composed pre-compute block stays verifiable to the worktree-isolation guard, and the + command still begins `${CLAUDE_SKILL_DIR}/scripts/detect.sh`, so the existing + `Bash(${CLAUDE_SKILL_DIR}/scripts/detect.sh:*)` grant still matches its leading token. + +- **`audit`: the effective-config probe broke on any install path containing a space.** + Pre-existing, not introduced by the fix above, but the fix is what makes it visible: the + expansion was unquoted, so an install under a path with a space in it (a Windows profile + directory named ``, a macOS `Application Support` tree) word-split into two + arguments, the script was never found, and the guard short-circuited. Before this release that + rendered an empty line; now it renders `detector unavailable` on a detector that is present and + working. Reproduced by copying the real `detect.sh` into a directory whose name contains a + space: unquoted renders `detector unavailable`, quoted renders the full config, and on a + space-free path both render it. Both the guard run and the data run are now quoted, matching the + form `firecrawl:update` already ships. + + Quoting changes the literal command string, and Bash permission rules are globs over that literal + string, so `Bash(${CLAUDE_SKILL_DIR}/scripts/detect.sh:*)` no longer matches the quoted + invocation. A companion rule `Bash("${CLAUDE_SKILL_DIR}/scripts/detect.sh":*)` is added for it. + The existing unquoted rule is kept, because the skill body's own instructions still invoke the + script unquoted. Both rules name the same script under the same `${CLAUDE_SKILL_DIR}` anchor and + carry the same `:*` argument scope, so this authorizes nothing the plugin could not already run. + ## [0.5.4] ### Fixed diff --git a/plugins/ai-slop/skills/audit/SKILL.md b/plugins/ai-slop/skills/audit/SKILL.md index b2fe31228..d2f56fda6 100644 --- a/plugins/ai-slop/skills/audit/SKILL.md +++ b/plugins/ai-slop/skills/audit/SKILL.md @@ -3,7 +3,7 @@ description: "Audit markdown prose for AI-writing tells (slop): em dashes (zero- argument-hint: "[audit|fix] [target]" user-invocable: true disable-model-invocation: false -allowed-tools: ["Bash(${CLAUDE_SKILL_DIR}/scripts/detect.sh:*)", "Bash(${CLAUDE_SKILL_DIR}/scripts/emit-findings.sh:*)", "Bash(git:*)", "Bash(grep:*)", "Bash(head:*)", "Bash(wc:*)"] +allowed-tools: ["Bash(${CLAUDE_SKILL_DIR}/scripts/detect.sh:*)", "Bash(\"${CLAUDE_SKILL_DIR}/scripts/detect.sh\":*)", "Bash(${CLAUDE_SKILL_DIR}/scripts/emit-findings.sh:*)", "Bash(git:*)", "Bash(grep:*)", "Bash(head:*)", "Bash(wc:*)"] shell: bash metadata: workflow-stage: anytime @@ -13,7 +13,7 @@ metadata: ## Pre-computed context Current branch: !`git branch --show-current 2>/dev/null || echo "unknown"` -Effective config: !`${CLAUDE_SKILL_DIR}/scripts/detect.sh --show-config >/dev/null 2>&1 && ${CLAUDE_SKILL_DIR}/scripts/detect.sh --show-config 2>/dev/null | head -8 || echo "detector unavailable"` +Effective config: !`"${CLAUDE_SKILL_DIR}/scripts/detect.sh" --show-config >/dev/null 2>&1 && { "${CLAUDE_SKILL_DIR}/scripts/detect.sh" --show-config 2>/dev/null | head -8; :; } || echo "detector unavailable"` ## Purpose diff --git a/plugins/code-tidying/.claude-plugin/plugin.json b/plugins/code-tidying/.claude-plugin/plugin.json index 27462466c..66403f0d3 100644 --- a/plugins/code-tidying/.claude-plugin/plugin.json +++ b/plugins/code-tidying/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "code-tidying", - "version": "0.14.13", + "version": "0.14.14", "description": "Code tidying and comment hygiene: /code-tidying:tidy proactively hunts a rotated, glob-scoped lane for Beck-style tidyings under a research-backed scope budget and ships one tight PR; /code-tidying:batch-simplify sweeps a time window, a branch, or an entire repository through grouped, dependency-ordered simplification waves with a never-drop deferred-items contract; /code-tidying:dissolve-comments enforces self-describing expressive code over a diff or target, widening to the branch diff and then the whole repository when the tree is clean — deletes zero-information comments, dissolves code-expressible ones into names and structure behind a tests gate (safe mode restricts applied edits to removals), and keeps only terse load-bearing comments code cannot express; /code-tidying:audit-comment-residue is a read-only classifier that flags history, plan, conversational, and ticket/PR residue in code comments for author-applied deletion; /code-tidying:audit-dead-code is a read-only whole-repo dead-code hunter running four labelled lanes of unequal confidence (knip for TS/JS, vulture for Python, gopls for Go, and a portable grep lane for shell and other symbol languages), adjudicating every candidate against dynamic-usage evidence into a dead, uncertain, or alive verdict. Project-specific tidy lanes are scaffolded into a tracked .claude/tidy-lanes/ config folder by a re-runnable setup skill.", "author": { "name": "Melodic Software", diff --git a/plugins/code-tidying/CHANGELOG.md b/plugins/code-tidying/CHANGELOG.md index 8f6060bdf..713cae362 100644 --- a/plugins/code-tidying/CHANGELOG.md +++ b/plugins/code-tidying/CHANGELOG.md @@ -3,6 +3,27 @@ All notable changes to the `code-tidying` plugin are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. +## [0.14.14] + +### Fixed + +- **`tidy`: a stray third `unknown` line in the throttle probe under pipefail.** Cosmetic, not a + false failure claim. `open-pr-count.sh` exits 1 while printing well-formed output when `gh` cannot + reach the API, and the probe was + `open-pr-count.sh 2>/dev/null | grep -E '^(Open tidy|Throttle)' || echo "unknown"`. Without + `pipefail` the pipeline's status is `grep`'s, which is 0 when it matches, and the `||` stays shut. + With `pipefail` the script's 1 becomes the pipeline's status and `unknown` is appended beneath the + two well-formed lines, garbling a block that already carries its own `unknown` values. Reproduced + and fixed by execution: with the real script under `pipefail` the old shape renders three lines, + the third a bare `unknown`, and the new one renders two. + + The `||` moves inside a brace group on the `grep` end of the pipe, so it is driven by the filter's + status alone and the script's exit code no longer reaches it. The token still fires when the + script is missing entirely, which is the case it exists for, verified under both settings. This + form was chosen over the brace-group-first shape used elsewhere precisely to keep the leading + token unchanged: the command still begins `${CLAUDE_SKILL_DIR}/scripts/open-pr-count.sh`, so the + existing grant still matches it and no rule was added or widened. + ## [0.14.13] ### Fixed diff --git a/plugins/code-tidying/skills/tidy/SKILL.md b/plugins/code-tidying/skills/tidy/SKILL.md index 0b9094971..fe4a2a361 100644 --- a/plugins/code-tidying/skills/tidy/SKILL.md +++ b/plugins/code-tidying/skills/tidy/SKILL.md @@ -15,7 +15,7 @@ metadata: Current branch: !`git branch --show-current 2>/dev/null || echo "unknown"` Recent commits: !`git log --oneline -5 2>/dev/null || echo "no commits"` Working tree status (empty = clean): !`{ git status --porcelain 2>/dev/null || echo "(git status unavailable)"; } | head -20` -Open chore/tidy-* PRs: !`${CLAUDE_SKILL_DIR}/scripts/open-pr-count.sh 2>/dev/null | grep -E '^(Open tidy|Throttle)' || echo "unknown"` +Open chore/tidy-* PRs: !`${CLAUDE_SKILL_DIR}/scripts/open-pr-count.sh 2>/dev/null | { grep -E '^(Open tidy|Throttle)' || echo "unknown"; }; :` ## Variables diff --git a/plugins/docs-hygiene/.claude-plugin/plugin.json b/plugins/docs-hygiene/.claude-plugin/plugin.json index 3af70c841..fe25ce525 100644 --- a/plugins/docs-hygiene/.claude-plugin/plugin.json +++ b/plugins/docs-hygiene/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "docs-hygiene", - "version": "0.21.25", + "version": "0.21.26", "description": "Documentation-hygiene toolkit: compress (flavor-trim markdown with a semantic-diff safety net), audit-noise (classify markdown noise), extract-ssot (deduplicate repeated content into a single source of truth), audit-encapsulation (detect citations into skill-private surfaces), rename-references (sweep stale references after renames), audit-derivability (classify whether a whole document earns its existence \u2014 could a fresh agent re-derive it from the code?), audit-progressive-disclosure (grade instruction files against a load-tier model for split opportunities and hub/spoke disclosure defects), write-for-agents (authoring-time doctrine that fires while agent-consumed markdown is being written), and write-for-humans (the same moment for the other reader \u2014 end-user READMEs, RFCs, release notes and guides \u2014 resolving the consuming project's own style guide first).", "author": { "name": "Melodic Software", diff --git a/plugins/docs-hygiene/CHANGELOG.md b/plugins/docs-hygiene/CHANGELOG.md index 5e1b5f8e7..4feb861f9 100644 --- a/plugins/docs-hygiene/CHANGELOG.md +++ b/plugins/docs-hygiene/CHANGELOG.md @@ -1,5 +1,28 @@ # Changelog — docs-hygiene plugin +## [0.21.26] + +### Fixed + +- **`audit-derivability`: the sixth filtered probe, missed when the other five were fixed.** 0.21.23 + made five filtered-probe injections pipefail-proof and left this one, on the reading that its + capture-first shape was already safe. Only half of it is. The capture, + `s=$(git status --porcelain 2>/dev/null) && …`, does carry git's own exit status outside any + pipeline, so a genuinely unavailable `git` is still detected. But the data run that follows is + `printf … | awk … | head -20`, an ordinary pipeline, and `head` closing the pipe at the cap kills + `awk` with SIGPIPE. Under `set -o pipefail` that becomes the `&&` list's status and fires + `(status unavailable)` on a healthy git. + + Reachable at 21 or more dirty `.md` files. Reproduced on a repository with 3,000 of them: without + `pipefail` the probe renders 20 paths; with `pipefail` it renders 21 lines, the twenty-first + being `(status unavailable)` printed under a correct listing. After the fix it renders 20 paths + under both settings, and outside a git repository it still renders `(status unavailable)` under + both, which is the case the token exists for. + + Only the data pipeline moves into the brace group closed by `:`; the `$s` capture stays where it + is, because that is the part that legitimately drives the `||`. The five sites 0.21.23 fixed were + re-verified at 3,000 dirty files under both settings and are correct as shipped. + ## [0.21.25] ### Added diff --git a/plugins/docs-hygiene/skills/audit-derivability/SKILL.md b/plugins/docs-hygiene/skills/audit-derivability/SKILL.md index cef77e297..2158bebb5 100644 --- a/plugins/docs-hygiene/skills/audit-derivability/SKILL.md +++ b/plugins/docs-hygiene/skills/audit-derivability/SKILL.md @@ -12,7 +12,7 @@ metadata: ## Pre-computed context Current branch: !`git branch --show-current 2>/dev/null || echo "unknown"` -Uncommitted .md files (first 20; empty = none): !`s=$(git status --porcelain 2>/dev/null) && printf '%s\n' "$s" | awk '/\.md$/{p=substr($0,4); sub(/^.* -> /,"",p); print p}' | head -20 || echo "(status unavailable)"` +Uncommitted .md files (first 20; empty = none): !`s=$(git status --porcelain 2>/dev/null) && { printf '%s\n' "$s" | awk '/\.md$/{p=substr($0,4); sub(/^.* -> /,"",p); print p}' | head -20; :; } || echo "(status unavailable)"` ## Purpose diff --git a/plugins/firecrawl/.claude-plugin/plugin.json b/plugins/firecrawl/.claude-plugin/plugin.json index 2bb6abed2..698239a2c 100644 --- a/plugins/firecrawl/.claude-plugin/plugin.json +++ b/plugins/firecrawl/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "firecrawl", - "version": "0.5.6", + "version": "0.5.7", "description": "Web scraping, search, crawling, and file parsing through the firecrawl-cli binary with a write-to-disk-then-Read pattern that keeps large results out of context — a user-facing wrapper skill, a lazy-install setup skill, and a separate gated maintainer update skill tracking the upstream CLI and skill source.", "author": { "name": "Melodic Software", diff --git a/plugins/firecrawl/CHANGELOG.md b/plugins/firecrawl/CHANGELOG.md index 5ad077464..97fb0966d 100644 --- a/plugins/firecrawl/CHANGELOG.md +++ b/plugins/firecrawl/CHANGELOG.md @@ -3,6 +3,34 @@ All notable changes to the `firecrawl` plugin are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this plugin uses semantic versioning. +## [0.5.7] + +### Fixed + +- **`firecrawl`: the `NOT INSTALLED` token could fire on an installed, working CLI.** The status + probe was + `command -v firecrawl >/dev/null 2>&1 && firecrawl --status 2>/dev/null | head -10 || echo "NOT + INSTALLED — run: npm install -g firecrawl-cli"`. Under `set -o pipefail` the `&&` list takes the + pipeline's status, and `head -10` closing the pipe kills `firecrawl` with SIGPIPE when + `--status` prints more than the cap, so the `||` fires on a healthy CLI. The rendered context + then shows ten lines of real status followed by an instruction to install a CLI that is already + installed, and the paragraph beneath it tells the reader to go get an API key. + + This site predates the guard sweep that introduced the same defect elsewhere: it is where the + guard-first shape was copied FROM, so it was never touched by that sweep and has carried the + exposure since it was written. Fixed in the same pass as the sites that copied it. + + Proven by execution in three states, each with and without `pipefail`, against a fake `firecrawl` + on `PATH`. Absent: both shapes render `NOT INSTALLED …` under both settings. Present, output under + the cap: both render the output, no token, under both settings. Present, output over the cap: + without `pipefail` both render ten lines and no token; with `pipefail` the old shape renders ten + lines **and** `NOT INSTALLED — run: npm install -g firecrawl-cli`, and this one renders the ten + lines alone. + + The data pipeline now sits in a brace group closed by `:`, the shape `docs-hygiene` 0.21.23 and + `code-tidying` 0.14.13 established. The command still begins `command -v firecrawl`, so the + existing `Bash(command -v firecrawl*)` grant still matches. No grant changed. + ## [0.5.6] ### Fixed diff --git a/plugins/firecrawl/skills/firecrawl/SKILL.md b/plugins/firecrawl/skills/firecrawl/SKILL.md index c3ba28571..b09d687f5 100644 --- a/plugins/firecrawl/skills/firecrawl/SKILL.md +++ b/plugins/firecrawl/skills/firecrawl/SKILL.md @@ -12,7 +12,7 @@ metadata: ## Pre-computed context -Status: !`command -v firecrawl >/dev/null 2>&1 && firecrawl --status 2>/dev/null | head -10 || echo "NOT INSTALLED — run: npm install -g firecrawl-cli"` +Status: !`command -v firecrawl >/dev/null 2>&1 && { firecrawl --status 2>/dev/null | head -10; :; } || echo "NOT INSTALLED — run: npm install -g firecrawl-cli"` The `firecrawl --status` line above includes auth state. If it shows unauthenticated (or the CLI is missing), the fix is: obtain a key from the dashboard and set `FIRECRAWL_API_KEY` as an OS user environment variable. diff --git a/plugins/knowledge/.claude-plugin/plugin.json b/plugins/knowledge/.claude-plugin/plugin.json index ffa2fec40..5b20fc502 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.23", + "version": "0.13.24", "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 9547951f3..b254b547b 100644 --- a/plugins/knowledge/CHANGELOG.md +++ b/plugins/knowledge/CHANGELOG.md @@ -4,6 +4,55 @@ 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.24] + +### Fixed + +- **`video-digest` and `course-digest`: the prerequisites gate would refuse to run on a machine that + HAS the toolchain.** 0.13.23 fixed a gate that failed open and left one that fails closed for the + wrong reason. The five tool probes were + `command -v ffmpeg >/dev/null 2>&1 && ffmpeg -version 2>/dev/null | head -1 || echo "MISSING …"`. + Under `set -o pipefail` the `&&` list takes the pipeline's exit status, and `head -1` closes the + pipe while a multi-line version banner is still being written, so `ffmpeg` dies of SIGPIPE (exit + 141) and pipefail promotes that to the list's status. The `||` then fires on a working tool. The + rendered context shows the real version line and `MISSING — install ffmpeg` directly beneath it. + + That is not cosmetic. Both skills instruct the agent to STOP when the pre-computed context shows + `MISSING` for yt-dlp, ffmpeg, or ImageMagick. On a correctly provisioned machine the context now + shows `MISSING`, so the skill refuses to run against a toolchain that is installed and working. + 0.13.23 turned a gate that failed open into one that spuriously fails closed. The direction is + safer, the behaviour is still wrong. + + The five probes are not equally exposed, and the difference matters for diagnosis. Whether the + token fires is a race between the tool still writing its banner and `head -1` closing the pipe, + so it scales with how much the tool prints. Measured over 30 runs per size against a synthetic + tool on `PATH`, under `pipefail`, with the tool installed and working: + + | Tool output | 0.13.23 shape fires `MISSING` | This shape | + |---|---|---| + | 1 line (`yt-dlp --version`) | 0/30 | 0/30 | + | 5 lines (`magick -version`) | 19/30 | 0/30 | + | 41 lines (`ffmpeg -version`) | 29/30 | 0/30 | + + So `yt-dlp` is safe by output size alone, `ffmpeg` fails on nearly every run, and `magick` is a + genuine race that fails on roughly two runs in three. The intermittent one is the worst to live + with: a gate that stops the skill on most invocations and lets it through on the rest reads as + flakiness in the skill rather than as a defect in the probe. All five are fixed together, because + the shape is wrong regardless of how often it trips. + + Proven by execution in three states, each with and without `pipefail`. Tool absent: both shapes + render `MISSING …` under both settings. Tool present, single-line output: both shapes render the + version, no token, under both settings. Tool present, banner long enough to close the pipe: + without `pipefail` both render one version line and no token; with `pipefail` the 0.13.23 shape + renders the version line **and** `MISSING — install ffmpeg (watch action only)`, and this one + renders the version line alone. + + The version pipeline now sits in a brace group closed by `:`, a command that cannot fail, so the + `||` is reachable only when `command -v` short-circuits. This is the shape `docs-hygiene` 0.21.23 + and `code-tidying` 0.14.13 established. No `$` expansion is introduced, so the composed + pre-compute block stays verifiable to the worktree-isolation guard. Neither skill declares + `allowed-tools`, so no grant changed. + ## [0.13.23] ### Fixed diff --git a/plugins/knowledge/skills/course-digest/SKILL.md b/plugins/knowledge/skills/course-digest/SKILL.md index 1c68afb88..cfa36da4c 100644 --- a/plugins/knowledge/skills/course-digest/SKILL.md +++ b/plugins/knowledge/skills/course-digest/SKILL.md @@ -10,8 +10,8 @@ shell: bash course-extraction deps: !`node -e "const fs=require('fs'),path=require('path'),p=process.env.CLAUDE_PLUGIN_DATA;process.stdout.write(p&&fs.existsSync(path.join(p,'node_modules','@melodic','video-digestion'))?'installed':'MISSING - run setup-deps.mjs (see Prerequisites)')"` Playwright Chromium: !`node -e "const fs=require('fs'),path=require('path');const b=process.env.PLAYWRIGHT_BROWSERS_PATH||(process.env.CLAUDE_PLUGIN_DATA&&path.join(process.env.CLAUDE_PLUGIN_DATA,'ms-playwright'));const ok=b&&fs.existsSync(b)&&fs.readdirSync(b).some(n=>n.startsWith('chromium'));process.stdout.write(ok?'installed':'MISSING - run setup-deps.mjs (see Prerequisites)')"` -ffmpeg: !`command -v ffmpeg >/dev/null 2>&1 && ffmpeg -version 2>/dev/null | head -1 || echo "MISSING — install ffmpeg (see Prerequisites)"` -ImageMagick: !`command -v magick >/dev/null 2>&1 && magick -version 2>/dev/null | head -1 || echo "MISSING — install ImageMagick 7 (see Prerequisites)"` +ffmpeg: !`command -v ffmpeg >/dev/null 2>&1 && { ffmpeg -version 2>/dev/null | head -1; :; } || echo "MISSING — install ffmpeg (see Prerequisites)"` +ImageMagick: !`command -v magick >/dev/null 2>&1 && { magick -version 2>/dev/null | head -1; :; } || echo "MISSING — install ImageMagick 7 (see Prerequisites)"` # Course Digest diff --git a/plugins/knowledge/skills/video-digest/SKILL.md b/plugins/knowledge/skills/video-digest/SKILL.md index a5ea8012d..1407fa461 100644 --- a/plugins/knowledge/skills/video-digest/SKILL.md +++ b/plugins/knowledge/skills/video-digest/SKILL.md @@ -9,9 +9,9 @@ shell: bash ## Pre-computed context video-extraction deps: !`node -e "const fs=require('fs'),path=require('path'),p=process.env.CLAUDE_PLUGIN_DATA;process.stdout.write(p&&fs.existsSync(path.join(p,'node_modules','@melodic','video-digestion'))?'installed':'MISSING - run setup-deps.mjs (see Prerequisites)')"` -yt-dlp: !`command -v yt-dlp >/dev/null 2>&1 && yt-dlp --version 2>/dev/null | head -1 || echo "MISSING — install yt-dlp (see Prerequisites)"` -ffmpeg: !`command -v ffmpeg >/dev/null 2>&1 && ffmpeg -version 2>/dev/null | head -1 || echo "MISSING — install ffmpeg (watch action only)"` -ImageMagick: !`command -v magick >/dev/null 2>&1 && magick -version 2>/dev/null | head -1 || echo "MISSING — install ImageMagick 7 (watch action only)"` +yt-dlp: !`command -v yt-dlp >/dev/null 2>&1 && { yt-dlp --version 2>/dev/null | head -1; :; } || echo "MISSING — install yt-dlp (see Prerequisites)"` +ffmpeg: !`command -v ffmpeg >/dev/null 2>&1 && { ffmpeg -version 2>/dev/null | head -1; :; } || echo "MISSING — install ffmpeg (watch action only)"` +ImageMagick: !`command -v magick >/dev/null 2>&1 && { magick -version 2>/dev/null | head -1; :; } || echo "MISSING — install ImageMagick 7 (watch action only)"` # Video digest. YouTube and X diff --git a/plugins/provenance/.claude-plugin/plugin.json b/plugins/provenance/.claude-plugin/plugin.json index 0c44fc82f..57bceb421 100644 --- a/plugins/provenance/.claude-plugin/plugin.json +++ b/plugins/provenance/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json", "name": "provenance", - "version": "0.4.0", + "version": "0.4.1", "description": "Finds prose in tracked markdown that restates content an external source owns (vendor docs, blogs, articles) without adequate attribution, confirms the source, and refactors the copy into a pointer, a citation, or a dated stamped record. Documentation provenance, not software supply chain. Nomination and judgment are LLM work; the scripts do only reasoning-free work (corpus scoping, breadcrumb extraction, stamp expiry, fingerprint compare of two concrete texts). Read-only audit by default; explicit fix and sweep actions apply dispositions behind a semantic-diff guard and live pointer verification. Findings conform to the detector-findings convention.", "author": { "name": "Melodic Software", diff --git a/plugins/provenance/CHANGELOG.md b/plugins/provenance/CHANGELOG.md index 6dd28269b..00f24634e 100644 --- a/plugins/provenance/CHANGELOG.md +++ b/plugins/provenance/CHANGELOG.md @@ -1,5 +1,40 @@ # Changelog +## [0.4.1] + +### Fixed + +- **`audit`: the two config probes broke on any install path containing a space.** Both expansions + were unquoted, so an install under a path with a space in it (a Windows profile directory named + ``, a macOS `Application Support` tree) word-split into two arguments, the script was + never found, and the guard short-circuited to `detector unavailable` on scripts that are present + and working. Reproduced by copying a detector into a directory whose name contains a space: + unquoted renders `detector unavailable`, quoted renders the config, and on a space-free path both + render it. Both the guard run and the data run are quoted now, matching the form + `firecrawl:update` already ships. + + Quoting changes the literal command string, and Bash permission rules are globs over that literal + string, so the existing `Bash(${CLAUDE_SKILL_DIR}/scripts/list-corpus.sh:*)` and + `Bash(${CLAUDE_SKILL_DIR}/scripts/check-stamps.sh:*)` rules no longer match the quoted + invocations. A companion quoted rule is added for each. The unquoted rules are kept, because the + audit flow's own steps 1 and 3 still invoke both scripts unquoted. Each pair names one script + under the same `${CLAUDE_SKILL_DIR}` anchor with the same `:*` argument scope, so this authorizes + nothing the plugin could not already run. + +### Changed + +- **Both config probes adopt the pipefail-proof filtered-probe shape, on shape rather than on an + observed failure.** `list-corpus.sh --show-config` emits 7 lines against a `head -10` cap, so + `head` never closes the pipe early, and `check-stamps.sh --show-config` is piped into `tail -3`, + which drains its input and cannot raise SIGPIPE at all. Both were verified by execution in three + states under both `pipefail` settings and neither showed any difference: **these were latent by + shape, not live defects, and nothing observable is fixed here.** The change is that a later + `--show-config` growing past ten lines would silently start asserting `detector unavailable` + under a correct detector, which is exactly what happened to `ai-slop:audit`. Confirmed by + substituting a 500-line detector: the old shape renders 10 lines plus the token under `pipefail`, + the new one renders 10 lines. The filter pipelines now sit in a brace group closed by `:`, the + shape `docs-hygiene` 0.21.23 and `code-tidying` 0.14.13 established. + ## [0.4.0] ### Changed diff --git a/plugins/provenance/skills/audit/SKILL.md b/plugins/provenance/skills/audit/SKILL.md index e5214bd85..ca2a9cca9 100644 --- a/plugins/provenance/skills/audit/SKILL.md +++ b/plugins/provenance/skills/audit/SKILL.md @@ -3,7 +3,7 @@ description: "Audit tracked markdown for prose restating content an external sou argument-hint: "[audit|fix|sweep] [target]" user-invocable: true disable-model-invocation: false -allowed-tools: ["Bash(${CLAUDE_SKILL_DIR}/scripts/list-corpus.sh:*)", "Bash(${CLAUDE_SKILL_DIR}/scripts/extract-breadcrumbs.sh:*)", "Bash(${CLAUDE_SKILL_DIR}/scripts/check-stamps.sh:*)", "Bash(${CLAUDE_SKILL_DIR}/scripts/emit-findings.sh:*)", "Bash(${CLAUDE_SKILL_DIR}/scripts/score-golden.sh:*)", "Bash(node ${CLAUDE_SKILL_DIR}/scripts/fingerprint.mjs:*)", "Bash(git:*)", "Bash(jq:*)", "Bash(grep:*)", "Bash(head:*)", "Bash(wc:*)"] +allowed-tools: ["Bash(${CLAUDE_SKILL_DIR}/scripts/list-corpus.sh:*)", "Bash(\"${CLAUDE_SKILL_DIR}/scripts/list-corpus.sh\":*)", "Bash(${CLAUDE_SKILL_DIR}/scripts/extract-breadcrumbs.sh:*)", "Bash(${CLAUDE_SKILL_DIR}/scripts/check-stamps.sh:*)", "Bash(\"${CLAUDE_SKILL_DIR}/scripts/check-stamps.sh\":*)", "Bash(${CLAUDE_SKILL_DIR}/scripts/emit-findings.sh:*)", "Bash(${CLAUDE_SKILL_DIR}/scripts/score-golden.sh:*)", "Bash(node ${CLAUDE_SKILL_DIR}/scripts/fingerprint.mjs:*)", "Bash(git:*)", "Bash(jq:*)", "Bash(grep:*)", "Bash(head:*)", "Bash(wc:*)"] shell: bash metadata: workflow-stage: anytime @@ -13,8 +13,8 @@ metadata: ## Pre-computed context Current branch: !`git branch --show-current 2>/dev/null || echo "unknown"` -Effective config: !`${CLAUDE_SKILL_DIR}/scripts/list-corpus.sh --show-config >/dev/null 2>&1 && ${CLAUDE_SKILL_DIR}/scripts/list-corpus.sh --show-config 2>/dev/null | head -10 || echo "detector unavailable"` -Stamp config: !`${CLAUDE_SKILL_DIR}/scripts/check-stamps.sh --show-config >/dev/null 2>&1 && ${CLAUDE_SKILL_DIR}/scripts/check-stamps.sh --show-config 2>/dev/null | tail -3 || echo "detector unavailable"` +Effective config: !`"${CLAUDE_SKILL_DIR}/scripts/list-corpus.sh" --show-config >/dev/null 2>&1 && { "${CLAUDE_SKILL_DIR}/scripts/list-corpus.sh" --show-config 2>/dev/null | head -10; :; } || echo "detector unavailable"` +Stamp config: !`"${CLAUDE_SKILL_DIR}/scripts/check-stamps.sh" --show-config >/dev/null 2>&1 && { "${CLAUDE_SKILL_DIR}/scripts/check-stamps.sh" --show-config 2>/dev/null | tail -3; :; } || echo "detector unavailable"` ## Purpose