Skip to content

Commit 7ee2384

Browse files
hightempCopilot
andcommitted
docs: add guidelines for AI coding agents and update README badges
Co-authored-by: Copilot <copilot@github.com>
1 parent 8a2f126 commit 7ee2384

2 files changed

Lines changed: 263 additions & 3 deletions

File tree

AGENTS.md

Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
# AGENTS.md - Guidelines for AI Coding Agents
2+
3+
This document provides guidelines for AI agents working on the phvm (PHP Version Manager) codebase.
4+
5+
## Project Overview
6+
7+
phvm is a cross-platform PHP version manager written in Go 1.22. It installs PHP from source, manages multiple versions via symlinks, and handles extensions and php.ini configuration. The CLI is built with [cobra](https://github.com/spf13/cobra).
8+
9+
## Build & Development Commands
10+
11+
```bash
12+
# Build
13+
make build # Build the binary
14+
make build-all # Build for all platforms (linux/darwin/windows, amd64/arm64)
15+
16+
# Run without building
17+
make dev ARGS="install 8.3" # Run with go run
18+
19+
# Install
20+
make install # Install to GOBIN
21+
make install-local # Install to ~/.phvm/bin
22+
23+
# Clean
24+
make clean # Remove build artifacts
25+
26+
# Dependencies
27+
make deps # Download and tidy dependencies
28+
make update-deps # Update all dependencies
29+
```
30+
31+
## Linting & Formatting
32+
33+
```bash
34+
make lint # Run golangci-lint (installs if missing)
35+
make fmt # Format code with go fmt
36+
make vet # Run go vet
37+
38+
# Direct golangci-lint (if installed)
39+
golangci-lint run ./...
40+
```
41+
42+
Enabled linters: `errcheck`, `gosimple`, `govet`, `ineffassign`, `staticcheck`, `unused`, `gofmt`, `goimports`, `misspell`, `unconvert`, `unparam`, `revive`.
43+
44+
## Testing
45+
46+
```bash
47+
# Run all tests
48+
make test # Runs: go test -v -race -cover ./...
49+
50+
# Run tests with coverage report
51+
make test-coverage # Generates coverage.html
52+
53+
# Run a single test
54+
go test -v -run TestFunctionName ./internal/package/
55+
56+
# Run specific test case in table-driven test
57+
go test -v -run TestFunctionName/test_case_name ./internal/package/
58+
59+
# Examples
60+
go test -v -run TestParseVersion ./internal/core/
61+
go test -v -run TestAtomicWriteFile ./internal/fsutil/
62+
go test -v -run TestConfDManager/Create ./internal/ini/
63+
```
64+
65+
## Code Style Guidelines
66+
67+
### Imports
68+
69+
Order imports in three groups separated by blank lines:
70+
1. Standard library
71+
2. Third-party packages
72+
3. Local packages (`github.com/hightemp/phvm/...`)
73+
74+
```go
75+
import (
76+
"context"
77+
"fmt"
78+
"os"
79+
80+
"github.com/spf13/cobra"
81+
82+
"github.com/hightemp/phvm/internal/core"
83+
"github.com/hightemp/phvm/internal/log"
84+
)
85+
```
86+
87+
**Rules:**
88+
- No dot imports (enforced by revive)
89+
- Use `goimports` for automatic ordering
90+
91+
### Formatting
92+
93+
- Use `gofmt` with simplify enabled
94+
- Tabs for indentation (Go standard)
95+
- No trailing whitespace
96+
97+
### Naming Conventions
98+
99+
| Element | Convention | Example |
100+
|---------|------------|---------|
101+
| Packages | lowercase, short, descriptive | `cli`, `core`, `fsutil`, `remote` |
102+
| Exported types | PascalCase | `Client`, `Paths`, `Version` |
103+
| Unexported types | camelCase | `clientOptions` |
104+
| Exported functions | PascalCase, verb prefix | `NewClient()`, `ParseVersion()` |
105+
| Unexported functions | camelCase | `extractPriority()`, `normalizeIniName()` |
106+
| Constants (exported) | PascalCase | `LevelDebug`, `SpecialVersionAliases` |
107+
| Constants (unexported) | camelCase | `disabledSuffix` |
108+
| Interfaces | PascalCase, `-er` suffix when applicable | `io.Reader`, `Locker` |
109+
| Receivers | short, 1-2 letters | `(c *Client)`, `(p *Paths)`, `(v *Version)` |
110+
111+
### Error Handling
112+
113+
**Wrap errors with context:**
114+
```go
115+
if err != nil {
116+
return fmt.Errorf("create request: %w", err)
117+
}
118+
```
119+
120+
**Return early, avoid deep nesting:**
121+
```go
122+
func doSomething() error {
123+
if err := step1(); err != nil {
124+
return fmt.Errorf("step1: %w", err)
125+
}
126+
if err := step2(); err != nil {
127+
return fmt.Errorf("step2: %w", err)
128+
}
129+
return nil
130+
}
131+
```
132+
133+
**CLI error handling pattern:**
134+
```go
135+
func runCommand(cmd *cobra.Command, args []string) {
136+
if err := doWork(); err != nil {
137+
log.Error("Failed to do work: %v", err)
138+
os.Exit(1)
139+
}
140+
log.Success("Work completed")
141+
}
142+
```
143+
144+
### Comments & Documentation
145+
146+
**Package comments (required):**
147+
```go
148+
// Package core provides core functionality for phvm.
149+
package core
150+
```
151+
152+
**Exported function comments:**
153+
```go
154+
// ParseVersion parses a version string into a Version struct.
155+
func ParseVersion(s string) (*Version, error) {
156+
```
157+
158+
**Exported type comments:**
159+
```go
160+
// Client is an HTTP client with retry support.
161+
type Client struct {
162+
```
163+
164+
### Testing Patterns
165+
166+
**Table-driven tests with subtests:**
167+
```go
168+
func TestParseVersion(t *testing.T) {
169+
tests := []struct {
170+
input string
171+
expected *Version
172+
wantErr bool
173+
}{
174+
{"8.3.30", &Version{Major: 8, Minor: 3, Patch: 30}, false},
175+
{"", nil, true},
176+
}
177+
178+
for _, tt := range tests {
179+
t.Run(tt.input, func(t *testing.T) {
180+
v, err := ParseVersion(tt.input)
181+
if (err != nil) != tt.wantErr {
182+
t.Errorf("ParseVersion(%q) error = %v, wantErr %v", tt.input, err, tt.wantErr)
183+
}
184+
// ... assertions
185+
})
186+
}
187+
}
188+
```
189+
190+
**Temp directory cleanup:**
191+
```go
192+
tmpDir, err := os.MkdirTemp("", "phvm-test-*")
193+
if err != nil {
194+
t.Fatalf("Failed to create temp dir: %v", err)
195+
}
196+
defer os.RemoveAll(tmpDir)
197+
```
198+
199+
## Project Structure
200+
201+
```
202+
phvm/
203+
├── cmd/phvm/main.go # Entry point
204+
├── internal/
205+
│ ├── cli/ # Cobra commands (root.go, install.go, etc.)
206+
│ ├── core/ # Core types: Paths, Version, Config, Alias
207+
│ ├── build/ # PHP build logic and profiles
208+
│ ├── remote/ # HTTP client, php.net API, PECL
209+
│ ├── fsutil/ # Filesystem utilities (atomic writes, symlinks)
210+
│ ├── ini/ # php.ini management, conf.d
211+
│ ├── ext/ # Extension installation
212+
│ ├── shell/ # Shell init scripts
213+
│ ├── composer/ # Composer installation
214+
│ ├── doctor/ # Dependency checking
215+
│ └── log/ # Structured logging
216+
├── scripts/ # Install scripts (bash, PowerShell)
217+
├── Makefile # Build automation
218+
├── .golangci.yml # Linter configuration
219+
└── .goreleaser.yml # Release configuration
220+
```
221+
222+
## Dependencies
223+
224+
Key dependencies (see `go.mod`):
225+
- `github.com/spf13/cobra` - CLI framework
226+
- `github.com/Masterminds/semver/v3` - Semantic versioning
227+
- `github.com/fatih/color` - Terminal colors
228+
- `github.com/hashicorp/go-retryablehttp` - HTTP client with retries
229+
- `github.com/pelletier/go-toml/v2` - TOML config parsing
230+
- `github.com/schollz/progressbar/v3` - Progress bars
231+
232+
## Common Patterns
233+
234+
**Manager pattern for domain logic:**
235+
```go
236+
type InstalledManager struct {
237+
paths *Paths
238+
}
239+
240+
func NewInstalledManager(paths *Paths) *InstalledManager {
241+
return &InstalledManager{paths: paths}
242+
}
243+
244+
func (m *InstalledManager) IsInstalled(version string) bool { ... }
245+
```
246+
247+
**Options pattern for configuration:**
248+
```go
249+
type ClientOptions struct {
250+
UserAgent string
251+
Timeout time.Duration
252+
Retries int
253+
}
254+
255+
func DefaultClientOptions() ClientOptions { ... }
256+
func NewClient(opts ClientOptions) *Client { ... }
257+
```
258+
259+
**Atomic file operations:** Use `fsutil.AtomicWriteFile()` for safe file writes.

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
# phvm - PHP Version Manager
22

3-
![Experimental](https://img.shields.io/badge/status-experimental-orange)
4-
![Vibe Coded](https://img.shields.io/badge/vibe-coded-blueviolet)
3+
[![GitHub release](https://img.shields.io/github/v/release/hightemp/phvm)](https://github.com/hightemp/phvm/releases/latest)
4+
[![GitHub downloads](https://img.shields.io/github/downloads/hightemp/phvm/total)](https://github.com/hightemp/phvm/releases)
5+
[![Go Report Card](https://goreportcard.com/badge/github.com/hightemp/phvm)](https://goreportcard.com/report/github.com/hightemp/phvm)
6+
![](https://asdertasd.site/counter/phvm)
57

68
A fast, cross-platform PHP version manager inspired by [nvm](https://github.com/nvm-sh/nvm). Install PHP from source, manage multiple versions, and switch between them seamlessly.
79

@@ -350,4 +352,3 @@ MIT License - see [LICENSE](LICENSE) for details.
350352
- PHP source from [php.net](https://www.php.net/)
351353
- Extensions from [PECL](https://pecl.php.net/)
352354

353-
![](https://asdertasd.site/counter/phvm)

0 commit comments

Comments
 (0)