Skip to content

fix: 🐛 Revert memory MCP to per-session stdio (Cowork regression) (#14) #66

fix: 🐛 Revert memory MCP to per-session stdio (Cowork regression) (#14)

fix: 🐛 Revert memory MCP to per-session stdio (Cowork regression) (#14) #66

Workflow file for this run

name: validate
on:
pull_request:
push:
branches: [main]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: plugin.json — valid JSON, required fields, semver version
run: |
set -euo pipefail
f=.claude-plugin/plugin.json
jq empty "$f"
for field in name version description author; do
jq -e ".${field}" "$f" > /dev/null \
|| { echo "::error file=${f}::missing required field: ${field}"; exit 1; }
done
version=$(jq -r '.version' "$f")
if ! [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+([-+][A-Za-z0-9.-]+)?$ ]]; then
echo "::error file=${f}::version '$version' is not semver"
exit 1
fi
- name: MCP tool-name refs match plugin + server names in plugin.json
run: |
set -euo pipefail
plugin_name=$(jq -r '.name' .claude-plugin/plugin.json)
# For every MCP server declared in plugin.json, the tool prefix must be
# mcp__plugin_<plugin_name>_<server_name>__<tool>. Any reference that
# doesn't match is stale (usually from a plugin or server rename).
mapfile -t servers < <(jq -r '.mcpServers // {} | keys[]' .claude-plugin/plugin.json)
fail=0
# Collect every mcp__plugin_ reference from sources.
mapfile -t refs < <(grep -rhoE 'mcp__plugin_[A-Za-z0-9_-]+__[A-Za-z0-9_]+' \
--include='*.md' --include='*.sh' --include='*.json' \
agents hooks references skills assets 2>/dev/null | sort -u)
for ref in "${refs[@]}"; do
# Strip the trailing __<tool> to get mcp__plugin_<name>_<server>
prefix="${ref%__*}"
# Strip leading mcp__plugin_ to get <name>_<server>
body="${prefix#mcp__plugin_}"
matched=0
for server in "${servers[@]}"; do
if [ "$body" = "${plugin_name}_${server}" ]; then
matched=1
break
fi
done
if [ "$matched" -eq 0 ]; then
echo "::error::stale MCP tool ref: ${ref} (expected prefix for plugin '${plugin_name}', servers: ${servers[*]})"
fail=1
fi
done
exit "$fail"
- name: shellcheck hooks + libs + fixtures + scripts
run: |
set -euo pipefail
# -x lets shellcheck follow `source`d libraries under hooks/lib.
shellcheck --severity=warning -x \
hooks/*.sh hooks/lib/*.sh hooks/fixtures/*.sh scripts/*.sh
- name: bash -n on hooks + libs + fixtures + scripts
run: |
set -euo pipefail
for f in hooks/*.sh hooks/lib/*.sh hooks/fixtures/*.sh scripts/*.sh; do
bash -n "$f"
done
- name: hook test suite (offline; fake-server fixture, no real server)
run: |
set -euo pipefail
fail=0
for t in hooks/test-*.sh; do
echo "::group::$t"
if bash "$t"; then
echo "::endgroup::"
else
echo "::endgroup::"
echo "::error file=${t}::test suite failed"
fail=1
fi
done
exit "$fail"
- name: Frontmatter present on skills and agents
run: |
set -euo pipefail
fail=0
for f in skills/*/SKILL.md agents/*.md; do
[ -f "$f" ] || continue
if ! head -1 "$f" | grep -qx -- '---'; then
echo "::error file=${f}::missing opening frontmatter"
fail=1
continue
fi
if ! awk 'NR>1 && /^---$/ {print NR; exit}' "$f" | grep -qE '^[0-9]+$'; then
echo "::error file=${f}::missing closing frontmatter"
fail=1
continue
fi
fm=$(awk 'NR==1&&/^---$/ {on=1; next} on && /^---$/ {exit} on' "$f")
if ! echo "$fm" | grep -qE '^description:'; then
echo "::error file=${f}::frontmatter missing required field: description"
fail=1
fi
done
exit "$fail"
- name: CLAUDE_PLUGIN_ROOT references resolve
run: |
set -euo pipefail
fail=0
# Strip a trailing dot from each match: prose and comments often end a
# sentence right after a path ("see ${CLAUDE_PLUGIN_ROOT}/hooks/x.sh."),
# and the char class above would otherwise fold that period into the
# path and report a spurious broken reference. No plugin path legitimately
# ends in a dot, so this is safe.
mapfile -t refs < <(grep -rhoE '\$\{CLAUDE_PLUGIN_ROOT\}/[A-Za-z0-9_./-]+' \
--include='*.md' --include='*.sh' \
agents hooks references skills assets 2>/dev/null \
| sed 's|${CLAUDE_PLUGIN_ROOT}/||; s|[.]*$||' \
| sort -u)
for r in "${refs[@]}"; do
if [ ! -e "$r" ]; then
echo "::error::broken reference: \${CLAUDE_PLUGIN_ROOT}/$r"
fail=1
fi
done
exit "$fail"