Files
gh-netresearch-claude-code-…/references/examples/coding-agent-cli/AGENTS.md
2025-11-30 08:43:17 +08:00

309 lines
9.4 KiB
Markdown

<!-- Managed by agent: keep sections & order; edit content, not structure. Last updated: 2025-10-09 -->
# AI CLI Preparation - Agent Guide (Root)
**Thin root file**: See scoped AGENTS.md files for specific areas.
## Precedence & Scoped Files
This root AGENTS.md provides global defaults. **Nearest AGENTS.md wins** for specific rules.
**Scoped files:**
- [scripts/AGENTS.md](scripts/AGENTS.md) - Shell installation scripts
## Overview
AI CLI Preparation is an environment audit tool ensuring AI coding agents (like Claude Code) have access to necessary developer tools. It detects 50+ tools, reports versions, and provides installation guidance.
**Architecture:**
- **Phase 1 (Complete)**: Tool detection, version auditing, offline-first caching
- **Phase 2 (Planned)**: Context-aware installation/upgrade management (see [docs/PRD.md](docs/PRD.md))
**Tech Stack:**
- Python 3.10+ (standard library only, no external deps for core)
- Make for task automation
- Shell scripts (Bash) for installation
- JSON for caching (latest_versions.json, tools_snapshot.json)
**Key Files:**
- `cli_audit.py` (2,375 lines): Main audit engine, 50+ tool definitions
- `smart_column.py`: ANSI/emoji-aware table formatting
- `scripts/`: 13+ installation scripts (install/update/uninstall/reconcile)
- `docs/`: Comprehensive technical documentation (12 files, 189KB)
## Setup
**Requirements:**
- Python 3.10+ (Python 3.14.0rc2 tested)
- Standard library only (no pip install needed for core)
- Optional: pyflakes for linting
**First-time setup:**
```bash
# Allow direnv (if using)
direnv allow
# Show available commands
make help
# Update snapshot (requires network)
make update
# Run audit from snapshot (fast, offline-capable)
make audit
```
**Environment variables:**
```bash
# See .env.default for all options
CLI_AUDIT_COLLECT=1 # Collect-only mode (write snapshot)
CLI_AUDIT_RENDER=1 # Render-only mode (read snapshot)
CLI_AUDIT_OFFLINE=1 # Offline mode (manual cache only)
CLI_AUDIT_DEBUG=1 # Debug output
CLI_AUDIT_JSON=1 # JSON output
```
## Build & Tests
**Primary commands:**
```bash
make audit # Render from snapshot (no network, <100ms)
make update # Collect fresh data, write snapshot (~10s)
make audit-offline # Offline audit with hints
make lint # Run pyflakes (if installed)
make upgrade # Interactive upgrade guide
```
**Single tool audit:**
```bash
make audit-ripgrep # Audit specific tool
make audit-offline-python-core # Role-based preset
```
**Installation scripts:**
```bash
make install-python # Install Python toolchain (uv)
make install-node # Install Node.js (nvm)
make install-core # Install core tools (fd, fzf, ripgrep, jq, etc.)
```
**Testing:**
```bash
# Smoke test (verifies table output and JSON format)
./scripts/test_smoke.sh
# Test single tool detection
CLI_AUDIT_DEBUG=1 python3 cli_audit.py --only ripgrep
# Validate snapshot
jq '.__meta__' tools_snapshot.json
```
**No formal test suite yet** - README acknowledges: "currently ships without tests"
- Smoke tests exist (test_smoke.sh)
- Manual validation workflows documented
## Code Style
**Python:**
- PEP 8 style (4-space indent, snake_case)
- Type hints used (`from __future__ import annotations`)
- Frozen dataclasses for immutability (`@dataclass(frozen=True)`)
- Docstrings minimal (focus on inline comments)
**Formatting:**
- EditorConfig enforced: LF, UTF-8, 4 spaces, trim trailing whitespace
- No auto-formatter configured (manual formatting)
- Lint via pyflakes: `make lint`
**Shell scripts:**
- Bash with `set -euo pipefail`
- Shellcheck-compliant (best effort)
- Consistent error handling (see scripts/lib/)
**Conventions:**
- File paths: Absolute paths, no auto-commit
- Functions: Snake_case, descriptive names
- Constants: UPPER_CASE (e.g., MANUAL_LOCK, HINTS_LOCK)
- Lock ordering: MANUAL_LOCK → HINTS_LOCK (enforced for safety)
## Security
**Secrets:**
- No secrets in VCS
- GITHUB_TOKEN optional (for GitHub API rate limit increase)
- Set via environment: `export GITHUB_TOKEN=ghp_...`
**Network:**
- HTTPS-only for upstream queries
- Retry logic with exponential backoff
- Per-origin rate limits (GitHub: 5/min, PyPI: 10/min, crates.io: 5/min)
- Timeout enforcement (default: 3s, configurable)
**Input validation:**
- Tool names validated against TOOLS registry
- Version strings sanitized (extract_version_number)
- Subprocess calls use lists, not shell=True (where possible)
**Caching:**
- Atomic file writes prevent corruption
- Offline-first design (committed latest_versions.json)
- No arbitrary code execution (package manager commands only)
## PR/Commit Checklist
**Before commit:**
- [ ] Run `make lint` (pyflakes clean)
- [ ] Run `make audit` (verify snapshot renders)
- [ ] Test affected tool: `make audit-<tool>`
- [ ] Update docs if behavior changed (README.md, docs/, scripts/README.md)
- [ ] Add/update smoke test if new output format
**Commit messages:**
- Conventional Commits format: `type(scope): description`
- Examples:
- `feat(audit): add snapshot-based collect/render modes`
- `fix(locks): enforce MANUAL_LOCK→HINTS_LOCK ordering`
- `docs(prd): add Phase 2 specifications and ADRs`
- `chore(cache): update latest_versions.json`
**Pull requests:**
- Keep PRs small (~≤300 net LOC changed)
- Link to issue/ticket if exists
- Update CHANGELOG section in PR description
- Ensure CI passes (when added)
## Good vs Bad Examples
**Good: Atomic dataclass with type safety**
```python
@dataclass(frozen=True)
class Tool:
name: str
candidates: tuple[str, ...]
source_kind: str # gh|pypi|crates|npm|gnu|skip
source_args: tuple[str, ...]
```
**Bad: Mutable dict with unclear types**
```python
# Don't do this
tool = {
'name': 'ripgrep',
'candidates': ['rg'], # List instead of tuple
'source': 'github', # Unclear allowed values
}
```
**Good: Lock ordering enforcement**
```python
def update_manual_cache(tool: str, version: str) -> None:
with MANUAL_LOCK: # Acquire first
with HINTS_LOCK: # Then hints
# Safe: consistent ordering prevents deadlock
```
**Bad: Lock ordering violation**
```python
def update_cache(tool: str) -> None:
with HINTS_LOCK: # Wrong order!
with MANUAL_LOCK:
# Deadlock risk
```
**Good: Parallel execution with isolation**
```python
with ThreadPoolExecutor(max_workers=16) as executor:
futures = [executor.submit(audit_tool, tool) for tool in TOOLS]
for future in as_completed(futures):
result = future.result() # Failures isolated
```
**Bad: Sequential execution**
```python
results = []
for tool in TOOLS: # Slow: 50 tools * 3s = 150s
results.append(audit_tool(tool))
```
## When Stuck
**Tool detection failing:**
1. Check PATH: `echo $PATH | tr ':' '\n'`
2. Debug single tool: `CLI_AUDIT_DEBUG=1 python3 cli_audit.py --only <tool>`
3. Check version flag: `<tool> --version` or `<tool> -v`
4. See [docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md#version-detection-failures)
**Network issues:**
1. Increase timeout: `CLI_AUDIT_TIMEOUT_SECONDS=10 make update`
2. More retries: `CLI_AUDIT_HTTP_RETRIES=5 make update`
3. Use offline mode: `make audit-offline`
4. See [docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md#network-timeout-issues)
**Cache corruption:**
1. Remove caches: `rm latest_versions.json tools_snapshot.json`
2. Regenerate: `make update`
**Installation script fails:**
1. Check permissions: `make scripts-perms`
2. Debug script: `bash -x ./scripts/install_<tool>.sh`
3. See [scripts/README.md](scripts/README.md) for per-script troubleshooting
**Documentation:**
- Start with [docs/QUICK_REFERENCE.md](docs/QUICK_REFERENCE.md) for one-liners
- See [docs/INDEX.md](docs/INDEX.md) for navigation by role/task
- Architecture details: [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)
- API reference: [docs/API_REFERENCE.md](docs/API_REFERENCE.md)
## House Rules
**Defaults** (override in scoped AGENTS.md if needed):
**Commits:**
- Atomic commits (single logical change)
- Conventional Commits: `type(scope): description`
- Keep PRs small (~≤300 net LOC changed)
- Ticket IDs in commits/PRs if exists
**Type-safety:**
- Use type hints (`from __future__ import annotations`)
- Frozen dataclasses for immutability
- No `Any` unless truly dynamic
**Design principles:**
- SOLID, KISS, DRY, YAGNI
- Composition > Inheritance
- Law of Demeter (minimal coupling)
**Dependencies:**
- Standard library preferred (no external Python deps for core)
- Latest stable versions when external deps needed
- Document why in Decision Log (ADRs for Phase 2)
**Security:**
- No secrets in VCS
- HTTPS-only for network calls
- No arbitrary code execution
- Input validation on external data
**Documentation currency:**
- Update docs in same PR as behavior changes
- No drift between code and docs
- Document non-obvious decisions in ADRs (see docs/adr/)
**Testing:**
- Aim for ≥80% coverage on changed code (when test suite added)
- Bugfixes use TDD: failing test first, then fix
- New code paths need tests (future requirement)
**Current status:**
- Phase 1: Production-ready detection/audit
- Phase 2: Planned installation/upgrade (see [docs/PRD.md](docs/PRD.md))
- No unit tests yet (acknowledged in README)
---
**Quick Start:** New to the project? Start with [README.md](README.md) → [docs/QUICK_REFERENCE.md](docs/QUICK_REFERENCE.md) → [docs/INDEX.md](docs/INDEX.md)
**Contributing:** See [docs/DEVELOPER_GUIDE.md](docs/DEVELOPER_GUIDE.md) for detailed contribution guide