Agent Skills: Verify Bundle Sync

Verify the dev-workflow-bundle canonical and bundle copy directories are in sync. Workaround for upstream symlink bug; delete this skill and its callers when symlinks are restored.

UncategorizedID: hiroro-work/claude-plugins/verify-bundle-sync

Install this agent skill to your local

pnpm dlx add-skill https://github.com/hiroro-work/claude-plugins/tree/HEAD/.claude/skills/verify-bundle-sync

Skill Files

Browse the full folder contents for verify-bundle-sync.

Download Skill

Loading file tree…

.claude/skills/verify-bundle-sync/SKILL.md

Skill Metadata

Name
verify-bundle-sync
Description
Verify the dev-workflow-bundle canonical and bundle copy directories are in sync. Workaround for upstream symlink bug; delete this skill and its callers when symlinks are restored.

Verify Bundle Sync

This skill exists solely to work around an upstream Claude Code symlink bug (anthropics/claude-code#53948) that requires plugins/dev-workflow-bundle/skills/<name>/ to be a real directory copy of skills/<name>/ rather than a symlink.

The skill compares each bundle member's canonical directory against its bundle copy and reports drift. It is detect-only — it never modifies any files.

Process

Accepts an optional --base-commit <sha> argument (ignored — the scope is structural, not changeset-dependent). Running with no arguments behaves identically.

Run the following directly in the main thread (no subagent dispatch is needed — the check is lightweight: one jq invocation plus one diff -rq per bundle member).

  1. Load the bundle membership list from .claude-plugin/marketplace.json:

    bundle_skills=$(jq -r '(.plugins[] | select(.name == "dev-workflow-bundle") | .skills[]) // empty' .claude-plugin/marketplace.json 2>/dev/null)
    # If $bundle_skills is empty after this guard, halt and emit the Return contract response
    # (Layer 1 prose `Status: EXECUTION_ERROR` + Layer 2 fenced JSON with `status: "error"`,
    # `reason: "marketplace.json missing, malformed, or dev-workflow-bundle plugin entry absent"`)
    # immediately — see § Return contract.
    
  2. For each bundle member entry ./skills/<name>:

    • Resolve canonical=skills/<name>/
    • Resolve bundle_copy=plugins/dev-workflow-bundle/skills/<name>/
    • Verify both directories exist with test -d "$canonical" && test -d "$bundle_copy". If either is missing, exit immediately with EXECUTION_ERROR and report which path was missing.
    • Run diff -rq "$canonical" "$bundle_copy". Capture stdout. If exit code is non-zero AND stdout is empty, treat as EXECUTION_ERROR (tool failure). If stdout is non-empty, treat every output line as a drift entry — each line is one of:
      • Files <canonical-path> and <bundle-copy-path> differ → type: "differ"
      • Only in <canonical-dir>: <file> → type: "only_in_canonical"
      • Only in <bundle-copy-dir>: <file> → type: "only_in_copy"
  3. Aggregate the result:

    • All entries drift-free → SUCCESS (e.g. <n> bundle skills verified, 0 drift)
    • Any entry has drift → TEST_FAILED. Include the per-entry drift list and a remediation hint of the form cp -R skills/<name>/. plugins/dev-workflow-bundle/skills/<name>/ for each affected member
    • jq failed / diff missing / marketplace.json unreadable / per-entry path missing → EXECUTION_ERROR

Return contract

The skill emits its result in two layers in a single response so that both prose-reading callers (such as dev-workflow Phase 9 (Check / Test)) and JSON-parsing callers (such as dev-workflow-triage (f.5)) can extract the verdict mechanically.

Layer 1 — Prose summary (first, at the top of the response):

Status: SUCCESS | TEST_FAILED | EXECUTION_ERROR

<one-paragraph human-readable summary>
<if TEST_FAILED: per-entry drift list with remediation hint lines>
<if EXECUTION_ERROR: reason and which step failed>

Layer 2 — Fenced JSON verdict (last, at the end of the response):

```json
{
  "status": "ok" | "drift" | "error",
  "checked_count": <int>,
  "drift_files": [{"skill": "<name>", "path": "<relative-path>", "type": "differ|only_in_canonical|only_in_copy"}],
  "reason": "<optional, required when status=error>"
}
```

Mapping between the prose status token and the JSON status field:

| Prose Status: | JSON status | |---|---| | SUCCESS | ok | | TEST_FAILED | drift | | EXECUTION_ERROR | error |

  • checked_count: number of bundle member entries actually inspected (the length of Step 1's list). If the list could not be loaded (EXECUTION_ERROR from Step 1), set this to 0.
  • drift_files[]: drift / one-sided-presence entries, populated only for status: "drift". Empty array for ok and error. The path value preserves the raw line as it appeared in diff -rq output so that downstream rendering does not need to re-derive it.
  • reason: required on status: "error". Short, ≤ 80 characters. Examples: marketplace.json missing, dev-workflow-bundle plugin entry absent, jq not in PATH, canonical missing: skills/ask-peer.