#!/usr/bin/env bats setup() { REPO_ROOT="$(cd "$BATS_TEST_DIRNAME/../../../../../" && pwd)" load "$REPO_ROOT/tests/test_helper/bats-support/load" load "$REPO_ROOT/tests/test_helper/bats-assert/load" SCRIPT="$(cd "$BATS_TEST_DIRNAME/../scripts" && pwd)/validate.sh" TMPDIR="$(mktemp -d)" # Helper: create an APM package root at (apm.yml with a top-level # type: line, marking it a real package manifest — not marketplace-only) # plus a single vendor-neutral agent file at # /.apm/agents/.agent.md. , if given, is # inserted as additional raw frontmatter lines (used to inject fields # under test). make_apm_agent() { local root="$1" local name="$2" local extra_frontmatter="${3:-}" mkdir -p "$root/.apm/agents" cat > "$root/apm.yml" < "$root/.apm/agents/${name}.agent.md" < "$root/.claude/agents/my-agent.md" < "$root/.github/agents/my-agent.agent.md" < "$fake_home/.claude/agents/my-agent.md" < "$fake_home/.copilot/agents/my-agent.agent.md" < "$fake_home/my-agent.md" < "$fake_home/.copilot/agents/my-agent.agent.md" < "$nested/.claude/agents/my-agent.md" < "$nested/.github/agents/my-agent.agent.md" < "$nested/.claude/agents/my-agent.md" < "$fake_home/.copilot/agents/my-agent.agent.md" < "$root/.claude/agents/my-agent.md" < "$root/.github/agents/my-agent.agent.md" < one level below a .git ancestor resolves scope to , not to wherever .git was found (subdirectory of a larger git-tracked tree)" { local repo="$TMPDIR/repo-with-subdir" local root="$repo/subdir" mkdir -p "$repo/.git" "$root/.claude/agents" "$root/.github/agents" cat > "$root/.claude/agents/my-agent.md" < "$root/.github/agents/my-agent.agent.md" < as its root argument, would place the # counterpart at /.github/agents — not at the repo root's # .github/agents, even though .git lives at the repo root one level up. run bash "$SCRIPT" "$root/.claude/agents/my-agent.md" assert_success refute_output --partial "FAIL" refute_output --partial "counterpart" } @test "project scope: a non-conventional path (agent file not directly under a literal 'agents' dir) falls back to the nearest .git boundary instead of two-segments-up arithmetic" { local outer="$TMPDIR/outer-repo" local pkg="$outer/pkgA" mkdir -p "$pkg/.git" "$pkg/.github/agents" "$pkg/extra" # Misplaced file: sits two path segments below $outer (pkgA/extra), which # matches the conventional_root arithmetic by coincidence, but its # immediate parent dir is "extra", not "agents" — conventional_shape is # false, so the fix must fall back to the nearest .git boundary (pkgA), # not trust $outer. cat > "$pkg/extra/my-agent.md" < "$pkg/.github/agents/my-agent.agent.md" < "$root/.claude/agents/my-agent.md" < "$root/.github/agents/my-agent.agent.md" < "$root/.claude/agents/my-agent.md" < "$root/.github/agents/my-agent.agent.md" < "$root/.claude/agents/my-agent.md" < "$root/apm.yml" < "$root/.apm/agents/my-agent.agent.md" < "$root/apm.yml" < "$root/.apm/agents/my-agent.agent.md" < "$root/apm.yml" < "$root/.apm/agents/my-agent.agent.md" < "$root/apm.yml" < "$root/.apm/agents/my-agent.agent.md" < "$root/apm.yml" < "$root/.apm/agents/my-agent.agent.md" < --- You are a test agent. When invoked, do the thing. EOF run bash "$SCRIPT" "$root/.apm/agents/my-agent.agent.md" assert_failure assert_output --partial "template HTML comments" } @test "fails when body contains unfilled FILL IN: placeholder in a plugin/APM-scope agent file" { local root="$TMPDIR/pkg" mkdir -p "$root/.apm/agents" cat > "$root/apm.yml" < "$root/.apm/agents/my-agent.agent.md" < "$root/apm.yml" < "$root/.apm/agents/nested/apm.yml" < "$root/.apm/agents/nested/deeper/my-agent.agent.md" < "$root/apm.yml" < "$root/.claude/agents/my-agent.md" < "$root/.github/agents/my-agent.agent.md" < "$root/plugin.json" # 'hooks' is plugin-silently-ignored only at (old) plugin scope; at # project scope it's a legitimate CC field. If this directory were # mis-detected as plugin scope (old plugin.json-based logic), this would # FAIL with a plugin-silently-ignored-fields finding on 'hooks'. cat > "$root/.claude/agents/my-agent.md" < "$root/.github/agents/my-agent.agent.md" <