📦 deps(thirdparty): update snapshots
This commit is contained in:
+204
@@ -0,0 +1,204 @@
|
||||
# Language Adapter Schema
|
||||
|
||||
Every language adapter must follow this schema. Adapters are the single source of truth
|
||||
for all language-specific behavior across the harness system.
|
||||
|
||||
## Design Principles
|
||||
|
||||
1. **Discover, don't assume**: Adapters define detection rules, not the core system
|
||||
2. **One adapter, one language**: Each adapter is self-contained for one language ecosystem
|
||||
3. **Graceful degradation**: Every field is optional — missing fields fall back to generic behavior
|
||||
4. **Extensibility**: Adding a new language = adding one adapter file, zero core changes
|
||||
|
||||
## Schema Definition
|
||||
|
||||
```yaml
|
||||
adapter:
|
||||
# ─── Metadata ───────────────────────────────────────────────
|
||||
language: string # Unique identifier: go, typescript, python, java, rust, etc.
|
||||
display_name: string # Human-readable: "Go", "TypeScript", "Python", etc.
|
||||
version: string # Adapter schema version (currently "1.0")
|
||||
|
||||
# ─── Detection ──────────────────────────────────────────────
|
||||
# How to identify this language in a project.
|
||||
# Detection runs in order; first match with highest confidence wins.
|
||||
detection:
|
||||
# Files whose existence signals this language (ANY match = candidate)
|
||||
files: [string]
|
||||
# Optional: require file content patterns for higher confidence
|
||||
content_patterns:
|
||||
- file: string # Glob pattern (e.g., "*.toml", "package.json")
|
||||
pattern: string # Regex to match inside the file
|
||||
# Overall confidence when detection.files match (0.0 - 1.0)
|
||||
confidence: float
|
||||
|
||||
# ─── Commands ───────────────────────────────────────────────
|
||||
# Standard development commands. null = not applicable for this language.
|
||||
# These are defaults; project-level overrides in DEVELOPMENT.md or
|
||||
# harness/config/validate.json always take priority.
|
||||
commands:
|
||||
build: string | null # Compile/transpile: "go build ./...", "npm run build"
|
||||
test: string | null # Run tests: "go test ./...", "npm test"
|
||||
lint: string | null # General linting: "golangci-lint run", "npm run lint"
|
||||
lint_arch: string | null # Architectural linting: "make lint-arch", "npm run lint:arch"
|
||||
format: string | null # Code formatting: "gofmt -w .", "prettier --write ."
|
||||
start: string | null # Start the application: "go run main.go", "npm start"
|
||||
dev: string | null # Development mode: "air", "npm run dev"
|
||||
|
||||
# ─── Package Manager ────────────────────────────────────────
|
||||
# How to detect and use the package manager.
|
||||
package_manager:
|
||||
# Detection priority: first match wins
|
||||
detection:
|
||||
- lockfile: string # e.g., "pnpm-lock.yaml"
|
||||
manager: string # e.g., "pnpm"
|
||||
- lockfile: string
|
||||
manager: string
|
||||
default: string # Fallback if no lockfile: "npm", "pip", etc.
|
||||
install_command: string # Template: "{manager} install"
|
||||
|
||||
# ─── Route Detection ────────────────────────────────────────
|
||||
# How to find HTTP routes, CLI commands, and other entry points.
|
||||
# Used by verify.py and generate_task_verification.py.
|
||||
route_detection:
|
||||
# Indicators that this project is a server (scan file contents)
|
||||
server_indicators:
|
||||
- pattern: string # Regex to find in source files
|
||||
description: string # Human-readable explanation
|
||||
frameworks: [string] # Associated frameworks: ["chi", "gin"]
|
||||
|
||||
# Indicators that this project is a CLI tool
|
||||
cli_indicators:
|
||||
- pattern: string
|
||||
description: string
|
||||
frameworks: [string]
|
||||
|
||||
# Indicators that this project is a frontend app
|
||||
frontend_indicators:
|
||||
- pattern: string
|
||||
description: string
|
||||
frameworks: [string]
|
||||
|
||||
# Route/command extraction patterns
|
||||
patterns:
|
||||
- type: route # "route" for HTTP, "command" for CLI
|
||||
regex: string # Extraction regex with named groups
|
||||
groups: [string] # Named groups: [method, path] or [command_name]
|
||||
frameworks: [string] # Which frameworks this pattern matches
|
||||
|
||||
# ─── Import Analysis ────────────────────────────────────────
|
||||
# How to analyze imports for dependency linting.
|
||||
import_analysis:
|
||||
# Command to list all packages/modules
|
||||
list_packages: string | null # "go list ./...", null for languages without this
|
||||
# Regex to extract imports from source files
|
||||
import_pattern: string # e.g., '"([^"]+)"' for Go, 'from [\'"]([^\'"]+)' for TS
|
||||
# File extensions to scan
|
||||
source_extensions: [string] # [".go"], [".ts", ".tsx", ".js", ".jsx"]
|
||||
# Module root detection
|
||||
module_root_file: string # "go.mod", "package.json", "pyproject.toml"
|
||||
|
||||
# ─── Layer Conventions ──────────────────────────────────────
|
||||
# Default layer hierarchy for architectural linting.
|
||||
# These are starting-point defaults; the analyzer agent adjusts based on
|
||||
# actual import graph analysis.
|
||||
layer_conventions:
|
||||
patterns:
|
||||
- layer: int # 0 = foundational, higher = more application-specific
|
||||
paths: [string] # Directory patterns: ["internal/types", "types", "domain"]
|
||||
description: string # "Pure types, zero internal imports"
|
||||
|
||||
# ─── Dependency Detection ───────────────────────────────────
|
||||
# How to detect external dependencies (databases, services, etc.)
|
||||
# from the project's dependency manifest.
|
||||
dependency_detection:
|
||||
manifest_file: string # "go.mod", "package.json", "requirements.txt"
|
||||
# Patterns to detect specific dependency types
|
||||
databases:
|
||||
- pattern: string # Regex on dependency name
|
||||
type: string # "postgres", "mysql", "mongodb", "redis", "sqlite"
|
||||
default_port: int
|
||||
services:
|
||||
- pattern: string
|
||||
type: string # "kafka", "rabbitmq", "elasticsearch", etc.
|
||||
default_port: int
|
||||
# Environment variable detection in source code
|
||||
env_var_patterns:
|
||||
- pattern: string # e.g., 'os\.Getenv\("([^"]+)"\)' for Go
|
||||
|
||||
# ─── Linter Template ────────────────────────────────────────
|
||||
# Reference to the linter implementation for this language.
|
||||
linter:
|
||||
# Pointer to the section in linter-templates.md
|
||||
template_section: string # "go-linter", "typescript-linter", etc.
|
||||
# File extension for the linter script
|
||||
script_extension: string # ".go", ".ts", ".py"
|
||||
# How to run the linter
|
||||
run_command: string # "go run scripts/lint-deps.go", "npx ts-node scripts/lint-deps.ts"
|
||||
|
||||
# ─── Naming Conventions ─────────────────────────────────────
|
||||
# File and directory naming rules for verify_action.py.
|
||||
naming:
|
||||
file_pattern: string # Regex: "^[a-z][a-z0-9_]*\\.go$"
|
||||
test_pattern: string # Regex: "^[a-z][a-z0-9_]*_test\\.go$"
|
||||
directory_style: string # "snake_case", "kebab-case", "camelCase"
|
||||
|
||||
# ─── CI Template ────────────────────────────────────────────
|
||||
# CI configuration template for this language.
|
||||
ci:
|
||||
# GitHub Actions template (primary)
|
||||
github_actions:
|
||||
image: string # "golang:1.22", "node:20", "python:3.12"
|
||||
setup_steps: [string] # Additional setup steps
|
||||
cache_paths: [string] # Paths to cache: ["~/go/pkg/mod"], ["node_modules"]
|
||||
# Other CI systems can be added here
|
||||
```
|
||||
|
||||
## Resolution Priority
|
||||
|
||||
When the harness system needs language-specific behavior, it follows this resolution chain:
|
||||
|
||||
1. **Project-level override** — `harness/config/validate.json`, `DEVELOPMENT.md` commands
|
||||
2. **Adapter defaults** — The matching adapter's `commands` section
|
||||
3. **Generic fallback** — `generic.md` adapter (discovers from Makefile/README)
|
||||
|
||||
## Adding a New Language
|
||||
|
||||
To add support for a new language (e.g., Kotlin):
|
||||
|
||||
1. Create `references/adapters/kotlin.md` following this schema
|
||||
2. Fill in detection rules, commands, route patterns
|
||||
3. Optionally add a linter template section to `linter-templates.md`
|
||||
4. No changes to core scripts needed — `detect_adapter.py` auto-discovers adapters
|
||||
|
||||
## Adapter File Format
|
||||
|
||||
Each adapter file uses YAML front matter followed by prose documentation:
|
||||
|
||||
```markdown
|
||||
---
|
||||
adapter:
|
||||
language: kotlin
|
||||
display_name: "Kotlin"
|
||||
version: "1.0"
|
||||
detection:
|
||||
files: [build.gradle.kts, build.gradle]
|
||||
confidence: 0.9
|
||||
commands:
|
||||
build: "./gradlew build"
|
||||
test: "./gradlew test"
|
||||
# ...
|
||||
---
|
||||
|
||||
# Kotlin Adapter
|
||||
|
||||
## Framework-Specific Notes
|
||||
|
||||
### Ktor (server)
|
||||
- Routes defined via `routing { get("/path") { ... } }`
|
||||
- ...
|
||||
|
||||
### Spring Boot
|
||||
- Routes via `@GetMapping`, `@PostMapping` annotations
|
||||
- ...
|
||||
```
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
---
|
||||
adapter:
|
||||
language: generic
|
||||
display_name: "Generic (Auto-Discovery)"
|
||||
version: "1.0"
|
||||
|
||||
detection:
|
||||
files: [] # Always matches as fallback
|
||||
confidence: 0.10
|
||||
|
||||
commands:
|
||||
build: null # Discovered from Makefile / README
|
||||
test: null # Discovered from Makefile / README
|
||||
lint: null
|
||||
lint_arch: null
|
||||
format: null
|
||||
start: null
|
||||
dev: null
|
||||
|
||||
package_manager:
|
||||
detection: []
|
||||
default: null
|
||||
install_command: null
|
||||
|
||||
route_detection:
|
||||
server_indicators:
|
||||
- pattern: 'listen|serve|http|server'
|
||||
description: "Generic HTTP server indicator"
|
||||
frameworks: []
|
||||
cli_indicators:
|
||||
- pattern: 'argv|args|argparse|getopt|flag'
|
||||
description: "Generic CLI argument parsing"
|
||||
frameworks: []
|
||||
frontend_indicators:
|
||||
- pattern: 'index\\.html|<!DOCTYPE html>'
|
||||
description: "HTML file presence"
|
||||
frameworks: []
|
||||
patterns: []
|
||||
|
||||
import_analysis:
|
||||
list_packages: null
|
||||
import_pattern: null
|
||||
source_extensions: []
|
||||
module_root_file: null
|
||||
|
||||
layer_conventions:
|
||||
patterns:
|
||||
- layer: 0
|
||||
paths: ["types", "models", "domain", "entities"]
|
||||
description: "Core types (generic convention)"
|
||||
- layer: 1
|
||||
paths: ["utils", "lib", "common", "helpers", "shared"]
|
||||
description: "Shared utilities (generic convention)"
|
||||
- layer: 2
|
||||
paths: ["services", "core", "business", "logic"]
|
||||
description: "Business logic (generic convention)"
|
||||
- layer: 3
|
||||
paths: ["handlers", "controllers", "api", "routes", "endpoints"]
|
||||
description: "API layer (generic convention)"
|
||||
- layer: 4
|
||||
paths: ["main", "cmd", "bin", "app", "src/index", "src/main"]
|
||||
description: "Entry points (generic convention)"
|
||||
|
||||
dependency_detection:
|
||||
manifest_file: null
|
||||
databases: []
|
||||
services: []
|
||||
env_var_patterns: []
|
||||
|
||||
linter:
|
||||
template_section: null
|
||||
script_extension: null
|
||||
run_command: null
|
||||
|
||||
naming:
|
||||
file_pattern: null
|
||||
test_pattern: null
|
||||
directory_style: null
|
||||
|
||||
ci:
|
||||
github_actions:
|
||||
image: "ubuntu-latest"
|
||||
setup_steps: []
|
||||
cache_paths: []
|
||||
---
|
||||
|
||||
# Generic Adapter (Auto-Discovery Fallback)
|
||||
|
||||
This adapter activates when no language-specific adapter matches. Instead of
|
||||
assuming a specific language (previous behavior: defaulting to Go), it discovers
|
||||
commands from project conventions.
|
||||
|
||||
## Discovery Strategy
|
||||
|
||||
### 1. Makefile Discovery
|
||||
|
||||
If a `Makefile` exists, parse targets:
|
||||
|
||||
```bash
|
||||
# Extract make targets
|
||||
grep -E '^[a-zA-Z_-]+:' Makefile | sed 's/:.*//'
|
||||
```
|
||||
|
||||
Common target mappings:
|
||||
| Target Pattern | Mapped Command |
|
||||
|---------------|---------------|
|
||||
| `build`, `compile` | `commands.build` |
|
||||
| `test`, `check` | `commands.test` |
|
||||
| `lint`, `lint-arch` | `commands.lint`, `commands.lint_arch` |
|
||||
| `fmt`, `format` | `commands.format` |
|
||||
| `run`, `start`, `serve` | `commands.start` |
|
||||
| `dev`, `watch` | `commands.dev` |
|
||||
|
||||
### 2. README Discovery
|
||||
|
||||
If no Makefile, scan `README.md` for code blocks with common commands:
|
||||
|
||||
```bash
|
||||
# Look for fenced code blocks with build/test commands
|
||||
grep -A 2 '```' README.md
|
||||
```
|
||||
|
||||
### 3. package.json Scripts Discovery (non-Node projects)
|
||||
|
||||
Some non-Node projects use `package.json` for script aliases:
|
||||
|
||||
```bash
|
||||
# Check if package.json scripts exist
|
||||
cat package.json | python3 -c "import sys,json; [print(k,v) for k,v in json.load(sys.stdin).get('scripts',{}).items()]"
|
||||
```
|
||||
|
||||
### 4. docker-compose.yml Discovery
|
||||
|
||||
If `docker-compose.yml` exists, extract service definitions for environment setup.
|
||||
|
||||
## When Generic Adapter Activates
|
||||
|
||||
The generic adapter is the **last resort**. It activates only when:
|
||||
1. No `go.mod`, `package.json`, `pyproject.toml`, `pom.xml`, `Cargo.toml` exists
|
||||
2. Or when the user explicitly requests generic mode
|
||||
|
||||
## Behavior Differences from Language-Specific Adapters
|
||||
|
||||
| Aspect | Language Adapter | Generic Adapter |
|
||||
|--------|-----------------|-----------------|
|
||||
| Build command | Hardcoded default | Discovered from Makefile/README |
|
||||
| Route detection | Framework-specific regex | Generic HTTP patterns only |
|
||||
| Layer conventions | Language-idiomatic paths | Common directory names |
|
||||
| Linter | Language-specific template | None (rely on existing tools) |
|
||||
| CI template | Language-specific image | Ubuntu with custom steps |
|
||||
|
||||
## Extending to New Languages
|
||||
|
||||
If you find yourself repeatedly using the generic adapter for a specific language,
|
||||
that's a signal to create a proper language adapter. See `adapter-schema.md` for
|
||||
the schema to follow.
|
||||
@@ -0,0 +1,212 @@
|
||||
---
|
||||
adapter:
|
||||
language: go
|
||||
display_name: "Go"
|
||||
version: "1.0"
|
||||
|
||||
detection:
|
||||
files: [go.mod, go.sum]
|
||||
confidence: 0.95
|
||||
|
||||
commands:
|
||||
build: "go build ./..."
|
||||
test: "go test ./..."
|
||||
lint: "golangci-lint run"
|
||||
lint_arch: "make lint-arch"
|
||||
format: "gofmt -w ."
|
||||
start: null # Inferred from cmd/ structure or main.go
|
||||
dev: null # Often uses "air" but not assumed
|
||||
|
||||
package_manager:
|
||||
detection: [] # Go modules are built-in
|
||||
default: "go"
|
||||
install_command: "go mod download"
|
||||
|
||||
route_detection:
|
||||
server_indicators:
|
||||
- pattern: 'http\.ListenAndServe|http\.Server\{|\.Listen\('
|
||||
description: "Standard library HTTP server"
|
||||
frameworks: ["net/http"]
|
||||
- pattern: 'gin\.Default|gin\.New'
|
||||
description: "Gin web framework"
|
||||
frameworks: ["gin"]
|
||||
- pattern: 'chi\.NewRouter|chi\.NewMux'
|
||||
description: "Chi router"
|
||||
frameworks: ["chi"]
|
||||
- pattern: 'echo\.New\(\)'
|
||||
description: "Echo web framework"
|
||||
frameworks: ["echo"]
|
||||
- pattern: 'mux\.NewRouter'
|
||||
description: "Gorilla Mux router"
|
||||
frameworks: ["gorilla/mux"]
|
||||
- pattern: 'fiber\.New\(\)'
|
||||
description: "Fiber web framework"
|
||||
frameworks: ["fiber"]
|
||||
|
||||
cli_indicators:
|
||||
- pattern: 'github\.com/spf13/cobra'
|
||||
description: "Cobra CLI framework"
|
||||
frameworks: ["cobra"]
|
||||
- pattern: 'github\.com/urfave/cli'
|
||||
description: "urfave/cli framework"
|
||||
frameworks: ["urfave/cli"]
|
||||
- pattern: 'flag\.Parse\(\)|flag\.String\('
|
||||
description: "Standard library flags"
|
||||
frameworks: ["flag"]
|
||||
|
||||
frontend_indicators: [] # Go is not typically used for frontend
|
||||
|
||||
patterns:
|
||||
# Chi router
|
||||
- type: route
|
||||
regex: 'r\.(Get|Post|Put|Delete|Patch|Head|Options)\s*\(\s*["\x27]([^"\x27]+)["\x27]'
|
||||
groups: [method, path]
|
||||
frameworks: ["chi"]
|
||||
# Gin
|
||||
- type: route
|
||||
regex: '\.(GET|POST|PUT|DELETE|PATCH)\s*\(\s*["\x27]([^"\x27]+)["\x27]'
|
||||
groups: [method, path]
|
||||
frameworks: ["gin"]
|
||||
# Echo
|
||||
- type: route
|
||||
regex: 'e\.(GET|POST|PUT|DELETE|PATCH)\s*\(\s*["\x27]([^"\x27]+)["\x27]'
|
||||
groups: [method, path]
|
||||
frameworks: ["echo"]
|
||||
# Gorilla Mux
|
||||
- type: route
|
||||
regex: '\.HandleFunc\s*\(\s*["\x27]([^"\x27]+)["\x27].*\)\.(Methods)\s*\(\s*["\x27]([^"\x27]+)["\x27]\)'
|
||||
groups: [path, _, method]
|
||||
frameworks: ["gorilla/mux"]
|
||||
# net/http
|
||||
- type: route
|
||||
regex: 'http\.HandleFunc\s*\(\s*["\x27]([^"\x27]+)["\x27]'
|
||||
groups: [path]
|
||||
frameworks: ["net/http"]
|
||||
# Cobra CLI
|
||||
- type: command
|
||||
regex: '&cobra\.Command\s*\{\s*Use:\s*["\x27]([^"\x27\s]+)'
|
||||
groups: [command_name]
|
||||
frameworks: ["cobra"]
|
||||
|
||||
import_analysis:
|
||||
list_packages: "go list -json ./..."
|
||||
import_pattern: '"([^"]+)"'
|
||||
source_extensions: [".go"]
|
||||
module_root_file: "go.mod"
|
||||
|
||||
layer_conventions:
|
||||
patterns:
|
||||
- layer: 0
|
||||
paths: ["internal/types", "types", "domain", "model", "entity"]
|
||||
description: "Pure types, zero internal imports"
|
||||
- layer: 1
|
||||
paths: ["internal/utils", "utils", "pkg/utils", "lib"]
|
||||
description: "Utilities, depend only on types"
|
||||
- layer: 2
|
||||
paths: ["internal/core", "core", "internal/service", "service"]
|
||||
description: "Business logic, depend on types + utils"
|
||||
- layer: 3
|
||||
paths: ["internal/handler", "handler", "api", "internal/api"]
|
||||
description: "HTTP/gRPC handlers, depend on core"
|
||||
- layer: 4
|
||||
paths: ["cmd"]
|
||||
description: "Entry points, depend on everything"
|
||||
|
||||
dependency_detection:
|
||||
manifest_file: "go.mod"
|
||||
databases:
|
||||
- pattern: "github.com/jackc/pgx|github.com/lib/pq"
|
||||
type: "postgres"
|
||||
default_port: 5432
|
||||
- pattern: "github.com/go-sql-driver/mysql"
|
||||
type: "mysql"
|
||||
default_port: 3306
|
||||
- pattern: "go.mongodb.org/mongo-driver"
|
||||
type: "mongodb"
|
||||
default_port: 27017
|
||||
- pattern: "github.com/go-redis/redis|github.com/redis/go-redis"
|
||||
type: "redis"
|
||||
default_port: 6379
|
||||
- pattern: "github.com/mattn/go-sqlite3|modernc.org/sqlite"
|
||||
type: "sqlite"
|
||||
default_port: 0
|
||||
services:
|
||||
- pattern: "github.com/segmentio/kafka-go|github.com/IBM/sarama"
|
||||
type: "kafka"
|
||||
default_port: 9092
|
||||
- pattern: "github.com/rabbitmq/amqp091-go|github.com/streadway/amqp"
|
||||
type: "rabbitmq"
|
||||
default_port: 5672
|
||||
- pattern: "github.com/nats-io/nats.go"
|
||||
type: "nats"
|
||||
default_port: 4222
|
||||
- pattern: "github.com/elastic/go-elasticsearch"
|
||||
type: "elasticsearch"
|
||||
default_port: 9200
|
||||
env_var_patterns:
|
||||
- pattern: 'os\.Getenv\("([^"]+)"\)'
|
||||
- pattern: 'os\.LookupEnv\("([^"]+)"\)'
|
||||
- pattern: 'viper\.\w+\("([^"]+)"\)'
|
||||
|
||||
linter:
|
||||
template_section: "go-linter"
|
||||
script_extension: ".go"
|
||||
run_command: "go run scripts/lint-deps.go"
|
||||
|
||||
naming:
|
||||
file_pattern: "^[a-z][a-z0-9_]*\\.go$"
|
||||
test_pattern: "^[a-z][a-z0-9_]*_test\\.go$"
|
||||
directory_style: "snake_case"
|
||||
|
||||
ci:
|
||||
github_actions:
|
||||
image: "golang:1.22"
|
||||
setup_steps:
|
||||
- "uses: actions/setup-go@v5\n with:\n go-version: '1.22'"
|
||||
cache_paths: ["~/go/pkg/mod", "~/.cache/go-build"]
|
||||
---
|
||||
|
||||
# Go Adapter
|
||||
|
||||
## Server Start Command Inference
|
||||
|
||||
Priority order for detecting the server start command:
|
||||
|
||||
1. Existing `harness/config/environment.json` startup command, if present
|
||||
2. `cmd/server/main.go` exists → `go run cmd/server/main.go`
|
||||
3. `cmd/api/main.go` exists → `go run cmd/api/main.go`
|
||||
4. `main.go` at root with `http` import → `go run main.go`
|
||||
5. Fail with actionable error
|
||||
|
||||
## CLI Binary Inference
|
||||
|
||||
1. `cmd/cli/main.go` exists → `go build -o bin/cli cmd/cli/main.go`
|
||||
2. `cmd/<name>/main.go` exists → `go build -o bin/<name> cmd/<name>/main.go`
|
||||
3. `main.go` at root with `cobra`/`flag` import → `go build -o bin/app .`
|
||||
|
||||
## Testing Patterns
|
||||
|
||||
- Unit tests: `*_test.go` files alongside source
|
||||
- Integration tests: `//go:build integration` build tag → `go test -tags=integration ./...`
|
||||
- Table-driven tests are idiomatic
|
||||
|
||||
## Common Frameworks
|
||||
|
||||
| Framework | Detection Pattern | Route Style |
|
||||
|-----------|------------------|-------------|
|
||||
| chi | `github.com/go-chi/chi` | `r.Get("/path", handler)` |
|
||||
| gin | `github.com/gin-gonic/gin` | `r.GET("/path", handler)` |
|
||||
| echo | `github.com/labstack/echo` | `e.GET("/path", handler)` |
|
||||
| fiber | `github.com/gofiber/fiber` | `app.Get("/path", handler)` |
|
||||
| gorilla/mux | `github.com/gorilla/mux` | `r.HandleFunc("/path", handler).Methods("GET")` |
|
||||
| net/http | stdlib | `http.HandleFunc("/path", handler)` |
|
||||
|
||||
## Structured Logging
|
||||
|
||||
Go projects should use structured loggers. Common patterns to detect:
|
||||
- `go.uber.org/zap` → `zap.String()`, `zap.Int()`
|
||||
- `log/slog` (stdlib) → `slog.Info()`, `slog.With()`
|
||||
- `github.com/rs/zerolog` → `log.Info().Str().Msg()`
|
||||
- `github.com/sirupsen/logrus` → `logrus.WithFields()`
|
||||
|
||||
Unstructured patterns to flag: `log.Printf`, `log.Println`, `log.Fatalf`, `fmt.Printf` (in non-CLI code)
|
||||
@@ -0,0 +1,205 @@
|
||||
---
|
||||
adapter:
|
||||
language: java
|
||||
display_name: "Java / Kotlin"
|
||||
version: "1.0"
|
||||
|
||||
detection:
|
||||
files: [pom.xml, build.gradle, build.gradle.kts, settings.gradle, settings.gradle.kts]
|
||||
content_patterns:
|
||||
- file: "pom.xml"
|
||||
pattern: "<groupId>"
|
||||
- file: "build.gradle.kts"
|
||||
pattern: "plugins|dependencies"
|
||||
confidence: 0.90
|
||||
|
||||
commands:
|
||||
build: null # Detected from build tool
|
||||
test: null # Detected from build tool
|
||||
lint: null # Often spotbugs, checkstyle, or ktlint
|
||||
lint_arch: null
|
||||
format: null
|
||||
start: null
|
||||
dev: null
|
||||
|
||||
package_manager:
|
||||
detection:
|
||||
- lockfile: "pom.xml"
|
||||
manager: "maven"
|
||||
- lockfile: "build.gradle"
|
||||
manager: "gradle"
|
||||
- lockfile: "build.gradle.kts"
|
||||
manager: "gradle"
|
||||
default: "maven"
|
||||
install_command: null # Dependencies resolved during build
|
||||
|
||||
route_detection:
|
||||
server_indicators:
|
||||
- pattern: '@RestController|@Controller|@RequestMapping'
|
||||
description: "Spring MVC/Boot controller"
|
||||
frameworks: ["spring"]
|
||||
- pattern: 'import io\.micronaut'
|
||||
description: "Micronaut framework"
|
||||
frameworks: ["micronaut"]
|
||||
- pattern: 'import io\.quarkus'
|
||||
description: "Quarkus framework"
|
||||
frameworks: ["quarkus"]
|
||||
- pattern: 'import io\.vertx'
|
||||
description: "Vert.x framework"
|
||||
frameworks: ["vertx"]
|
||||
- pattern: 'import io\.ktor'
|
||||
description: "Ktor framework (Kotlin)"
|
||||
frameworks: ["ktor"]
|
||||
- pattern: 'import io\.javalin'
|
||||
description: "Javalin web framework"
|
||||
frameworks: ["javalin"]
|
||||
|
||||
cli_indicators:
|
||||
- pattern: 'import picocli|@CommandLine'
|
||||
description: "picocli CLI framework"
|
||||
frameworks: ["picocli"]
|
||||
- pattern: 'public static void main\(String'
|
||||
description: "Java main method (potential CLI)"
|
||||
frameworks: ["stdlib"]
|
||||
|
||||
frontend_indicators: []
|
||||
|
||||
patterns:
|
||||
# Spring MVC annotations
|
||||
- type: route
|
||||
regex: '@(GetMapping|PostMapping|PutMapping|DeleteMapping|PatchMapping)\s*\(\s*(?:value\s*=\s*)?["\x27]([^"\x27]*)["\x27]'
|
||||
groups: [method, path]
|
||||
frameworks: ["spring"]
|
||||
# Spring RequestMapping
|
||||
- type: route
|
||||
regex: '@RequestMapping\s*\(.*(?:value|path)\s*=\s*["\x27]([^"\x27]+)["\x27].*method\s*=\s*RequestMethod\.(\w+)'
|
||||
groups: [path, method]
|
||||
frameworks: ["spring"]
|
||||
# Ktor (Kotlin)
|
||||
- type: route
|
||||
regex: '(get|post|put|delete|patch)\s*\(\s*["\x27]([^"\x27]+)["\x27]'
|
||||
groups: [method, path]
|
||||
frameworks: ["ktor"]
|
||||
# Javalin
|
||||
- type: route
|
||||
regex: 'app\.(get|post|put|delete|patch)\s*\(\s*["\x27]([^"\x27]+)["\x27]'
|
||||
groups: [method, path]
|
||||
frameworks: ["javalin"]
|
||||
|
||||
import_analysis:
|
||||
list_packages: null
|
||||
import_pattern: "^import\\s+([\\w.]+)"
|
||||
source_extensions: [".java", ".kt"]
|
||||
module_root_file: "pom.xml"
|
||||
|
||||
layer_conventions:
|
||||
patterns:
|
||||
- layer: 0
|
||||
paths: ["src/main/java/**/model", "src/main/java/**/entity", "src/main/java/**/dto"]
|
||||
description: "Domain models, entities, DTOs"
|
||||
- layer: 1
|
||||
paths: ["src/main/java/**/util", "src/main/java/**/common", "src/main/java/**/config"]
|
||||
description: "Utilities and configuration"
|
||||
- layer: 2
|
||||
paths: ["src/main/java/**/service", "src/main/java/**/repository", "src/main/java/**/dao"]
|
||||
description: "Service and data access layer"
|
||||
- layer: 3
|
||||
paths: ["src/main/java/**/controller", "src/main/java/**/api", "src/main/java/**/resource"]
|
||||
description: "REST controllers, API endpoints"
|
||||
- layer: 4
|
||||
paths: ["src/main/java/**/Application.java", "src/main/java/**/Main.java"]
|
||||
description: "Application entry point"
|
||||
|
||||
dependency_detection:
|
||||
manifest_file: "pom.xml"
|
||||
databases:
|
||||
- pattern: "postgresql|postgres"
|
||||
type: "postgres"
|
||||
default_port: 5432
|
||||
- pattern: "mysql-connector"
|
||||
type: "mysql"
|
||||
default_port: 3306
|
||||
- pattern: "mongodb-driver|mongo-java-driver"
|
||||
type: "mongodb"
|
||||
default_port: 27017
|
||||
- pattern: "jedis|lettuce-core|spring-data-redis"
|
||||
type: "redis"
|
||||
default_port: 6379
|
||||
- pattern: "h2|sqlite-jdbc"
|
||||
type: "sqlite"
|
||||
default_port: 0
|
||||
services:
|
||||
- pattern: "kafka-clients|spring-kafka"
|
||||
type: "kafka"
|
||||
default_port: 9092
|
||||
- pattern: "amqp-client|spring-amqp|spring-rabbit"
|
||||
type: "rabbitmq"
|
||||
default_port: 5672
|
||||
- pattern: "elasticsearch-rest-client|spring-data-elasticsearch"
|
||||
type: "elasticsearch"
|
||||
default_port: 9200
|
||||
env_var_patterns:
|
||||
- pattern: 'System\.getenv\(\s*["\x27]([^"\x27]+)["\x27]\)'
|
||||
- pattern: '\\$\\{([A-Z_][A-Z0-9_]*)\\}'
|
||||
|
||||
linter:
|
||||
template_section: "java-linter"
|
||||
script_extension: ".java"
|
||||
run_command: null # Typically integrated into build tool (spotbugs, checkstyle)
|
||||
|
||||
naming:
|
||||
file_pattern: "^[A-Z][a-zA-Z0-9]*\\.java$"
|
||||
test_pattern: "^[A-Z][a-zA-Z0-9]*Test\\.java$"
|
||||
directory_style: "lowercase"
|
||||
|
||||
ci:
|
||||
github_actions:
|
||||
image: null # Uses setup-java action
|
||||
setup_steps:
|
||||
- "uses: actions/setup-java@v4\n with:\n distribution: 'temurin'\n java-version: '21'"
|
||||
cache_paths: ["~/.m2/repository", "~/.gradle/caches"]
|
||||
---
|
||||
|
||||
# Java / Kotlin Adapter
|
||||
|
||||
## Build Tool Detection
|
||||
|
||||
| File | Build Tool | Build Command | Test Command |
|
||||
|------|-----------|---------------|--------------|
|
||||
| `pom.xml` | Maven | `mvn package -DskipTests` | `mvn test` |
|
||||
| `build.gradle` | Gradle (Groovy) | `./gradlew build -x test` | `./gradlew test` |
|
||||
| `build.gradle.kts` | Gradle (Kotlin DSL) | `./gradlew build -x test` | `./gradlew test` |
|
||||
|
||||
If `mvnw` or `gradlew` wrapper exists, prefer the wrapper over system-installed tool.
|
||||
|
||||
## Server Start Command Inference
|
||||
|
||||
1. Existing `harness/config/environment.json` startup command, if present
|
||||
2. Spring Boot → `./gradlew bootRun` or `mvn spring-boot:run`
|
||||
3. Fat JAR exists → `java -jar target/*.jar` or `java -jar build/libs/*.jar`
|
||||
4. Main class annotated with `@SpringBootApplication` → infer from pom.xml/build.gradle
|
||||
|
||||
## Framework-Specific Notes
|
||||
|
||||
### Spring Boot
|
||||
- Routes via annotations: `@GetMapping("/path")`, `@PostMapping("/path")`
|
||||
- Controller prefix: `@RequestMapping("/api/v1")` on class
|
||||
- Auto-configuration: `application.properties` or `application.yml`
|
||||
- Default port: 8080 (configurable via `server.port`)
|
||||
- Actuator health: `/actuator/health`
|
||||
|
||||
### Micronaut
|
||||
- Similar annotation style to Spring: `@Get("/path")`, `@Post("/path")`
|
||||
- Compile-time DI (no reflection)
|
||||
- Default port: 8080
|
||||
|
||||
### Ktor (Kotlin)
|
||||
- DSL-based routing: `routing { get("/path") { ... } }`
|
||||
- Configuration via `application.conf` (HOCON) or `application.yaml`
|
||||
|
||||
## Testing Patterns
|
||||
|
||||
- JUnit 5 is standard: `@Test`, `@ParameterizedTest`
|
||||
- Kotlin: same JUnit 5 + kotest as alternative
|
||||
- Integration tests often use `@SpringBootTest` + Testcontainers
|
||||
- Test directory: `src/test/java/` or `src/test/kotlin/`
|
||||
@@ -0,0 +1,225 @@
|
||||
---
|
||||
adapter:
|
||||
language: python
|
||||
display_name: "Python"
|
||||
version: "1.0"
|
||||
|
||||
detection:
|
||||
files: [pyproject.toml, setup.py, requirements.txt, Pipfile]
|
||||
content_patterns:
|
||||
- file: "pyproject.toml"
|
||||
pattern: '\\[project\\]|\\[tool\\.poetry\\]'
|
||||
confidence: 0.90
|
||||
|
||||
commands:
|
||||
build: null # Python typically doesn't need a build step
|
||||
test: "pytest"
|
||||
lint: "ruff check ."
|
||||
lint_arch: "python scripts/lint_deps.py src/"
|
||||
format: "ruff format ."
|
||||
start: null # Inferred from framework
|
||||
dev: null
|
||||
|
||||
package_manager:
|
||||
detection:
|
||||
- lockfile: "poetry.lock"
|
||||
manager: "poetry"
|
||||
- lockfile: "uv.lock"
|
||||
manager: "uv"
|
||||
- lockfile: "Pipfile.lock"
|
||||
manager: "pipenv"
|
||||
- lockfile: "pdm.lock"
|
||||
manager: "pdm"
|
||||
default: "pip"
|
||||
install_command: "{manager} install"
|
||||
|
||||
route_detection:
|
||||
server_indicators:
|
||||
- pattern: 'from fastapi|import fastapi|FastAPI\(\)'
|
||||
description: "FastAPI ASGI framework"
|
||||
frameworks: ["fastapi"]
|
||||
- pattern: 'from flask|import flask|Flask\(__name__\)'
|
||||
description: "Flask WSGI framework"
|
||||
frameworks: ["flask"]
|
||||
- pattern: 'from django|import django'
|
||||
description: "Django web framework"
|
||||
frameworks: ["django"]
|
||||
- pattern: 'from aiohttp|import aiohttp\.web'
|
||||
description: "aiohttp async web framework"
|
||||
frameworks: ["aiohttp"]
|
||||
- pattern: 'from starlette|import starlette'
|
||||
description: "Starlette ASGI framework"
|
||||
frameworks: ["starlette"]
|
||||
- pattern: 'from litestar|import litestar'
|
||||
description: "Litestar ASGI framework"
|
||||
frameworks: ["litestar"]
|
||||
|
||||
cli_indicators:
|
||||
- pattern: 'import click|from click'
|
||||
description: "Click CLI framework"
|
||||
frameworks: ["click"]
|
||||
- pattern: 'import typer|from typer'
|
||||
description: "Typer CLI framework"
|
||||
frameworks: ["typer"]
|
||||
- pattern: 'import argparse|from argparse'
|
||||
description: "Standard library argparse"
|
||||
frameworks: ["argparse"]
|
||||
- pattern: 'import fire|from fire'
|
||||
description: "Google Python Fire"
|
||||
frameworks: ["fire"]
|
||||
|
||||
frontend_indicators: [] # Python is not typically used for frontend
|
||||
|
||||
patterns:
|
||||
# FastAPI
|
||||
- type: route
|
||||
regex: '@(?:app|router)\.(get|post|put|delete|patch)\s*\(\s*["\x27]([^"\x27]+)["\x27]'
|
||||
groups: [method, path]
|
||||
frameworks: ["fastapi", "starlette", "litestar"]
|
||||
# Flask
|
||||
- type: route
|
||||
regex: '@(?:app|bp|blueprint)\.(route)\s*\(\s*["\x27]([^"\x27]+)["\x27](?:.*methods\s*=\s*\[([^\]]+)\])?'
|
||||
groups: [_, path, method]
|
||||
frameworks: ["flask"]
|
||||
# Django URLs
|
||||
- type: route
|
||||
regex: 'path\s*\(\s*["\x27]([^"\x27]+)["\x27]'
|
||||
groups: [path]
|
||||
frameworks: ["django"]
|
||||
# Click
|
||||
- type: command
|
||||
regex: '@\w+\.command\s*\(\s*(?:name\s*=\s*)?["\x27]?([^"\x27\)]+)'
|
||||
groups: [command_name]
|
||||
frameworks: ["click"]
|
||||
# Typer
|
||||
- type: command
|
||||
regex: '@app\.command\s*\(\s*(?:name\s*=\s*)?["\x27]?([^"\x27\)]*)'
|
||||
groups: [command_name]
|
||||
frameworks: ["typer"]
|
||||
|
||||
import_analysis:
|
||||
list_packages: null
|
||||
import_pattern: "^(?:from|import)\\s+([\\w.]+)"
|
||||
source_extensions: [".py"]
|
||||
module_root_file: "pyproject.toml"
|
||||
|
||||
layer_conventions:
|
||||
patterns:
|
||||
- layer: 0
|
||||
paths: ["src/models", "src/schemas", "src/types", "models", "schemas"]
|
||||
description: "Data models, Pydantic schemas, type definitions"
|
||||
- layer: 1
|
||||
paths: ["src/utils", "src/lib", "src/common", "utils", "lib"]
|
||||
description: "Shared utilities"
|
||||
- layer: 2
|
||||
paths: ["src/services", "src/core", "src/domain", "services", "core"]
|
||||
description: "Business logic, service layer"
|
||||
- layer: 3
|
||||
paths: ["src/api", "src/routes", "src/views", "src/handlers", "api", "routes"]
|
||||
description: "API endpoints, request handlers"
|
||||
- layer: 4
|
||||
paths: ["src/main.py", "src/app.py", "src/cli.py", "main.py", "app.py"]
|
||||
description: "Application entry points"
|
||||
|
||||
dependency_detection:
|
||||
manifest_file: "pyproject.toml"
|
||||
databases:
|
||||
- pattern: "psycopg|asyncpg|sqlalchemy.*postgres|databases.*postgres"
|
||||
type: "postgres"
|
||||
default_port: 5432
|
||||
- pattern: "pymysql|aiomysql|mysqlclient"
|
||||
type: "mysql"
|
||||
default_port: 3306
|
||||
- pattern: "pymongo|motor"
|
||||
type: "mongodb"
|
||||
default_port: 27017
|
||||
- pattern: "redis|aioredis"
|
||||
type: "redis"
|
||||
default_port: 6379
|
||||
- pattern: "aiosqlite|sqlite3"
|
||||
type: "sqlite"
|
||||
default_port: 0
|
||||
services:
|
||||
- pattern: "confluent-kafka|aiokafka"
|
||||
type: "kafka"
|
||||
default_port: 9092
|
||||
- pattern: "pika|aio-pika"
|
||||
type: "rabbitmq"
|
||||
default_port: 5672
|
||||
- pattern: "elasticsearch|elastic-transport"
|
||||
type: "elasticsearch"
|
||||
default_port: 9200
|
||||
env_var_patterns:
|
||||
- pattern: 'os\.environ\.get\(\s*["\x27]([^"\x27]+)["\x27]'
|
||||
- pattern: 'os\.environ\[["\x27]([^"\x27]+)["\x27]\]'
|
||||
- pattern: 'os\.getenv\(\s*["\x27]([^"\x27]+)["\x27]'
|
||||
|
||||
linter:
|
||||
template_section: "python-linter"
|
||||
script_extension: ".py"
|
||||
run_command: "python scripts/lint_deps.py src/"
|
||||
|
||||
naming:
|
||||
file_pattern: "^[a-z][a-z0-9_]*\\.py$"
|
||||
test_pattern: "^test_[a-z][a-z0-9_]*\\.py$"
|
||||
directory_style: "snake_case"
|
||||
|
||||
ci:
|
||||
github_actions:
|
||||
image: "python:3.12"
|
||||
setup_steps:
|
||||
- "uses: actions/setup-python@v5\n with:\n python-version: '3.12'"
|
||||
cache_paths: ["~/.cache/pip", ".venv"]
|
||||
---
|
||||
|
||||
# Python Adapter
|
||||
|
||||
## Server Start Command Inference
|
||||
|
||||
1. Existing `harness/config/environment.json` startup command, if present
|
||||
2. FastAPI detected → `python -m uvicorn {module}:app --port 8080`
|
||||
- Module inferred from main app file location
|
||||
3. Flask detected → `python -m flask run --port 8080`
|
||||
4. Django detected → `python manage.py runserver 8080`
|
||||
5. `main.py` exists → `python main.py`
|
||||
|
||||
## Virtual Environment Detection
|
||||
|
||||
The adapter checks for virtual environments in this order:
|
||||
1. `.venv/` directory → `source .venv/bin/activate`
|
||||
2. `venv/` directory → `source venv/bin/activate`
|
||||
3. `poetry.lock` → `poetry shell` or prefix with `poetry run`
|
||||
4. `uv.lock` → prefix with `uv run`
|
||||
5. `Pipfile.lock` → prefix with `pipenv run`
|
||||
|
||||
## Framework-Specific Notes
|
||||
|
||||
### FastAPI
|
||||
- Routes via decorators: `@app.get("/path")`, `@router.post("/path")`
|
||||
- Dependency injection via `Depends()`
|
||||
- Auto-generated OpenAPI docs at `/docs` and `/redoc`
|
||||
- Start with uvicorn: `uvicorn app.main:app --reload`
|
||||
|
||||
### Flask
|
||||
- Routes via decorators: `@app.route("/path", methods=["GET"])`
|
||||
- Blueprints for modular routing
|
||||
- Start with: `flask run` or `python -m flask run`
|
||||
|
||||
### Django
|
||||
- URL configuration in `urls.py`: `path("api/", include("app.urls"))`
|
||||
- Class-based views and function-based views
|
||||
- Start with: `python manage.py runserver`
|
||||
- Migrations: `python manage.py migrate`
|
||||
|
||||
### Click / Typer (CLI)
|
||||
- Click: `@cli.command()` decorator pattern
|
||||
- Typer: `@app.command()` decorator pattern, with auto-generated help
|
||||
|
||||
## Type Checking
|
||||
|
||||
Python projects may use type checkers:
|
||||
- `mypy` — most common, configured in `pyproject.toml` or `mypy.ini`
|
||||
- `pyright` — Microsoft's type checker, often via Pylance
|
||||
- `pytype` — Google's type checker
|
||||
|
||||
Detection: check `pyproject.toml` `[tool.mypy]` or `mypy.ini` existence.
|
||||
@@ -0,0 +1,220 @@
|
||||
---
|
||||
adapter:
|
||||
language: rust
|
||||
display_name: "Rust"
|
||||
version: "1.0"
|
||||
|
||||
detection:
|
||||
files: [Cargo.toml, Cargo.lock]
|
||||
content_patterns:
|
||||
- file: "Cargo.toml"
|
||||
pattern: '\\[package\\]'
|
||||
confidence: 0.95
|
||||
|
||||
commands:
|
||||
build: "cargo build"
|
||||
test: "cargo test"
|
||||
lint: "cargo clippy -- -D warnings"
|
||||
lint_arch: null # Rust module system enforces architecture naturally
|
||||
format: "cargo fmt"
|
||||
start: "cargo run"
|
||||
dev: "cargo watch -x run"
|
||||
|
||||
package_manager:
|
||||
detection: [] # Cargo is built-in
|
||||
default: "cargo"
|
||||
install_command: "cargo build"
|
||||
|
||||
route_detection:
|
||||
server_indicators:
|
||||
- pattern: 'use actix_web|actix_web::'
|
||||
description: "Actix-web framework"
|
||||
frameworks: ["actix-web"]
|
||||
- pattern: 'use axum|axum::'
|
||||
description: "Axum web framework"
|
||||
frameworks: ["axum"]
|
||||
- pattern: 'use rocket|#\[rocket::main\]'
|
||||
description: "Rocket web framework"
|
||||
frameworks: ["rocket"]
|
||||
- pattern: 'use warp|warp::'
|
||||
description: "Warp web framework"
|
||||
frameworks: ["warp"]
|
||||
- pattern: 'use hyper|hyper::'
|
||||
description: "Hyper HTTP library"
|
||||
frameworks: ["hyper"]
|
||||
- pattern: 'use tide|tide::'
|
||||
description: "Tide web framework"
|
||||
frameworks: ["tide"]
|
||||
|
||||
cli_indicators:
|
||||
- pattern: 'use clap|clap::'
|
||||
description: "Clap CLI framework"
|
||||
frameworks: ["clap"]
|
||||
- pattern: 'use structopt|structopt::'
|
||||
description: "StructOpt CLI (legacy clap)"
|
||||
frameworks: ["structopt"]
|
||||
- pattern: 'std::env::args'
|
||||
description: "Standard library args parsing"
|
||||
frameworks: ["stdlib"]
|
||||
|
||||
frontend_indicators:
|
||||
- pattern: 'use leptos|leptos::'
|
||||
description: "Leptos WASM framework"
|
||||
frameworks: ["leptos"]
|
||||
- pattern: 'use yew|yew::'
|
||||
description: "Yew WASM framework"
|
||||
frameworks: ["yew"]
|
||||
- pattern: 'use dioxus|dioxus::'
|
||||
description: "Dioxus UI framework"
|
||||
frameworks: ["dioxus"]
|
||||
|
||||
patterns:
|
||||
# Actix-web
|
||||
- type: route
|
||||
regex: '#\[(?:web::)?(get|post|put|delete|patch)\s*\(\s*"([^"]+)"'
|
||||
groups: [method, path]
|
||||
frameworks: ["actix-web"]
|
||||
# Axum
|
||||
- type: route
|
||||
regex: '\.(get|post|put|delete|patch)\s*\(\s*"([^"]+)"'
|
||||
groups: [method, path]
|
||||
frameworks: ["axum"]
|
||||
# Rocket
|
||||
- type: route
|
||||
regex: '#\[(get|post|put|delete|patch)\s*\(\s*"([^"]+)"'
|
||||
groups: [method, path]
|
||||
frameworks: ["rocket"]
|
||||
# Clap derive
|
||||
- type: command
|
||||
regex: '#\[command\s*\(.*name\s*=\s*"([^"]+)"'
|
||||
groups: [command_name]
|
||||
frameworks: ["clap"]
|
||||
# Clap builder
|
||||
- type: command
|
||||
regex: 'Command::new\s*\(\s*"([^"]+)"'
|
||||
groups: [command_name]
|
||||
frameworks: ["clap"]
|
||||
|
||||
import_analysis:
|
||||
list_packages: "cargo metadata --format-version 1"
|
||||
import_pattern: "use\\s+([\\w:]+)"
|
||||
source_extensions: [".rs"]
|
||||
module_root_file: "Cargo.toml"
|
||||
|
||||
layer_conventions:
|
||||
patterns:
|
||||
- layer: 0
|
||||
paths: ["src/models", "src/types", "src/domain"]
|
||||
description: "Domain types and models"
|
||||
- layer: 1
|
||||
paths: ["src/utils", "src/common", "src/lib.rs"]
|
||||
description: "Shared utilities"
|
||||
- layer: 2
|
||||
paths: ["src/services", "src/core", "src/repository"]
|
||||
description: "Business logic"
|
||||
- layer: 3
|
||||
paths: ["src/handlers", "src/routes", "src/api"]
|
||||
description: "HTTP/API handlers"
|
||||
- layer: 4
|
||||
paths: ["src/main.rs", "src/bin"]
|
||||
description: "Entry points"
|
||||
|
||||
dependency_detection:
|
||||
manifest_file: "Cargo.toml"
|
||||
databases:
|
||||
- pattern: 'sqlx.*postgres|tokio-postgres|diesel.*postgres'
|
||||
type: "postgres"
|
||||
default_port: 5432
|
||||
- pattern: 'sqlx.*mysql|diesel.*mysql'
|
||||
type: "mysql"
|
||||
default_port: 3306
|
||||
- pattern: 'mongodb'
|
||||
type: "mongodb"
|
||||
default_port: 27017
|
||||
- pattern: 'redis|deadpool-redis'
|
||||
type: "redis"
|
||||
default_port: 6379
|
||||
- pattern: 'rusqlite|sqlx.*sqlite'
|
||||
type: "sqlite"
|
||||
default_port: 0
|
||||
services:
|
||||
- pattern: 'rdkafka|kafka'
|
||||
type: "kafka"
|
||||
default_port: 9092
|
||||
- pattern: 'lapin|amqp'
|
||||
type: "rabbitmq"
|
||||
default_port: 5672
|
||||
- pattern: 'elasticsearch'
|
||||
type: "elasticsearch"
|
||||
default_port: 9200
|
||||
env_var_patterns:
|
||||
- pattern: 'std::env::var\(\s*"([^"]+)"'
|
||||
- pattern: 'env::var\(\s*"([^"]+)"'
|
||||
- pattern: 'dotenv::var\(\s*"([^"]+)"'
|
||||
|
||||
linter:
|
||||
template_section: "rust-linter"
|
||||
script_extension: ".rs"
|
||||
run_command: "cargo clippy"
|
||||
|
||||
naming:
|
||||
file_pattern: "^[a-z][a-z0-9_]*\\.rs$"
|
||||
test_pattern: "^[a-z][a-z0-9_]*\\.rs$" # Tests are inline in Rust
|
||||
directory_style: "snake_case"
|
||||
|
||||
ci:
|
||||
github_actions:
|
||||
image: null
|
||||
setup_steps:
|
||||
- "uses: dtolnay/rust-toolchain@stable\n with:\n components: clippy, rustfmt"
|
||||
cache_paths: ["~/.cargo/registry", "~/.cargo/git", "target"]
|
||||
---
|
||||
|
||||
# Rust Adapter
|
||||
|
||||
## Architecture Note
|
||||
|
||||
Rust's module system (`mod`, `pub`, `pub(crate)`) naturally enforces encapsulation.
|
||||
The `lint_arch` command is `null` because Rust's compiler already prevents many
|
||||
dependency violations at compile time. However, a custom architectural linter can
|
||||
still be valuable for enforcing higher-level layer boundaries.
|
||||
|
||||
## Server Start Command Inference
|
||||
|
||||
1. Existing `harness/config/environment.json` startup command, if present
|
||||
2. `Cargo.toml` has `[[bin]]` section → `cargo run --bin <name>`
|
||||
3. Default → `cargo run`
|
||||
|
||||
For release builds: `cargo build --release && ./target/release/<name>`
|
||||
|
||||
## Framework-Specific Notes
|
||||
|
||||
### Axum
|
||||
- Router-based: `Router::new().route("/path", get(handler))`
|
||||
- Extractors for request parsing: `Json<T>`, `Path<T>`, `Query<T>`
|
||||
- State sharing via `Extension` or `State`
|
||||
- Default: runs on `0.0.0.0:3000`
|
||||
|
||||
### Actix-web
|
||||
- Attribute macros: `#[get("/path")]`, `#[post("/path")]`
|
||||
- App factory pattern: `App::new().service(handler)`
|
||||
- Default: `HttpServer::new(...).bind("127.0.0.1:8080")`
|
||||
|
||||
### Rocket
|
||||
- Attribute macros: `#[get("/path")]`, `#[post("/path")]`
|
||||
- Fairings for middleware
|
||||
- Config via `Rocket.toml`
|
||||
|
||||
## Testing Patterns
|
||||
|
||||
- Unit tests: inline `#[cfg(test)] mod tests { ... }` in same file
|
||||
- Integration tests: `tests/` directory at crate root
|
||||
- `cargo test` runs both
|
||||
- Useful flags: `cargo test -- --nocapture` (show println output)
|
||||
|
||||
## Workspace Support
|
||||
|
||||
If `[workspace]` in root `Cargo.toml`:
|
||||
- Each member crate may have its own layer conventions
|
||||
- Build: `cargo build --workspace`
|
||||
- Test: `cargo test --workspace`
|
||||
+245
@@ -0,0 +1,245 @@
|
||||
---
|
||||
adapter:
|
||||
language: typescript
|
||||
display_name: "TypeScript / JavaScript"
|
||||
version: "1.0"
|
||||
|
||||
detection:
|
||||
files: [package.json, tsconfig.json]
|
||||
content_patterns:
|
||||
- file: "package.json"
|
||||
pattern: '"(typescript|@types/node)"'
|
||||
confidence: 0.90
|
||||
|
||||
commands:
|
||||
build: "{pkg_manager} run build"
|
||||
test: "{pkg_manager} test"
|
||||
lint: "{pkg_manager} run lint"
|
||||
lint_arch: "{pkg_manager} run lint:arch"
|
||||
format: "{pkg_manager} run format"
|
||||
start: "{pkg_manager} start"
|
||||
dev: "{pkg_manager} run dev"
|
||||
|
||||
package_manager:
|
||||
detection:
|
||||
- lockfile: "pnpm-lock.yaml"
|
||||
manager: "pnpm"
|
||||
- lockfile: "yarn.lock"
|
||||
manager: "yarn"
|
||||
- lockfile: "bun.lockb"
|
||||
manager: "bun"
|
||||
- lockfile: "package-lock.json"
|
||||
manager: "npm"
|
||||
default: "npm"
|
||||
install_command: "{manager} install"
|
||||
|
||||
route_detection:
|
||||
server_indicators:
|
||||
- pattern: 'require\(["\x27]express["\x27]\)|from ["\x27]express["\x27]'
|
||||
description: "Express.js web framework"
|
||||
frameworks: ["express"]
|
||||
- pattern: 'require\(["\x27]fastify["\x27]\)|from ["\x27]fastify["\x27]'
|
||||
description: "Fastify web framework"
|
||||
frameworks: ["fastify"]
|
||||
- pattern: 'from ["\x27]@nestjs/common["\x27]'
|
||||
description: "NestJS framework"
|
||||
frameworks: ["nestjs"]
|
||||
- pattern: 'require\(["\x27]koa["\x27]\)|from ["\x27]koa["\x27]'
|
||||
description: "Koa web framework"
|
||||
frameworks: ["koa"]
|
||||
- pattern: 'require\(["\x27]hono["\x27]\)|from ["\x27]hono["\x27]'
|
||||
description: "Hono web framework"
|
||||
frameworks: ["hono"]
|
||||
- pattern: 'createServer|http\.Server'
|
||||
description: "Node.js HTTP server"
|
||||
frameworks: ["http"]
|
||||
|
||||
cli_indicators:
|
||||
- pattern: 'require\(["\x27]commander["\x27]\)|from ["\x27]commander["\x27]'
|
||||
description: "Commander.js CLI framework"
|
||||
frameworks: ["commander"]
|
||||
- pattern: 'require\(["\x27]yargs["\x27]\)|from ["\x27]yargs["\x27]'
|
||||
description: "Yargs CLI framework"
|
||||
frameworks: ["yargs"]
|
||||
- pattern: 'require\(["\x27]@oclif/core["\x27]\)|from ["\x27]@oclif'
|
||||
description: "Oclif CLI framework"
|
||||
frameworks: ["oclif"]
|
||||
- pattern: 'require\(["\x27]inquirer["\x27]\)|from ["\x27]inquirer["\x27]'
|
||||
description: "Inquirer.js interactive CLI"
|
||||
frameworks: ["inquirer"]
|
||||
|
||||
frontend_indicators:
|
||||
- pattern: 'from ["\x27]react["\x27]|require\(["\x27]react["\x27]\)'
|
||||
description: "React"
|
||||
frameworks: ["react"]
|
||||
- pattern: 'from ["\x27]vue["\x27]|createApp'
|
||||
description: "Vue.js"
|
||||
frameworks: ["vue"]
|
||||
- pattern: 'from ["\x27]svelte["\x27]'
|
||||
description: "Svelte"
|
||||
frameworks: ["svelte"]
|
||||
- pattern: 'from ["\x27]next["\x27]|from ["\x27]next/'
|
||||
description: "Next.js"
|
||||
frameworks: ["next"]
|
||||
- pattern: 'defineNuxtConfig|from ["\x27]nuxt["\x27]'
|
||||
description: "Nuxt"
|
||||
frameworks: ["nuxt"]
|
||||
|
||||
patterns:
|
||||
# Express / Koa style
|
||||
- type: route
|
||||
regex: '(app|router)\.(get|post|put|delete|patch|all)\s*\(\s*["\x27]([^"\x27]+)["\x27]'
|
||||
groups: [_, method, path]
|
||||
frameworks: ["express", "koa", "hono"]
|
||||
# Fastify
|
||||
- type: route
|
||||
regex: '(fastify|server|app)\.(get|post|put|delete|patch)\s*\(\s*["\x27]([^"\x27]+)["\x27]'
|
||||
groups: [_, method, path]
|
||||
frameworks: ["fastify"]
|
||||
# NestJS decorators
|
||||
- type: route
|
||||
regex: '@(Get|Post|Put|Delete|Patch)\s*\(\s*["\x27]([^"\x27]*)["\x27]?\s*\)'
|
||||
groups: [method, path]
|
||||
frameworks: ["nestjs"]
|
||||
# Next.js app router (file-based)
|
||||
- type: route
|
||||
regex: 'export\s+(?:async\s+)?function\s+(GET|POST|PUT|DELETE|PATCH)'
|
||||
groups: [method]
|
||||
frameworks: ["next"]
|
||||
# Commander CLI
|
||||
- type: command
|
||||
regex: '\.command\s*\(\s*["\x27]([^"\x27]+)["\x27]'
|
||||
groups: [command_name]
|
||||
frameworks: ["commander"]
|
||||
# Yargs
|
||||
- type: command
|
||||
regex: '\.command\s*\(\s*["\x27]([^"\x27\s]+)'
|
||||
groups: [command_name]
|
||||
frameworks: ["yargs"]
|
||||
|
||||
import_analysis:
|
||||
list_packages: null # TS doesn't have a native package lister
|
||||
import_pattern: "from ['\"]([^'\"]+)['\"]|require\\(['\"]([^'\"]+)['\"]\\)"
|
||||
source_extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]
|
||||
module_root_file: "package.json"
|
||||
|
||||
layer_conventions:
|
||||
patterns:
|
||||
- layer: 0
|
||||
paths: ["src/types", "src/models", "types", "shared/types"]
|
||||
description: "Type definitions, interfaces, schemas"
|
||||
- layer: 1
|
||||
paths: ["src/utils", "src/lib", "src/helpers", "utils", "lib"]
|
||||
description: "Utility functions, depend only on types"
|
||||
- layer: 2
|
||||
paths: ["src/services", "src/core", "services", "core"]
|
||||
description: "Business logic layer"
|
||||
- layer: 3
|
||||
paths: ["src/controllers", "src/handlers", "src/routes", "src/api"]
|
||||
description: "HTTP/API handlers"
|
||||
- layer: 4
|
||||
paths: ["src/app", "src/pages", "src/index.ts", "src/main.ts"]
|
||||
description: "Application entry points"
|
||||
|
||||
dependency_detection:
|
||||
manifest_file: "package.json"
|
||||
databases:
|
||||
- pattern: '"(pg|postgres|@prisma/client|typeorm|knex|drizzle-orm|sequelize)"'
|
||||
type: "postgres"
|
||||
default_port: 5432
|
||||
- pattern: '"(mysql2|mysql)"'
|
||||
type: "mysql"
|
||||
default_port: 3306
|
||||
- pattern: '"(mongodb|mongoose|mongosh)"'
|
||||
type: "mongodb"
|
||||
default_port: 27017
|
||||
- pattern: '"(redis|ioredis|@redis/client)"'
|
||||
type: "redis"
|
||||
default_port: 6379
|
||||
- pattern: '"(better-sqlite3|sql.js)"'
|
||||
type: "sqlite"
|
||||
default_port: 0
|
||||
services:
|
||||
- pattern: '"(kafkajs|@kafka-js/confluent-schema-registry)"'
|
||||
type: "kafka"
|
||||
default_port: 9092
|
||||
- pattern: '"(amqplib|amqp-connection-manager)"'
|
||||
type: "rabbitmq"
|
||||
default_port: 5672
|
||||
- pattern: '"(@elastic/elasticsearch)"'
|
||||
type: "elasticsearch"
|
||||
default_port: 9200
|
||||
env_var_patterns:
|
||||
- pattern: 'process\.env\.([A-Z_][A-Z0-9_]*)'
|
||||
- pattern: 'process\.env\[[\x27"]([A-Z_][A-Z0-9_]*)[\x27"]\]'
|
||||
|
||||
linter:
|
||||
template_section: "typescript-linter"
|
||||
script_extension: ".ts"
|
||||
run_command: "npx ts-node scripts/lint-deps.ts"
|
||||
|
||||
naming:
|
||||
file_pattern: "^[a-zA-Z][a-zA-Z0-9.-]*\\.(ts|tsx|js|jsx|mjs|cjs)$"
|
||||
test_pattern: "^[a-zA-Z][a-zA-Z0-9.-]*\\.(test|spec)\\.(ts|tsx|js|jsx)$"
|
||||
directory_style: "kebab-case"
|
||||
|
||||
ci:
|
||||
github_actions:
|
||||
image: "node:20"
|
||||
setup_steps:
|
||||
- "uses: actions/setup-node@v4\n with:\n node-version: '20'"
|
||||
cache_paths: ["node_modules", ".next/cache"]
|
||||
---
|
||||
|
||||
# TypeScript / JavaScript Adapter
|
||||
|
||||
## Package Manager Detection
|
||||
|
||||
TypeScript projects have multiple package managers. Detection priority:
|
||||
|
||||
| Lock File | Manager | Run Command |
|
||||
|-----------|---------|-------------|
|
||||
| `pnpm-lock.yaml` | pnpm | `pnpm run <script>` |
|
||||
| `yarn.lock` | yarn | `yarn <script>` |
|
||||
| `bun.lockb` | bun | `bun run <script>` |
|
||||
| `package-lock.json` | npm | `npm run <script>` |
|
||||
|
||||
All `{pkg_manager}` placeholders in commands are resolved at detection time.
|
||||
|
||||
## Server Start Command Inference
|
||||
|
||||
1. Existing `harness/config/environment.json` startup command, if present
|
||||
2. `package.json` → `scripts.start` exists → `{pkg_manager} start`
|
||||
3. `package.json` → `scripts.dev` exists → `{pkg_manager} run dev`
|
||||
4. `dist/index.js` exists → `node dist/index.js`
|
||||
5. `src/index.ts` exists → `npx ts-node src/index.ts`
|
||||
|
||||
## Port Detection
|
||||
|
||||
1. Existing `harness/config/environment.json` readiness port, if present
|
||||
2. `package.json` scripts containing `PORT=(\d+)` → use that port
|
||||
3. `.env` containing `PORT=(\d+)` → use that port
|
||||
4. Default: 3000 (frontend), 8080 (server)
|
||||
|
||||
## Framework-Specific Notes
|
||||
|
||||
### Next.js / Nuxt
|
||||
- File-based routing: routes are derived from `app/` or `pages/` directory structure
|
||||
- API routes: `app/api/**/route.ts` (Next.js App Router)
|
||||
- Use `next build && next start` for production verification
|
||||
|
||||
### NestJS
|
||||
- Decorator-based routing: `@Get()`, `@Post()`, `@Controller('prefix')`
|
||||
- Module system: scan `*.module.ts` for service registration
|
||||
- Default port: 3000
|
||||
|
||||
### Express / Fastify
|
||||
- Explicit routing: `app.get('/path', handler)`
|
||||
- Middleware chain matters for verification order
|
||||
|
||||
## Monorepo Support
|
||||
|
||||
If `workspaces` in `package.json` or `pnpm-workspace.yaml` exists:
|
||||
- Run detection per-workspace
|
||||
- Each workspace may have its own adapter overlay
|
||||
- Build order respects workspace dependency graph
|
||||
Reference in New Issue
Block a user