The find -> sort -> read chain in both scripts used newline-delimited
records (plain read -r), so a skill directory name containing a
literal newline would be split across two records. Verified with a
directory literally named "evil\nskill": the old reader produced a
truncated "evil" fragment plus an orphan "skill/SKILL.md" fragment,
inflating the skill count and throwing awk/date errors on the garbage
paths.
Switch to -print0 / sort -z / read -r -d '' in both scripts so a path
is always read as a single record, regardless of its contents. Paths
under scan are untrusted input.
Addresses further CodeRabbit review feedback on PR #2640.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FhDjpSfrbPpnpqT3CZBEX1
Following up on the -L fix: find -L can now traverse symlinks, but a
broken symlink target or an unreadable directory makes find skip that
entry and exit non-zero. Both scripts previously redirected find's
stderr to /dev/null and never checked its exit status, so a scan could
silently under-count skills with no indication anything was wrong.
Capture find's exit status and stderr in both scripts; on failure,
print a warning (with the underlying find error) to stderr while still
emitting the best-effort results for whatever was found. Verified with
a permission-denied skill directory: real BSD find exits 1 and reports
"Permission denied" on stderr, now surfaced as an explicit warning
instead of silently dropped.
Addresses CodeRabbit review feedback on PR #2640.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FhDjpSfrbPpnpqT3CZBEX1
scan.sh and quick-diff.sh both used `find "$dir" -name "*.md" -type f`,
which missed symlinked skill directories (no -L) and miscounted any
non-skill markdown file sitting in a skills directory as a skill
(matched *.md instead of SKILL.md). Both call sites now use
`find -L "$dir" -name "SKILL.md" -type f`.
Repro (temp dir with 1 real skill, 1 symlinked skill, 1 stray .md file):
before: 2 skills found (real skill + the stray .md, symlinked skill invisible)
after: 2 skills found (real skill + symlinked skill, stray .md excluded)
Fixes#2598
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FhDjpSfrbPpnpqT3CZBEX1
The Explore agent is a "Fast agent" optimized for codebase exploration,
not deep reasoning. The skill-stocktake V4 design requires holistic AI
judgment (actionability, scope fit, uniqueness, currency) which needs
the full reasoning capability of the conversation's main model.
Additionally, the Agent tool has no `model` parameter — specifying
`model: opus` was silently ignored, causing the evaluation to run on
the lightweight Explore model. This resulted in all skills receiving
"Keep" verdicts without genuine critical analysis.
Changing to `general-purpose` agent ensures evaluation runs on the
conversation's main model (e.g., Opus 4.6), enabling the holistic
judgment that V4 was designed for.
Add origin field to all skill files to track their source repository.
This enables users to identify where distributed skills originated from.
Fixesaffaan-m/everything-claude-code#246