Publish AGENTS.md生成器 skill to marketplace
Constraint: Public skills are published only by explicit administrator action unless they are tracked third-party market sources. Confidence: high Scope-risk: narrow Directive: Keep private/internal skills out of the public marketplace and preserve normal incremental market Git history. Tested: Marketplace validation passed.
This commit is contained in:
@@ -303,6 +303,18 @@
|
||||
"authentication": "ON_INSTALL"
|
||||
},
|
||||
"category": "开发工具"
|
||||
},
|
||||
{
|
||||
"name": "generate-agents-md",
|
||||
"source": {
|
||||
"source": "local",
|
||||
"path": "./plugins/codex/plugins/generate-agents-md"
|
||||
},
|
||||
"policy": {
|
||||
"installation": "AVAILABLE",
|
||||
"authentication": "ON_INSTALL"
|
||||
},
|
||||
"category": "知识库与检索"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -303,6 +303,18 @@
|
||||
"authentication": "ON_INSTALL"
|
||||
},
|
||||
"category": "开发工具"
|
||||
},
|
||||
{
|
||||
"name": "generate-agents-md",
|
||||
"source": {
|
||||
"source": "local",
|
||||
"path": "./plugins/generate-agents-md"
|
||||
},
|
||||
"policy": {
|
||||
"installation": "AVAILABLE",
|
||||
"authentication": "ON_INSTALL"
|
||||
},
|
||||
"category": "知识库与检索"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "generate-agents-md",
|
||||
"version": "0.1.0",
|
||||
"description": "当需要创建、更新、标准化、审核或迁移 AGENTS.md 文件以及仓库级的 AI 智能体配置时使用,这些配置包括顶层指南或嵌套指南、项目入门相关内容、与 Claude/Copilot/Cursor 的兼容性设置,以及冗余上下文的清理工作。",
|
||||
"author": {
|
||||
"name": "EAPIL",
|
||||
"url": "https://git.playones.com/arechen/EapilSkillMarket"
|
||||
},
|
||||
"homepage": "https://git.playones.com/arechen/EapilSkillMarket",
|
||||
"repository": "https://git.playones.com/arechen/EapilSkillMarket",
|
||||
"license": "Proprietary",
|
||||
"keywords": [
|
||||
"eapil",
|
||||
"codex-skill",
|
||||
"generate-agents-md"
|
||||
],
|
||||
"skills": "./skills/",
|
||||
"interface": {
|
||||
"displayName": "AGENTS.md生成器",
|
||||
"shortDescription": "当需要创建、更新、标准化、审核或迁移 AGENTS.md 文件以及仓库级的 AI 智能体配置时使用,这些配置包括顶层指南或嵌套指南、项目入门相关内容、与 Claude/Copilot/Cursor 的兼容性设置,以及冗余上下文的清理工作。",
|
||||
"longDescription": "当需要创建、更新、标准化、审核或迁移 AGENTS.md 文件以及仓库级的 AI 智能体配置时使用,这些配置包括顶层指南或嵌套指南、项目入门相关内容、与 Claude/Copilot/Cursor 的兼容性设置,以及冗余上下文的清理工作。",
|
||||
"developerName": "EAPIL",
|
||||
"category": "知识库与检索",
|
||||
"capabilities": [
|
||||
"Read",
|
||||
"Write"
|
||||
],
|
||||
"defaultPrompt": [
|
||||
"使用 AGENTS.md生成器 帮我完成这个任务。"
|
||||
],
|
||||
"websiteURL": "https://git.playones.com/arechen/EapilSkillMarket",
|
||||
"privacyPolicyURL": "https://git.playones.com/arechen/EapilSkillMarket",
|
||||
"termsOfServiceURL": "https://git.playones.com/arechen/EapilSkillMarket",
|
||||
"brandColor": "#2563EB",
|
||||
"screenshots": [],
|
||||
"composerIcon": "./assets/market-icon.svg",
|
||||
"logo": "./assets/market-icon.svg"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="360" height="360" viewBox="0 0 32 32"><title>AGENTS.md生成器</title><g fill="none"><path fill="url(#SVGklx3zJXo)" d="M7.5 3A4.5 4.5 0 0 0 3 7.5v17A4.5 4.5 0 0 0 7.5 29h17a4.5 4.5 0 0 0 4.5-4.5v-17A4.5 4.5 0 0 0 24.5 3z"/><path fill="url(#SVGxO13MgXq)" d="M7.5 3A4.5 4.5 0 0 0 3 7.5v17A4.5 4.5 0 0 0 7.5 29h17a4.5 4.5 0 0 0 4.5-4.5v-17A4.5 4.5 0 0 0 24.5 3z"/><path fill="url(#SVGxluVFb5q)" d="M7.5 3A4.5 4.5 0 0 0 3 7.5v17A4.5 4.5 0 0 0 7.5 29h17a4.5 4.5 0 0 0 4.5-4.5v-17A4.5 4.5 0 0 0 24.5 3z"/><path fill="url(#SVGPD31pBoO)" d="M7.5 3A4.5 4.5 0 0 0 3 7.5v17A4.5 4.5 0 0 0 7.5 29h17a4.5 4.5 0 0 0 4.5-4.5v-17A4.5 4.5 0 0 0 24.5 3z"/><path fill="url(#SVGOvZEKcyA)" d="M7.5 3A4.5 4.5 0 0 0 3 7.5v17A4.5 4.5 0 0 0 7.5 29h17a4.5 4.5 0 0 0 4.5-4.5v-17A4.5 4.5 0 0 0 24.5 3z"/><path fill="url(#SVGdi1M5dPd)" d="M12 10.5a1.5 1.5 0 1 0-3 0a1.5 1.5 0 0 0 3 0m0 5.5a1.5 1.5 0 1 0-3 0a1.5 1.5 0 0 0 3 0m-1.5 7a1.5 1.5 0 1 0 0-3a1.5 1.5 0 0 0 0 3M14 10.5a1 1 0 0 0 1 1h7a1 1 0 1 0 0-2h-7a1 1 0 0 0-1 1m1 4.5a1 1 0 1 0 0 2h7a1 1 0 1 0 0-2zm-1 6.5a1 1 0 0 0 1 1h7a1 1 0 1 0 0-2h-7a1 1 0 0 0-1 1"/><path fill="url(#SVG2J5EFbQO)" d="m31.74 13.656l-.919-.299a1.9 1.9 0 0 1-1.199-1.197l-.298-.918a.363.363 0 0 0-.684 0l-.299.918a1.89 1.89 0 0 1-1.18 1.197l-.919.299a.363.363 0 0 0 0 .684l.919.298a1.9 1.9 0 0 1 1.198 1.202l.299.918a.363.363 0 0 0 .684 0l.299-.918a1.89 1.89 0 0 1 1.198-1.197l.919-.299a.363.363 0 0 0 0-.684z"/><path fill="url(#SVGNaWMwbPh)" d="M21.775 8.837a3.5 3.5 0 0 0-1.647-1.168l-1.684-.546a.665.665 0 0 1 0-1.254l1.684-.547a3.47 3.47 0 0 0 2.15-2.154l.014-.042l.547-1.682a.665.665 0 0 1 1.255 0l.547 1.682a3.47 3.47 0 0 0 2.198 2.196l1.683.547l.034.008a.665.665 0 0 1 0 1.254l-1.684.547a3.47 3.47 0 0 0-2.197 2.196l-.548 1.682l-.016.042a.664.664 0 0 1-1.238-.042l-.548-1.682a3.5 3.5 0 0 0-.55-1.037"/><defs><radialGradient id="SVGxO13MgXq" cx="0" cy="0" r="1" gradientTransform="matrix(-3.5 0 0 -1.74793 29 14.5)" gradientUnits="userSpaceOnUse"><stop stop-color="#4a43cb"/><stop offset="1" stop-color="#4a43cb" stop-opacity="0"/></radialGradient><radialGradient id="SVGxluVFb5q" cx="0" cy="0" r="1" gradientTransform="matrix(-7 0 0 -3.49587 23.5 7.5)" gradientUnits="userSpaceOnUse"><stop stop-color="#4a43cb"/><stop offset="1" stop-color="#4a43cb" stop-opacity="0"/></radialGradient><radialGradient id="SVGPD31pBoO" cx="0" cy="0" r="1" gradientTransform="matrix(0 6 -2.99646 0 23.5 7.5)" gradientUnits="userSpaceOnUse"><stop stop-color="#4a43cb"/><stop offset="1" stop-color="#4a43cb" stop-opacity="0"/></radialGradient><radialGradient id="SVGOvZEKcyA" cx="0" cy="0" r="1" gradientTransform="matrix(0 4 -1.99764 0 29 14.5)" gradientUnits="userSpaceOnUse"><stop stop-color="#4a43cb"/><stop offset="1" stop-color="#4a43cb" stop-opacity="0"/></radialGradient><radialGradient id="SVG2J5EFbQO" cx="0" cy="0" r="1" gradientTransform="rotate(63.379 17.2 6.887)scale(34.3364 26.737)" gradientUnits="userSpaceOnUse"><stop offset=".718" stop-color="#ffcd0f"/><stop offset=".991" stop-color="#e67505"/></radialGradient><radialGradient id="SVGNaWMwbPh" cx="0" cy="0" r="1" gradientTransform="rotate(61.2 24.745 -9.672)scale(47.2968 36.829)" gradientUnits="userSpaceOnUse"><stop offset=".698" stop-color="#ffcd0f"/><stop offset=".991" stop-color="#e67505"/></radialGradient><linearGradient id="SVGklx3zJXo" x1="3.929" x2="21.872" y1="7.875" y2="26.517" gradientUnits="userSpaceOnUse"><stop stop-color="#0fafff"/><stop offset="1" stop-color="#2764e7"/></linearGradient><linearGradient id="SVGdi1M5dPd" x1="11.692" x2="21.978" y1="10.077" y2="34.999" gradientUnits="userSpaceOnUse"><stop stop-color="#fff"/><stop offset="1" stop-color="#b3e0ff"/></linearGradient></defs></g></svg>
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
@@ -0,0 +1,65 @@
|
||||
---
|
||||
name: generate-agents-md
|
||||
description: Use when Codex needs to create, refresh, standardize, audit, or migrate AGENTS.md files or repository-level AI agent instructions, including root or nested guides, project onboarding context, Claude/Copilot/Cursor compatibility, and context-bloat cleanup.
|
||||
---
|
||||
|
||||
# Generate AGENTS.md
|
||||
|
||||
## Overview
|
||||
|
||||
Create lean, scoped, verifiable `AGENTS.md` files from repository facts. Treat root `AGENTS.md` as always-on context: a map and guardrail, not an encyclopedia.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. **Scan facts before drafting.** Inspect existing `AGENTS.md`, `CLAUDE.md`, `.github/copilot-instructions.md`, tool rules, manifests, CI, key directories, and docs. Use `rg --files` first. Record unknowns instead of guessing.
|
||||
2. **Extract only verifiable facts.** Commands must come from files such as `package.json`, `Makefile`, `pyproject.toml`, `Cargo.toml`, `go.mod`, CI workflows, or repo docs. Paths must exist.
|
||||
3. **Choose the scope model.**
|
||||
- Use one root file for small repos with shared commands and conventions.
|
||||
- Use root plus child `AGENTS.md` files for monorepos or directories with distinct commands, risks, or conventions.
|
||||
- Keep complex task workflows in skills or references, not in always-on `AGENTS.md`.
|
||||
4. **Draft with the standard contract.** Read `references/agents-md-reference.md` for root and child templates, section guidance, and validation criteria.
|
||||
5. **Update conservatively.** If `AGENTS.md` already exists, merge rather than replace. Preserve user-written sections unless they are clearly stale or conflict with verified facts. Show conflicts before changing them when possible.
|
||||
6. **Validate before finishing.** Run the bundled validator when applicable:
|
||||
|
||||
```bash
|
||||
python path/to/generate-agents-md/scripts/validate_agents_md.py --repo /path/to/repo --file /path/to/repo/AGENTS.md
|
||||
```
|
||||
|
||||
Also run repo-native markdown/prose checks if they exist.
|
||||
|
||||
## Content Placement
|
||||
|
||||
| Content | Put it in |
|
||||
|---|---|
|
||||
| Global project purpose, key paths, commands, completion checks, risk boundaries | Root `AGENTS.md` |
|
||||
| Directory-specific commands, naming, tests, generated files, local risks | Child `AGENTS.md` |
|
||||
| Long release/migration/audit workflows, repeated procedures, tool recipes | Skill or reference file |
|
||||
| Human contributor background, product explanation, broad docs | `README.md` or `docs/` |
|
||||
|
||||
## Quality Bar
|
||||
|
||||
- Keep root files concise, usually under 200 lines.
|
||||
- Use exact commands, exact paths, and concrete rules.
|
||||
- Prefer `Always`, `Ask first`, and `Never` boundaries for risk.
|
||||
- State user instructions override repo guidance; child files override parent files for their directory.
|
||||
- Do not include secrets, internal credentials, or unverifiable environment assumptions.
|
||||
- Do not invent commands, paths, tests, package managers, ownership, or architecture.
|
||||
|
||||
## Final Response
|
||||
|
||||
Report:
|
||||
|
||||
- Files created or updated.
|
||||
- Evidence used for commands and key paths.
|
||||
- Validation commands run and results.
|
||||
- Unknowns or items that need human confirmation.
|
||||
|
||||
## Common Mistakes
|
||||
|
||||
| Mistake | Fix |
|
||||
|---|---|
|
||||
| Root file repeats docs or long workflows | Move detail to child guides, skills, or references |
|
||||
| Commands are tool names instead of runnable commands | Use exact invocations like `pnpm test` or `make check` |
|
||||
| Child guide repeats parent rules | Keep only local differences |
|
||||
| Existing custom guidance is overwritten | Merge and preserve non-conflicting user content |
|
||||
| Placeholder text remains | Replace with verified facts or write `Unknown` in review notes, not in final guide |
|
||||
@@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "Generate AGENTS.md"
|
||||
short_description: "Create lean project agent guides"
|
||||
default_prompt: "Use $generate-agents-md to create a lean, verified AGENTS.md for this repository."
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
# AGENTS.md Reference
|
||||
|
||||
Use this reference when drafting, updating, or auditing `AGENTS.md`.
|
||||
|
||||
## Fact Sources
|
||||
|
||||
| Need | Prefer these sources |
|
||||
|---|---|
|
||||
| Package manager and scripts | `package.json`, `pnpm-lock.yaml`, `yarn.lock`, `package-lock.json`, `bun.lockb` |
|
||||
| Python commands | `pyproject.toml`, `uv.lock`, `poetry.lock`, `requirements*.txt`, `tox.ini`, `noxfile.py` |
|
||||
| Go/Rust/.NET/Java commands | `go.mod`, `Cargo.toml`, `*.csproj`, `pom.xml`, `build.gradle*` |
|
||||
| CI expectations | `.github/workflows/*`, `.gitlab-ci.yml`, `azure-pipelines.yml`, `Jenkinsfile` |
|
||||
| Architecture and boundaries | `README.md`, `CONTRIBUTING.md`, `docs/`, existing instruction files |
|
||||
| Generated or dangerous paths | `.gitignore`, generator configs, migration dirs, infra dirs, lockfiles |
|
||||
|
||||
Never promote a guessed command or path into final `AGENTS.md`. If a fact cannot be confirmed, omit it or list it as a final-response unknown.
|
||||
|
||||
## Scope Decision
|
||||
|
||||
Choose **root only** when:
|
||||
|
||||
- The repo has one main stack and one set of commands.
|
||||
- Directory conventions are uniform.
|
||||
- A concise root guide can cover common tasks without local exceptions.
|
||||
|
||||
Choose **root plus child guides** when:
|
||||
|
||||
- The repo is a monorepo or has separate apps, services, docs, packages, or examples.
|
||||
- Commands differ by directory.
|
||||
- Generated files, migrations, security code, or public API contracts are localized.
|
||||
- Parent guidance would become long because of local exceptions.
|
||||
|
||||
Root files should orient. Child files should specialize.
|
||||
|
||||
## Root Template
|
||||
|
||||
```markdown
|
||||
# Project Agent Guide
|
||||
|
||||
## Project Overview
|
||||
[1-3 factual sentences: project type, primary stack, most important working constraint.]
|
||||
|
||||
## Scope
|
||||
- This file applies to the whole repository.
|
||||
- More specific `AGENTS.md` files in subdirectories override this file for their paths.
|
||||
- User instructions in the current task override repository guidance.
|
||||
|
||||
## Quick Commands
|
||||
- Install: `[exact command]`
|
||||
- Dev: `[exact command]`
|
||||
- Test: `[exact command]`
|
||||
- Lint: `[exact command]`
|
||||
- Build: `[exact command]`
|
||||
- Typecheck: `[exact command]`
|
||||
|
||||
## Key Paths
|
||||
- `path/` - purpose
|
||||
- `path/file.ext` - purpose
|
||||
|
||||
## Architecture Boundaries
|
||||
- [Concrete boundary or dependency rule.]
|
||||
- [High-risk area and why it matters.]
|
||||
|
||||
## Conventions
|
||||
- [Style, naming, formatting, import, or documentation rule that is specific to this repo.]
|
||||
- [Testing expectation that is actually supported by the repo.]
|
||||
|
||||
## Definition of Done
|
||||
- Run `[exact command]` before finishing changes that touch [scope].
|
||||
- If a required command cannot run, report the reason and the expected follow-up.
|
||||
|
||||
## Boundaries
|
||||
- Always: [concrete safe behavior]
|
||||
- Ask first: [dependency, schema, CI, public API, security, data migration, billing, destructive operation]
|
||||
- Never: [secrets, generated/vendor edits, broad refactors without request]
|
||||
|
||||
## Child Guides
|
||||
- `subsystem/AGENTS.md` - local rules for [subsystem]
|
||||
|
||||
## References
|
||||
- `docs/file.md` - when to read it
|
||||
```
|
||||
|
||||
Remove sections that have no verified content. Do not leave placeholder text.
|
||||
|
||||
## Child Template
|
||||
|
||||
```markdown
|
||||
# Local Agent Guide
|
||||
|
||||
## Local Purpose
|
||||
[What this directory owns. Keep it factual.]
|
||||
|
||||
## Inherits
|
||||
- Follow the nearest parent `AGENTS.md` unless this file gives a more specific local rule.
|
||||
|
||||
## Local Commands
|
||||
- Test: `[exact command]`
|
||||
- Lint: `[exact command]`
|
||||
|
||||
## Local Conventions
|
||||
- [Naming, code organization, generated files, docs, or test placement specific to this path.]
|
||||
|
||||
## Local Risks
|
||||
- Ask first: [local high-risk changes]
|
||||
- Never: [local forbidden edits]
|
||||
```
|
||||
|
||||
If a child directory has no distinct commands, omit `Local Commands` rather than inventing commands.
|
||||
|
||||
## Scoring Checklist
|
||||
|
||||
A strong guide passes these checks:
|
||||
|
||||
- **Specific:** Every command and path is concrete.
|
||||
- **Verified:** Commands and paths trace to repository files.
|
||||
- **Scoped:** Root guidance stays global; child guidance contains only local differences.
|
||||
- **Short:** Root is usually under 200 lines and avoids long procedures.
|
||||
- **Actionable:** A new agent can find the right files, run the right checks, and avoid high-risk edits.
|
||||
- **Compatible:** It states parent/child precedence and user-instruction precedence.
|
||||
- **Maintainable:** It avoids duplicated docs and points to references for deep background.
|
||||
|
||||
## Audit Signals
|
||||
|
||||
Flag these during updates:
|
||||
|
||||
- `TODO`, `TBD`, `FIXME`, bracket placeholders, or template language.
|
||||
- Commands that do not exist in manifests, Makefiles, CI, or docs.
|
||||
- Paths that no longer exist.
|
||||
- Duplicated or conflicting parent/child rules.
|
||||
- Long release, migration, or audit procedures in the root guide.
|
||||
- Tool-specific assumptions presented as cross-tool rules.
|
||||
- Secrets, internal credentials, or sensitive environment details.
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Lightweight AGENTS.md validator.
|
||||
|
||||
Checks for common problems before an agent guide is treated as done:
|
||||
missing sections, placeholders, nonexistent referenced paths, and package
|
||||
manager commands that do not map to package.json scripts.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
PLACEHOLDER_RE = re.compile(
|
||||
r"\b(TODO|TBD|FIXME|XXX|REVIEW_NEEDED)\b|"
|
||||
r"\{\{[^}]+\}\}|"
|
||||
r"<[^>\n]+>|"
|
||||
r"\[[^\]\n]*(exact command|path|project|真实|项目类型|关键)[^\]\n]*\]",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
|
||||
CODE_SPAN_RE = re.compile(r"`([^`\n]+)`")
|
||||
HEADING_RE = re.compile(r"^##\s+(.+?)\s*$", re.MULTILINE)
|
||||
|
||||
ROOT_REQUIRED_HEADINGS = {
|
||||
"Project Overview",
|
||||
"Scope",
|
||||
"Quick Commands",
|
||||
"Key Paths",
|
||||
"Definition of Done",
|
||||
"Boundaries",
|
||||
}
|
||||
|
||||
LOCAL_REQUIRED_HEADINGS = {
|
||||
"Local Purpose",
|
||||
"Inherits",
|
||||
"Local Conventions",
|
||||
"Local Risks",
|
||||
}
|
||||
|
||||
PATH_HINT_RE = re.compile(r"(^\.{1,2}[\\/]|[\\/]|^[\w.-]+\.[A-Za-z0-9]+$)")
|
||||
COMMAND_PREFIX_RE = re.compile(
|
||||
r"^(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?([\w:.-]+)(?:\s|$)"
|
||||
)
|
||||
|
||||
|
||||
def load_package_scripts(repo: Path) -> dict[str, set[str]]:
|
||||
scripts: dict[str, set[str]] = {}
|
||||
for package_file in repo.rglob("package.json"):
|
||||
if "node_modules" in package_file.parts:
|
||||
continue
|
||||
try:
|
||||
data = json.loads(package_file.read_text(encoding="utf-8"))
|
||||
except (OSError, json.JSONDecodeError):
|
||||
continue
|
||||
package_scripts = data.get("scripts")
|
||||
if isinstance(package_scripts, dict):
|
||||
scripts[str(package_file.relative_to(repo))] = set(package_scripts)
|
||||
return scripts
|
||||
|
||||
|
||||
def normalize_path_token(token: str) -> str | None:
|
||||
if token.startswith(("http://", "https://", "$")):
|
||||
return None
|
||||
if any(part in token for part in ("&&", "||", " --", " -")):
|
||||
return None
|
||||
if token in {"AGENTS.md", "CLAUDE.md", "README.md"}:
|
||||
return token
|
||||
if PATH_HINT_RE.search(token):
|
||||
return token.rstrip("/")
|
||||
return None
|
||||
|
||||
|
||||
def path_exists(repo: Path, token: str) -> bool:
|
||||
candidate = (repo / token).resolve()
|
||||
try:
|
||||
candidate.relative_to(repo.resolve())
|
||||
except ValueError:
|
||||
return False
|
||||
return candidate.exists()
|
||||
|
||||
|
||||
def validate(args: argparse.Namespace) -> tuple[list[str], list[str]]:
|
||||
repo = Path(args.repo).resolve()
|
||||
guide = Path(args.file).resolve()
|
||||
errors: list[str] = []
|
||||
warnings: list[str] = []
|
||||
|
||||
if not repo.exists():
|
||||
return [f"Repository path does not exist: {repo}"], warnings
|
||||
if not guide.exists():
|
||||
return [f"Guide file does not exist: {guide}"], warnings
|
||||
|
||||
text = guide.read_text(encoding="utf-8")
|
||||
headings = set(HEADING_RE.findall(text))
|
||||
|
||||
required = LOCAL_REQUIRED_HEADINGS if args.local else ROOT_REQUIRED_HEADINGS
|
||||
missing = sorted(required - headings)
|
||||
if missing:
|
||||
errors.append("Missing recommended headings: " + ", ".join(missing))
|
||||
|
||||
placeholders = sorted(set(match.group(0) for match in PLACEHOLDER_RE.finditer(text)))
|
||||
if placeholders:
|
||||
errors.append("Placeholder or review marker remains: " + ", ".join(placeholders[:10]))
|
||||
|
||||
code_spans = CODE_SPAN_RE.findall(text)
|
||||
for token in code_spans:
|
||||
path_token = normalize_path_token(token.strip())
|
||||
if path_token and not path_exists(repo, path_token):
|
||||
warnings.append(f"Referenced path may not exist: `{token}`")
|
||||
|
||||
package_scripts = load_package_scripts(repo)
|
||||
known_scripts = set().union(*package_scripts.values()) if package_scripts else set()
|
||||
for token in code_spans:
|
||||
match = COMMAND_PREFIX_RE.match(token.strip())
|
||||
if not match:
|
||||
continue
|
||||
script_name = match.group(1)
|
||||
if script_name in {"install", "add", "remove", "exec", "dlx", "create"}:
|
||||
continue
|
||||
if known_scripts and script_name not in known_scripts:
|
||||
warnings.append(
|
||||
f"Package command references missing package.json script: `{token}`"
|
||||
)
|
||||
|
||||
return errors, warnings
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Validate AGENTS.md guardrails.")
|
||||
parser.add_argument("--repo", required=True, help="Repository root to validate against.")
|
||||
parser.add_argument("--file", required=True, help="AGENTS.md file to validate.")
|
||||
parser.add_argument("--local", action="store_true", help="Validate a child/local guide.")
|
||||
parser.add_argument(
|
||||
"--warnings-as-errors",
|
||||
action="store_true",
|
||||
help="Exit nonzero when warnings are present.",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
errors, warnings = validate(args)
|
||||
for error in errors:
|
||||
print(f"ERROR: {error}", file=sys.stderr)
|
||||
for warning in warnings:
|
||||
print(f"WARNING: {warning}", file=sys.stderr)
|
||||
|
||||
if errors or (args.warnings_as_errors and warnings):
|
||||
return 1
|
||||
print("AGENTS.md validation passed")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user