Skip to content

Commit 26cf21f

Browse files
authored
fix(ai-slop): close leftover directory-expansion defects (0.3.9) (#3331)
<!-- CURSOR_AGENT_PR_BODY_BEGIN --> Closes #3332 ## Summary Three defects in `detect.sh` directory expansion survived the 0.3.8 path-anchor fix: a tracked non-ASCII filename was dropped, a filesystem walk still ran silently when git could not answer, and the new tests asserted only a scan count so the original spelling-rebuild defect could return unnoticed. ## Fix - `git -c core.quotePath=false ls-files` so a filename holding an em dash is actually opened. - Report on stderr when git is missing or `rev-parse --is-inside-work-tree` fails; a silent walk remains only when git reports the directory is genuinely outside a checkout. - Dir-target tests now assert the emitted `file=` path, subtree restriction, a non-ASCII filename, and the git-absent report. - `normalize_dir_target` still keeps a Windows drive-root slash (`C:/`). `ai-slop` 0.3.9. Duplicate stale PR #3330 is still `DIRTY` and would regress drive-root slash preservation; ignore it. ## Verification - `bash plugins/ai-slop/skills/audit/scripts/detect.test.sh`: 149 cases passed - `scripts/check-changed-skills.sh origin/main`: 0 failed - `scripts/check-changelog-parity.sh --check-bump origin/main`: pass - `python3 scripts/sync-plugin-options-docs.py --check`: up to date ## Related Follow-up to the merged directory-anchor work. Do not merge #3330. <!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-363de5b1-6044-4e78-99f7-867a293bcfcf?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a>&nbsp;<a href="https://cursor.com/background-agent?bcId=bc-363de5b1-6044-4e78-99f7-867a293bcfcf&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a>&nbsp;</div> --------- Co-authored-by: Kyle Sexton <kyle-sexton@users.noreply.github.com>
1 parent bc2cf55 commit 26cf21f

4 files changed

Lines changed: 75 additions & 7 deletions

File tree

plugins/ai-slop/.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
33
"name": "ai-slop",
4-
"version": "0.3.8",
4+
"version": "0.3.9",
55
"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.",
66
"author": {
77
"name": "Melodic Software",

plugins/ai-slop/CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
# Changelog
22

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

521
- **Directory targets silently fell back to an untracked-inclusive filesystem

plugins/ai-slop/skills/audit/scripts/detect.sh

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -266,14 +266,23 @@ fi
266266
# prefix from `git rev-parse --show-toplevel` and its filter from `pwd`, so on
267267
# any host where those disagree no candidate survived the filter and the walk
268268
# below silently replaced the tracked-files listing it was meant to back up.
269+
# `ls-files` C-quotes any path holding a non-ASCII byte unless
270+
# `core.quotePath=false`, so a tracked `café.md` (or a filename that itself
271+
# holds an em dash) would arrive as a literal quoted escape, fail the scan
272+
# loop's existence test, and produce neither a finding nor a declined row.
273+
#
269274
# Running `ls-files` with `-C <dir>` needs neither: it is already
270275
# restricted to that directory's subtree and answers in paths relative to it,
271276
# so `<dir>` is the only anchor and cannot disagree with itself.
272277
#
273278
# The branch is chosen up front from `--is-inside-work-tree`, never from an
274-
# empty pipeline, so a walk is only ever the answer for a directory that is
275-
# genuinely outside a checkout. Inside one, a listing that fails says so on
276-
# stderr rather than degrading into a different set of files.
279+
# empty pipeline. A silent walk is only the answer when git is present and
280+
# reports the directory is genuinely outside a checkout. If git is missing,
281+
# or git cannot confirm a work tree (safe.directory refusal, unreadable
282+
# .git, nonzero rev-parse), the walk still runs because tracked-files-only
283+
# is not achievable, and that fallback is reported on stderr. Inside a
284+
# confirmed checkout, a listing that fails says so on stderr rather than
285+
# degrading into a different set of files.
277286
#
278287
# Strip one trailing slash, except when that would turn a Windows drive root
279288
# (`C:/`) into a drive-relative path (`C:`). Windows then treats the target as
@@ -293,13 +302,25 @@ expand_dir_target() {
293302
local dir inside listing status
294303
dir="$(normalize_dir_target "$1")"
295304

296-
inside="$(git -C "$dir" rev-parse --is-inside-work-tree 2>/dev/null || true)"
305+
if ! command -v git >/dev/null 2>&1; then
306+
echo "detect.sh: git is not on PATH; directory $dir expanded via filesystem walk (tracked-files-only is not achievable)" >&2
307+
find "$dir" -name '*.md' -type f 2>/dev/null
308+
return 0
309+
fi
310+
311+
inside="$(git -C "$dir" rev-parse --is-inside-work-tree 2>/dev/null)"
312+
status=$?
313+
if [[ "$status" -ne 0 ]]; then
314+
echo "detect.sh: git could not confirm a work tree under $dir (exit $status); expanding via filesystem walk" >&2
315+
find "$dir" -name '*.md' -type f 2>/dev/null
316+
return 0
317+
fi
297318
if [[ "$inside" != "true" ]]; then
298319
find "$dir" -name '*.md' -type f 2>/dev/null
299320
return 0
300321
fi
301322

302-
listing="$(git -C "$dir" ls-files '*.md')"
323+
listing="$(git -C "$dir" -c core.quotePath=false ls-files '*.md')"
303324
status=$?
304325
if [[ "$status" -ne 0 ]]; then
305326
echo "detect.sh: git ls-files failed under $dir (exit $status); that directory expanded to nothing" >&2

plugins/ai-slop/skills/audit/scripts/detect.test.sh

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -403,9 +403,14 @@ cat >"$GITDIR/docs/untracked.md" <<EOF
403403
An untracked em dash ${EM} here.
404404
EOF
405405
git -C "$GITDIR" add docs/tracked.md
406+
cat >"$GITDIR/sibling.md" <<EOF
407+
A sibling em dash ${EM} here.
408+
EOF
409+
git -C "$GITDIR" add sibling.md
406410
out="$(bash "$DETECT" "$GITDIR/docs" 2>&1)"
407-
assert_contains "dir target in git repo: tracked file scanned via ls-files" "$out" "tracked.md"
411+
assert_contains "dir target in git repo: tracked file scanned via ls-files" "$out" "file=$GITDIR/docs/tracked.md"
408412
assert_contains "dir target in git repo: only the tracked file counts" "$out" "1 files scanned"
413+
assert_not_contains "dir target in git repo: sibling outside the subtree is not scanned" "$out" "sibling.md"
409414

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

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

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

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

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

468+
# git C-quotes non-ASCII path bytes unless core.quotePath=false. A tracked
469+
# filename holding an em dash would then fail the scan loop's existence test
470+
# and vanish from the report. The listing must emit the raw filename.
471+
mkdir -p "$GITDIR/unicode"
472+
printf 'A tracked em dash %s here.\n' "$EM" >"$GITDIR/unicode/dash${EM}name.md"
473+
git -C "$GITDIR" add "unicode/dash${EM}name.md"
474+
out="$(bash "$DETECT" "$GITDIR/unicode" 2>&1)"
475+
assert_contains "dir target, non-ASCII filename: the raw path is scanned" "$out" "file=$GITDIR/unicode/dash${EM}name.md"
476+
assert_contains "dir target, non-ASCII filename: the file is not dropped" "$out" "1 files scanned"
477+
478+
# git absent: tracked-files-only is not achievable, so the walk still runs,
479+
# but the fallback must be reported rather than silent.
480+
NOGIT_BIN="$TEST_TMPDIR/bin-nogit"
481+
mkdir -p "$NOGIT_BIN"
482+
for name in bash find sort awk sed cat printf mkdir uname env dirname basename head tail wc tr; do
483+
src="$(command -v "$name" 2>/dev/null)" || continue
484+
ln -s "$src" "$NOGIT_BIN/$name"
485+
done
486+
out="$(PATH="$NOGIT_BIN" bash "$DETECT" "$GITDIR/docs" 2>&1)"
487+
assert_contains "dir target, git absent: reports the walk" "$out" "git is not on PATH"
488+
assert_contains "dir target, git absent: walk scans tracked and untracked markdown" "$out" "2 files scanned"
489+
459490
# --- Excerpt truncation at the byte boundary --------------------------------------
460491

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

0 commit comments

Comments
 (0)