Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion plugins/ai-slop/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
"name": "ai-slop",
"version": "0.3.8",
"version": "0.3.9",
"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, and the rest of a catalog distilled from Wikipedia's Signs of AI writing. 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",
Expand Down
16 changes: 16 additions & 0 deletions plugins/ai-slop/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Changelog

## [0.3.9]

- **Three directory-expansion defects survived 0.3.8.** A tracked file
whose name held a non-ASCII byte was dropped with no trace, because
`git ls-files` C-quotes those paths unless told otherwise; the listing
now sets `core.quotePath=false` and stays newline-delimited. A
filesystem walk still ran when git was missing or could not confirm a
work tree, while the comment claimed that case was gone; the walk
remains the fallback when tracked-files-only is not achievable, and
that fallback is now reported on stderr (`git is not on PATH`, or
`git could not confirm a work tree`). The new dir-target tests now
assert the emitted `file=` path, not only the scan count, so rebuilding
paths from `git rev-parse --show-toplevel` fails the suite; they also
pin subtree restriction and a non-ASCII filename. Drive-root slash
preservation from 0.3.8 is unchanged.

## [0.3.8]

- **Directory targets silently fell back to an untracked-inclusive filesystem
Expand Down
31 changes: 26 additions & 5 deletions plugins/ai-slop/skills/audit/scripts/detect.sh
Original file line number Diff line number Diff line change
Expand Up @@ -266,14 +266,23 @@ fi
# prefix from `git rev-parse --show-toplevel` and its filter from `pwd`, so on
# any host where those disagree no candidate survived the filter and the walk
# below silently replaced the tracked-files listing it was meant to back up.
# `ls-files` C-quotes any path holding a non-ASCII byte unless
# `core.quotePath=false`, so a tracked `café.md` (or a filename that itself
# holds an em dash) would arrive as a literal quoted escape, fail the scan
# loop's existence test, and produce neither a finding nor a declined row.
#
# Running `ls-files` with `-C <dir>` needs neither: it is already
# restricted to that directory's subtree and answers in paths relative to it,
# so `<dir>` is the only anchor and cannot disagree with itself.
#
# The branch is chosen up front from `--is-inside-work-tree`, never from an
# empty pipeline, so a walk is only ever the answer for a directory that is
# genuinely outside a checkout. Inside one, a listing that fails says so on
# stderr rather than degrading into a different set of files.
# empty pipeline. A silent walk is only the answer when git is present and
# reports the directory is genuinely outside a checkout. If git is missing,
# or git cannot confirm a work tree (safe.directory refusal, unreadable
# .git, nonzero rev-parse), the walk still runs because tracked-files-only
# is not achievable, and that fallback is reported on stderr. Inside a
# confirmed checkout, a listing that fails says so on stderr rather than
# degrading into a different set of files.
#
# Strip one trailing slash, except when that would turn a Windows drive root
# (`C:/`) into a drive-relative path (`C:`). Windows then treats the target as
Expand All @@ -293,13 +302,25 @@ expand_dir_target() {
local dir inside listing status
dir="$(normalize_dir_target "$1")"

inside="$(git -C "$dir" rev-parse --is-inside-work-tree 2>/dev/null || true)"
if ! command -v git >/dev/null 2>&1; then
echo "detect.sh: git is not on PATH; directory $dir expanded via filesystem walk (tracked-files-only is not achievable)" >&2
find "$dir" -name '*.md' -type f 2>/dev/null
return 0
fi

inside="$(git -C "$dir" rev-parse --is-inside-work-tree 2>/dev/null)"
status=$?
if [[ "$status" -ne 0 ]]; then
echo "detect.sh: git could not confirm a work tree under $dir (exit $status); expanding via filesystem walk" >&2
find "$dir" -name '*.md' -type f 2>/dev/null
return 0
fi
if [[ "$inside" != "true" ]]; then
find "$dir" -name '*.md' -type f 2>/dev/null
return 0
fi

listing="$(git -C "$dir" ls-files '*.md')"
listing="$(git -C "$dir" -c core.quotePath=false ls-files '*.md')"
status=$?
if [[ "$status" -ne 0 ]]; then
echo "detect.sh: git ls-files failed under $dir (exit $status); that directory expanded to nothing" >&2
Expand Down
33 changes: 32 additions & 1 deletion plugins/ai-slop/skills/audit/scripts/detect.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -403,9 +403,14 @@ cat >"$GITDIR/docs/untracked.md" <<EOF
An untracked em dash ${EM} here.
EOF
git -C "$GITDIR" add docs/tracked.md
cat >"$GITDIR/sibling.md" <<EOF
A sibling em dash ${EM} here.
EOF
git -C "$GITDIR" add sibling.md
out="$(bash "$DETECT" "$GITDIR/docs" 2>&1)"
assert_contains "dir target in git repo: tracked file scanned via ls-files" "$out" "tracked.md"
assert_contains "dir target in git repo: tracked file scanned via ls-files" "$out" "file=$GITDIR/docs/tracked.md"
assert_contains "dir target in git repo: only the tracked file counts" "$out" "1 files scanned"
assert_not_contains "dir target in git repo: sibling outside the subtree is not scanned" "$out" "sibling.md"

# Path agreement. One directory has several SPELLINGS on Git Bash: git answers
# the Windows form of the same checkout a shell reaches as "/tmp/...". An
Expand All @@ -420,15 +425,19 @@ GITSPELL="$(git -C "$GITDIR/docs" rev-parse --show-toplevel)/docs"
PWDSPELL="$(cd "$GITDIR/docs" && pwd)"

out="$(bash "$DETECT" "$GITSPELL" 2>&1)"
assert_contains "dir target, git spelling: the emitted path keeps that spelling" "$out" "file=$GITSPELL/tracked.md"
assert_contains "dir target, git spelling: only the tracked file counts" "$out" "1 files scanned"

out="$(bash "$DETECT" "$PWDSPELL" 2>&1)"
assert_contains "dir target, shell spelling: the emitted path keeps that spelling" "$out" "file=$PWDSPELL/tracked.md"
assert_contains "dir target, shell spelling: only the tracked file counts" "$out" "1 files scanned"

# A trailing slash is the same directory and must expand identically; the
# expansion builds paths by concatenation, so an unnormalized target would emit
# a doubled separator and scan nothing.
out="$(bash "$DETECT" "$GITDIR/docs/" 2>&1)"
assert_contains "dir target with a trailing slash: the emitted path is not doubled" "$out" "file=$GITDIR/docs/tracked.md"
assert_not_contains "dir target with a trailing slash: no doubled separator" "$out" "file=$GITDIR/docs//tracked.md"
assert_contains "dir target with a trailing slash: only the tracked file counts" "$out" "1 files scanned"

# Drive-root slash preservation is a string contract, not a host contract: the
Expand Down Expand Up @@ -456,6 +465,28 @@ EOF
out="$(bash "$DETECT" "$GITDIR/untrackedonly" 2>&1)"
assert_contains "dir target in git repo, no tracked markdown: expands to nothing" "$out" "0 files scanned"

# git C-quotes non-ASCII path bytes unless core.quotePath=false. A tracked
# filename holding an em dash would then fail the scan loop's existence test
# and vanish from the report. The listing must emit the raw filename.
mkdir -p "$GITDIR/unicode"
printf 'A tracked em dash %s here.\n' "$EM" >"$GITDIR/unicode/dash${EM}name.md"
git -C "$GITDIR" add "unicode/dash${EM}name.md"
out="$(bash "$DETECT" "$GITDIR/unicode" 2>&1)"
assert_contains "dir target, non-ASCII filename: the raw path is scanned" "$out" "file=$GITDIR/unicode/dash${EM}name.md"
assert_contains "dir target, non-ASCII filename: the file is not dropped" "$out" "1 files scanned"

# git absent: tracked-files-only is not achievable, so the walk still runs,
# but the fallback must be reported rather than silent.
NOGIT_BIN="$TEST_TMPDIR/bin-nogit"
mkdir -p "$NOGIT_BIN"
for name in bash find sort awk sed cat printf mkdir uname env dirname basename head tail wc tr; do
src="$(command -v "$name" 2>/dev/null)" || continue
ln -s "$src" "$NOGIT_BIN/$name"
done
out="$(PATH="$NOGIT_BIN" bash "$DETECT" "$GITDIR/docs" 2>&1)"
assert_contains "dir target, git absent: reports the walk" "$out" "git is not on PATH"
assert_contains "dir target, git absent: walk scans tracked and untracked markdown" "$out" "2 files scanned"

# --- Excerpt truncation at the byte boundary --------------------------------------

# 79 ASCII bytes then an em dash: a byte cut at 80 would keep only the first
Expand Down