From d42b3a8c04702cb391042ae5c57a5f71ec2d9231 Mon Sep 17 00:00:00 2001 From: "Calvin A. Allen" Date: Sun, 4 Jan 2026 16:30:09 -0500 Subject: [PATCH 1/3] docs: replace CLAUDE.md with Astro-specific content --- CLAUDE.md | 398 +++++++++--------------------------------------------- 1 file changed, 62 insertions(+), 336 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 7b25314..b791c5a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,378 +1,104 @@ # CLAUDE.md -Guidance for Claude Code when working with the dtvem codebase. - -## Related Documentation - -| Document | Purpose | -|----------|---------| -| [`README.md`](../README.md) | User-facing documentation, installation, usage examples | -| [`CONTRIBUTING.md`](../CONTRIBUTING.md) | Contribution guidelines, PR process, development setup | -| [`CODE_OF_CONDUCT.md`](../CODE_OF_CONDUCT.md) | Community standards and expected behavior | -| [`GO_STYLEGUIDE.md`](GO_STYLEGUIDE.md) | Complete Go coding standards (Google style) | - ---- +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Critical Rules **These rules override all other instructions:** -1. **NEVER commit directly to main** - Always create a feature branch and submit a pull request. No exceptions. -2. **Follow the styleguide** - All code must comply with `GO_STYLEGUIDE.md` -3. **Write tests** - All new/refactored code requires comprehensive unit tests -4. **Cross-platform** - All features must work on Windows, macOS, and Linux -5. **Conventional commits** - Format: `type(scope): description` -6. **GitHub Issues for TODOs** - Use `gh` CLI to manage issues, no local TODO files. Use conventional commit format for issue titles -7. **Pull Requests** - Use the conventional commit format for PR titles as you do for commits -8. **Run validation before commits** - Run `npm run check` (format, lint, test) before committing and pushing -9. **Working an issue** - When working an issue, always create a new branch from an updated main branch -10. **Branch Names** - Always use the conventional commit `type` from the issue title as the first prefix, and the `scope` as the second, then a very short description, example `feat/ci/integration-tests` -11. **Check branch status before pushing** - ALWAYS verify the remote tracking branch still exists before pushing. If a PR was merged/deleted, create a new branch from main instead of trying to push to the old one. -12. **No co-authors** - Do not add any co-author information on commits or pull requests -13. **No "generated by" statements** - Do not add generated-by statements on pull requests +1. **NEVER commit directly to main** - Always create a feature branch and submit a pull request +2. **Conventional commits** - Format: `type(scope): description` +3. **GitHub Issues for TODOs** - Use `gh` CLI to manage issues, no local TODO files. Use conventional commit format for issue titles +4. **Pull Request titles** - Use conventional commit format (same as commits) +5. **Branch naming** - Use format: `type/scope/short-description` (e.g., `feat/site/new-page`) +6. **Working an issue** - Always create a new branch from an updated main branch +7. **Check branch status before pushing** - Verify the remote tracking branch still exists. If a PR was merged/deleted, create a new branch from main instead +8. **Write tests** - All new/refactored code requires tests where applicable +9. **Run validation before commits** - Run `npm run build` (type check, build) in the website directory before committing and pushing +10. **No co-authors** - Do not add co-author information on commits or pull requests +11. **No "generated by" statements** - Do not add generated-by statements on pull requests --- -## Quick Reference - -### Build Commands - -```bash -# Build executables -go build -o dist/dtvem.exe ./src -go build -o dist/dtvem-shim.exe ./src/cmd/shim - -# Run directly -go run ./src/main.go - -# Run tests -cd src && go test ./... -``` - -### Deploy After Building - -```bash -cp dist/dtvem.exe ~/.dtvem/bin/dtvem.exe -cp dist/dtvem-shim.exe ~/.dtvem/bin/dtvem-shim.exe -~/.dtvem/bin/dtvem.exe reshim -``` - -### GitHub Issues +### GitHub CLI Commands ```bash gh issue list # List open issues gh issue view # View details -gh issue create --title "..." --label enhancement --body "..." +gh issue create --title "type(scope): description" --body "..." gh issue close ``` -### GitHub Issue Dependencies (Blocked By / Blocking) - -```bash -# List what blocks an issue -gh api repos/CodingWithCalvin/dtvem.cli/issues//dependencies/blocked_by --jq '.[] | "#\(.number) \(.title)"' +### Conventional Commit Types -# List what an issue blocks -gh api repos/CodingWithCalvin/dtvem.cli/issues//dependencies/blocking --jq '.[] | "#\(.number) \(.title)"' - -# Add a blocking relationship (issue is blocked by ) -# First get the blocker's numeric ID (not issue number): -gh api repos/CodingWithCalvin/dtvem.cli/issues/ --jq '.id' -# Then add the dependency: -gh api repos/CodingWithCalvin/dtvem.cli/issues//dependencies/blocked_by -X POST -F issue_id= - -# Remove a blocking relationship -gh api repos/CodingWithCalvin/dtvem.cli/issues//dependencies/blocked_by/ -X DELETE -``` - -**Note:** The API uses numeric issue IDs (not issue numbers) for POST/DELETE operations. Get the ID with `gh api repos/CodingWithCalvin/dtvem.cli/issues/ --jq '.id'` +| Type | Description | +|------|-------------| +| `feat` | New feature | +| `fix` | Bug fix | +| `docs` | Documentation only | +| `refactor` | Code change that neither fixes a bug nor adds a feature | +| `test` | Adding or updating tests | +| `chore` | Maintenance tasks | +| `perf` | Performance improvement | +| `ci` | CI/CD changes | --- ## Project Overview -**dtvem** (Development Tool Virtual Environment Manager) is a cross-platform runtime version manager written in Go. Similar to `asdf` but with first-class Windows support. - -| Attribute | Value | -|-----------|-------| -| Version | dev (pre-1.0) | -| Runtimes | Python, Node.js, Ruby | -| Tests | 160+ passing | -| Style | Google Go Style Guide | - -**Key Concept**: Shims are Go executables that intercept runtime commands (like `python`, `node`), resolve versions, and execute the appropriate binary. - -### Available Commands - -`init`, `install`, `uninstall`, `list`, `list-all`, `global`, `local`, `current`, `freeze`, `migrate`, `reshim`, `which`, `where`, `update`, `request`, `version`, `help` - ---- +This is the dtvem.io website - the official documentation and landing page for dtvem (Development Tool Virtual Environment Manager). It's built with Astro and hosted on Cloudflare Pages. -## Architecture +## Build Commands -### Two-Binary System +```bash +# Navigate to website directory +cd website -1. **Main CLI** (`src/main.go`) - The `dtvem` command -2. **Shim Executable** (`src/cmd/shim/main.go`) - Copied/renamed for each runtime command +# Install dependencies +npm install -### Shim Flow +# Start dev server +npm run dev -``` -User runs: python --version - ↓ -~/.dtvem/shims/python.exe (shim) - ↓ -Maps to runtime provider → Resolves version - ↓ -├─ Version configured & installed? → Execute ~/.dtvem/versions/python/3.11.0/bin/python -├─ Version configured but not installed? → Show error with install command -└─ No version configured? → Fall back to system PATH or show install instructions -``` +# Build production site +npm run build -### Directory Structure +# Type check +npx astro check -``` -~/.dtvem/ -├── bin/ # dtvem binaries (added to PATH) -│ ├── dtvem -│ └── dtvem-shim -├── shims/ # Runtime shims (python.exe, node.exe, etc.) -├── versions/ # Installed runtimes by name/version -│ ├── python/3.11.0/ -│ └── node/18.16.0/ -└── config/ - └── runtimes.json # Global version config +# Preview production build +npm run preview ``` -### Key Packages - -| Package | Purpose | -|---------|---------| -| `internal/config/` | Paths, version resolution, config file handling | -| `internal/runtime/` | Provider interface, registry, version types | -| `internal/shim/` | Shim lifecycle management | -| `internal/path/` | PATH configuration (platform-specific) | -| `internal/ui/` | Colored output, prompts, verbose/debug logging | -| `internal/tui/` | Table formatting and styles | -| `internal/download/` | File downloads with progress | -| `internal/manifest/` | Version manifest fetching and caching | -| `internal/migration/` | Migration detection and helpers | -| `internal/testutil/` | Shared test utility functions | -| `internal/constants/` | Platform constants | -| `src/cmd/` | CLI commands (one file per command) | -| `src/runtimes/` | Runtime providers (node/, python/, ruby/) | - ---- - -## Provider System - -All runtimes implement the `Provider` interface (`src/internal/runtime/provider.go`, 20 methods total). Providers auto-register via `init()`: +## Architecture -```go -// src/runtimes/node/provider.go -func init() { - runtime.Register(NewProvider()) -} +### Directory Structure -// src/main.go - blank imports trigger registration -import ( - _ "github.com/CodingWithCalvin/dtvem.cli/src/runtimes/node" - _ "github.com/CodingWithCalvin/dtvem.cli/src/runtimes/python" - _ "github.com/CodingWithCalvin/dtvem.cli/src/runtimes/ruby" -) ``` - -### Key Provider Methods - -| Method | Purpose | -|--------|---------| -| `Name()` | Runtime identifier (e.g., "python") | -| `DisplayName()` | Human-readable name (e.g., "Python") | -| `Shims()` | Executable names (e.g., ["python", "pip"]) | -| `ShouldReshimAfter()` | Detect global package installs | -| `Install(version)` | Download and install a version | -| `ExecutablePath(version)` | Path to versioned executable | -| `GlobalPackages(path)` | Detect installed global packages | -| `InstallGlobalPackages()` | Reinstall packages to new version | - -### Adding a New Runtime - -1. Create `src/runtimes//provider.go` -2. Implement `runtime.Provider` interface (all 20 methods) -3. Add `init()` function: `runtime.Register(NewProvider())` -4. Import in `src/main.go`: `_ "github.com/CodingWithCalvin/dtvem.cli/src/runtimes/"` -5. Update `schemas/runtimes.schema.json` enum - -The shim mappings are automatically registered via `Shims()`. - ---- - -## Version Resolution - -**Priority order:** -1. **Local**: Walk up from `pwd` looking for `.dtvem/runtimes.json` (stops at git root) -2. **Global**: `~/.dtvem/config/runtimes.json` -3. **Error**: No version configured - -**Config format** (both local and global): -```json -{ - "python": "3.11.0", - "node": "18.16.0" -} +website/ +├── src/ +│ ├── pages/ # Astro pages +│ ├── layouts/ # Page layouts +│ ├── components/ # Reusable components +│ └── styles/ # Global styles +├── public/ # Static assets (install scripts) +│ ├── install.sh # Unix installer +│ └── install.ps1 # Windows installer +├── astro.config.mjs # Astro configuration +└── package.json ``` ---- - -## Key Features +### Key Features -### Automatic Reshim Detection - -After `npm install -g` or `pip install`, shims prompt to run `dtvem reshim` to create shims for newly installed executables. - -### PATH Fallback - -When no dtvem version is configured, shims fall back to system PATH (excluding the shims directory). - -### Migration System - -The `migrate` command detects existing installations (nvm, pyenv, fnm, system) and offers to: -- Install versions via dtvem -- Preserve global packages (npm packages, pip packages) -- Clean up old installations (automated for version managers, manual instructions for system installs) - -**Note**: Configuration file preservation (`.npmrc`, `pip.conf`) is not yet implemented. - ---- - -## Coding Standards - -All code follows `GO_STYLEGUIDE.md`. Key points: - -- **Naming**: Avoid package/receiver repetition, no "Get" prefix -- **Errors**: Use structured errors, `%w` for wrapping -- **Paths**: Always use `filepath.Join()`, never hardcode `/` or `\` -- **Output**: Use `internal/ui` package for user-facing messages -- **Tests**: Must pass all linters (no special treatment for `*_test.go`) - ---- - -## Testing - -### Running Tests - -```bash -cd src && go test ./... # All tests -cd src && go test ./internal/config -v # Specific package -cd src && go test -cover ./... # With coverage -``` - -### Test Coverage - -- `internal/config/` - Paths, version resolution, git root detection -- `internal/runtime/` - Registry, provider test harness -- `internal/shim/` - Shim mapping, cache, file operations -- `internal/ui/` - Output formatting functions -- `internal/testutil/` - Test utility functions -- `runtimes/*/` - Provider contract validation -- `cmd/` - Command helpers (migrate, uninstall) - -### Provider Test Harness - -`internal/runtime/provider_test_harness.go` validates all Provider implementations consistently. Used by node, python, and ruby providers. - -### Import Cycle Avoidance - -- Runtime providers import `internal/shim` -- Tests in `internal/shim/` use mock providers (not real ones) -- Real providers tested via the test harness in their own packages - ---- +- Static site generation with Astro +- Install script hosting (`dtvem.io/install.sh`, `dtvem.io/install.ps1`) +- Documentation pages +- Cloudflare Pages deployment ## CI/CD -### Workflows in This Repo (`.github/workflows/`) - -| Workflow | Trigger | Purpose | -|----------|---------|---------| -| `build.yml` | PR, push to main | Lint, build, test on Windows/macOS/Linux. Posts coverage reports on PRs | -| `release.yml` | Manual dispatch | Full release: validate, build 5 platforms, create GitHub Release, notify | -| `commit-lint.yml` | PR | Validate PR titles follow conventional commits | -| `script-lint.yml` | PR (install scripts) | Lint install.sh and install.ps1 with shellcheck/PSScriptAnalyzer | -| `contributors.yml` | Push to main | Auto-update contributors section in README | -| `preview-changelog.yml` | PR | Preview release notes for PRs | -| `integration-test.yml` | Manual dispatch | Full integration test suite (runtimes + migrations) | -| `integration-test-runtimes.yml` | Manual dispatch | Runtime install/uninstall tests only | -| `integration-test-migrations.yml` | Manual dispatch | Migration tests only (all platforms/managers) | -| `generate-manifests-from-r2.yml` | Manual/scheduled | Generate version manifests from R2 mirror | -| `deploy-manifests.yml` | Push to main (manifests/) | Deploy manifest files to R2 | -| `mirror-all.yml` | Manual dispatch | Mirror all runtime binaries to R2 | -| `mirror-sync.yml` | Scheduled | Sync new versions to R2 mirror | - -### Reusable Workflows (from `dtvem/.github` repo) - -Integration tests and changelog generation use reusable workflows stored in the separate `dtvem/.github` repository: - -**Runtime Tests:** -- `integration-test-node.yml` - Node.js install/global/local/uninstall -- `integration-test-python.yml` - Python install/global/local/uninstall -- `integration-test-ruby.yml` - Ruby install/global/local/uninstall - -**Migration Tests** (per runtime × platform × version manager): -- `integration-test-migrate-{runtime}-{platform}-{manager}.yml` -- Platforms: ubuntu, macos, windows -- Managers: system, nvm, fnm, pyenv, rbenv, uru - -**Utilities:** -- `generate-changelog.yml` - Generate release notes from commits - -Version injected at build time; main branch always shows `Version = "dev"`. - ---- - -## Installation Scripts - -### One-Command Installers - -**Unix:** -```bash -curl -fsSL dtvem.io/install.sh | bash -``` - -**Windows:** -```powershell -irm dtvem.io/install.ps1 | iex -``` - -Features: Auto platform detection, PATH configuration, runs `dtvem init`. - ---- - -## UI Output System - -Use `internal/ui` for all user-facing output: - -| Function | Purpose | -|----------|---------| -| `Success()` | Green ✓ - completed operations | -| `Error()` | Red ✗ - failures | -| `Warning()` | Yellow ⚠ - non-critical issues | -| `Info()` | Cyan → - informational | -| `Progress()` | Blue → (indented) - operation steps | -| `Header()` | Bold - section titles | -| `Highlight()` | Cyan bold - emphasis | -| `HighlightVersion()` | Magenta bold - version numbers | -| `ActiveVersion()` | Green bold - active/selected versions | -| `DimText()` | Gray/faint - secondary info | -| `Debug()` / `Debugf()` | Debug output (requires `DTVEM_VERBOSE`) | - ---- - -## Important Notes +GitHub Actions workflows in `.github/workflows/`: -- **Cross-platform paths**: Use `filepath.Join()`, check `runtime.GOOS` -- **Windows shims**: Must be `.exe` files -- **Shim execution**: Unix uses `syscall.Exec()`; Windows uses `exec.Command()` -- **Version strings**: Strip `v` prefix (e.g., "v22.0.0" → "22.0.0") -- **Registry is global**: Providers auto-register on import via `init()` -- **Verbose mode**: Set `DTVEM_VERBOSE=1` for debug output +- **build.yml** - Build validation on push/PR +- **commit-lint.yml** - Validate PR titles follow conventional commits +- **contributors.yml** - Auto-update contributors in README From 772f0a3ed2a1d5a7a32c1646f86052f2cdbc9a22 Mon Sep 17 00:00:00 2001 From: "Calvin A. Allen" Date: Mon, 5 Jan 2026 09:38:37 -0500 Subject: [PATCH 2/3] chore: add commitlint config --- commitlint.config.js | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 commitlint.config.js diff --git a/commitlint.config.js b/commitlint.config.js new file mode 100644 index 0000000..84dcb12 --- /dev/null +++ b/commitlint.config.js @@ -0,0 +1,3 @@ +module.exports = { + extends: ['@commitlint/config-conventional'], +}; From 39b19ab6087fe31d316ba027bc69e76d20d59d96 Mon Sep 17 00:00:00 2001 From: "Calvin A. Allen" Date: Mon, 5 Jan 2026 09:40:40 -0500 Subject: [PATCH 3/3] chore: use .commitlintrc.yml matching other repos --- .commitlintrc.yml | 80 ++++++++++++++++++++++++++++++++++++++++++++ commitlint.config.js | 3 -- 2 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 .commitlintrc.yml delete mode 100644 commitlint.config.js diff --git a/.commitlintrc.yml b/.commitlintrc.yml new file mode 100644 index 0000000..9d61732 --- /dev/null +++ b/.commitlintrc.yml @@ -0,0 +1,80 @@ +# Commitlint configuration for conventional commits +# Based on: https://www.conventionalcommits.org/ + +extends: + - '@commitlint/config-conventional' + +rules: + # Type enum - allowed commit types + type-enum: + - 2 # Level: error + - always + - # Allowed types: + - feat # New feature + - fix # Bug fix + - docs # Documentation only changes + - style # Code style changes (formatting, missing semi-colons, etc) + - refactor # Code refactoring (neither fixes a bug nor adds a feature) + - perf # Performance improvements + - test # Adding or updating tests + - build # Changes to build system or dependencies + - ci # CI/CD configuration changes + - chore # Other changes that don't modify src or test files + - revert # Revert a previous commit + + # Type case should be lowercase + type-case: + - 2 + - always + - lower-case + + # Type must not be empty + type-empty: + - 2 + - never + + # Scope case should be lowercase + scope-case: + - 2 + - always + - lower-case + + # Subject must not be empty + subject-empty: + - 2 + - never + + # Subject must not end with a period + subject-full-stop: + - 2 + - never + - '.' + + # Disable subject-case to allow uppercase abbreviations (PR, API, CLI, etc.) + subject-case: + - 0 + + # Header (first line) max length + header-max-length: + - 2 + - always + - 72 + + # Body should have a blank line before it + body-leading-blank: + - 1 # Warning level + - always + + # Footer should have a blank line before it + footer-leading-blank: + - 1 # Warning level + - always + + # Body max line length + body-max-line-length: + - 1 # Warning level + - always + - 100 + +# Help URL shown in error messages +helpUrl: 'https://www.conventionalcommits.org/' diff --git a/commitlint.config.js b/commitlint.config.js deleted file mode 100644 index 84dcb12..0000000 --- a/commitlint.config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - extends: ['@commitlint/config-conventional'], -};