feat(core): add provider-adapter-author skill
Converts a target repo's provider-specific instruction file (CLAUDE.md, .cursor/rules, copilot-instructions.md, etc.) into a thin adapter over AGENTS.md, mirroring this repo's own two-tier CLAUDE.md pattern (ADR-0002/0003). Self-validates via a bundled deterministic script (scripts/validate-adapter.sh) rather than a separate paired audit skill. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
30
plugins/core/skills/provider-adapter-author/README.md
Normal file
30
plugins/core/skills/provider-adapter-author/README.md
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# provider-adapter-author
|
||||||
|
|
||||||
|
Convert a target repo's provider-specific instruction file (CLAUDE.md, .cursor/rules, copilot-instructions.md, etc.) into a thin adapter over AGENTS.md.
|
||||||
|
|
||||||
|
## What it does
|
||||||
|
|
||||||
|
Detects a provider-specific AI instruction file in a target repo, diffs it against the repo's `AGENTS.md`, and rewrites it down to a minimal reference — an `@AGENTS.md`-style import for providers that support one, or a text pointer for those that don't — plus only genuinely provider-specific additions. Self-validates its own output with a bundled deterministic script (no LLM judgment, no separate audit skill) before finishing.
|
||||||
|
|
||||||
|
## Before you start
|
||||||
|
|
||||||
|
The target repo must already have an `AGENTS.md`. If it doesn't, run `agentsmd-author` first — this skill never creates or edits `AGENTS.md` itself.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
/provider-adapter-author
|
||||||
|
```
|
||||||
|
|
||||||
|
Provide the path to the provider-specific file to convert (and the target repo root, if not inferable). Can be invoked directly, or composed into by `agentsmd-author` when it detects an existing provider file with content overlapping AGENTS.md.
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `SKILL.md` | Skill instructions for agents |
|
||||||
|
| `references/sources.md` | Provenance record — the in-repo ADR precedent this skill's design is modeled on |
|
||||||
|
| `scripts/validate-adapter.sh` | Self-check gate: reference to AGENTS.md present, no excessive duplication, adapter stays thin |
|
||||||
|
| `scripts/README.md` | Directory documentation for `scripts/` |
|
||||||
|
| `tests/README.md` | Bats test dependency and run instructions |
|
||||||
|
| `tests/validate-adapter.bats` | Bats test suite for `scripts/validate-adapter.sh` |
|
||||||
54
plugins/core/skills/provider-adapter-author/SKILL.md
Normal file
54
plugins/core/skills/provider-adapter-author/SKILL.md
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
---
|
||||||
|
name: provider-adapter-author
|
||||||
|
description: >
|
||||||
|
Use when the user wants to convert a provider-specific AI instruction file
|
||||||
|
(CLAUDE.md, .cursor/rules/*.mdc, copilot-instructions.md, etc.) into a
|
||||||
|
thin adapter that defers to a repo's AGENTS.md — e.g. "reduce duplication
|
||||||
|
between CLAUDE.md and AGENTS.md", "make CLAUDE.md just import AGENTS.md"
|
||||||
|
— even if the pattern isn't named explicitly. Also invoke when
|
||||||
|
agentsmd-author detects an existing provider file overlapping with
|
||||||
|
AGENTS.md it just wrote. Detects redundant content in a provider file
|
||||||
|
relative to AGENTS.md and rewrites it down to a minimal reference (an
|
||||||
|
`@AGENTS.md`-style import where supported, or a text pointer otherwise)
|
||||||
|
plus genuinely provider-specific additions. Self-validates via a bundled
|
||||||
|
deterministic script before finishing. Do not use to write or audit
|
||||||
|
AGENTS.md itself — use agentsmd-author or agentsmd-audit.
|
||||||
|
allowed-tools: Bash Read Edit Write
|
||||||
|
metadata:
|
||||||
|
category: docs
|
||||||
|
source_keys:
|
||||||
|
- adr-0002-0003-two-tier-claude-md
|
||||||
|
version: "0.1.0"
|
||||||
|
---
|
||||||
|
|
||||||
|
## Gotchas
|
||||||
|
|
||||||
|
- Not every provider supports cross-file imports. Claude Code does — a `CLAUDE.md` can consist of nothing but one or more `@path` lines (e.g. `@AGENTS.md`), with no other content required. Cursor's `.cursor/rules/*.mdc` and GitHub Copilot's `copilot-instructions.md` have no native import mechanism as of current tooling — for those, "thin" means a short text pointer to AGENTS.md plus only what that tool actually needs, not a literal import line. Pass `--no-import-syntax` to `scripts/validate-adapter.sh` for these providers.
|
||||||
|
- This skill never creates or edits `AGENTS.md` itself. If the target repo has no `AGENTS.md` yet, stop and point the user to `agentsmd-author` first — there's nothing to adapt to.
|
||||||
|
- Only strip content from the provider file that's genuinely redundant with AGENTS.md. Provider-specific material (IDE settings, tool-only syntax, model-specific instructions) stays — the goal is thin, not empty.
|
||||||
|
- Works standalone or composed-into by `agentsmd-author` — behave identically either way; don't assume a caller skill exists.
|
||||||
|
|
||||||
|
## Step 1 — Detect
|
||||||
|
|
||||||
|
Look for known provider instruction files in the target repo: `CLAUDE.md` (repo root, and any deployed copies), `.cursor/rules/*.mdc`, `.github/copilot-instructions.md`, and similar tool-specific files. Confirm `AGENTS.md` exists at the repo root — if not, stop and tell the user to run `agentsmd-author` first.
|
||||||
|
|
||||||
|
## Step 2 — Diff and rewrite
|
||||||
|
|
||||||
|
Read the provider file and `AGENTS.md` side by side. Separate the provider file's content into two buckets: lines that restate what `AGENTS.md` already owns (universal rules, conventions, project overview) versus lines that are genuinely provider-specific (tool syntax, IDE behavior, model-specific instructions). Rewrite the provider file:
|
||||||
|
|
||||||
|
- **Providers with import syntax** (Claude Code): replace the redundant bucket with an `@AGENTS.md` (or correct relative path) import line, keep the provider-specific bucket below it.
|
||||||
|
- **Providers without import syntax** (Cursor, Copilot, etc.): replace the redundant bucket with a short pointer sentence mentioning `AGENTS.md`, keep the provider-specific bucket.
|
||||||
|
|
||||||
|
## Step 3 — Self-validate
|
||||||
|
|
||||||
|
Run the bundled check before finishing — this is the skill's own closeout gate; there is no separate paired audit skill for this concern:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash scripts/validate-adapter.sh [--no-import-syntax] [--max-lines N] <adapter-file> <agents-md-file>
|
||||||
|
```
|
||||||
|
|
||||||
|
Fix any `FAIL` and re-run until it exits `0`.
|
||||||
|
|
||||||
|
## Step 4 — Report
|
||||||
|
|
||||||
|
State which file was converted, what was removed versus kept, and the validator's final result.
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# Sources
|
||||||
|
|
||||||
|
## adr-0002-0003-two-tier-claude-md
|
||||||
|
|
||||||
|
- **URL:** (in-repo precedent — not an external source or plugin research corpus entry)
|
||||||
|
- **Description:** This repo's own two-tier CLAUDE.md/AGENTS.md pattern: AGENTS.md is the provider-agnostic source of always-on rules; provider-specific files (CLAUDE.md) become thin adapters that import it (`@AGENTS.md` plus provider-specific additions). Grounds this skill's entire adapter-conversion design — the "thin adapter" shape, the `@`-import convention, and the size/duplication expectations enforced by `scripts/validate-adapter.sh`.
|
||||||
|
- **Research doc:** docs/adr/0002-two-tier-claude-md.md, docs/adr/0003-agents-md-provider-agnostic-entry-point.md, providers/claude-code/CLAUDE.md (in-repo ADRs and a live example, not a plugin research corpus entry; referenced here since this skill's design is modeled directly on an existing implementation rather than external research)
|
||||||
|
- **Contributing files:** SKILL.md
|
||||||
|
- **Status:** `extracted`
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
# scripts/
|
||||||
|
|
||||||
|
Deterministic self-check this skill shells out to instead of relying on LLM judgment for a mechanical check.
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `validate-adapter.sh` | Checks a rewritten provider file (CLAUDE.md, etc.) has a reference to AGENTS.md, doesn't duplicate its content, and stays under a thin-file line threshold |
|
||||||
|
|
||||||
|
Takes `<adapter-file> <agents-md-file>`, with optional `--no-import-syntax` and `--max-lines N` flags. Prints `FAIL` findings to stdout and exits non-zero on any failure.
|
||||||
141
plugins/core/skills/provider-adapter-author/scripts/validate-adapter.sh
Executable file
141
plugins/core/skills/provider-adapter-author/scripts/validate-adapter.sh
Executable file
@@ -0,0 +1,141 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<EOF
|
||||||
|
Usage: validate-adapter.sh [--no-import-syntax] [--max-lines N] <adapter-file> <agents-md-file>
|
||||||
|
|
||||||
|
Self-check gate for provider-adapter-author. Checks that a rewritten
|
||||||
|
provider-specific instruction file (CLAUDE.md, .cursor/rules/*.mdc,
|
||||||
|
copilot-instructions.md, etc.) is actually a thin adapter over AGENTS.md,
|
||||||
|
not a duplicate copy of it.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
adapter-file Path to the provider-specific file to check.
|
||||||
|
agents-md-file Path to the AGENTS.md file it should defer to.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--no-import-syntax The target provider has no native cross-file import
|
||||||
|
mechanism. Accept a plain-text pointer mention of
|
||||||
|
"AGENTS.md" instead of requiring an @import-style line.
|
||||||
|
--max-lines N Max non-blank lines allowed in the adapter file before
|
||||||
|
it's considered no longer "thin". Default: 60.
|
||||||
|
--help, -h Show this help and exit 0.
|
||||||
|
|
||||||
|
Exit codes:
|
||||||
|
0 Adapter file passes all checks
|
||||||
|
1 One or more checks failed (empty file, no reference to AGENTS.md,
|
||||||
|
excessive duplication, or file too long)
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
NO_IMPORT_SYNTAX=0
|
||||||
|
MAX_LINES=60
|
||||||
|
ARGS=()
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--help|-h)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
--no-import-syntax)
|
||||||
|
NO_IMPORT_SYNTAX=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--max-lines)
|
||||||
|
MAX_LINES="${2:-}"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
ARGS+=("$1")
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ ${#ARGS[@]} -lt 2 ]]; then
|
||||||
|
echo "Error: adapter-file and agents-md-file are required." >&2
|
||||||
|
echo "" >&2
|
||||||
|
usage >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
python3 -u - "${ARGS[0]}" "${ARGS[1]}" "$NO_IMPORT_SYNTAX" "$MAX_LINES" <<'PYTHON'
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
adapter_path, agents_md_path, no_import_syntax, max_lines = sys.argv[1:5]
|
||||||
|
no_import_syntax = no_import_syntax == "1"
|
||||||
|
max_lines = int(max_lines)
|
||||||
|
|
||||||
|
if not os.path.isfile(adapter_path):
|
||||||
|
print(f"Error: '{adapter_path}' is not a file.", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
if not os.path.isfile(agents_md_path):
|
||||||
|
print(f"Error: '{agents_md_path}' is not a file.", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
with open(adapter_path, encoding="utf-8", errors="replace") as f:
|
||||||
|
adapter_content = f.read()
|
||||||
|
with open(agents_md_path, encoding="utf-8", errors="replace") as f:
|
||||||
|
agents_md_content = f.read()
|
||||||
|
|
||||||
|
has_fail = False
|
||||||
|
|
||||||
|
if not adapter_content.strip():
|
||||||
|
print(f"FAIL Adapter file is empty — {adapter_path}")
|
||||||
|
print(" Why: An empty adapter carries no reference to AGENTS.md and no provider-specific content.")
|
||||||
|
print(" Fix: Add at least an import (or text pointer) to AGENTS.md.")
|
||||||
|
print()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
IMPORT_RE = re.compile(r'(?m)^\s*@\S*AGENTS\.md\s*$')
|
||||||
|
lines = adapter_content.splitlines()
|
||||||
|
import_lines = [ln for ln in lines if IMPORT_RE.match(ln)]
|
||||||
|
|
||||||
|
if no_import_syntax:
|
||||||
|
has_reference = "AGENTS.md" in adapter_content
|
||||||
|
else:
|
||||||
|
has_reference = bool(import_lines) or "AGENTS.md" in adapter_content
|
||||||
|
|
||||||
|
if not has_reference:
|
||||||
|
has_fail = True
|
||||||
|
print(f"FAIL Adapter has no reference to AGENTS.md — {adapter_path}")
|
||||||
|
if no_import_syntax:
|
||||||
|
print(" Why: This provider has no import syntax, so the adapter must at least mention AGENTS.md as a text pointer.")
|
||||||
|
print(" Fix: Add a sentence like \"See AGENTS.md at the repo root for shared conventions.\"")
|
||||||
|
else:
|
||||||
|
print(" Why: A thin adapter must import AGENTS.md (e.g. `@AGENTS.md`) rather than silently omitting it.")
|
||||||
|
print(" Fix: Add an `@AGENTS.md` (or equivalent relative path) import line.")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# --- Duplication check ---
|
||||||
|
non_import_lines = [ln for ln in lines if not IMPORT_RE.match(ln)]
|
||||||
|
adapter_lines = [ln.strip() for ln in non_import_lines if ln.strip()]
|
||||||
|
agents_lines = {ln.strip() for ln in agents_md_content.splitlines() if ln.strip()}
|
||||||
|
|
||||||
|
if adapter_lines:
|
||||||
|
overlap = sum(1 for ln in adapter_lines if ln in agents_lines)
|
||||||
|
ratio = overlap / len(adapter_lines)
|
||||||
|
if ratio > 0.3:
|
||||||
|
has_fail = True
|
||||||
|
print(f"FAIL Adapter duplicates AGENTS.md content — {adapter_path}")
|
||||||
|
print(f" Why: {ratio:.0%} of the adapter's non-import lines already appear verbatim in AGENTS.md. A thin adapter should import shared content, not restate it.")
|
||||||
|
print(" Fix: Remove the duplicated lines and rely on the AGENTS.md import (or pointer) instead.")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# --- Size check ---
|
||||||
|
non_blank_count = len([ln for ln in lines if ln.strip()])
|
||||||
|
if non_blank_count > max_lines:
|
||||||
|
has_fail = True
|
||||||
|
print(f"FAIL Adapter is not thin — {adapter_path}")
|
||||||
|
print(f" Why: {non_blank_count} non-blank lines exceeds the {max_lines}-line threshold for a thin adapter.")
|
||||||
|
print(" Fix: Move provider-agnostic content into AGENTS.md; keep only genuinely provider-specific additions here.")
|
||||||
|
print()
|
||||||
|
|
||||||
|
if has_fail:
|
||||||
|
sys.exit(1)
|
||||||
|
sys.exit(0)
|
||||||
|
PYTHON
|
||||||
28
plugins/core/skills/provider-adapter-author/tests/README.md
Normal file
28
plugins/core/skills/provider-adapter-author/tests/README.md
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# tests/
|
||||||
|
|
||||||
|
Test files for scripts bundled with this skill.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
|
||||||
|
Tests require [bats-support](https://github.com/bats-core/bats-support) and
|
||||||
|
[bats-assert](https://github.com/bats-core/bats-assert). The test files load
|
||||||
|
helpers from the repo root's `tests/test_helper/`.
|
||||||
|
|
||||||
|
From the repo root:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/bats-core/bats-support tests/test_helper/bats-support
|
||||||
|
git clone https://github.com/bats-core/bats-assert tests/test_helper/bats-assert
|
||||||
|
```
|
||||||
|
|
||||||
|
Run all tests for this skill (from the repo root):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bats plugins/core/skills/provider-adapter-author/tests/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `validate-adapter.bats` | Bats test suite for `scripts/validate-adapter.sh` |
|
||||||
@@ -0,0 +1,128 @@
|
|||||||
|
#!/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-adapter.sh"
|
||||||
|
TMPDIR="$(mktemp -d)"
|
||||||
|
AGENTS_MD="$TMPDIR/AGENTS.md"
|
||||||
|
cat > "$AGENTS_MD" <<'EOF'
|
||||||
|
# AGENTS.md
|
||||||
|
|
||||||
|
## Setup commands
|
||||||
|
- Install deps: `pnpm install`
|
||||||
|
- Run tests: `pnpm test`
|
||||||
|
|
||||||
|
## Code style
|
||||||
|
- TypeScript strict mode, single quotes, no semicolons.
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
teardown() {
|
||||||
|
rm -rf "$TMPDIR"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "fails when the adapter file is empty" {
|
||||||
|
ADAPTER="$TMPDIR/CLAUDE.md"
|
||||||
|
: > "$ADAPTER"
|
||||||
|
run bash "$SCRIPT" "$ADAPTER" "$AGENTS_MD"
|
||||||
|
assert_failure
|
||||||
|
assert_output --partial "empty"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "fails when the adapter has no reference to AGENTS.md" {
|
||||||
|
ADAPTER="$TMPDIR/CLAUDE.md"
|
||||||
|
cat > "$ADAPTER" <<'EOF'
|
||||||
|
# Claude-specific notes
|
||||||
|
Use the internal linter before committing.
|
||||||
|
EOF
|
||||||
|
run bash "$SCRIPT" "$ADAPTER" "$AGENTS_MD"
|
||||||
|
assert_failure
|
||||||
|
assert_output --partial "no reference"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "passes a thin adapter with an @import line and provider-specific additions" {
|
||||||
|
ADAPTER="$TMPDIR/CLAUDE.md"
|
||||||
|
cat > "$ADAPTER" <<'EOF'
|
||||||
|
@AGENTS.md
|
||||||
|
@core/instructions/governance.md
|
||||||
|
EOF
|
||||||
|
run bash "$SCRIPT" "$ADAPTER" "$AGENTS_MD"
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "fails when the adapter duplicates most of AGENTS.md's content" {
|
||||||
|
ADAPTER="$TMPDIR/CLAUDE.md"
|
||||||
|
cat > "$ADAPTER" <<'EOF'
|
||||||
|
@AGENTS.md
|
||||||
|
|
||||||
|
## Setup commands
|
||||||
|
- Install deps: `pnpm install`
|
||||||
|
- Run tests: `pnpm test`
|
||||||
|
|
||||||
|
## Code style
|
||||||
|
- TypeScript strict mode, single quotes, no semicolons.
|
||||||
|
EOF
|
||||||
|
run bash "$SCRIPT" "$ADAPTER" "$AGENTS_MD"
|
||||||
|
assert_failure
|
||||||
|
assert_output --partial "duplicat"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "fails when the adapter exceeds the max line threshold" {
|
||||||
|
ADAPTER="$TMPDIR/CLAUDE.md"
|
||||||
|
{
|
||||||
|
echo "@AGENTS.md"
|
||||||
|
for i in $(seq 1 80); do echo "Provider-specific line $i unrelated to AGENTS.md content."; done
|
||||||
|
} > "$ADAPTER"
|
||||||
|
run bash "$SCRIPT" "$ADAPTER" "$AGENTS_MD"
|
||||||
|
assert_failure
|
||||||
|
assert_output --partial "thin"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "allows a custom --max-lines threshold" {
|
||||||
|
ADAPTER="$TMPDIR/CLAUDE.md"
|
||||||
|
{
|
||||||
|
echo "@AGENTS.md"
|
||||||
|
for i in $(seq 1 10); do echo "Provider-specific line $i unrelated to AGENTS.md content."; done
|
||||||
|
} > "$ADAPTER"
|
||||||
|
run bash "$SCRIPT" --max-lines 5 "$ADAPTER" "$AGENTS_MD"
|
||||||
|
assert_failure
|
||||||
|
assert_output --partial "thin"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "with --no-import-syntax, a text pointer to AGENTS.md is accepted instead of an @import line" {
|
||||||
|
ADAPTER="$TMPDIR/copilot-instructions.md"
|
||||||
|
cat > "$ADAPTER" <<'EOF'
|
||||||
|
See AGENTS.md at the repo root for setup, style, and testing conventions.
|
||||||
|
|
||||||
|
## Copilot-specific
|
||||||
|
Prefer inline suggestions over chat for one-line edits.
|
||||||
|
EOF
|
||||||
|
run bash "$SCRIPT" --no-import-syntax "$ADAPTER" "$AGENTS_MD"
|
||||||
|
assert_success
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "with --no-import-syntax, still fails if there is no mention of AGENTS.md at all" {
|
||||||
|
ADAPTER="$TMPDIR/copilot-instructions.md"
|
||||||
|
cat > "$ADAPTER" <<'EOF'
|
||||||
|
## Copilot-specific
|
||||||
|
Prefer inline suggestions over chat for one-line edits.
|
||||||
|
EOF
|
||||||
|
run bash "$SCRIPT" --no-import-syntax "$ADAPTER" "$AGENTS_MD"
|
||||||
|
assert_failure
|
||||||
|
assert_output --partial "no reference"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "--help exits 0 and documents usage" {
|
||||||
|
run bash "$SCRIPT" --help
|
||||||
|
assert_success
|
||||||
|
assert_output --partial "Usage:"
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "fails with a clear error when the adapter file argument is missing" {
|
||||||
|
run bash "$SCRIPT"
|
||||||
|
assert_failure
|
||||||
|
assert_output --partial "required"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user